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.uon;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.junit.jupiter.api.Assertions.*;
21  
22  import java.io.*;
23  import java.util.*;
24  
25  import org.apache.juneau.*;
26  import org.apache.juneau.collections.*;
27  import org.apache.juneau.parser.*;
28  import org.junit.jupiter.api.*;
29  
30  @SuppressWarnings("rawtypes")
31  class UonParser_Test extends TestBase {
32  
33  	static UonParser p = UonParser.DEFAULT;
34  	static UonParser pe = UonParser.DEFAULT_DECODING;
35  
36  	//====================================================================================================
37  	// Basic test
38  	//====================================================================================================
39  	@Test void a01_basic() throws Exception {
40  
41  		// Simple string
42  		// Top level
43  		var t = "a";
44  		assertEquals("a", p.parse(t, String.class));
45  		assertEquals("a", p.parse(t, Object.class));
46  		assertEquals("a", pe.parse(t, String.class));
47  		t = "'a'";
48  		assertEquals("a", p.parse(t, String.class));
49  		assertEquals("a", p.parse(t, Object.class));
50  		t = " 'a' ";
51  		assertEquals("a", p.parse(t, String.class));
52  
53  		// 2nd level
54  		t = "(a=a)";
55  		assertEquals("a", p.parse(t, Map.class).get("a"));
56  		assertEquals("a", pe.parse(t, Map.class).get("a"));
57  
58  		t = "('a'='a')";
59  		assertEquals("a", p.parse(t, Map.class).get("a"));
60  		assertEquals("a", pe.parse(t, Map.class).get("a"));
61  
62  		// Simple map
63  		// Top level
64  		t = "(a=b,c=123,d=false,e=true,f=null)";
65  		var m = p.parse(t, Map.class);
66  		assertBean(m, "a,c,d,e", "b,123,false,true");
67  		assertTrue(m.get("c") instanceof Number);
68  		assertTrue(m.get("d") instanceof Boolean);
69  		assertTrue(m.get("e") instanceof Boolean);
70  		m = pe.parse(t, Map.class);
71  		assertNull(m.get("f"));
72  
73  		t = "(a=true)";
74  		m = p.parse(t, HashMap.class, String.class, Boolean.class);
75  		assertTrue(m.get("a") instanceof Boolean);
76  		assertEquals("true", m.get("a").toString());
77  
78  		// null
79  		// Top level
80  		t = "null";
81  		assertNull(p.parse(t, Object.class));
82  		assertNull(pe.parse(t, Object.class));
83  
84  		// 2nd level
85  		t = "(null=null)";
86  		m = p.parse(t, Map.class);
87  		assertTrue(m.containsKey(null));
88  		assertNull(m.get(null));
89  		m = pe.parse(t, Map.class);
90  		assertTrue(m.containsKey(null));
91  		assertNull(m.get(null));
92  
93  		t = " ( null = null ) ";
94  		m = p.parse(t, Map.class);
95  		assertTrue(m.containsKey(null));
96  		assertNull(m.get(null));
97  		m = pe.parse(t, Map.class);
98  		assertTrue(m.containsKey(null));
99  		assertNull(m.get(null));
100 
101 		// 3rd level
102 		t = "(null=(null=null))";
103 		m = p.parse(t, Map.class);
104 		assertTrue(((Map)m.get(null)).containsKey(null));
105 		assertNull(((Map)m.get(null)).get(null));
106 		m = pe.parse(t, Map.class);
107 		assertTrue(((Map)m.get(null)).containsKey(null));
108 		assertNull(((Map)m.get(null)).get(null));
109 
110 		// Empty array
111 		// Top level
112 		t = "@()";
113 		var l = (List)p.parse(t, Object.class);
114 		assertTrue(l.isEmpty());
115 		t = " @( ) ";
116 		l = p.parse(t, List.class);
117 		assertTrue(l.isEmpty());
118 
119 		// 2nd level in map
120 		t = "(x=@())";
121 		m = p.parse(t, HashMap.class, String.class, List.class);
122 		assertTrue(m.containsKey("x"));
123 		assertTrue(((List)m.get("x")).isEmpty());
124 		m = (Map)p.parse(t, Object.class);
125 		assertTrue(m.containsKey("x"));
126 		assertTrue(((List)m.get("x")).isEmpty());
127 		t = " ( x = @( ) )";
128 		m = p.parse(t, HashMap.class, String.class, List.class);
129 		assertTrue(m.containsKey("x"));
130 		assertTrue(((List)m.get("x")).isEmpty());
131 
132 		// Empty 2 dimensional array
133 		t = "@(@())";
134 		l = (List)p.parse(t, Object.class);
135 		assertEquals(1, l.size());
136 		l = (List)l.get(0);
137 		assertTrue(l.isEmpty());
138 		t = " @( @( ) ) ";
139 		l = p.parse(t, LinkedList.class, List.class);
140 		assertEquals(1, l.size());
141 		l = (List)l.get(0);
142 		assertTrue(l.isEmpty());
143 
144 		// Array containing empty string
145 		// Top level
146 		t = "@('')";
147 		l = (List)p.parse(t, Object.class);
148 		assertEquals(1, l.size());
149 		assertEquals("", l.get(0));
150 		t = " @( '' ) ";
151 		l = p.parse(t, List.class, String.class);
152 		assertEquals(1, l.size());
153 		assertEquals("", l.get(0));
154 
155 		// 2nd level
156 		t = "(''=@(''))";
157 		m = (Map)p.parse(t, Object.class);
158 		assertEquals("", ((List)m.get("")).get(0));
159 		t = " ( '' = @( '' ) ) ";
160 		m = p.parse(t, HashMap.class, String.class, List.class);
161 		assertEquals("", ((List)m.get("")).get(0));
162 
163 		// Array containing 3 empty strings
164 		t = "@('','','')";
165 		l = (List)p.parse(t, Object.class);
166 		assertEquals(3, l.size());
167 		assertEquals("", l.get(0));
168 		assertEquals("", l.get(1));
169 		assertEquals("", l.get(2));
170 		t = " @( '' , '' , '' ) ";
171 		l = p.parse(t, List.class, Object.class);
172 		assertEquals(3, l.size());
173 		assertEquals("", l.get(0));
174 		assertEquals("", l.get(1));
175 		assertEquals("", l.get(2));
176 
177 		// String containing \u0000
178 		// Top level
179 		t = "'\u0000'";
180 		assertEquals("\u0000", p.parse(t, Object.class));
181 		t = " '\u0000' ";
182 		assertEquals("\u0000", p.parse(t, String.class));
183 		assertEquals("\u0000", p.parse(t, Object.class));
184 
185 		// 2nd level
186 		t = "('\u0000'='\u0000')";
187 		m = (Map)p.parse(t, Object.class);
188 		assertEquals(1, m.size());
189 		assertEquals("\u0000", m.get("\u0000"));
190 		t = " ( '\u0000' = '\u0000' ) ";
191 		m = p.parse(t, HashMap.class, String.class, String.class);
192 		assertEquals(1, m.size());
193 		assertEquals("\u0000", m.get("\u0000"));
194 		m = p.parse(t, HashMap.class, String.class, Object.class);
195 		assertEquals(1, m.size());
196 		assertEquals("\u0000", m.get("\u0000"));
197 
198 		// Boolean
199 		// Top level
200 		t = "false";
201 		var b = (Boolean)p.parse(t, Object.class);
202 		assertEquals(Boolean.FALSE, b);
203 		b = p.parse(t, Boolean.class);
204 		assertEquals(Boolean.FALSE, b);
205 		t = " false ";
206 		b = p.parse(t, Boolean.class);
207 		assertEquals(Boolean.FALSE, b);
208 
209 		// 2nd level
210 		t = "(x=false)";
211 		m = (Map)p.parse(t, Object.class);
212 		assertEquals(Boolean.FALSE, m.get("x"));
213 		t = " ( x = false ) ";
214 		m = p.parse(t, HashMap.class, String.class, Object.class);
215 		assertEquals(Boolean.FALSE, m.get("x"));
216 
217 		// Number
218 		// Top level
219 		t = "123";
220 		var i = (Integer)p.parse(t, Object.class);
221 		assertEquals(123, i.intValue());
222 		i = p.parse(t, Integer.class);
223 		assertEquals(123, i.intValue());
224 		var d = p.parse(t, Double.class);
225 		assertEquals(123, d.intValue());
226 		var f = p.parse(t, Float.class);
227 		assertEquals(123, f.intValue());
228 		t = " 123 ";
229 		i = p.parse(t, Integer.class);
230 		assertEquals(123, i.intValue());
231 
232 		// 2nd level
233 		t = "(x=123)";
234 		m = (Map)p.parse(t, Object.class);
235 		assertEquals(123, ((Integer)m.get("x")).intValue());
236 		t = " ( x = 123 ) ";
237 		m = p.parse(t, HashMap.class, String.class, Number.class);
238 		assertEquals(123, ((Integer)m.get("x")).intValue());
239 		m = p.parse(t, HashMap.class, String.class, Double.class);
240 		assertEquals(123, ((Double)m.get("x")).intValue());
241 
242 		// Unencoded chars
243 		// Top level
244 		t = "x;/?:@-_.!*~'";
245 		assertEquals("x;/?:@-_.!*'", p.parse(t, Object.class));
246 		assertEquals("x;/?:@-_.!*'", pe.parse(t, Object.class));
247 
248 		// 2nd level
249 		t = "(x;/?:@-_.!*~'=x;/?:@-_.!*~')";
250 		m = (Map)p.parse(t, Object.class);
251 		assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'"));
252 		m = p.parse(t, HashMap.class, String.class, Object.class);
253 		assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'"));
254 		m = p.parse(t, HashMap.class, String.class, String.class);
255 		assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'"));
256 
257 		// Encoded chars
258 		// Top level
259 		t = "x{}|\\^[]`<>#%\"&+";
260 		assertEquals("x{}|\\^[]`<>#%\"&+", p.parse(t, Object.class));
261 		assertEquals("x{}|\\^[]`<>#%\"&+", p.parse(t, String.class));
262 		assertThrows(ParseException.class, ()->pe.parse( "x{}|\\^[]`<>#%\"&+", Object.class));
263 		t = "x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B";
264 		assertEquals("x{}|\\^[]`<>#%\"&+", pe.parse(t, Object.class));
265 		assertEquals("x{}|\\^[]`<>#%\"&+", pe.parse(t, String.class));
266 
267 		// 2nd level
268 		t = "(x{}|\\^[]`<>#%\"&+=x{}|\\^[]`<>#%\"&+)";
269 		m = (Map)p.parse(t, Object.class);
270 		assertEquals("x{}|\\^[]`<>#%\"&+", m.get("x{}|\\^[]`<>#%\"&+"));
271 		assertThrows(ParseException.class, ()->pe.parse("(x{}|\\^[]`<>#%\"&+=x{}|\\^[]`<>#%\"&+)", Object.class));
272 		t = "(x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B=x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B)";
273 		m = (Map)pe.parse(t, Object.class);
274 		assertEquals("x{}|\\^[]`<>#%\"&+", m.get("x{}|\\^[]`<>#%\"&+"));
275 
276 		// Special chars
277 		// Top level
278 		t = "'x$,()~''";
279 		assertEquals("x$,()'", p.parse(t, Object.class));
280 		t = " 'x$,()~'' ";
281 		assertEquals("x$,()'", p.parse(t, Object.class));
282 
283 		// 2nd level
284 		t = "('x$,()~''='x$,()~'')";
285 		m = (Map)p.parse(t, Object.class);
286 		assertEquals("x$,()'", m.get("x$,()'"));
287 		t = " ( 'x$,()~'' = 'x$,()~'' ) ";
288 		m = (Map)p.parse(t, Object.class);
289 		assertEquals("x$,()'", m.get("x$,()'"));
290 
291 		// Equals sign
292 		// Gets encoded at top level, and encoded+escaped at 2nd level.
293 		// Top level
294 		t = "x=";
295 		assertEquals("x=", p.parse(t, Object.class));
296 		t = "x%3D";
297 		assertEquals("x=", pe.parse(t, Object.class));
298 
299 		// 2nd level
300 		t = "('x='='x=')";
301 		m = (Map)p.parse(t, Object.class);
302 		assertEquals("x=", m.get("x="));
303 		t = "('x='='x=')";
304 		m = (Map)p.parse(t, Object.class);
305 		assertEquals("x=", m.get("x="));
306 		t = " ( 'x=' = 'x=' ) ";
307 		m = (Map)p.parse(t, Object.class);
308 		assertEquals("x=", m.get("x="));
309 		t = "('x='='x=')";
310 		m = p.parse(t, HashMap.class, String.class, Object.class);
311 		assertEquals("x=", m.get("x="));
312 		t = " ( 'x=' = 'x=' ) ";
313 		m = p.parse(t, HashMap.class, String.class, Object.class);
314 		assertEquals("x=", m.get("x="));
315 		t = "('x%3D'='x%3D')";
316 		m = (Map)pe.parse(t, Object.class);
317 		assertEquals("x=", m.get("x="));
318 		t = " ( 'x%3D' = 'x%3D' ) ";
319 		m = (Map)pe.parse(t, Object.class);
320 		assertEquals("x=", m.get("x="));
321 
322 		// String starting with parenthesis
323 		// Top level
324 		t = "'()'";
325 		assertEquals("()", p.parse(t, Object.class));
326 		assertEquals("()", p.parse(t, String.class));
327 
328 		t = " '()' ";
329 		assertEquals("()", p.parse(t, Object.class));
330 		assertEquals("()", p.parse(t, String.class));
331 
332 		// 2nd level
333 		t = "('()'='()')";
334 		m = (Map)p.parse(t, Object.class);
335 		assertEquals("()", m.get("()"));
336 		t = " ( '()' = '()' ) ";
337 		m = p.parse(t, HashMap.class, String.class, Object.class);
338 		assertEquals("()", m.get("()"));
339 
340 		// String starting with $
341 		// Top level
342 		t = "$a";
343 		assertEquals("$a", p.parse(t, Object.class));
344 		t = "'$a'";
345 		assertEquals("$a", p.parse(t, Object.class));
346 
347 		// 2nd level
348 		t = "($a=$a)";
349 		m = (Map)p.parse(t, Object.class);
350 		assertEquals("$a", m.get("$a"));
351 		t = " ( $a = $a ) ";
352 		m = (Map)p.parse(t, Object.class);
353 		assertEquals("$a", m.get("$a"));
354 		t = "('$a'='$a')";
355 		m = p.parse(t, HashMap.class, String.class, Object.class);
356 		assertEquals("$a", m.get("$a"));
357 		t = " ( '$a' = '$a' ) ";
358 		m = p.parse(t, HashMap.class, String.class, Object.class);
359 		assertEquals("$a", m.get("$a"));
360 
361 		// Blank string
362 		// Top level
363 		t = "";
364 		assertEquals("", p.parse(t, Object.class));
365 		assertEquals("", pe.parse(t, Object.class));
366 
367 		// 2nd level
368 		t = "(=)";
369 		m = (Map)p.parse(t, Object.class);
370 		assertEquals("", m.get(""));
371 		t = "(''='')";
372 		m = p.parse(t, HashMap.class, String.class, Object.class);
373 		assertEquals("", m.get(""));
374 
375 		// 3rd level
376 		t = "(=(=))";
377 		m = (Map)p.parse(t, Object.class);
378 		assertEquals("", ((Map)m.get("")).get(""));
379 		t = " ( = ( = ) ) ";
380 		m = p.parse(t, HashMap.class, String.class, HashMap.class);
381 		assertEquals("", ((Map)m.get("")).get(""));
382 
383 		// Newline character
384 		// Top level
385 		t = "'%0A'";
386 		assertEquals("\n", pe.parse(t, Object.class));
387 		assertEquals("%0A", p.parse(t, Object.class));
388 
389 		// 2nd level
390 		t = "('%0A'='%0A')";
391 		m = (Map)pe.parse(t, Object.class);
392 		assertEquals("\n", m.get("\n"));
393 		m = (Map)p.parse(t, Object.class);
394 		assertEquals("%0A", m.get("%0A"));
395 
396 		// 3rd level
397 		t = "('%0A'=('%0A'='%0A'))";
398 		m = (Map)pe.parse(t, Object.class);
399 		assertEquals("\n", ((Map)m.get("\n")).get("\n"));
400 	}
401 
402 	//====================================================================================================
403 	// Unicode character test
404 	//====================================================================================================
405 	@Test void a02_unicodeChars() throws Exception {
406 		// 2-byte UTF-8 character
407 		// Top level
408 		var t = "¢";
409 		assertEquals("¢", p.parse(t, Object.class));
410 		assertEquals("¢", p.parse(t, String.class));
411 		t = "%C2%A2";
412 		assertEquals("¢", pe.parse(t, Object.class));
413 		assertEquals("¢", pe.parse(t, String.class));
414 
415 		// 2nd level
416 		t = "(¢=¢)";
417 		var m = (Map)p.parse(t, Object.class);
418 		assertEquals("¢", m.get("¢"));
419 		t = "(%C2%A2=%C2%A2)";
420 		m = (Map)pe.parse(t, Object.class);
421 		assertEquals("¢", m.get("¢"));
422 
423 		// 3rd level
424 		t = "(¢=(¢=¢))";
425 		m = (Map)p.parse(t, Object.class);
426 		assertEquals("¢", ((Map)m.get("¢")).get("¢"));
427 		t = "(%C2%A2=(%C2%A2=%C2%A2))";
428 		m = (Map)pe.parse(t, Object.class);
429 		assertEquals("¢", ((Map)m.get("¢")).get("¢"));
430 
431 		// 3-byte UTF-8 character
432 		// Top level
433 		t = "€";
434 		assertEquals("€", p.parse(t, Object.class));
435 		assertEquals("€", p.parse(t, String.class));
436 		t = "%E2%82%AC";
437 		assertEquals("€", pe.parse(t, Object.class));
438 		assertEquals("€", pe.parse(t, String.class));
439 
440 		// 2nd level
441 		t = "(€=€)";
442 		m = (Map)p.parse(t, Object.class);
443 		assertEquals("€", m.get("€"));
444 		t = "(%E2%82%AC=%E2%82%AC)";
445 		m = (Map)pe.parse(t, Object.class);
446 		assertEquals("€", m.get("€"));
447 
448 		// 3rd level
449 		t = "(€=(€=€))";
450 		m = (Map)p.parse(t, Object.class);
451 		assertEquals("€", ((Map)m.get("€")).get("€"));
452 		t = "(%E2%82%AC=(%E2%82%AC=%E2%82%AC))";
453 		m = (Map)pe.parse(t, Object.class);
454 		assertEquals("€", ((Map)m.get("€")).get("€"));
455 
456 		// 4-byte UTF-8 character
457 		// Top level
458 		t = "𤭢";
459 		assertEquals("𤭢", p.parse(t, Object.class));
460 		assertEquals("𤭢", p.parse(t, String.class));
461 		t = "%F0%A4%AD%A2";
462 		assertEquals("𤭢", pe.parse(t, Object.class));
463 		assertEquals("𤭢", pe.parse(t, String.class));
464 
465 		// 2nd level
466 		t = "(𤭢=𤭢)";
467 		m = (Map)p.parse(t, Object.class);
468 		assertEquals("𤭢", m.get("𤭢"));
469 		t = "(%F0%A4%AD%A2=%F0%A4%AD%A2)";
470 		m = (Map)pe.parse(t, Object.class);
471 		assertEquals("𤭢", m.get("𤭢"));
472 
473 		// 3rd level
474 		t = "(𤭢=(𤭢=𤭢))";
475 		m = (Map)p.parse(t, Object.class);
476 		assertEquals("𤭢", ((Map)m.get("𤭢")).get("𤭢"));
477 		t = "(%F0%A4%AD%A2=(%F0%A4%AD%A2=%F0%A4%AD%A2))";
478 		m = (Map)pe.parse(t, Object.class);
479 		assertEquals("𤭢", ((Map)m.get("𤭢")).get("𤭢"));
480 	}
481 
482 	//====================================================================================================
483 	// Test simple bean
484 	//====================================================================================================
485 	@Test void a03_simpleBean() throws Exception {
486 		var p2 = UonParser.DEFAULT;
487 		var s = "(f1=foo,f2=123)";
488 		var t = p2.parse(s, A.class);
489 		assertBean(t, "f1,f2", "foo,123");
490 	}
491 
492 	public static class A {
493 		public String f1;
494 		public int f2;
495 	}
496 
497 	//====================================================================================================
498 	// testStreamsAutoClose
499 	// Validates PARSER_autoCloseStreams.
500 	//====================================================================================================
501 	@Test void a04_streamsAutoClose() throws Exception {
502 		var p2 = UonParser.DEFAULT.copy().autoCloseStreams().build();
503 		var r = reader("(foo=bar)(foo=bar)");
504 		var x = p2.parse(r, JsonMap.class);
505 		assertBean(x, "foo", "bar");
506 		assertThrowsWithMessage(Exception.class, "Reader is closed", ()->p2.parse(r, JsonMap.class));
507 	}
508 
509 	//====================================================================================================
510 	// testMultipleObjectsInStream
511 	// Validates that readers are not closed so that we can read streams of POJOs.
512 	//====================================================================================================
513 	@Test void a05_multipleObjectsInStream() throws Exception {
514 		var p2 = UonParser.create().unbuffered().build();
515 		var r = reader("(foo=bar)(baz=qux)");
516 		var x = p2.parse(r, JsonMap.class);
517 		assertBean(x, "foo", "bar");
518 		x = p2.parse(r, JsonMap.class);
519 		assertBean(x, "baz", "qux");
520 
521 		r = reader("@(123)@(456)");
522 		var x2 = p2.parse(r, JsonList.class);
523 		assertList(x2, "123");
524 		x2 = p2.parse(r, JsonList.class);
525 		assertList(x2, "456");
526 	}
527 
528 	private Reader reader(String in) {
529 		return new CloseableStringReader(in);
530 	}
531 }