source: josm/trunk/test/unit/org/openstreetmap/josm/actions/search/SearchCompilerTest.java@ 10299

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

sonar - Performance - Method passes constant String of length 1 to character overridden method + add unit tests/javadoc

  • Property svn:eol-style set to native
File size: 16.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.search;
3
4import static org.junit.Assert.assertEquals;
5import static org.junit.Assert.assertFalse;
6import static org.junit.Assert.assertTrue;
7
8import org.junit.Before;
9import org.junit.Test;
10import org.openstreetmap.josm.JOSMFixture;
11import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
12import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
13import org.openstreetmap.josm.data.coor.LatLon;
14import org.openstreetmap.josm.data.osm.DataSet;
15import org.openstreetmap.josm.data.osm.Node;
16import org.openstreetmap.josm.data.osm.OsmPrimitive;
17import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
18import org.openstreetmap.josm.data.osm.Relation;
19import org.openstreetmap.josm.data.osm.RelationData;
20import org.openstreetmap.josm.data.osm.RelationMember;
21import org.openstreetmap.josm.data.osm.Tag;
22import org.openstreetmap.josm.data.osm.User;
23import org.openstreetmap.josm.data.osm.Way;
24import org.openstreetmap.josm.data.osm.WayData;
25import org.openstreetmap.josm.tools.date.DateUtils;
26
27/**
28 * Unit tests for class {@link SearchCompiler}.
29 */
30public class SearchCompilerTest {
31
32 /**
33 * Setup test.
34 */
35 @Before
36 public void setUp() {
37 JOSMFixture.createUnitTestFixture().init();
38 }
39
40 private static final class SearchContext {
41 final DataSet ds = new DataSet();
42 final Node n1 = new Node(LatLon.ZERO);
43 final Node n2 = new Node(new LatLon(5, 5));
44 final Way w1 = new Way();
45 final Way w2 = new Way();
46 final Relation r1 = new Relation();
47 final Relation r2 = new Relation();
48
49 private final Match m;
50 private final Match n;
51
52 private SearchContext(String state) throws ParseError {
53 m = SearchCompiler.compile(state);
54 n = SearchCompiler.compile('-' + state);
55 ds.addPrimitive(n1);
56 ds.addPrimitive(n2);
57 w1.addNode(n1);
58 w1.addNode(n2);
59 w2.addNode(n1);
60 w2.addNode(n2);
61 ds.addPrimitive(w1);
62 ds.addPrimitive(w2);
63 r1.addMember(new RelationMember("", w1));
64 r1.addMember(new RelationMember("", w2));
65 r2.addMember(new RelationMember("", w1));
66 r2.addMember(new RelationMember("", w2));
67 ds.addPrimitive(r1);
68 ds.addPrimitive(r2);
69 }
70
71 private void match(OsmPrimitive p, boolean cond) {
72 if (cond) {
73 assertTrue(p.toString(), m.match(p));
74 assertFalse(p.toString(), n.match(p));
75 } else {
76 assertFalse(p.toString(), m.match(p));
77 assertTrue(p.toString(), n.match(p));
78 }
79 }
80 }
81
82 protected OsmPrimitive newPrimitive(String key, String value) {
83 final Node p = new Node();
84 p.put(key, value);
85 return p;
86 }
87
88 /**
89 * Search anything.
90 * @throws ParseError if an error has been encountered while compiling
91 */
92 @Test
93 public void testAny() throws ParseError {
94 final SearchCompiler.Match c = SearchCompiler.compile("foo");
95 assertTrue(c.match(newPrimitive("foobar", "true")));
96 assertTrue(c.match(newPrimitive("name", "hello-foo-xy")));
97 assertFalse(c.match(newPrimitive("name", "X")));
98 assertEquals("foo", c.toString());
99 }
100
101 /**
102 * Search by equality key=value.
103 * @throws ParseError if an error has been encountered while compiling
104 */
105 @Test
106 public void testEquals() throws ParseError {
107 final SearchCompiler.Match c = SearchCompiler.compile("foo=bar");
108 assertFalse(c.match(newPrimitive("foobar", "true")));
109 assertTrue(c.match(newPrimitive("foo", "bar")));
110 assertFalse(c.match(newPrimitive("fooX", "bar")));
111 assertFalse(c.match(newPrimitive("foo", "barX")));
112 assertEquals("foo=bar", c.toString());
113 }
114
115 /**
116 * Search by comparison.
117 * @throws ParseError if an error has been encountered while compiling
118 */
119 @Test
120 public void testCompare() throws ParseError {
121 final SearchCompiler.Match c1 = SearchCompiler.compile("start_date>1950");
122 assertTrue(c1.match(newPrimitive("start_date", "1950-01-01")));
123 assertTrue(c1.match(newPrimitive("start_date", "1960")));
124 assertFalse(c1.match(newPrimitive("start_date", "1950")));
125 assertFalse(c1.match(newPrimitive("start_date", "1000")));
126 assertTrue(c1.match(newPrimitive("start_date", "101010")));
127
128 final SearchCompiler.Match c2 = SearchCompiler.compile("start_date<1960");
129 assertTrue(c2.match(newPrimitive("start_date", "1950-01-01")));
130 assertFalse(c2.match(newPrimitive("start_date", "1960")));
131 assertTrue(c2.match(newPrimitive("start_date", "1950")));
132 assertTrue(c2.match(newPrimitive("start_date", "1000")));
133 assertTrue(c2.match(newPrimitive("start_date", "200")));
134
135 final SearchCompiler.Match c3 = SearchCompiler.compile("name<I");
136 assertTrue(c3.match(newPrimitive("name", "Alpha")));
137 assertFalse(c3.match(newPrimitive("name", "Sigma")));
138
139 final SearchCompiler.Match c4 = SearchCompiler.compile("\"start_date\"<1960");
140 assertTrue(c4.match(newPrimitive("start_date", "1950-01-01")));
141 assertFalse(c4.match(newPrimitive("start_date", "2000")));
142
143 final SearchCompiler.Match c5 = SearchCompiler.compile("height>180");
144 assertTrue(c5.match(newPrimitive("height", "200")));
145 assertTrue(c5.match(newPrimitive("height", "99999")));
146 assertFalse(c5.match(newPrimitive("height", "50")));
147 assertFalse(c5.match(newPrimitive("height", "-9999")));
148 assertFalse(c5.match(newPrimitive("height", "fixme")));
149
150 final SearchCompiler.Match c6 = SearchCompiler.compile("name>C");
151 assertTrue(c6.match(newPrimitive("name", "Delta")));
152 assertFalse(c6.match(newPrimitive("name", "Alpha")));
153 }
154
155 /**
156 * Search by nth.
157 * @throws ParseError if an error has been encountered while compiling
158 */
159 @Test
160 public void testNth() throws ParseError {
161 final DataSet dataSet = new DataSet();
162 final Way way = new Way();
163 final Node node0 = new Node(new LatLon(1, 1));
164 final Node node1 = new Node(new LatLon(2, 2));
165 final Node node2 = new Node(new LatLon(3, 3));
166 dataSet.addPrimitive(way);
167 dataSet.addPrimitive(node0);
168 dataSet.addPrimitive(node1);
169 dataSet.addPrimitive(node2);
170 way.addNode(node0);
171 way.addNode(node1);
172 way.addNode(node2);
173 assertFalse(SearchCompiler.compile("nth:2").match(node1));
174 assertTrue(SearchCompiler.compile("nth:1").match(node1));
175 assertFalse(SearchCompiler.compile("nth:0").match(node1));
176 assertTrue(SearchCompiler.compile("nth:0").match(node0));
177 assertTrue(SearchCompiler.compile("nth:2").match(node2));
178 assertTrue(SearchCompiler.compile("nth:-1").match(node2));
179 assertTrue(SearchCompiler.compile("nth:-2").match(node1));
180 assertTrue(SearchCompiler.compile("nth:-3").match(node0));
181 }
182
183 /**
184 * Search by negative nth.
185 * @throws ParseError if an error has been encountered while compiling
186 */
187 @Test
188 public void testNthParseNegative() throws ParseError {
189 assertEquals("Nth{nth=-1, modulo=false}", SearchCompiler.compile("nth:-1").toString());
190 }
191
192 /**
193 * Search by modified status.
194 * @throws ParseError if an error has been encountered while compiling
195 */
196 @Test
197 public void testModified() throws ParseError {
198 SearchContext sc = new SearchContext("modified");
199 // Not modified but new
200 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
201 assertFalse(p.toString(), p.isModified());
202 assertTrue(p.toString(), p.isNewOrUndeleted());
203 sc.match(p, true);
204 }
205 // Modified and new
206 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
207 p.setModified(true);
208 assertTrue(p.toString(), p.isModified());
209 assertTrue(p.toString(), p.isNewOrUndeleted());
210 sc.match(p, true);
211 }
212 // Modified but not new
213 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
214 p.setOsmId(1, 1);
215 assertTrue(p.toString(), p.isModified());
216 assertFalse(p.toString(), p.isNewOrUndeleted());
217 sc.match(p, true);
218 }
219 // Not modified nor new
220 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
221 p.setOsmId(2, 2);
222 assertFalse(p.toString(), p.isModified());
223 assertFalse(p.toString(), p.isNewOrUndeleted());
224 sc.match(p, false);
225 }
226 }
227
228 /**
229 * Search by selected status.
230 * @throws ParseError if an error has been encountered while compiling
231 */
232 @Test
233 public void testSelected() throws ParseError {
234 SearchContext sc = new SearchContext("selected");
235 // Not selected
236 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
237 assertFalse(p.toString(), p.isSelected());
238 sc.match(p, false);
239 }
240 // Selected
241 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
242 sc.ds.addSelected(p);
243 assertTrue(p.toString(), p.isSelected());
244 sc.match(p, true);
245 }
246 }
247
248 /**
249 * Search by incomplete status.
250 * @throws ParseError if an error has been encountered while compiling
251 */
252 @Test
253 public void testIncomplete() throws ParseError {
254 SearchContext sc = new SearchContext("incomplete");
255 // Not incomplete
256 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
257 assertFalse(p.toString(), p.isIncomplete());
258 sc.match(p, false);
259 }
260 // Incomplete
261 sc.n2.setCoor(null);
262 WayData wd = new WayData();
263 wd.setIncomplete(true);
264 sc.w2.load(wd);
265 RelationData rd = new RelationData();
266 rd.setIncomplete(true);
267 sc.r2.load(rd);
268 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
269 assertTrue(p.toString(), p.isIncomplete());
270 sc.match(p, true);
271 }
272 }
273
274 /**
275 * Search by untagged status.
276 * @throws ParseError if an error has been encountered while compiling
277 */
278 @Test
279 public void testUntagged() throws ParseError {
280 SearchContext sc = new SearchContext("untagged");
281 // Untagged
282 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
283 assertFalse(p.toString(), p.isTagged());
284 sc.match(p, true);
285 }
286 // Tagged
287 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
288 p.put("foo", "bar");
289 assertTrue(p.toString(), p.isTagged());
290 sc.match(p, false);
291 }
292 }
293
294 /**
295 * Search by closed status.
296 * @throws ParseError if an error has been encountered while compiling
297 */
298 @Test
299 public void testClosed() throws ParseError {
300 SearchContext sc = new SearchContext("closed");
301 // Closed
302 sc.w1.addNode(sc.n1);
303 for (Way w : new Way[]{sc.w1}) {
304 assertTrue(w.toString(), w.isClosed());
305 sc.match(w, true);
306 }
307 // Unclosed
308 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.n2, sc.w2, sc.r1, sc.r2}) {
309 sc.match(p, false);
310 }
311 }
312
313 /**
314 * Search by new status.
315 * @throws ParseError if an error has been encountered while compiling
316 */
317 @Test
318 public void testNew() throws ParseError {
319 SearchContext sc = new SearchContext("new");
320 // New
321 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
322 assertTrue(p.toString(), p.isNew());
323 sc.match(p, true);
324 }
325 // Not new
326 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
327 p.setOsmId(2, 2);
328 assertFalse(p.toString(), p.isNew());
329 sc.match(p, false);
330 }
331 }
332
333 /**
334 * Search for node objects.
335 * @throws ParseError if an error has been encountered while compiling
336 */
337 @Test
338 public void testTypeNode() throws ParseError {
339 final SearchContext sc = new SearchContext("type:node");
340 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.n2, sc.w1, sc.w2, sc.r1, sc.r2}) {
341 sc.match(p, OsmPrimitiveType.NODE.equals(p.getType()));
342 }
343 }
344
345 /**
346 * Search for way objects.
347 * @throws ParseError if an error has been encountered while compiling
348 */
349 @Test
350 public void testTypeWay() throws ParseError {
351 final SearchContext sc = new SearchContext("type:way");
352 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.n2, sc.w1, sc.w2, sc.r1, sc.r2}) {
353 sc.match(p, OsmPrimitiveType.WAY.equals(p.getType()));
354 }
355 }
356
357 /**
358 * Search for relation objects.
359 * @throws ParseError if an error has been encountered while compiling
360 */
361 @Test
362 public void testTypeRelation() throws ParseError {
363 final SearchContext sc = new SearchContext("type:relation");
364 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.n2, sc.w1, sc.w2, sc.r1, sc.r2}) {
365 sc.match(p, OsmPrimitiveType.RELATION.equals(p.getType()));
366 }
367 }
368
369 /**
370 * Search for users.
371 * @throws ParseError if an error has been encountered while compiling
372 */
373 @Test
374 public void testUser() throws ParseError {
375 final SearchContext foobar = new SearchContext("user:foobar");
376 foobar.n1.setUser(User.createLocalUser("foobar"));
377 foobar.match(foobar.n1, true);
378 foobar.match(foobar.n2, false);
379 final SearchContext anonymous = new SearchContext("user:anonymous");
380 anonymous.n1.setUser(User.createLocalUser("foobar"));
381 anonymous.match(anonymous.n1, false);
382 anonymous.match(anonymous.n2, true);
383 }
384
385 /**
386 * Compiles "foo type bar" and tests the parse error message
387 */
388 @Test
389 public void testFooTypeBar() {
390 try {
391 SearchCompiler.compile("foo type bar");
392 throw new RuntimeException();
393 } catch (ParseError parseError) {
394 assertEquals("<html>Expecting <code>:</code> after <i>type</i>", parseError.getMessage());
395 }
396 }
397
398 /**
399 * Search for primitive timestamps.
400 * @throws ParseError if an error has been encountered while compiling
401 */
402 @Test
403 public void testTimestamp() throws ParseError {
404 final Match search = SearchCompiler.compile("timestamp:2010/2011");
405 final Node n1 = new Node();
406 n1.setTimestamp(DateUtils.fromString("2010-01-22"));
407 assertTrue(search.match(n1));
408 n1.setTimestamp(DateUtils.fromString("2016-01-22"));
409 assertFalse(search.match(n1));
410 }
411
412 /**
413 * Tests the implementation of the Boolean logic.
414 * @throws ParseError if an error has been encountered while compiling
415 */
416 @Test
417 public void testBooleanLogic() throws ParseError {
418 final SearchCompiler.Match c1 = SearchCompiler.compile("foo AND bar AND baz");
419 assertTrue(c1.match(newPrimitive("foobar", "baz")));
420 assertEquals("foo && bar && baz", c1.toString());
421 final SearchCompiler.Match c2 = SearchCompiler.compile("foo AND (bar OR baz)");
422 assertTrue(c2.match(newPrimitive("foobar", "yes")));
423 assertTrue(c2.match(newPrimitive("foobaz", "yes")));
424 assertEquals("foo && (bar || baz)", c2.toString());
425 final SearchCompiler.Match c3 = SearchCompiler.compile("foo OR (bar baz)");
426 assertEquals("foo || (bar && baz)", c3.toString());
427 final SearchCompiler.Match c4 = SearchCompiler.compile("foo1 OR (bar1 bar2 baz1 XOR baz2) OR foo2");
428 assertEquals("foo1 || (bar1 && bar2 && (baz1 ^ baz2)) || foo2", c4.toString());
429 final SearchCompiler.Match c5 = SearchCompiler.compile("foo1 XOR (baz1 XOR (bar baz))");
430 assertEquals("foo1 ^ baz1 ^ (bar && baz)", c5.toString());
431 final SearchCompiler.Match c6 = SearchCompiler.compile("foo1 XOR ((baz1 baz2) XOR (bar OR baz))");
432 assertEquals("foo1 ^ (baz1 && baz2) ^ (bar || baz)", c6.toString());
433 }
434
435 /**
436 * Tests {@code buildSearchStringForTag}.
437 * @throws ParseError if an error has been encountered while compiling
438 */
439 @Test
440 public void testBuildSearchStringForTag() throws ParseError {
441 final Tag tag1 = new Tag("foo=", "bar\"");
442 final Tag tag2 = new Tag("foo=", "=bar");
443 final String search1 = SearchCompiler.buildSearchStringForTag(tag1.getKey(), tag1.getValue());
444 assertEquals("\"foo=\"=\"bar\\\"\"", search1);
445 assertTrue(SearchCompiler.compile(search1).match(tag1));
446 assertFalse(SearchCompiler.compile(search1).match(tag2));
447 final String search2 = SearchCompiler.buildSearchStringForTag(tag1.getKey(), "");
448 assertEquals("\"foo=\"=*", search2);
449 assertTrue(SearchCompiler.compile(search2).match(tag1));
450 assertTrue(SearchCompiler.compile(search2).match(tag2));
451 }
452}
Note: See TracBrowser for help on using the repository browser.