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

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

fix #12949 - Use test rule instead of JOSMFixture to speed up tests (patch by michael2402) - gsoc-core

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