source: josm/trunk/test/unit/org/openstreetmap/josm/actions/JoinAreasActionTest.java@ 17275

Last change on this file since 17275 was 17275, checked in by Don-vip, 3 years ago

see #16567 - upgrade almost all tests to JUnit 5, except those depending on WiremockRule

See https://github.com/tomakehurst/wiremock/issues/684

  • Property svn:eol-style set to native
File size: 11.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.junit.jupiter.api.Assertions.assertEquals;
5import static org.junit.jupiter.api.Assertions.assertTrue;
6
7import java.io.IOException;
8import java.io.InputStream;
9import java.nio.file.Files;
10import java.nio.file.Paths;
11import java.util.Arrays;
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.Objects;
15import java.util.Set;
16
17import org.junit.jupiter.api.Test;
18import org.junit.jupiter.api.extension.RegisterExtension;
19import org.openstreetmap.josm.TestUtils;
20import org.openstreetmap.josm.actions.search.SearchAction;
21import org.openstreetmap.josm.data.Bounds;
22import org.openstreetmap.josm.data.DataSource;
23import org.openstreetmap.josm.data.osm.DataSet;
24import org.openstreetmap.josm.data.osm.IPrimitive;
25import org.openstreetmap.josm.data.osm.Node;
26import org.openstreetmap.josm.data.osm.OsmPrimitive;
27import org.openstreetmap.josm.data.osm.Relation;
28import org.openstreetmap.josm.data.osm.RelationMember;
29import org.openstreetmap.josm.data.osm.Way;
30import org.openstreetmap.josm.data.osm.search.SearchMode;
31import org.openstreetmap.josm.gui.MainApplication;
32import org.openstreetmap.josm.gui.layer.Layer;
33import org.openstreetmap.josm.gui.layer.OsmDataLayer;
34import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
35import org.openstreetmap.josm.io.IllegalDataException;
36import org.openstreetmap.josm.io.OsmReader;
37import org.openstreetmap.josm.testutils.JOSMTestRules;
38import org.openstreetmap.josm.tools.MultiMap;
39import org.openstreetmap.josm.tools.Utils;
40
41import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
42
43/**
44 * Unit tests of {@link JoinAreasAction} class.
45 */
46class JoinAreasActionTest {
47
48 /**
49 * Setup test.
50 */
51 @RegisterExtension
52 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
53 public JOSMTestRules test = new JOSMTestRules().main().projection().preferences();
54
55 /**
56 * Non-regression test for bug #9599.
57 * @throws IOException if any I/O error occurs
58 * @throws IllegalDataException if OSM parsing fails
59 */
60 @Test
61 void testTicket9599() throws IOException, IllegalDataException {
62 try (InputStream is = TestUtils.getRegressionDataStream(9599, "ex5.osm")) {
63 DataSet ds = OsmReader.parseDataSet(is, null);
64 Layer layer = new OsmDataLayer(ds, null, null);
65 MainApplication.getLayerManager().addLayer(layer);
66 try {
67 new JoinAreasAction(false).join(ds.getWays());
68 Collection<IPrimitive> found = SearchAction.searchAndReturn("type:way", SearchMode.replace);
69 assertEquals(1, found.size());
70 assertEquals(257786939, found.iterator().next().getUniqueId());
71 } finally {
72 // Ensure we clean the place before leaving, even if test fails.
73 MainApplication.getLayerManager().removeLayer(layer);
74 }
75 }
76 }
77
78 /**
79 * Non-regression test for bug #9599.
80 * @throws IOException if any I/O error occurs
81 * @throws IllegalDataException if OSM parsing fails
82 */
83 @Test
84 void testTicket9599Simple() throws IOException, IllegalDataException {
85 try (InputStream is = TestUtils.getRegressionDataStream(9599, "three_old.osm")) {
86 DataSet ds = OsmReader.parseDataSet(is, null);
87 ds.addDataSource(new DataSource(new Bounds(-90, -180, 90, 180), "Everywhere"));
88 Layer layer = new OsmDataLayer(ds, null, null);
89 MainApplication.getLayerManager().addLayer(layer);
90 try {
91 new JoinAreasAction(false).join(ds.getWays());
92 Collection<IPrimitive> found = SearchAction.searchAndReturn("type:way", SearchMode.replace);
93 assertEquals(1, found.size());
94 assertEquals(31567319, found.iterator().next().getUniqueId());
95 } finally {
96 // Ensure we clean the place before leaving, even if test fails.
97 MainApplication.getLayerManager().removeLayer(layer);
98 }
99 }
100 }
101
102 /**
103 * Non-regression test for bug #10511.
104 * @throws IOException if any I/O error occurs
105 * @throws IllegalDataException if OSM parsing fails
106 */
107 @Test
108 void testTicket10511() throws IOException, IllegalDataException {
109 try (InputStream is = TestUtils.getRegressionDataStream(10511, "10511_mini.osm")) {
110 DataSet ds = OsmReader.parseDataSet(is, null);
111 Layer layer = new OsmDataLayer(ds, null, null);
112 MainApplication.getLayerManager().addLayer(layer);
113 try {
114 new JoinAreasAction(false).join(ds.getWays());
115 Collection<IPrimitive> found = SearchAction.searchAndReturn("type:way", SearchMode.replace);
116 assertEquals(1, found.size());
117 } finally {
118 // Ensure we clean the place before leaving, even if test fails.
119 MainApplication.getLayerManager().removeLayer(layer);
120 }
121 }
122 }
123
124 /**
125 * Non-regression test for bug #11992.
126 * @throws IOException if any I/O error occurs
127 * @throws IllegalDataException if OSM parsing fails
128 */
129 @Test
130 void testTicket11992() throws IOException, IllegalDataException {
131 try (InputStream is = TestUtils.getRegressionDataStream(11992, "shapes.osm")) {
132 DataSet ds = OsmReader.parseDataSet(is, null);
133 assertEquals(10, ds.getWays().size());
134 Layer layer = new OsmDataLayer(ds, null, null);
135 MainApplication.getLayerManager().addLayer(layer);
136 for (String ref : new String[]{"A", "B", "C", "D", "E"}) {
137 System.out.print("Joining ways " + ref);
138 Collection<IPrimitive> found = SearchAction.searchAndReturn("type:way ref="+ref, SearchMode.replace);
139 assertEquals(2, found.size());
140
141 MainApplication.getMenu().joinAreas.join(Utils.filteredCollection(found, Way.class));
142
143 Collection<IPrimitive> found2 = SearchAction.searchAndReturn("type:way ref="+ref, SearchMode.replace);
144 assertEquals(1, found2.size());
145 System.out.println(" ==> OK");
146 }
147 }
148 }
149
150 /**
151 * Non-regression test for bug #18744.
152 * @throws IOException if any I/O error occurs
153 * @throws IllegalDataException if OSM parsing fails
154 */
155 @Test
156 void testTicket18744() throws IOException, IllegalDataException {
157 try (InputStream is = TestUtils.getRegressionDataStream(18744, "18744-sample.osm")) {
158 DataSet ds = OsmReader.parseDataSet(is, null);
159 ds.addDataSource(new DataSource(new Bounds(-90, -180, 90, 180), "Everywhere"));
160 Layer layer = new OsmDataLayer(ds, null, null);
161 MainApplication.getLayerManager().addLayer(layer);
162 try {
163 assertEquals(3, ds.getWays().size());
164 new JoinAreasAction(false).join(ds.getWays());
165 // join should not have changed anything
166 assertEquals(3, ds.getWays().size());
167 } finally {
168 // Ensure we clean the place before leaving, even if test fails.
169 MainApplication.getLayerManager().removeLayer(layer);
170 }
171 }
172 }
173
174
175 /**
176 * Non-regression test which checks example files in nodist/data
177 * @throws Exception if an error occurs
178 */
179 @Test
180 @SuppressWarnings({ "rawtypes", "unchecked" })
181 void testExamples() throws Exception {
182 DataSet dsToJoin, dsExpected;
183 try (InputStream is = Files.newInputStream(Paths.get("nodist/data/Join_Areas_Tests.osm"))) {
184 dsToJoin = OsmReader.parseDataSet(is, NullProgressMonitor.INSTANCE);
185 }
186 try (InputStream is = Files.newInputStream(Paths.get("nodist/data/Join_Areas_Tests_joined.osm"))) {
187 dsExpected = OsmReader.parseDataSet(is, NullProgressMonitor.INSTANCE);
188 }
189
190 // set current edit layer
191 MainApplication.getLayerManager().addLayer(new OsmDataLayer(dsToJoin, "join", null));
192
193 Collection<OsmPrimitive> testPrims = dsToJoin.getPrimitives(osm -> osm.get("test") != null);
194 MultiMap<String, OsmPrimitive> tests = new MultiMap<>();
195 for (OsmPrimitive testPrim : testPrims) {
196 tests.put(testPrim.get("test"), testPrim);
197 }
198 for (String test : tests.keySet()) {
199 Collection<OsmPrimitive> primitives = tests.get(test);
200 for (OsmPrimitive osm : primitives) {
201 assertTrue(osm instanceof Way, test + "; expected way, but got: " + osm);
202 }
203 new JoinAreasAction(false).join((Collection) primitives);
204 Collection<OsmPrimitive> joinedCol = dsToJoin.getPrimitives(osm -> !osm.isDeleted() && Objects.equals(osm.get("test"), test));
205 assertEquals(1, joinedCol.size(), "in test " + test + ":");
206 Collection<OsmPrimitive> expectedCol = dsExpected.getPrimitives(osm -> !osm.isDeleted() && Objects.equals(osm.get("test"), test));
207 assertEquals(1, expectedCol.size(), "in test " + test + ":");
208 OsmPrimitive osmJoined = joinedCol.iterator().next();
209 OsmPrimitive osmExpected = expectedCol.iterator().next();
210 assertTrue(isSemanticallyEqual(osmExpected, osmJoined), "difference in test " + test);
211 }
212 }
213
214 /**
215 * Check if 2 primitives are semantically equal as result of a join areas
216 * operation.
217 * @param osm1 first primitive
218 * @param osm2 second primitive
219 * @return true if both primitives are semantically equal
220 */
221 private boolean isSemanticallyEqual(OsmPrimitive osm1, OsmPrimitive osm2) {
222 if (osm1 instanceof Node && osm2 instanceof Node)
223 return isSemanticallyEqualNode((Node) osm1, (Node) osm2);
224 if (osm1 instanceof Way && osm2 instanceof Way)
225 return isSemanticallyEqualWay((Way) osm1, (Way) osm2);
226 if (osm1 instanceof Relation && osm2 instanceof Relation)
227 return isSemanticallyEqualRelation((Relation) osm1, (Relation) osm2);
228 return false;
229 }
230
231 private boolean isSemanticallyEqualRelation(Relation r1, Relation r2) {
232 if (!r1.getKeys().equals(r2.getKeys())) return false;
233 if (r1.getMembersCount() != r2.getMembersCount()) return false;
234 Set<RelationMember> matchCandidates = new HashSet<>(r2.getMembers());
235 for (RelationMember rm : r1.getMembers()) {
236 RelationMember matched = matchCandidates.stream()
237 .filter(m -> rm.getRole().equals(m.getRole()))
238 .filter(m -> isSemanticallyEqual(rm.getMember(), m.getMember()))
239 .findFirst().orElse(null);
240 if (matched == null) return false;
241 matchCandidates.remove(matched);
242 }
243 return true;
244 }
245
246 private boolean isSemanticallyEqualWay(Way w1, Way w2) {
247 if (!w1.isClosed() || !w2.isClosed()) throw new UnsupportedOperationException();
248 if (!w1.getKeys().equals(w2.getKeys())) return false;
249 if (w1.getNodesCount() != w2.getNodesCount()) return false;
250 int n = w1.getNodesCount() - 1;
251 for (int dir : Arrays.asList(1, -1)) {
252 for (int i = 0; i < n; i++) {
253 boolean different = false;
254 for (int j = 0; j < n; j++) {
255 Node n1 = w1.getNode(j);
256 Node n2 = w2.getNode(Utils.mod(i + dir*j, n));
257 if (!isSemanticallyEqualNode(n1, n2)) {
258 different = true;
259 break;
260 }
261 }
262 if (!different)
263 return true;
264 }
265 }
266 return false;
267 }
268
269 private boolean isSemanticallyEqualNode(Node n1, Node n2) {
270 return n1.hasEqualSemanticAttributes(n2);
271 }
272}
Note: See TracBrowser for help on using the repository browser.