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

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