View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.objecttools;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import java.util.*;
21  
22  import org.apache.juneau.*;
23  import org.apache.juneau.internal.*;
24  import org.apache.juneau.json.*;
25  import org.apache.juneau.serializer.*;
26  import org.apache.juneau.swaps.*;
27  import org.junit.jupiter.api.*;
28  
29  /**
30   * Tests the PojoSearcher class.
31   */
32  public class ObjectSearcher_Test extends TestBase {
33  
34  	private static BeanSession bs = BeanContext.DEFAULT_SESSION;
35  	private static ObjectSearcher os = ObjectSearcher.DEFAULT;
36  	private static WriterSerializer ws = JsonSerializer.create().json5().swaps(TemporalCalendarSwap.IsoLocalDateTime.class).build();
37  
38  	//-----------------------------------------------------------------------------------------------------------------
39  	// Utility
40  	//-----------------------------------------------------------------------------------------------------------------
41  
42  	static SearchArgs[] create(String...search) {
43  		var sa = new SearchArgs[search.length];
44  		for (var i = 0; i < search.length; i++)
45  			sa[i] = SearchArgs.create(search[i]);
46  		return sa;
47  	}
48  
49  	static SearchArgs create(String search) {
50  		return SearchArgs.create(search);
51  	}
52  
53  	static Object run(Object in, String search) {
54  		return os.run(bs, in, create(search));
55  	}
56  
57  	static Object run(Object in, SearchArgs sa) {
58  		return os.run(bs, in, sa);
59  	}
60  
61  	static String[] a(String...s) {
62  		return s;
63  	}
64  
65  	//-----------------------------------------------------------------------------------------------------------------
66  	// String search
67  	//-----------------------------------------------------------------------------------------------------------------
68  
69  	public static class A {
70  		public String f;
71  
72  		public static A create(String f) {
73  			var a = new A();
74  			a.f = f;
75  			return a;
76  		}
77  	}
78  
79  	public static List<A> A_LIST = list(A.create("foo"), A.create("bar"), A.create("baz"), A.create("q ux"), A.create("qu'ux"), null, A.create(null));
80  	public static Set<A> A_SET = set(A.create("foo"), A.create("bar"), A.create("baz"), A.create("q ux"), A.create("qu'ux"), null, A.create(null));
81  	public static A[] A_ARRAY = {A.create("foo"), A.create("bar"), A.create("baz"), A.create("q ux"), A.create("qu'ux"), null, A.create(null)};
82  
83  	@Test void a01_stringSearch_singleWord() {
84  		assertBeans(run(A_LIST, "f=foo"), "f", "foo");
85  		assertBeans(run(A_SET, "f=foo"), "f", "foo");
86  		assertBeans(run(A_ARRAY, "f=foo"), "f", "foo");
87  		assertBeans(os.run(A_LIST, "f=foo"), "f", "foo");
88  		assertBeans(os.run(A_SET, "f=foo"), "f", "foo");
89  		assertBeans(os.run(A_ARRAY, "f=foo"), "f", "foo");
90  	}
91  
92  	@Test void a02_stringSearch_pattern1() {
93  		assertBeans(run(A_LIST, "f=fo*"), "f", "foo");
94  		assertBeans(run(A_SET, "f=fo*"), "f", "foo");
95  		assertBeans(run(A_ARRAY, "f=fo*"), "f", "foo");
96  	}
97  
98  	@Test void a03_stringSearch_pattern2() {
99  		assertBeans(run(A_LIST, "f=*ar"), "f", "bar");
100 		assertBeans(run(A_SET, "f=*ar"), "f", "bar");
101 		assertBeans(run(A_ARRAY, "f=*ar"), "f", "bar");
102 	}
103 
104 	@Test void a04_stringSearch_pattern3() {
105 		assertBeans(run(A_LIST, "f=?ar"), "f", "bar");
106 		assertBeans(run(A_SET, "f=?ar"), "f", "bar");
107 		assertBeans(run(A_ARRAY, "f=?ar"), "f", "bar");
108 	}
109 
110 	@Test void a05_stringSearch_multiple() {
111 		assertBeans(run(A_LIST, "f=foo bar q ux"), "f", "foo", "bar");
112 		assertBeans(run(A_SET, "f=foo bar q ux"), "f", "foo", "bar");
113 		assertBeans(run(A_ARRAY, "f=foo bar q ux"), "f", "foo", "bar");
114 	}
115 
116 	@Test void a06_stringSearch_quoted() {
117 		assertBeans(run(A_LIST, "f='q ux'"), "f", "q ux");
118 		assertBeans(run(A_SET, "f='q ux'"), "f", "q ux");
119 		assertBeans(run(A_ARRAY, "f='q ux'"), "f", "q ux");
120 	}
121 
122 	@Test void a07_stringSearch_quotedWithPattern() {
123 		assertBeans(run(A_LIST, "f='q *x'"), "f", "q ux");
124 		assertBeans(run(A_SET, "f='q *x'"), "f", "q ux");
125 		assertBeans(run(A_ARRAY, "f='q *x'"), "f", "q ux");
126 	}
127 
128 	@Test void a08_stringSearch_unquotedContainingQuote() {
129 		assertBeans(run(A_LIST, "f=qu'ux"), "f", "qu'ux");
130 		assertBeans(run(A_SET, "f=qu'ux"), "f", "qu'ux");
131 		assertBeans(run(A_ARRAY, "f=qu'ux"), "f", "qu'ux");
132 	}
133 
134 	@Test void a09_stringSearch_quotedContainingQuote() {
135 		assertBeans(run(A_LIST, "f='qu\\'ux'"), "f", "qu'ux");
136 		assertBeans(run(A_SET, "f='qu\\'ux'"), "f", "qu'ux");
137 		assertBeans(run(A_ARRAY, "f='qu\\'ux'"), "f", "qu'ux");
138 	}
139 
140 	@Test void a10_stringSearch_regExp() {
141 		assertBeans(run(A_LIST, "f=/q\\sux/"), "f", "q ux");
142 		assertBeans(run(A_SET, "f=/q\\sux/"), "f", "q ux");
143 		assertBeans(run(A_ARRAY, "f=/q\\sux/"), "f", "q ux");
144 	}
145 
146 	@Test void a11_stringSearch_regExp_noEndSlash() {
147 		var in = list(A.create("/foo"), A.create("bar"));
148 		for (var s : a("f=/foo","f='/foo'"))
149 			assertBeans(run(in, s), "f", "/foo");
150 	}
151 
152 	@Test void a12_stringSearch_regExp_onlySlash() {
153 		var in = list(A.create("/"), A.create("bar"));
154 		for (var s : a("f=/", "f='/'"))
155 			assertBeans(run(in, s), "f", "/");
156 	}
157 
158 	@Test void a13_stringSearch_or_pattern() {
159 		var in = list(A.create("foo"), A.create("bar"), A.create("baz"));
160 		assertBeans(run(in, "f=f* *r"), "f", "foo", "bar");
161 		assertEmpty(run(in, "f='f* *r'"));
162 		assertBeans(run(in, "f='f*oo'"), "f", "foo");
163 	}
164 
165 	@Test void a14_stringSearch_explicit_or_pattern() {
166 		var in = list(A.create("foo"), A.create("bar"), A.create("baz"));
167 		assertBeans(run(in, "f=^f* ^*r"), "f", "foo", "bar");
168 		assertEmpty(run(in, "f=^'f* *r'"));
169 		assertBeans(run(in, "f=^'f*oo'"), "f", "foo");
170 	}
171 
172 	@Test void a15_stringSearch_and_pattern() {
173 		var in = list(A.create("foo"), A.create("bar"), A.create("baz"));
174 		assertBeans(run(in, "f=+b* +*r"), "f", "bar");
175 		assertBeans(run(in, "f=+'b*' +'*r'"), "f", "bar");
176 	}
177 
178 	@Test void a16_stringSearch_not_pattern() {
179 		var in = list(A.create("foo"), A.create("bar"), A.create("baz"));
180 		assertBeans(run(in, "f=b* -*r"), "f", "baz");
181 		assertBeans(run(in, "f=+'b*' -'*r'"), "f", "baz");
182 	}
183 
184 	@Test void a17_stringSearch_caseSensitive() {
185 		var in = list(A.create("foo"), A.create("bar"), A.create("baz"));
186 		assertEmpty(run(in, "f=F*"));
187 		assertEmpty(run(in, "f=\"F*\""));
188 		assertBeans(run(in, "f='F*'"), "f", "foo");
189 	}
190 
191 	@Test void a18_stringSearch_malformedQuotes() {
192 		var in = list(A.create("'foo"), A.create("\"bar"), A.create("baz"));
193 
194 		assertThrowsWithMessage(Exception.class, "Unmatched string quotes", ()->run(in, "f='*"));
195 
196 		assertThrowsWithMessage(Exception.class, "Unmatched string quotes", ()->run(in, "f=\"*"));
197 
198 		assertBeans(run(in, "f='\\'*'"), "f", "'foo");
199 		assertBeans(run(in, "f='\"*'"), "f", "\"bar");
200 		assertBeans(run(in, "f=\"\\\"*\""), "f", "\"bar");
201 	}
202 
203 	@Test void a19_stringSearch_regexChars() {
204 		var in = list(A.create("+\\[]{}()^$."), A.create("bar"), A.create("baz"));
205 		assertBeans(run(in, "f=*+*"), "f", "+\\[]{}()^$.");
206 		assertBeans(run(in, "f='+\\\\[]{}()^$.'"), "f", "+\\[]{}()^$.");
207 		assertBeans(run(in, "f=++\\\\[]{}()^$."), "f", "+\\[]{}()^$.");
208 	}
209 
210 	@Test void a20_stringSearch_metaChars() {
211 		var in = list(A.create("*?\\'\""), A.create("bar"), A.create("baz"));
212 		assertBeans(run(in, "f='\\*\\?\\\\\\'\"'"), "f", "*?\\'\"");
213 	}
214 
215 	@Test void a21_stringSearch_metaChars_escapedQuotes() {
216 		var in = list(A.create("'"), A.create("\""), A.create("baz"));
217 		assertBeans(run(in, "f=\\'"), "f", "'");
218 		assertBeans(run(in, "f=\\\""), "f", "\"");
219 	}
220 
221 	@Test void a22_stringSearch_metaChars_falseEscape() {
222 		var in = list(A.create("foo"), A.create("bar"), A.create("baz"));
223 		assertBeans(run(in, "f=\\f\\o\\o"), "f", "foo");
224 	}
225 
226 	//-----------------------------------------------------------------------------------------------------------------
227 	// Number search
228 	//-----------------------------------------------------------------------------------------------------------------
229 
230 	public static class C {
231 		public int f;
232 
233 		static C create(int f) {
234 			var c = new C();
235 			c.f = f;
236 			return c;
237 		}
238 	}
239 
240 	C[] INT_BEAN_ARRAY = {C.create(-2), C.create(-1), C.create(0), C.create(1), C.create(2), C.create(3)};
241 
242 	@Test void b01_intSearch_oneNumber() {
243 		for (var s : a("f=1", "f = 1"))
244 			assertBeans(run(INT_BEAN_ARRAY, s), "f", "1");
245 	}
246 
247 	@Test void b02_intSearch_twoNumbers() {
248 		for (var s : a("f=1 2", "f = 1  2 "))
249 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("1,2"));
250 	}
251 
252 	@Test void b03_intSearch_oneNegativeNumber() {
253 		for (var s : a("f=-1", "f = -1 "))
254 			assertBeans(run(INT_BEAN_ARRAY, s), "f", "-1");
255 	}
256 
257 	@Test void b04_intSearch_twoNegativeNumbers() {
258 		assertBeans(run(INT_BEAN_ARRAY, "f=-1 -2"), "f", splita("-2,-1"));
259 	}
260 
261 	@Test void b05_intSearch_simpleRange() {
262 		for (var s : a("f=1-2", "f = 1 - 2 ", "f = 1- 2 "))
263 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("1,2"));
264 	}
265 
266 	@Test void b06_intSearch_simpleRange_invalid() {
267 		assertEmpty(run(INT_BEAN_ARRAY, "f=2-1"));
268 	}
269 
270 	@Test void b07_intSearch_twoNumbersThatLookLikeRange() {
271 		assertBeans(run(INT_BEAN_ARRAY, "f = 1 -2 "), "f", splita("-2,1"));
272 	}
273 
274 	@Test void b08_intSearch_rangeWithNegativeNumbers() {
275 		assertBeans(run(INT_BEAN_ARRAY, "f = -2--1 "), "f", splita("-2,-1"));
276 	}
277 
278 	@Test void b09_intSearch_rangeWithNegativeNumbers_invalidRange() {
279 		assertEmpty(run(INT_BEAN_ARRAY, "f = -1--2 "));
280 	}
281 
282 	@Test void b10_intSearch_multipleRanges() {
283 		assertBeans(run(INT_BEAN_ARRAY, "f = 0-1 3-4"), "f", splita("0,1,3"));
284 	}
285 
286 	@Test void b11_intSearch_overlappingRanges() {
287 		assertBeans(run(INT_BEAN_ARRAY, "f = 0-0 2-2"), "f", splita("0,2"));
288 	}
289 
290 	@Test void b12_intSearch_LT() {
291 		for (var s : a("f = <0", "f<0", "f = < 0 ", "f < 0 "))
292 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("-2,-1"));
293 	}
294 
295 	@Test void b13_intSearch_LT_negativeNumber() {
296 		for (var s : a("f = <-1", "f<-1", "f = < -1 ", "f < -1 "))
297 			assertBeans(run(INT_BEAN_ARRAY, s), "f", "-2");
298 	}
299 
300 	@Test void b14_intSearch_GT() {
301 		for (var s : a("f = >1", "f>1", "f = > 1 ", "f > 1 "))
302 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("2,3"));
303 	}
304 
305 	@Test void b15_intSearch_GT_negativeNumber() {
306 		for (var s : a("f = >-1", "f>-1", "f = > -1 ", "f > -1 ", "f =  >  -1  ", "f >  -1  "))
307 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("0,1,2,3"));
308 	}
309 
310 	@Test void b16_intSearch_LTE() {
311 		for (var s : a("f = <=0", "f<=0", "f = <= 0 ", "f <= 0 ", "f =  <=  0  "))
312 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("-2,-1,0"));
313 	}
314 
315 	@Test void b17_intSearch_LTE_negativeNumber() {
316 		for (var s : a("f = <=-1", "f <=-1", "f = <= -1 ", "f =  <=  -1  ", "f <=  -1  "))
317 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("-2,-1"));
318 	}
319 
320 	@Test void b18_intSearch_GTE() {
321 		for (var s : a("f = >=1", "f >=1", "f = >= 1 ", "f >= 1 ", "f =  >=  1  "))
322 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("1,2,3"));
323 	}
324 
325 	@Test void b19_intSearch_GTE_negativeNumber() {
326 		for (var s : a("f = >=-1", "f >=-1", "f = >= -1 ", "f >= -1 ", "f =  >=  -1  "))
327 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("-1,0,1,2,3"));
328 	}
329 
330 	@Test void b20_intSearch_not_singleNumber() {
331 		for (var s : a("f = !1", "f = ! 1 ", "f =  !  1  "))
332 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("-2,-1,0,2,3"));
333 	}
334 
335 	@Test void b21_intSearch_not_range() {
336 		assertBeans(run(INT_BEAN_ARRAY, "f = !1-2"), "f", splita("-2,-1,0,3"));
337 	}
338 
339 	@Test void b22_intSearch_not_range_negativeNumbers() {
340 		for (var s : a("f = !-2--1", "f = ! -2 - -1", "f =  !  -2  -  -1 "))
341 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("0,1,2,3"));
342 	}
343 
344 	@Test void b23_intSearch_not_looksLikeRange() {
345 		assertBeans(run(INT_BEAN_ARRAY, "f = ! -2 -2"), "f", splita("-2,-1,0,1,2,3"));
346 	}
347 
348 	@Test void b24_intSearch_empty() {
349 		for (var s : a("f=", "f = ", "f =  "))
350 			assertBeans(run(INT_BEAN_ARRAY, s), "f", splita("-2,-1,0,1,2,3"));
351 	}
352 
353 	@Test void b25_intSearch_badSearches() {
354 		var ss = a(
355 			"f=x","(S01)",
356 			"f=>x","(S02)",
357 			"f=<x","(S03)",
358 			"f=>=x","(S04)",
359 			"f=>= x","(S05)",
360 			"f=1x","(S06)",
361 			"f=1 x","(S07)",
362 			"f=1-x","(S08)",
363 			"f=1 -x","(S09)",
364 			"f=1 - x","(S10)",
365 			"f=1 - 1x","(S11)",
366 			"f=>","(ES02)",
367 			"f=<","(ES03)",
368 			"f=>=","(ES04)",
369 			"f=123-","(ES08)",
370 			"f=123 -","(ES09)"
371 		);
372 
373 		for (var i = 0; i < ss.length; i+=2) {
374 			final int i2 = i;
375 			assertThrowsWithMessage(Exception.class, ss[i+1], ()->run(INT_BEAN_ARRAY, ss[i2]));
376 		}
377 	}
378 
379 	//-----------------------------------------------------------------------------------------------------------------
380 	// Date search
381 	//-----------------------------------------------------------------------------------------------------------------
382 
383 	public static class B {
384 		public Calendar f;
385 
386 		static B[] create(String...dates) {
387 			var bb = new B[dates.length];
388 			for (var i = 0; i < dates.length; i++) {
389 				bb[i] = new B();
390 				bb[i].f = DateUtils.parseISO8601Calendar(dates[i]);
391 			}
392 			return bb;
393 		}
394 	}
395 
396 	@Test void c01_dateSearch_singleDate_y() {
397 		var in = B.create("2010-01-01", "2011-01-01", "2011-01-31", "2012-01-01");
398 		for (var s : a(
399 				"f=2011",
400 				"f = 2011 ",
401 				"f = '2011' ",
402 				"f = \"2011\" "
403 			))
404 			assertSerialized(run(in, s), ws, "[{f:'2011-01-01T00:00:00'},{f:'2011-01-31T00:00:00'}]");
405 	}
406 
407 	@Test void c02_dateSearch_singleDate_ym() {
408 		var in = B.create("2010-01-01", "2011-01-01", "2011-01-31", "2012-01-01");
409 		for (var s : a(
410 				"f=2011-01",
411 				"f = 2011-01 ",
412 				"f='2011-01'",
413 				"f=\"2011-01\""
414 			))
415 			assertSerialized(run(in, s), ws, "[{f:'2011-01-01T00:00:00'},{f:'2011-01-31T00:00:00'}]");
416 	}
417 
418 	@Test void c03_dateSearch_singleDate_ymd() {
419 		var in = B.create("2010-01-01", "2011-01-01", "2011-01-31", "2012-01-01");
420 		assertSerialized(run(in, "f=2011-01-01"), ws, "[{f:'2011-01-01T00:00:00'}]");
421 	}
422 
423 
424 	@Test void c04_dateSearch_singleDate_ymdh() {
425 		var in = B.create("2011-01-01T11:15:59", "2011-01-01T12:00:00", "2011-01-01T12:59:59", "2011-01-01T13:00:00");
426 		assertSerialized(run(in, "f=2011-01-01T12"), ws, "[{f:'2011-01-01T12:00:00'},{f:'2011-01-01T12:59:59'}]");
427 	}
428 
429 	@Test void c05_dateSearch_singleDate_ymdhm() {
430 		var in = B.create("2011-01-01T12:29:59", "2011-01-01T12:30:00", "2011-01-01T12:30:59", "2011-01-01T12:31:00");
431 		assertSerialized(run(in, "f=2011-01-01T12:30"), ws, "[{f:'2011-01-01T12:30:00'},{f:'2011-01-01T12:30:59'}]");
432 	}
433 
434 	@Test void c06_dateSearch_singleDate_ymdhms() {
435 		var in = B.create("2011-01-01T12:30:29", "2011-01-01T12:30:30", "2011-01-01T12:30:31");
436 		assertSerialized(run(in, "f=2011-01-01T12:30:30"), ws, "[{f:'2011-01-01T12:30:30'}]");
437 	}
438 
439 	@Test void c07_dateSearch_openEndedRanges_y() {
440 		var in = B.create("2000-12-31", "2001-01-01");
441 		for (var s : a(
442 				"f>2000",
443 				"f > 2000 ",
444 				"f>'2000'",
445 				"f > '2000' ",
446 				"f>\"2000\"",
447 				"f > \"2000\" ",
448 				"f>=2001",
449 				"f >= 2001 ",
450 				"f>='2001'",
451 				"f >= '2001' ",
452 				"f>=\"2001\"",
453 				"f >= \"2001\" "
454 			))
455 			assertSerialized(run(in, s), ws, "[{f:'2001-01-01T00:00:00'}]");
456 		for (var s : a(
457 				"f<2001",
458 				"f < 2001 ",
459 				"f<'2001'",
460 				"f < '2001'",
461 				"f<\"2001\"",
462 				"f < \"2001\" ",
463 				"f<=2000",
464 				"f <= 2000 ",
465 				"f<='2000'",
466 				"f <= '2000'",
467 				"f<=\"2000\"",
468 				"f <= \"2000\" "
469 			))
470 			assertSerialized(run(in, s), ws, "[{f:'2000-12-31T00:00:00'}]");
471 	}
472 
473 	@Test void c08_dateSearch_openEndedRanges_toMinute() {
474 		var in = B.create("2011-01-01T12:29:59", "2011-01-01T12:30:00");
475 		assertSerialized(run(in, "f>=2011-01-01T12:30"), ws, "[{f:'2011-01-01T12:30:00'}]");
476 		assertSerialized(run(in, "f<2011-01-01T12:30"), ws, "[{f:'2011-01-01T12:29:59'}]");
477 	}
478 
479 	@Test void c09_dateSearch_openEndedRanges_toSecond() {
480 		var in = B.create("2011-01-01T12:30:59", "2011-01-01T12:31:00");
481 		assertSerialized(run(in, "f>2011-01-01T12:30"), ws, "[{f:'2011-01-01T12:31:00'}]");
482 		assertSerialized(run(in, "f<=2011-01-01T12:30"), ws, "[{f:'2011-01-01T12:30:59'}]");
483 	}
484 
485 	@Test void c10_dateSearch_closedRanges() {
486 		var in = B.create("2000-12-31T23:59:59", "2001-01-01T00:00:00", "2003-06-30T23:59:59", "2003-07-01T00:00:00");
487 
488 		for (var s : a(
489 				"f= 2001 - 2003-06-30 ",
490 				"f= 2001 - 2003-06-30",
491 				"f='2001'-'2003-06-30'",
492 				"f= '2001' - '2003-06-30' ",
493 				"f=\"2001\"-\"2003-06-30\"",
494 				"f= \"2001\" - \"2003-06-30\" ",
495 				"f=2001 -'2003-06-30'",
496 				"f= 2001 - '2003-06-30' ",
497 				"f=2001 -\"2003-06-30\"",
498 				"f= 2001 - \"2003-06-30\" "
499 			))
500 			assertSerialized(run(in, s), ws, "[{f:'2001-01-01T00:00:00'},{f:'2003-06-30T23:59:59'}]");
501 
502 		for (var s : a(
503 			"f= 2001 - 2003-06-30 2000",
504 			"f= 2001 - 2003-06-30 '2000'",
505 			"f= 2001 - 2003-06-30 \"2000\"",
506 			"f='2001'-'2003-06-30' 2000",
507 			"f='2001'-'2003-06-30' '2000'",
508 			"f='2001'-'2003-06-30' \"2000\"",
509 			"f= '2001' - '2003-06-30'  2000",
510 			"f= '2001' - '2003-06-30'  '2000'",
511 			"f= '2001' - '2003-06-30'  \"2000\"",
512 			"f=\"2001\"-\"2003-06-30\" 2000",
513 			"f=\"2001\"-\"2003-06-30\" '2000'",
514 			"f=\"2001\"-\"2003-06-30\" \"2000\"",
515 			"f= \"2001\" - \"2003-06-30\"  2000",
516 			"f= \"2001\" - \"2003-06-30\"  '2000'",
517 			"f= \"2001\" - \"2003-06-30\"  \"2000\"",
518 			"f= 2001 - '2003-06-30'  2000",
519 			"f= 2001 - '2003-06-30'  '2000'",
520 			"f= 2001 - '2003-06-30'  \"2000\"",
521 			"f= 2001 - \"2003-06-30\"  2000",
522 			"f= 2001 - \"2003-06-30\"  '2000'",
523 			"f= 2001 - \"2003-06-30\"  \"2000\""
524 		))
525 			assertSerialized(run(in, s), ws, "[{f:'2000-12-31T23:59:59'},{f:'2001-01-01T00:00:00'},{f:'2003-06-30T23:59:59'}]");
526 	}
527 
528 	@Test void c11_dateSearch_or1() {
529 		var in = B.create("2000-12-31", "2001-01-01", "2001-12-31", "2002-01-01");
530 		for (var s : a(
531 				"f=2001 2003 2005",
532 				"f= 2001  2003  2005 ",
533 				"f='2001' '2003' '2005'",
534 				"f= '2001'  '2003'  '2005' ",
535 				"f=\"2001\" \"2003\" \"2005\"",
536 				"f= \"2001\"  \"2003\"  \"2005\" "
537 			))
538 			assertSerialized(run(in, s), ws, "[{f:'2001-01-01T00:00:00'},{f:'2001-12-31T00:00:00'}]");
539 	}
540 
541 	@Test void c12_dateSearch_or2() {
542 		var in = B.create("2002-12-31", "2003-01-01", "2003-12-31", "2004-01-01");
543 		for (var s : a(
544 				"f=2001 2003 2005",
545 				"f= 2001  2003  2005 ",
546 				"f='2001' '2003' '2005'",
547 				"f= '2001'  '2003'  '2005' ",
548 				"f=\"2001\" \"2003\" \"2005\"",
549 				"f= \"2001\"  \"2003\"  \"2005\" "
550 			))
551 			assertSerialized(run(in, s), ws, "[{f:'2003-01-01T00:00:00'},{f:'2003-12-31T00:00:00'}]");
552 	}
553 
554 	@Test void c13_dateSearch_or3() {
555 		var in = B.create("2004-12-31", "2005-01-01", "2005-12-31", "2006-01-01");
556 		for (var s : a(
557 				"f=2001 2003 2005",
558 				"f= 2001  2003  2005 ",
559 				"f='2001' '2003' '2005'",
560 				"f= '2001'  '2003'  '2005' ",
561 				"f=\"2001\" \"2003\" \"2005\"",
562 				"f= \"2001\"  \"2003\"  \"2005\" "
563 			))
564 			assertSerialized(run(in, s), ws, "[{f:'2005-01-01T00:00:00'},{f:'2005-12-31T00:00:00'}]");
565 	}
566 
567 	@Test void c14_dateSearch_or_singleAndRange() {
568 		var in = B.create("2000-12-31", "2001-01-01", "2002-12-31", "2003-01-01");
569 		for (var s : a(
570 				"f=2001 >2002",
571 				"f= 2001   >2002 ",
572 				"f='2001' >'2002'",
573 				"f= '2001'  >'2002' ",
574 				"f=\"2001\" >\"2002\"",
575 				"f= \"2001\"  >\"2002\" ",
576 				"f=>2002 2001",
577 				"f= >2002  2001 ",
578 				"f=>'2002' '2001'",
579 				"f= >'2002'  '2001' ",
580 				"f=>\"2002\" \"2001\"",
581 				"f= >\"2002\"  \"2001\" ",
582 				"f=2001 >=2003",
583 				"f= 2001  >=2003 ",
584 				"f='2001' >='2003'",
585 				"f= '2001'  >='2003' ",
586 				"f=\"2001\" >=\"2003\"",
587 				"f= \"2001\"  >=\"2003\" ",
588 				"f=>=2003 2001",
589 				"f= >=2003  2001 ",
590 				"f=>='2003' '2001'",
591 				"f= >='2003'  '2001' ",
592 				"f=>=\"2003\" \"2001\"",
593 				"f= >=\"2003\"  \"2001\" "
594 			))
595 			assertSerialized(run(in, s), ws, "[{f:'2001-01-01T00:00:00'},{f:'2003-01-01T00:00:00'}]");
596 		for (var s : a(
597 				"f=<2001 2003",
598 				"f= <2001  2003 ",
599 				"f=<'2001' '2003'",
600 				"f= <'2001'  '2003' ",
601 				"f=<\"2001\" \"2003\"",
602 				"f= <\"2001\"  \"2003\" ",
603 				"f=2003 <2001",
604 				"f= 2003  <2001 ",
605 				"f='2003' <'2001'",
606 				"f= '2003'  <'2001' ",
607 				"f=\"2003\" <\"2001\"",
608 				"f= \"2003\"  <\"2001\" ",
609 				"f=<=2000 2003",
610 				"f= <=2000  2003 ",
611 				"f=<='2000' '2003'",
612 				"f= <='2000'  '2003' ",
613 				"f=<=\"2000\" \"2003\"",
614 				"f= <=\"2000\"  \"2003\" ",
615 				"f=2003 <=2000",
616 				"f= 2003  <=2000 ",
617 				"f='2003' <='2000'",
618 				"f= '2003'  <='2000' ",
619 				"f=\"2003\" <=\"2000\"",
620 				"f= \"2003\"  <=\"2000\" "
621 			))
622 			assertSerialized(run(in, s), ws, "[{f:'2000-12-31T00:00:00'},{f:'2003-01-01T00:00:00'}]");
623 	}
624 
625 	//-----------------------------------------------------------------------------------------------------------------
626 	// Other data structures.
627 	//-----------------------------------------------------------------------------------------------------------------
628 
629 	@Test void d01_d2ListOfMaps() {
630 		List<Map<?,?>> in = list(
631 			map("f","foo"),
632 			map("f","bar"),
633 			null,
634 			map(null,"qux"),
635 			map("quux",null),
636 			map(null,null)
637 		);
638 		assertBeans(run(in, "f=foo"), "f", "foo");
639 	}
640 
641 	@Test void d02_d2SetOfMaps() {
642 		Set<Map<?,?>> in = set(
643 			map("f","foo"),
644 			map("f","bar"),
645 			null,
646 			map(null,"qux"),
647 			map("quux",null),
648 			map(null,null)
649 		);
650 		assertBeans(run(in, "f=foo"), "f", "foo");
651 	}
652 
653 
654 	@Test void d03_d2ArrayOfMaps() {
655 		Map<?,?>[] in = new Map[]{
656 			map("f","foo"),
657 			map("f","bar"),
658 			null,
659 			map(null,"qux"),
660 			map("quux",null),
661 			map(null,null)
662 		};
663 		assertBeans(run(in, "f=foo"), "f", "foo");
664 	}
665 
666 	@Test void d04_d2ListOfObjects() {
667 		List<Object> in = list(
668 			map("f","foo"),
669 			map("f","bar"),
670 			null,
671 			map(null,"qux"),
672 			map("quux",null),
673 			map(null,null),
674 			"xxx",
675 			123
676 		);
677 		assertBeans(run(in, "f=foo"), "f", "foo");
678 	}
679 
680 	@Test void d05_d2SetOfObjects() {
681 		Set<Object> in = set(
682 			map("f","foo"),
683 			map("f","bar"),
684 			null,
685 			map(null,"qux"),
686 			map("quux",null),
687 			map(null,null),
688 			"xxx",
689 			123
690 		);
691 		assertBeans(run(in, "f=foo"), "f", "foo");
692 	}
693 
694 	@Test void d06_d2ArrayOfObjects() {
695 		Object[] in = {
696 			map("f","foo"),
697 			map("f","bar"),
698 			null,
699 			map(null,"qux"),
700 			map("quux",null),
701 			map(null,null),
702 			"xxx",
703 			123
704 		};
705 		assertBeans(run(in, "f=foo"), "f", "foo");
706 	}
707 
708 	@Test void d07_d2ListOfMapsWithLists() {
709 		List<Map<?,?>> in = list(
710 			map("f",list("foo")),
711 			map("f",list("bar")),
712 			null,
713 			map(null,list("qux")),
714 			map("quux",list((Object)null)),
715 			map(null,list((Object)null))
716 		);
717 		assertBeans(run(in, "f=foo"), "f", "[foo]");
718 	}
719 
720 	@Test void d08_d2SetOfMapsWithSets() {
721 		Set<Map<?,?>> in = set(
722 			map("f",set("foo")),
723 			map("f",set("bar")),
724 			null,
725 			map(null,set("qux")),
726 			map("quux",set((Object)null)),
727 			map(null,set((Object)null))
728 		);
729 		assertBeans(run(in, "f=foo"), "f", "[foo]");
730 	}
731 
732 	@Test void d09_d2ArrayOfMapsWithArrays() {
733 		Map<?,?>[] in = new Map[]{
734 			map("f",new Object[]{"foo"}),
735 			map("f",new Object[]{"bar"}),
736 			null,
737 			map(null,new Object[]{"qux"}),
738 			map("quux",new Object[]{null}),
739 			map(null,new Object[]{null})
740 		};
741 		assertBeans(run(in, "f=foo"), "f", "[foo]");
742 	}
743 
744 	@Test void d10_d2ListOfBeans() {
745 		List<A> in = list(
746 			A.create("foo"),
747 			A.create("bar"),
748 			null,
749 			A.create(null)
750 		);
751 		assertBeans(run(in, "f=foo"), "f", "foo");
752 	}
753 
754 	@Test void d11_d3ListOfListOfMaps() {
755 		List<List<Map<?,?>>> in = list(
756 			list(map("f","foo")),
757 			list(map("f","bar")),
758 			list((Map<?,?>)null),
759 			list(map(null,"qux")),
760 			list(map("quux",null)),
761 			list(map(null,null)),
762 			null
763 		);
764 		assertBeans(run(in, "f=foo"), "#{f}", "[{foo}]");
765 	}
766 
767 	@Test void d12_d3SetOfSetOfMaps() {
768 		Set<Set<Map<?,?>>> in = set(
769 			set(map("f","foo")),
770 			set(map("f","bar")),
771 			set(map("f","baz")),
772 			set((Map<?,?>)null),
773 			set(map(null,"qux")),
774 			set(map("quux",null)),
775 			set(map(null,null)),
776 			null
777 		);
778 		assertBeans(run(in, "f=foo"), "#{f}", "[{foo}]");
779 	}
780 
781 	@Test void d13_d3ArrayOfArrayOfMaps() {
782 		Map<?,?>[][] in = new Map[][]{
783 			new Map[]{map("f","foo")},
784 			new Map[]{map("f","bar")},
785 			new Map[]{map("f","baz")},
786 			new Map[]{null},
787 			new Map[]{map(null,"qux")},
788 			new Map[]{map("quux",null)},
789 			new Map[]{map(null,null)},
790 			null
791 		};
792 		assertBeans(run(in, "f=foo"), "#{f}", "[{foo}]");
793 	}
794 
795 	@Test void d14_d3ListOfListOfObjects() {
796 		List<List<Object>> in = list(
797 			list(map("f","foo")),
798 			list(map("f","bar")),
799 			list((Object)null),
800 			list(map(null,"qux")),
801 			list(map("quux",null)),
802 			list(map(null,null)),
803 			list("xxx"),
804 			null
805 		);
806 		assertBeans(run(in, "f=foo"), "#{f}", "[{foo}]");
807 	}
808 
809 	@Test void d15_d3SetOfSetOfObjects() {
810 		Set<Set<Object>> in = set(
811 			set(map("f","foo")),
812 			set(map("f","bar")),
813 			set((Map<?,?>)null),
814 			set(map(null,"qux")),
815 			set(map("quux",null)),
816 			set(map(null,null)),
817 			set("xxx"),
818 			set(123),
819 			null
820 		);
821 		assertBeans(run(in, "f=foo"), "#{f}", "[{foo}]");
822 	}
823 
824 	@Test void d16_d3ArrayOfArrayOfObjects() {
825 		Object[][] in = {
826 			new Object[]{map("f","foo")},
827 			new Object[]{map("f","bar")},
828 			new Object[]{null},
829 			new Object[]{map(null,"qux")},
830 			new Object[]{map("quux",null)},
831 			new Object[]{map(null,null)},
832 			new Object[]{"xxx"},
833 			new Object[]{123},
834 			null
835 		};
836 		assertBeans(run(in, "f=foo"), "#{f}", "[{foo}]");
837 	}
838 
839 	@Test void d17_d3ListOfListOfMapsWithCollections() {
840 		List<List<Map<?,?>>> in = list(
841 			list(map("f",list("foo"))),
842 			list(map("f",list("bar"))),
843 			list((Map<?,?>)null),
844 			list(map(null,list("qux"))),
845 			list(map("quux",list((Object)null))),
846 			list(map(null,list((Object)null))),
847 			null
848 		);
849 		assertBeans(run(in, "f=foo"), "#{f}", "[{[foo]}]");
850 	}
851 
852 	@Test void d18_d3SetOfSetOfMapsWithCollections() {
853 		Set<Set<Map<?,?>>> in = set(
854 			set(map("f",set("foo"))),
855 			set(map("f",set("bar"))),
856 			set((Map<?,?>)null),
857 			set(map(null,set("qux"))),
858 			set(map("quux",set((Object)null))),
859 			set(map(null,set((Object)null))),
860 			null
861 		);
862 		assertBeans(run(in, "f=foo"), "#{f}", "[{[foo]}]");
863 	}
864 
865 	@Test void d19_d3ArrayOfArrayOfMapsWithCollections() {
866 		Map<?,?>[][] in = new Map[][]{
867 			new Map[]{map("f",new Object[]{"foo"})},
868 			new Map[]{map("f",new Object[]{"bar"})},
869 			new Map[]{null},
870 			new Map[]{map(null,new Object[]{"qux"})},
871 			new Map[]{map("quux",new Object[]{null})},
872 			new Map[]{map(null,new Object[]{null})},
873 			null
874 		};
875 		assertBeans(run(in, "f=foo"), "#{f}", "[{[foo]}]");
876 	}
877 
878 	@Test void d20_d3ArrayOfArrayOfBeans() {
879 		A[][] in = {
880 			new A[]{A.create("foo")},
881 			new A[]{A.create("bar")},
882 			new A[]{null},
883 			new A[]{A.create(null)},
884 			null
885 		};
886 		assertBeans(run(in, "f=foo"), "#{f}", "[{foo}]");
887 	}
888 }