source: josm/trunk/test/unit/org/openstreetmap/josm/io/OsmReaderTest.java@ 16641

Last change on this file since 16641 was 16641, checked in by simon04, 4 years ago

fix #18258 - OsmReader: Allow end user to know what the original id of a feature was (patch by taylor.smock, modified)

  • Property svn:eol-style set to native
File size: 19.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.junit.Assert.assertEquals;
5import static org.junit.Assert.assertFalse;
6import static org.junit.Assert.assertNull;
7import static org.junit.Assert.assertTrue;
8import static org.junit.Assert.fail;
9
10import java.io.ByteArrayInputStream;
11import java.io.InputStream;
12import java.nio.charset.StandardCharsets;
13import java.nio.file.Files;
14import java.nio.file.Paths;
15import java.util.Arrays;
16
17import org.junit.Rule;
18import org.junit.Test;
19import org.openstreetmap.josm.TestUtils;
20import org.openstreetmap.josm.data.osm.DataSet;
21import org.openstreetmap.josm.data.osm.Node;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
24import org.openstreetmap.josm.gui.progress.ProgressMonitor;
25import org.openstreetmap.josm.io.OsmReader.Options;
26import org.openstreetmap.josm.testutils.JOSMTestRules;
27
28import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
29
30/**
31 * Unit tests of {@link OsmReader} class.
32 */
33public class OsmReaderTest {
34
35 /**
36 * Setup rule
37 */
38 @Rule
39 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
40 public JOSMTestRules test = new JOSMTestRules();
41
42 private static final class PostProcessorStub implements OsmServerReadPostprocessor {
43 boolean called;
44
45 @Override
46 public void postprocessDataSet(DataSet ds, ProgressMonitor progress) {
47 called = true;
48 }
49 }
50
51 /**
52 * Unit test of {@link OsmReader#registerPostprocessor} / {@link OsmReader#deregisterPostprocessor}.
53 * @throws Exception if any error occurs
54 */
55 @Test
56 public void testPostProcessors() throws Exception {
57 PostProcessorStub registered = new PostProcessorStub();
58 PostProcessorStub unregistered = new PostProcessorStub();
59
60 OsmReader.registerPostprocessor(registered);
61
62 OsmReader.registerPostprocessor(unregistered);
63 OsmReader.deregisterPostprocessor(unregistered);
64
65 try (InputStream in = Files.newInputStream(Paths.get(TestUtils.getTestDataRoot(), "empty.osm"))) {
66 OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
67 assertTrue(registered.called);
68 assertFalse(unregistered.called);
69 } finally {
70 OsmReader.deregisterPostprocessor(registered);
71 }
72 }
73
74 private static void testUnknown(String osm) throws Exception {
75 try (InputStream in = new ByteArrayInputStream(
76 ("<?xml version='1.0' encoding='UTF-8'?>" + osm).getBytes(StandardCharsets.UTF_8))) {
77 assertTrue(OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE).allPrimitives().isEmpty());
78 }
79 testUnknown(osm, true);
80 testUnknown(osm, false);
81 }
82
83 private static void testUnknown(String osm, boolean parseUnknownAttributes) throws Exception {
84 try (InputStream in = new ByteArrayInputStream(
85 ("<?xml version='1.0' encoding='UTF-8'?>" + osm).getBytes(StandardCharsets.UTF_8))) {
86 assertTrue(OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE, Options.CONVERT_UNKNOWN_TO_TAGS).allPrimitives()
87 .isEmpty());
88 }
89 testUnknown(osm, parseUnknownAttributes, true);
90 testUnknown(osm, parseUnknownAttributes, true);
91 }
92
93 private static void testUnknown(String osm, boolean parseUnknownAttributes, boolean keepOriginalId)
94 throws Exception {
95 try (InputStream in = new ByteArrayInputStream(
96 ("<?xml version='1.0' encoding='UTF-8'?>" + osm).getBytes(StandardCharsets.UTF_8))) {
97 assertTrue(OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE, Options.CONVERT_UNKNOWN_TO_TAGS, Options.SAVE_ORIGINAL_ID)
98 .allPrimitives().isEmpty());
99 }
100 }
101
102 /**
103 * Unit test of {@link OsmReader#parseUnknown} - root case.
104 * @throws Exception if any error occurs
105 */
106 @Test
107 public void testUnknownRoot() throws Exception {
108 testUnknown("<nonosm/>");
109 }
110
111 /**
112 * Unit test of {@link OsmReader#parseUnknown} - meta case from Overpass API.
113 * @throws Exception if any error occurs
114 */
115 @Test
116 public void testUnknownMeta() throws Exception {
117 testUnknown("<osm version='0.6'><meta osm_base='2017-03-29T19:04:03Z'/></osm>");
118 }
119
120 /**
121 * Unit test of {@link OsmReader#parseUnknown} - note case from Overpass API.
122 * @throws Exception if any error occurs
123 */
124 @Test
125 public void testUnknownNote() throws Exception {
126 testUnknown("<osm version='0.6'><note>The data included in this document is from www.openstreetmap.org.</note></osm>");
127 }
128
129 /**
130 * Unit test of {@link OsmReader#parseUnknown} - other cases.
131 * @throws Exception if any error occurs
132 */
133 @Test
134 public void testUnknownTag() throws Exception {
135 testUnknown("<osm version='0.6'><foo>bar</foo></osm>");
136 testUnknown("<osm version='0.6'><foo><bar/></foo></osm>");
137 }
138
139 /**
140 * Test valid data.
141 * @param osm OSM data without XML prefix
142 * @return parsed data set
143 * @throws Exception if any error occurs
144 */
145 private static DataSet testValidData(String osm) throws Exception {
146 try (InputStream in = new ByteArrayInputStream(
147 ("<?xml version='1.0' encoding='UTF-8'?>" + osm).getBytes(StandardCharsets.UTF_8))) {
148 return OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
149 }
150 }
151
152 /**
153 * Test valid data.
154 * @param osm OSM data without XML prefix
155 * @param options The options to use to parse the data
156 * @return parsed data set
157 * @throws Exception if any error occurs
158 */
159 private static DataSet testValidData(String osm, Options... options) throws Exception {
160 try (InputStream in = new ByteArrayInputStream(
161 ("<?xml version='1.0' encoding='UTF-8'?>" + osm).getBytes(StandardCharsets.UTF_8))) {
162 return OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE, options);
163 }
164 }
165
166 /**
167 * Test invalid data.
168 * @param osm OSM data without XML prefix
169 * @param expectedError expected error message
170 * @throws Exception if any error occurs
171 */
172 private static void testInvalidData(String osm, String expectedError) throws Exception {
173 try (InputStream in = new ByteArrayInputStream(
174 ("<?xml version='1.0' encoding='UTF-8'?>" + osm).getBytes(StandardCharsets.UTF_8))) {
175 OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
176 fail("should throw exception");
177 } catch (IllegalDataException e) {
178 assertEquals(expectedError, e.getMessage());
179 }
180 testInvalidData(osm, expectedError, true);
181 testInvalidData(osm, expectedError, false);
182 }
183
184 /**
185 * Test invalid data.
186 *
187 * @param osm OSM data without XML prefix
188 * @param expectedError expected error message
189 * @param parseUnknownAttributes if true, attempt to parse unknown xml
190 * attributes
191 * @throws Exception if any error occurs
192 */
193 private static void testInvalidData(String osm, String expectedError, boolean parseUnknownAttributes)
194 throws Exception {
195 try (InputStream in = new ByteArrayInputStream(
196 ("<?xml version='1.0' encoding='UTF-8'?>" + osm).getBytes(StandardCharsets.UTF_8))) {
197 OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE, Options.CONVERT_UNKNOWN_TO_TAGS);
198 fail("should throw exception");
199 } catch (IllegalDataException e) {
200 assertEquals(expectedError, e.getMessage());
201 }
202 }
203
204 /**
205 * Test invalid UID.
206 * @throws Exception if any error occurs
207 */
208 @Test
209 public void testInvalidUid() throws Exception {
210 testInvalidData("<osm version='0.6'><node id='1' uid='nan'/></osm>",
211 "Illegal value for attribute 'uid'. Got 'nan'. (at line 1, column 82). 82 bytes have been read");
212 }
213
214 /**
215 * Test missing ID.
216 * @throws Exception if any error occurs
217 */
218 @Test
219 public void testMissingId() throws Exception {
220 testInvalidData("<osm version='0.6'><node/></osm>",
221 "Missing required attribute 'id'. (at line 1, column 65). 64 bytes have been read");
222 }
223
224 /**
225 * Test missing ref.
226 * @throws Exception if any error occurs
227 */
228 @Test
229 public void testMissingRef() throws Exception {
230 testInvalidData("<osm version='0.6'><way id='1' version='1'><nd/></way></osm>",
231 "Missing mandatory attribute 'ref' on <nd> of way 1. (at line 1, column 87). 88 bytes have been read");
232 testInvalidData("<osm version='0.6'><relation id='1' version='1'><member/></relation></osm>",
233 "Missing attribute 'ref' on member in relation 1. (at line 1, column 96). 101 bytes have been read");
234 }
235
236 /**
237 * Test illegal ref.
238 * @throws Exception if any error occurs
239 */
240 @Test
241 public void testIllegalRef() throws Exception {
242 testInvalidData("<osm version='0.6'><way id='1' version='1'><nd ref='0'/></way></osm>",
243 "Illegal value of attribute 'ref' of element <nd>. Got 0. (at line 1, column 95). 96 bytes have been read");
244 testInvalidData("<osm version='0.6'><way id='1' version='1'><nd ref='nan'/></way></osm>",
245 "Illegal long value for attribute 'ref'. Got 'nan'. (at line 1, column 97). 98 bytes have been read");
246
247 testInvalidData("<osm version='0.6'><relation id='1' version='1'><member type='node' ref='0'/></relation></osm>",
248 "Incomplete <member> specification with ref=0 (at line 1, column 116). 121 bytes have been read");
249 testInvalidData("<osm version='0.6'><relation id='1' version='1'><member type='node' ref='nan'/></relation></osm>",
250 "Illegal value for attribute 'ref' on member in relation 1. Got nan (at line 1, column 118). 123 bytes have been read");
251 }
252
253 /**
254 * Test missing member type.
255 * @throws Exception if any error occurs
256 */
257 @Test
258 public void testMissingType() throws Exception {
259 testInvalidData("<osm version='0.6'><relation id='1' version='1'><member ref='1'/></relation></osm>",
260 "Missing attribute 'type' on member 1 in relation 1. (at line 1, column 104). 109 bytes have been read");
261 }
262
263 /**
264 * Test illegal member type.
265 * @throws Exception if any error occurs
266 */
267 @Test
268 public void testIllegalType() throws Exception {
269 testInvalidData("<osm version='0.6'><relation id='1' version='1'><member type='foo' ref='1'/></relation></osm>",
270 "Illegal value for attribute 'type' on member 1 in relation 1. Got foo. (at line 1, column 115). 120 bytes have been read");
271 }
272
273 /**
274 * Test missing key/value.
275 * @throws Exception if any error occurs
276 */
277 @Test
278 public void testMissingKeyValue() throws Exception {
279 testInvalidData("<osm version='0.6'><node id='1' version='1'><tag/></node></osm>",
280 "Missing key or value attribute in tag. (at line 1, column 89). 89 bytes have been read");
281 testInvalidData("<osm version='0.6'><node id='1' version='1'><tag k='foo'/></node></osm>",
282 "Missing key or value attribute in tag. (at line 1, column 97). 97 bytes have been read");
283 testInvalidData("<osm version='0.6'><node id='1' version='1'><tag v='bar'/></node></osm>",
284 "Missing key or value attribute in tag. (at line 1, column 97). 97 bytes have been read");
285 }
286
287 /**
288 * Test missing version.
289 * @throws Exception if any error occurs
290 */
291 @Test
292 public void testMissingVersion() throws Exception {
293 testInvalidData("<osm/>",
294 "Missing mandatory attribute 'version'. (at line 1, column 45). 44 bytes have been read");
295 testInvalidData("<osm version='0.6'><node id='1'/></osm>",
296 "Missing attribute 'version' on OSM primitive with ID 1. (at line 1, column 72). 72 bytes have been read");
297 }
298
299 /**
300 * Test unsupported version.
301 * @throws Exception if any error occurs
302 */
303 @Test
304 public void testUnsupportedVersion() throws Exception {
305 testInvalidData("<osm version='0.1'/>",
306 "Unsupported version: 0.1 (at line 1, column 59). 58 bytes have been read");
307 }
308
309 /**
310 * Test illegal version.
311 * @throws Exception if any error occurs
312 */
313 @Test
314 public void testIllegalVersion() throws Exception {
315 testInvalidData("<osm version='0.6'><node id='1' version='nan'/></osm>",
316 "Illegal value for attribute 'version' on OSM primitive with ID 1. Got nan. (at line 1, column 86). 86 bytes have been read");
317 }
318
319 /**
320 * Test illegal changeset.
321 * @throws Exception if any error occurs
322 */
323 @Test
324 public void testIllegalChangeset() throws Exception {
325 testInvalidData("<osm version='0.6'><node id='1' version='1' changeset='nan'/></osm>",
326 "Illegal value for attribute 'changeset'. Got nan. (at line 1, column 100). 100 bytes have been read");
327 testInvalidData("<osm version='0.6'><node id='1' version='1' changeset='-1'/></osm>",
328 "Illegal value for attribute 'changeset'. Got -1. (at line 1, column 99). 99 bytes have been read");
329 }
330
331 /**
332 * Test GDPR-compliant changeset.
333 * @throws Exception if any error occurs
334 */
335 @Test
336 public void testGdprChangeset() throws Exception {
337 String gdprChangeset = "<osm version='0.6'><node id='1' version='1' changeset='0'/></osm>";
338 testValidData(gdprChangeset);
339 testValidData(gdprChangeset, Options.CONVERT_UNKNOWN_TO_TAGS);
340 testValidData(gdprChangeset, (Options) null);
341 testValidData(gdprChangeset, Options.SAVE_ORIGINAL_ID);
342 testValidData(gdprChangeset, Options.values());
343 }
344
345 /**
346 * Test invalid bounds.
347 * @throws Exception if any error occurs
348 */
349 @Test
350 public void testInvalidBounds() throws Exception {
351 testInvalidData("<osm version='0.6'><bounds/></osm>",
352 "Missing mandatory attributes on element 'bounds'. " +
353 "Got minlon='null',minlat='null',maxlon='null',maxlat='null', origin='null'. (at line 1, column 67). 72 bytes have been read");
354 testInvalidData("<osm version='0.6'><bounds minlon='0'/></osm>",
355 "Missing mandatory attributes on element 'bounds'. " +
356 "Got minlon='0',minlat='null',maxlon='null',maxlat='null', origin='null'. (at line 1, column 78). 83 bytes have been read");
357 testInvalidData("<osm version='0.6'><bounds minlon='0' minlat='0'/></osm>",
358 "Missing mandatory attributes on element 'bounds'. " +
359 "Got minlon='0',minlat='0',maxlon='null',maxlat='null', origin='null'. (at line 1, column 89). 94 bytes have been read");
360 testInvalidData("<osm version='0.6'><bounds minlon='0' minlat='0' maxlon='1'/></osm>",
361 "Missing mandatory attributes on element 'bounds'. " +
362 "Got minlon='0',minlat='0',maxlon='1',maxlat='null', origin='null'. (at line 1, column 100). 105 bytes have been read");
363 }
364
365 /**
366 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/14199">Bug #14199</a>.
367 * @throws Exception if any error occurs
368 */
369 @Test
370 public void testTicket14199() throws Exception {
371 try (InputStream in = TestUtils.getRegressionDataStream(14199, "emptytag.osm")) {
372 Way w = OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE).getWays().iterator().next();
373 assertEquals(1, w.getKeys().size());
374 assertNull(w.get(" "));
375 assertTrue(w.isModified());
376 }
377 }
378
379 /**
380 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/14754">Bug #14754</a>.
381 * @throws Exception if any error occurs
382 */
383 @Test
384 public void testTicket14754() throws Exception {
385 try (InputStream in = TestUtils.getRegressionDataStream(14754, "malformed_for_14754.osm")) {
386 OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
387 fail("should throw exception");
388 } catch (IllegalDataException e) {
389 assertEquals("Illegal value for attributes 'lat', 'lon' on node with ID 1425146006." +
390 " Got '550.3311950157', '10.49428298298'." +
391 " (at line 5, column 179). 578 bytes have been read", e.getMessage());
392 }
393 }
394
395 /**
396 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/14788">Bug #14788</a>.
397 * @throws Exception if any error occurs
398 */
399 @Test
400 public void testTicket14788() throws Exception {
401 try (InputStream in = TestUtils.getRegressionDataStream(14788, "remove_sign_test_4.osm")) {
402 OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
403 fail("should throw exception");
404 } catch (IllegalDataException e) {
405 assertEquals("Illegal value for attributes 'lat', 'lon' on node with ID 978." +
406 " Got 'nan', 'nan'." +
407 " (at line 4, column 151). 336 bytes have been read", e.getMessage());
408 }
409 }
410
411 /**
412 * Test reading remark from Overpass API.
413 * @throws Exception if any error occurs
414 */
415 @Test
416 public void testRemark() throws Exception {
417 String query = "<osm version=\"0.6\" generator=\"Overpass API 0.7.55.4 3079d8ea\">\r\n" +
418 "<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>\r\n" +
419 "<meta osm_base=\"2018-08-30T12:46:02Z\" areas=\"2018-08-30T12:40:02Z\"/>\r\n" +
420 "<remark>runtime error: Query ran out of memory in \"query\" at line 5.</remark>\r\n" +
421 "</osm>";
422 for (DataSet ds : Arrays.asList(testValidData(query), testValidData(query, Options.CONVERT_UNKNOWN_TO_TAGS), testValidData(query, (Options) null),
423 testValidData(query, Options.SAVE_ORIGINAL_ID), testValidData(query, Options.values()))) {
424 assertEquals("runtime error: Query ran out of memory in \"query\" at line 5.", ds.getRemark());
425 }
426 }
427
428 /**
429 * Test reading a file with unknown attributes in osm primitives
430 * @throws Exception if any error occurs
431 */
432 @Test
433 public void testUnknownAttributeTags() throws Exception {
434 String testData = "<osm version=\"0.6\" generator=\"fake generator\">"
435 + "<node id='1' version='1' visible='true' changeset='82' randomkey='randomvalue'></node>" + "</osm>";
436 DataSet ds = testValidData(testData);
437 assertEquals(0, ds.getNodes().iterator().next().getKeys().size());
438 assertEquals(1, ds.getNodes().iterator().next().getUniqueId());
439
440 ds = testValidData(testData, Options.CONVERT_UNKNOWN_TO_TAGS);
441 Node firstNode = ds.getNodes().iterator().next();
442 assertEquals(1, firstNode.getKeys().size());
443 assertEquals("randomvalue", firstNode.get("randomkey"));
444 assertEquals(1, ds.getNodes().iterator().next().getUniqueId());
445
446
447 ds = testValidData(testData, (Options) null);
448 assertEquals(0, ds.getNodes().iterator().next().getKeys().size());
449 assertEquals(1, ds.getNodes().iterator().next().getUniqueId());
450 }
451}
Note: See TracBrowser for help on using the repository browser.