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

Last change on this file since 9349 was 9349, checked in by simon04, 8 years ago

see #12083 - Search: improve error message when keyword without a required parameter is used

Example: foo type bar

  • Property svn:eol-style set to native
File size: 14.1 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.assertThat;
7import static org.junit.Assert.assertTrue;
8
9import org.hamcrest.CoreMatchers;
10import org.junit.Before;
11import org.junit.Test;
12import org.openstreetmap.josm.JOSMFixture;
13import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
14import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
15import org.openstreetmap.josm.data.coor.LatLon;
16import org.openstreetmap.josm.data.osm.DataSet;
17import org.openstreetmap.josm.data.osm.Node;
18import org.openstreetmap.josm.data.osm.OsmPrimitive;
19import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
20import org.openstreetmap.josm.data.osm.Relation;
21import org.openstreetmap.josm.data.osm.RelationData;
22import org.openstreetmap.josm.data.osm.RelationMember;
23import org.openstreetmap.josm.data.osm.User;
24import org.openstreetmap.josm.data.osm.Way;
25import org.openstreetmap.josm.data.osm.WayData;
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 }
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 }
112
113 /**
114 * Search by comparison.
115 * @throws ParseError if an error has been encountered while compiling
116 */
117 @Test
118 public void testCompare() throws ParseError {
119 final SearchCompiler.Match c1 = SearchCompiler.compile("start_date>1950");
120 assertTrue(c1.match(newPrimitive("start_date", "1950-01-01")));
121 assertTrue(c1.match(newPrimitive("start_date", "1960")));
122 assertFalse(c1.match(newPrimitive("start_date", "1950")));
123 assertFalse(c1.match(newPrimitive("start_date", "1000")));
124 assertTrue(c1.match(newPrimitive("start_date", "101010")));
125
126 final SearchCompiler.Match c2 = SearchCompiler.compile("start_date<1960");
127 assertTrue(c2.match(newPrimitive("start_date", "1950-01-01")));
128 assertFalse(c2.match(newPrimitive("start_date", "1960")));
129 assertTrue(c2.match(newPrimitive("start_date", "1950")));
130 assertTrue(c2.match(newPrimitive("start_date", "1000")));
131 assertTrue(c2.match(newPrimitive("start_date", "200")));
132
133 final SearchCompiler.Match c3 = SearchCompiler.compile("name<I");
134 assertTrue(c3.match(newPrimitive("name", "Alpha")));
135 assertFalse(c3.match(newPrimitive("name", "Sigma")));
136
137 final SearchCompiler.Match c4 = SearchCompiler.compile("\"start_date\"<1960");
138 assertTrue(c4.match(newPrimitive("start_date", "1950-01-01")));
139 assertFalse(c4.match(newPrimitive("start_date", "2000")));
140
141 final SearchCompiler.Match c5 = SearchCompiler.compile("height>180");
142 assertTrue(c5.match(newPrimitive("height", "200")));
143 assertTrue(c5.match(newPrimitive("height", "99999")));
144 assertFalse(c5.match(newPrimitive("height", "50")));
145 assertFalse(c5.match(newPrimitive("height", "-9999")));
146 assertFalse(c5.match(newPrimitive("height", "fixme")));
147
148 final SearchCompiler.Match c6 = SearchCompiler.compile("name>C");
149 assertTrue(c6.match(newPrimitive("name", "Delta")));
150 assertFalse(c6.match(newPrimitive("name", "Alpha")));
151 }
152
153 /**
154 * Search by nth.
155 * @throws ParseError if an error has been encountered while compiling
156 */
157 @Test
158 public void testNth() throws ParseError {
159 final DataSet dataSet = new DataSet();
160 final Way way = new Way();
161 final Node node0 = new Node(new LatLon(1, 1));
162 final Node node1 = new Node(new LatLon(2, 2));
163 final Node node2 = new Node(new LatLon(3, 3));
164 dataSet.addPrimitive(way);
165 dataSet.addPrimitive(node0);
166 dataSet.addPrimitive(node1);
167 dataSet.addPrimitive(node2);
168 way.addNode(node0);
169 way.addNode(node1);
170 way.addNode(node2);
171 assertFalse(SearchCompiler.compile("nth:2").match(node1));
172 assertTrue(SearchCompiler.compile("nth:1").match(node1));
173 assertFalse(SearchCompiler.compile("nth:0").match(node1));
174 assertTrue(SearchCompiler.compile("nth:0").match(node0));
175 assertTrue(SearchCompiler.compile("nth:2").match(node2));
176 assertTrue(SearchCompiler.compile("nth:-1").match(node2));
177 assertTrue(SearchCompiler.compile("nth:-2").match(node1));
178 assertTrue(SearchCompiler.compile("nth:-3").match(node0));
179 }
180
181 /**
182 * Search by negative nth.
183 * @throws ParseError if an error has been encountered while compiling
184 */
185 @Test
186 public void testNthParseNegative() throws ParseError {
187 assertThat(SearchCompiler.compile("nth:-1").toString(), CoreMatchers.is("Nth{nth=-1, modulo=false}"));
188 }
189
190 /**
191 * Search by modified status.
192 * @throws ParseError if an error has been encountered while compiling
193 */
194 @Test
195 public void testModified() throws ParseError {
196 SearchContext sc = new SearchContext("modified");
197 // Not modified but new
198 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
199 assertFalse(p.toString(), p.isModified());
200 assertTrue(p.toString(), p.isNewOrUndeleted());
201 sc.match(p, true);
202 }
203 // Modified and new
204 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
205 p.setModified(true);
206 assertTrue(p.toString(), p.isModified());
207 assertTrue(p.toString(), p.isNewOrUndeleted());
208 sc.match(p, true);
209 }
210 // Modified but not new
211 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
212 p.setOsmId(1, 1);
213 assertTrue(p.toString(), p.isModified());
214 assertFalse(p.toString(), p.isNewOrUndeleted());
215 sc.match(p, true);
216 }
217 // Not modified nor new
218 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
219 p.setOsmId(2, 2);
220 assertFalse(p.toString(), p.isModified());
221 assertFalse(p.toString(), p.isNewOrUndeleted());
222 sc.match(p, false);
223 }
224 }
225
226 /**
227 * Search by selected status.
228 * @throws ParseError if an error has been encountered while compiling
229 */
230 @Test
231 public void testSelected() throws ParseError {
232 SearchContext sc = new SearchContext("selected");
233 // Not selected
234 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
235 assertFalse(p.toString(), p.isSelected());
236 sc.match(p, false);
237 }
238 // Selected
239 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
240 sc.ds.addSelected(p);
241 assertTrue(p.toString(), p.isSelected());
242 sc.match(p, true);
243 }
244 }
245
246 /**
247 * Search by incomplete status.
248 * @throws ParseError if an error has been encountered while compiling
249 */
250 @Test
251 public void testIncomplete() throws ParseError {
252 SearchContext sc = new SearchContext("incomplete");
253 // Not incomplete
254 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
255 assertFalse(p.toString(), p.isIncomplete());
256 sc.match(p, false);
257 }
258 // Incomplete
259 sc.n2.setCoor(null);
260 WayData wd = new WayData();
261 wd.setIncomplete(true);
262 sc.w2.load(wd);
263 RelationData rd = new RelationData();
264 rd.setIncomplete(true);
265 sc.r2.load(rd);
266 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
267 assertTrue(p.toString(), p.isIncomplete());
268 sc.match(p, true);
269 }
270 }
271
272 /**
273 * Search by untagged status.
274 * @throws ParseError if an error has been encountered while compiling
275 */
276 @Test
277 public void testUntagged() throws ParseError {
278 SearchContext sc = new SearchContext("untagged");
279 // Untagged
280 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
281 assertFalse(p.toString(), p.isTagged());
282 sc.match(p, true);
283 }
284 // Tagged
285 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
286 p.put("foo", "bar");
287 assertTrue(p.toString(), p.isTagged());
288 sc.match(p, false);
289 }
290 }
291
292 /**
293 * Search by closed status.
294 * @throws ParseError if an error has been encountered while compiling
295 */
296 @Test
297 public void testClosed() throws ParseError {
298 SearchContext sc = new SearchContext("closed");
299 // Closed
300 sc.w1.addNode(sc.n1);
301 for (Way w : new Way[]{sc.w1}) {
302 assertTrue(w.toString(), w.isClosed());
303 sc.match(w, true);
304 }
305 // Unclosed
306 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.n2, sc.w2, sc.r1, sc.r2}) {
307 sc.match(p, false);
308 }
309 }
310
311 /**
312 * Search by new status.
313 * @throws ParseError if an error has been encountered while compiling
314 */
315 @Test
316 public void testNew() throws ParseError {
317 SearchContext sc = new SearchContext("new");
318 // New
319 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.w1, sc.r1}) {
320 assertTrue(p.toString(), p.isNew());
321 sc.match(p, true);
322 }
323 // Not new
324 for (OsmPrimitive p : new OsmPrimitive[]{sc.n2, sc.w2, sc.r2}) {
325 p.setOsmId(2, 2);
326 assertFalse(p.toString(), p.isNew());
327 sc.match(p, false);
328 }
329 }
330
331 /**
332 * Search for node objects.
333 * @throws ParseError if an error has been encountered while compiling
334 */
335 @Test
336 public void testTypeNode() throws ParseError {
337 final SearchContext sc = new SearchContext("type:node");
338 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.n2, sc.w1, sc.w2, sc.r1, sc.r2}) {
339 sc.match(p, OsmPrimitiveType.NODE.equals(p.getType()));
340 }
341 }
342
343 /**
344 * Search for way objects.
345 * @throws ParseError if an error has been encountered while compiling
346 */
347 @Test
348 public void testTypeWay() throws ParseError {
349 final SearchContext sc = new SearchContext("type:way");
350 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.n2, sc.w1, sc.w2, sc.r1, sc.r2}) {
351 sc.match(p, OsmPrimitiveType.WAY.equals(p.getType()));
352 }
353 }
354
355 /**
356 * Search for relation objects.
357 * @throws ParseError if an error has been encountered while compiling
358 */
359 @Test
360 public void testTypeRelation() throws ParseError {
361 final SearchContext sc = new SearchContext("type:relation");
362 for (OsmPrimitive p : new OsmPrimitive[]{sc.n1, sc.n2, sc.w1, sc.w2, sc.r1, sc.r2}) {
363 sc.match(p, OsmPrimitiveType.RELATION.equals(p.getType()));
364 }
365 }
366
367 /**
368 * Search for users.
369 * @throws ParseError if an error has been encountered while compiling
370 */
371 @Test
372 public void testUser() throws ParseError {
373 final SearchContext foobar = new SearchContext("user:foobar");
374 foobar.n1.setUser(User.createLocalUser("foobar"));
375 foobar.match(foobar.n1, true);
376 foobar.match(foobar.n2, false);
377 final SearchContext anonymous = new SearchContext("user:anonymous");
378 anonymous.n1.setUser(User.createLocalUser("foobar"));
379 anonymous.match(anonymous.n1, false);
380 anonymous.match(anonymous.n2, true);
381 }
382
383 @Test
384 public void testFooTypeBar() throws Exception {
385 try {
386 SearchCompiler.compile("foo type bar");
387 throw new RuntimeException();
388 } catch (ParseError parseError) {
389 assertEquals("<html>Expecting <code>:</code> after <i>type<i>", parseError.getMessage());
390 }
391 }
392}
Note: See TracBrowser for help on using the repository browser.