source: josm/trunk/test/unit/org/openstreetmap/josm/actions/CreateMultipolygonActionTest.java@ 18106

Last change on this file since 18106 was 17429, checked in by GerdP, 3 years ago

fix #20325: Update Multipolygon removes tags instead of moving them to relation

  • rewrite handling of update multipolygon cases
  • let removeTagsFromWaysIfNeeded() check if getDataset() returns null instead of checking isNew(). I assume it was always meant to work like this. JoinAreasAction works fine with that and I hope no plugin relies on the old behaviour.
  • add regression unit test and more unit tests to improve coverage
  • Property svn:eol-style set to native
File size: 13.8 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.assertFalse;
6import static org.junit.jupiter.api.Assertions.assertNotNull;
7import static org.junit.jupiter.api.Assertions.assertNull;
8import static org.junit.jupiter.api.Assertions.assertTrue;
9
10import java.nio.file.Files;
11import java.nio.file.Paths;
12import java.util.Collection;
13import java.util.Map;
14import java.util.TreeMap;
15
16import org.junit.jupiter.api.Test;
17import org.junit.jupiter.api.extension.RegisterExtension;
18import org.openstreetmap.josm.TestUtils;
19import org.openstreetmap.josm.command.SequenceCommand;
20import org.openstreetmap.josm.data.osm.DataSet;
21import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
22import org.openstreetmap.josm.data.osm.Relation;
23import org.openstreetmap.josm.data.osm.RelationMember;
24import org.openstreetmap.josm.data.osm.Way;
25import org.openstreetmap.josm.data.osm.search.SearchCompiler;
26import org.openstreetmap.josm.data.osm.search.SearchParseError;
27import org.openstreetmap.josm.data.osm.search.SearchSetting;
28import org.openstreetmap.josm.gui.MainApplication;
29import org.openstreetmap.josm.gui.layer.Layer;
30import org.openstreetmap.josm.gui.layer.OsmDataLayer;
31import org.openstreetmap.josm.io.OsmReader;
32import org.openstreetmap.josm.testutils.JOSMTestRules;
33import org.openstreetmap.josm.tools.Pair;
34import org.openstreetmap.josm.tools.SubclassFilteredCollection;
35
36import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
37
38/**
39 * Unit test of {@link CreateMultipolygonAction}
40 */
41class CreateMultipolygonActionTest {
42
43 /**
44 * Setup test.
45 */
46 @RegisterExtension
47 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
48 public JOSMTestRules test = new JOSMTestRules().projection().main().preferences().mapStyles();
49
50 private static Map<String, String> getRefToRoleMap(Relation relation) {
51 Map<String, String> refToRole = new TreeMap<>();
52 String ref = relation.get("ref");
53 if (ref != null) {
54 refToRole.put(ref, "outer");
55 }
56 for (RelationMember i : relation.getMembers()) {
57 ref = i.getMember().get("ref");
58 if (ref != null) {
59 refToRole.put(ref, i.getRole());
60 }
61 }
62 return refToRole;
63 }
64
65 private static SearchSetting regexpSearch(String search) {
66 SearchSetting setting = new SearchSetting();
67 setting.text = search;
68 setting.regexSearch = true;
69 return setting;
70 }
71
72 @SuppressWarnings("unchecked")
73 private static Relation createMultipolygon(Collection<Way> ways, String pattern, Relation r, boolean runCmd)
74 throws SearchParseError {
75 Pair<SequenceCommand, Relation> cmd = CreateMultipolygonAction.createMultipolygonCommand(
76 (Collection<Way>) (Collection<?>) SubclassFilteredCollection.filter(ways, SearchCompiler.compile(regexpSearch(pattern))), r);
77 if (runCmd) {
78 cmd.a.executeCommand();
79 }
80 return cmd.b;
81 }
82
83 @Test
84 void testCreate1() throws Exception {
85 DataSet ds = OsmReader.parseDataSet(Files.newInputStream(Paths.get(TestUtils.getTestDataRoot(), "create_multipolygon.osm")), null);
86 Pair<SequenceCommand, Relation> mp = CreateMultipolygonAction.createMultipolygonCommand(ds.getWays(), null);
87 assertEquals("Sequence: Create multipolygon", mp.a.getDescriptionText());
88 assertEquals("{1=outer, 1.1=inner, 1.1.1=outer, 1.1.2=outer, 1.2=inner}", getRefToRoleMap(mp.b).toString());
89 }
90
91 @Test
92 void testCreate2() throws Exception {
93 DataSet ds = OsmReader.parseDataSet(Files.newInputStream(Paths.get(TestUtils.getTestDataRoot(), "create_multipolygon.osm")), null);
94 Relation mp = createMultipolygon(ds.getWays(), "ref=1 OR ref:1.1.", null, true);
95 assertEquals("{1=outer, 1.1.1=inner, 1.1.2=inner}", getRefToRoleMap(mp).toString());
96 }
97
98 @Test
99 void testUpdate1() throws Exception {
100 DataSet ds = OsmReader.parseDataSet(Files.newInputStream(Paths.get(TestUtils.getTestDataRoot(), "create_multipolygon.osm")), null);
101 Relation mp = createMultipolygon(ds.getWays(), "ref=\".*1$\"", null, true);
102 assertEquals(3, mp.getMembersCount());
103 assertEquals("{1=outer, 1.1=inner, 1.1.1=outer}", getRefToRoleMap(mp).toString());
104 Relation mp2 = createMultipolygon(ds.getWays(), "ref=1.2", mp, true);
105 assertEquals(4, mp2.getMembersCount());
106 assertEquals("{1=outer, 1.1=inner, 1.1.1=outer, 1.2=inner}", getRefToRoleMap(mp2).toString());
107 }
108
109 @Test
110 void testUpdate2() throws Exception {
111 DataSet ds = OsmReader.parseDataSet(Files.newInputStream(Paths.get(TestUtils.getTestDataRoot(), "create_multipolygon.osm")), null);
112 Relation mp = createMultipolygon(ds.getWays(), "ref=1 OR ref:1.1.1", null, true);
113 assertEquals("{1=outer, 1.1.1=inner}", getRefToRoleMap(mp).toString());
114 Relation mp2 = createMultipolygon(ds.getWays(), "ref=1.1 OR ref=1.2 OR ref=1.1.2", mp, false);
115 assertEquals("{1=outer, 1.1=inner, 1.1.1=outer, 1.1.2=outer, 1.2=inner}", getRefToRoleMap(mp2).toString());
116 }
117
118 /**
119 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/17767">Bug #17767</a>.
120 * @throws Exception if an error occurs
121 */
122 @Test
123 void testTicket17767() throws Exception {
124 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(17767, "upd-mp.osm"), null);
125 Layer layer = new OsmDataLayer(ds, null, null);
126 MainApplication.getLayerManager().addLayer(layer);
127 try {
128 CreateMultipolygonAction updateAction = new CreateMultipolygonAction(true);
129 CreateMultipolygonAction createAction = new CreateMultipolygonAction(false);
130 assertFalse(updateAction.isEnabled());
131 assertFalse(createAction.isEnabled());
132 ds.setSelected(ds.getPrimitiveById(189944949L, OsmPrimitiveType.WAY));
133 assertFalse(updateAction.isEnabled());
134 assertTrue(createAction.isEnabled());
135 } finally {
136 MainApplication.getLayerManager().removeLayer(layer);
137 }
138 }
139
140 /**
141 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/17768">Bug #17768</a>.
142 * @throws Exception if an error occurs
143 */
144 @Test
145 void testTicket17768() throws Exception {
146 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(17768, "dupmem.osm"), null);
147 Layer layer = new OsmDataLayer(ds, null, null);
148 MainApplication.getLayerManager().addLayer(layer);
149 try {
150 Relation old = (Relation) ds.getPrimitiveById(580092, OsmPrimitiveType.RELATION);
151 assertEquals(3, old.getMembersCount());
152 Relation mp = createMultipolygon(ds.getWays(), "type:way", old, true);
153 assertEquals(mp.getPrimitiveId(), old.getPrimitiveId());
154 assertEquals(2, mp.getMembersCount());
155 } finally {
156 MainApplication.getLayerManager().removeLayer(layer);
157 }
158
159 }
160
161 /**
162 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/20110">Bug #20110</a>.
163 * @throws Exception if an error occurs
164 */
165 @Test
166 void testTicket20110() throws Exception {
167 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(20110, "data.osm"), null);
168 assertEquals(1, ds.getRelations().size());
169 Relation mp = ds.getRelations().iterator().next();
170 assertEquals("wetland", mp.get("natural"));
171 long numCoastlineWays = ds.getWays().stream().filter(w -> "coastline".equals(w.get("natural"))).count();
172 Relation modMp = createMultipolygon(ds.getWays(), "type:way", mp, false);
173 assertNotNull(modMp);
174 assertEquals("wetland", modMp.get("natural"));
175 assertEquals(numCoastlineWays, ds.getWays().stream().filter(w -> "coastline".equals(w.get("natural"))).count());
176 }
177
178 /**
179 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/20230">Bug #20230</a>.
180 * @throws Exception if an error occurs
181 */
182 @Test
183 void testTicket20230() throws Exception {
184 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(20230, "data.osm"), null);
185 assertEquals(1, ds.getRelations().size());
186 Relation mp = ds.getRelations().iterator().next();
187 Relation modMp = createMultipolygon(ds.getWays(), "type:way", mp, true);
188 assertNotNull(modMp);
189 assertEquals(1, ds.getRelations().size());
190 modMp = ds.getRelations().iterator().next();
191 assertTrue(modMp.hasTag("building", "yes"));
192 assertEquals(0, ds.getWays().stream().filter(w -> w.hasTag("building", "yes")).count());
193 }
194
195 /**
196 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/20238">Bug #20238</a>.
197 * @throws Exception if an error occurs
198 */
199 @Test
200 void testTicket20238() throws Exception {
201 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(20238, "data.osm"), null);
202 assertEquals(1, ds.getRelations().size());
203 Relation mp = ds.getRelations().iterator().next();
204 assertFalse(ds.getRelations().iterator().next().hasTag("building", "yes"));
205 assertEquals(1, ds.getWays().stream().filter(w -> w.hasTag("building", "yes")).count());
206 Pair<SequenceCommand, Relation> cmd = CreateMultipolygonAction.createMultipolygonCommand(ds.getWays(), mp);
207 assertNotNull(cmd);
208 cmd.a.executeCommand();
209 assertEquals(1, ds.getRelations().size());
210 assertTrue(ds.getRelations().iterator().next().hasTag("building", "yes"));
211 assertEquals(0, ds.getWays().stream().filter(w -> w.hasTag("building", "yes")).count());
212 cmd.a.undoCommand();
213 assertEquals(1, ds.getRelations().size());
214 assertFalse(ds.getRelations().iterator().next().hasTag("building", "yes"));
215 assertEquals(1, ds.getWays().stream().filter(w -> w.hasTag("building", "yes")).count());
216 }
217
218 /**
219 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/20325">Bug #20325</a>.
220 * @throws Exception if an error occurs
221 */
222 @Test
223 void testTicket20325() throws Exception {
224 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(20325, "data.osm"), null);
225 assertEquals(1, ds.getRelations().size());
226 Relation mp = ds.getRelations().iterator().next();
227 assertFalse(ds.getRelations().iterator().next().hasTag("landuse", "farmland"));
228 assertEquals(1, ds.getWays().stream().filter(w -> w.hasTag("landuse", "farmland")).count());
229 Pair<SequenceCommand, Relation> cmd = CreateMultipolygonAction.createMultipolygonCommand(ds.getWays(), mp);
230 assertNotNull(cmd);
231 cmd.a.executeCommand();
232 assertEquals(1, ds.getRelations().size());
233 assertTrue(ds.getRelations().iterator().next().hasTag("landuse", "farmland"));
234 assertEquals(0, ds.getWays().stream().filter(w -> w.hasTag("landuse", "farmland")).count());
235 cmd.a.undoCommand();
236 assertEquals(1, ds.getRelations().size());
237 assertFalse(ds.getRelations().iterator().next().hasTag("landuse", "farmland"));
238 assertEquals(1, ds.getWays().stream().filter(w -> w.hasTag("landuse", "farmland")).count());
239 }
240
241 /**
242 * Coverage test for <a href="https://josm.openstreetmap.de/ticket/20325">Bug #20325</a>.
243 * New relation, no update needed, no command should be produced.
244 * @throws Exception if an error occurs
245 */
246 @Test
247 void testTicket20325New() throws Exception {
248 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(20325, "no-change-new.osm"), null);
249 assertEquals(1, ds.getRelations().size());
250 Relation mp = ds.getRelations().iterator().next();
251 Pair<SequenceCommand, Relation> cmd = CreateMultipolygonAction.createMultipolygonCommand(ds.getWays(), mp);
252 assertNull(cmd);
253 }
254
255 /**
256 * Coverage test for <a href="https://josm.openstreetmap.de/ticket/20325">Bug #20325</a>.
257 * Old relation, no update needed, no command should be produced.
258 * @throws Exception if an error occurs
259 */
260 @Test
261 void testTicket20325Old() throws Exception {
262 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(20325, "no-change-old.osm"), null);
263 assertEquals(1, ds.getRelations().size());
264 Relation mp = ds.getRelations().iterator().next();
265 Pair<SequenceCommand, Relation> cmd = CreateMultipolygonAction.createMultipolygonCommand(ds.getWays(), mp);
266 assertNull(cmd);
267 }
268
269 /**
270 * Coverage test for <a href="https://josm.openstreetmap.de/ticket/20325">Bug #20325</a>.
271 * Relation cannot be updated but produces warnings. Doesn't test that a popup was shown.
272 * @throws Exception if an error occurs
273 */
274 @Test
275 void testTicket20325Invalid() throws Exception {
276 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(20325, "invalid-new-upldate.osm"), null);
277 assertEquals(1, ds.getRelations().size());
278 Relation mp = ds.getRelations().iterator().next();
279 Pair<SequenceCommand, Relation> cmd = CreateMultipolygonAction.createMultipolygonCommand(ds.getWays(), mp);
280 assertNull(cmd);
281 }
282
283 /**
284 * Coverage test for <a href="https://josm.openstreetmap.de/ticket/20325">Bug #20325</a>.
285 * Relation needs no updates but produces warnings. Doesn't test that a popup was shown.
286 * @throws Exception if an error occurs
287 */
288 @Test
289 void testTicket20325NoUpdateWarning() throws Exception {
290 DataSet ds = OsmReader.parseDataSet(TestUtils.getRegressionDataStream(20325, "update-no-command-warning.osm"), null);
291 assertEquals(1, ds.getRelations().size());
292 Relation mp = ds.getRelations().iterator().next();
293 Pair<SequenceCommand, Relation> cmd = CreateMultipolygonAction.createMultipolygonCommand(ds.getWays(), mp);
294 assertNull(cmd);
295 }
296
297}
Note: See TracBrowser for help on using the repository browser.