1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.junit.bct;
18
19 import static org.apache.juneau.junit.bct.BctAssertions.*;
20 import static org.apache.juneau.junit.bct.NestedTokenizer.*;
21 import static org.junit.jupiter.api.Assertions.*;
22
23 import java.util.*;
24
25 import org.apache.juneau.*;
26 import org.junit.jupiter.api.*;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 class NestedTokenizer_Test extends TestBase {
42
43
44
45
46
47 @Test void a01_simpleTokens() {
48 new NestedTokenizer();
49
50
51 var tokens = tokenize("foo");
52 assertList(tokens, token("foo"));
53
54
55 tokens = tokenize("foo,bar,baz");
56 assertList(tokens, token("foo"), token("bar"), token("baz"));
57
58
59 tokens = tokenize(" foo , bar , baz ");
60 assertList(tokens, token("foo"), token("bar"), token("baz"));
61 }
62
63 @Test void a02_nestedTokens() {
64
65 var tokens = tokenize("foo{a,b}");
66 assertEquals(1, tokens.size());
67 assertToken(tokens.get(0), "foo", "a", "b");
68
69
70 tokens = tokenize("foo{a,b},bar{c,d}");
71 assertEquals(2, tokens.size());
72 assertToken(tokens.get(0), "foo", "a", "b");
73 assertToken(tokens.get(1), "bar", "c", "d");
74
75
76 tokens = tokenize("foo{}");
77 assertEquals(1, tokens.size());
78 assertToken(tokens.get(0), "foo");
79 }
80
81 @Test void a03_deepNesting() {
82
83 var tokens = tokenize("root{level1{a,b},level2}");
84 assertEquals(1, tokens.size());
85 var root = tokens.get(0);
86 assertEquals("root", root.getValue());
87 assertEquals(2, root.getNested().size());
88 assertToken(root.getNested().get(0), "level1", "a", "b");
89 assertToken(root.getNested().get(1), "level2");
90
91
92 tokens = tokenize("root{level1{level2{a,b}}}");
93 assertEquals(1, tokens.size());
94 root = tokens.get(0);
95 assertEquals("root", root.getValue());
96 assertEquals(1, root.getNested().size());
97 var level1 = root.getNested().get(0);
98 assertEquals("level1", level1.getValue());
99 assertEquals(1, level1.getNested().size());
100 assertToken(level1.getNested().get(0), "level2", "a", "b");
101 }
102
103 @Test void a04_escapeSequences() {
104
105 var tokens = tokenize("foo\\,bar");
106 assertList(tokens, token("foo,bar"));
107
108
109 tokens = tokenize("foo\\{bar\\}");
110 assertList(tokens, token("foo{bar}"));
111
112
113 tokens = tokenize("foo\\\\bar");
114 assertList(tokens, token("foo\\bar"));
115
116
117 tokens = tokenize("foo\\,bar\\{baz\\}");
118 assertList(tokens, token("foo,bar{baz}"));
119
120
121 tokens = tokenize("root{foo\\,bar,baz}");
122 assertEquals(1, tokens.size());
123 assertToken(tokens.get(0), "root", "foo,bar", "baz");
124 }
125
126
127
128
129
130 @Test void b01_complexNestedStructures() {
131
132 var tokens = tokenize("user{name,email,address{street,city,zipcode{main,plus4}}},config{timeout,retries}");
133 assertEquals(2, tokens.size());
134
135
136 var user = tokens.get(0);
137 assertEquals("user", user.getValue());
138 assertEquals(3, user.getNested().size());
139 assertEquals("name", user.getNested().get(0).getValue());
140 assertEquals("email", user.getNested().get(1).getValue());
141
142 var address = user.getNested().get(2);
143 assertEquals("address", address.getValue());
144 assertEquals(3, address.getNested().size());
145 assertEquals("street", address.getNested().get(0).getValue());
146 assertEquals("city", address.getNested().get(1).getValue());
147
148 var zipcode = address.getNested().get(2);
149 assertEquals("zipcode", zipcode.getValue());
150 assertEquals(2, zipcode.getNested().size());
151 assertEquals("main", zipcode.getNested().get(0).getValue());
152 assertEquals("plus4", zipcode.getNested().get(1).getValue());
153
154
155 var config = tokens.get(1);
156 assertToken(config, "config", "timeout", "retries");
157 }
158
159 @Test void b02_mixedEscapingAndNesting() {
160
161 var tokens = tokenize("data{key\\,name,value\\{test\\}},info{desc\\,important}");
162 assertEquals(2, tokens.size());
163
164 assertToken(tokens.get(0), "data", "key,name", "value{test}");
165 assertToken(tokens.get(1), "info", "desc,important");
166 }
167
168 @Test void b03_extremeNesting() {
169
170 var tokens = tokenize("l1{l2{l3{l4{l5{value}}}}}");
171 assertEquals(1, tokens.size());
172
173 var current = tokens.get(0);
174 for (int i = 1; i <= 5; i++) {
175 assertEquals("l" + i, current.getValue());
176 assertEquals(1, current.getNested().size());
177 current = current.getNested().get(0);
178 }
179 assertEquals("value", current.getValue());
180 assertFalse(current.hasNested());
181 }
182
183
184
185
186
187 @Test void c01_edgeCases() {
188
189 var tokens = tokenize("a");
190 assertList(tokens, token("a"));
191
192
193 tokens = tokenize(",");
194 assertEquals(2, tokens.size());
195 assertEquals("", tokens.get(0).getValue());
196 assertEquals("", tokens.get(1).getValue());
197
198
199 tokens = tokenize("a,,b");
200 assertEquals(3, tokens.size());
201 assertEquals("a", tokens.get(0).getValue());
202 assertEquals("", tokens.get(1).getValue());
203 assertEquals("b", tokens.get(2).getValue());
204
205
206 tokens = tokenize("a,b,");
207 assertEquals(3, tokens.size());
208 assertEquals("a", tokens.get(0).getValue());
209 assertEquals("b", tokens.get(1).getValue());
210 assertEquals("", tokens.get(2).getValue());
211
212
213 tokens = tokenize(",a,b");
214 assertEquals(3, tokens.size());
215 assertEquals("", tokens.get(0).getValue());
216 assertEquals("a", tokens.get(1).getValue());
217 assertEquals("b", tokens.get(2).getValue());
218 }
219
220 @Test void c02_whitespaceHandling() {
221
222 var tokens = tokenize(" a , b ");
223 assertList(tokens, token("a"), token("b"));
224
225
226 tokens = tokenize("\ta\t,\nb\n");
227 assertList(tokens, token("a"), token("b"));
228
229
230 tokens = tokenize("root{ a , b }");
231 assertToken(tokens.get(0), "root", "a", "b");
232
233
234 tokens = tokenize("root { a,b } , other");
235 assertEquals(2, tokens.size());
236 assertToken(tokens.get(0), "root", "a", "b");
237 assertToken(tokens.get(1), "other");
238 }
239
240 @Test void c03_errorConditions() {
241
242 assertThrows(IllegalArgumentException.class, () -> tokenize(null));
243
244
245 assertThrows(IllegalArgumentException.class, () -> tokenize(""));
246
247
248 assertThrows(IllegalArgumentException.class, () -> tokenize(" "));
249 }
250
251 @Test void c04_finalTokenLogic() {
252
253
254
255 var tokens = tokenize("a,");
256 assertEquals(2, tokens.size());
257 assertEquals("a", tokens.get(0).getValue());
258 assertEquals("", tokens.get(1).getValue());
259
260
261
262 tokens = tokenize(", ");
263 assertEquals(2, tokens.size());
264 assertEquals("", tokens.get(0).getValue());
265 assertEquals("", tokens.get(1).getValue());
266
267
268 tokens = tokenize("a,b");
269 assertEquals(2, tokens.size());
270 assertEquals("a", tokens.get(0).getValue());
271 assertEquals("b", tokens.get(1).getValue());
272
273
274 tokens = tokenize("root{a,},next");
275 assertEquals(2, tokens.size());
276 assertToken(tokens.get(0), "root", "a", "");
277 assertEquals("next", tokens.get(1).getValue());
278 }
279
280
281
282
283
284 @Test void d01_tokenConstruction() {
285
286 var token = new Token("test");
287 assertEquals("test", token.getValue());
288 assertFalse(token.hasNested());
289 assertTrue(token.getNested().isEmpty());
290
291
292 token = new Token(null);
293 assertEquals("", token.getValue());
294 assertFalse(token.hasNested());
295 }
296
297 @Test void d02_tokenEquality() {
298
299 var token1 = new Token("test");
300 var token2 = new Token("test");
301 var token3 = new Token("other");
302
303 assertEquals(token1, token2);
304 assertNotEquals(token1, token3);
305 assertEquals(token1.hashCode(), token2.hashCode());
306
307
308 var nested1 = new Token("parent");
309 nested1.setNested(Arrays.asList(new Token("child1"), new Token("child2")));
310
311 var nested2 = new Token("parent");
312 nested2.setNested(Arrays.asList(new Token("child1"), new Token("child2")));
313
314 assertEquals(nested1, nested2);
315 assertEquals(nested1.hashCode(), nested2.hashCode());
316
317
318 var nested3 = new Token("parent");
319 nested3.setNested(Arrays.asList(new Token("child1"), new Token("different")));
320
321 assertNotEquals(nested1, nested3);
322 }
323
324 @Test void d06_tokenEqualsEdgeCases() {
325
326 var token = new Token("test");
327
328
329 assertEquals(token, token);
330
331
332 assertNotEquals(token, null);
333
334
335 assertNotEquals(token, "not a token");
336 assertNotEquals(token, Integer.valueOf(42));
337
338
339 var other = new Token("different");
340 assertNotEquals(token, other);
341
342
343 var token1 = new Token("same");
344 var token2 = new Token("same");
345 token1.setNested(Arrays.asList(new Token("child1")));
346 token2.setNested(Arrays.asList(new Token("child2")));
347 assertNotEquals(token1, token2);
348
349
350 var token3 = new Token("same");
351 var token4 = new Token("same");
352 token3.setNested(Arrays.asList(new Token("child")));
353
354 assertNotEquals(token3, token4);
355
356
357 var token5 = new Token("same");
358 var token6 = new Token("same");
359 token5.setNested(null);
360 token6.setNested(null);
361 assertEquals(token5, token6);
362 }
363
364 @Test void d03_tokenToString() {
365
366 var token = new Token("test");
367 assertEquals("test", token.toString());
368
369
370 token = new Token("parent");
371 token.setNested(Arrays.asList(new Token("child1"), new Token("child2")));
372 assertEquals("parent{child1,child2}", token.toString());
373
374
375 var child = new Token("child");
376 child.setNested(Arrays.asList(new Token("grandchild")));
377 token = new Token("parent");
378 token.setNested(Arrays.asList(child));
379 assertEquals("parent{child{grandchild}}", token.toString());
380 }
381
382 @Test void d04_tokenNestedAccess() {
383 var parent = new Token("parent");
384
385
386 assertFalse(parent.hasNested());
387 assertTrue(parent.getNested().isEmpty());
388
389
390 parent.setNested(Arrays.asList(new Token("child1"), new Token("child2")));
391 assertTrue(parent.hasNested());
392 assertEquals(2, parent.getNested().size());
393
394
395 var nested = parent.getNested();
396 assertThrows(UnsupportedOperationException.class, () -> nested.add(new Token("child3")));
397 }
398
399 @Test void d05_hasNestedEdgeCases() {
400
401 var token = new Token("test");
402
403
404 token.setNested(null);
405 assertFalse(token.hasNested());
406
407
408 token.setNested(new ArrayList<>());
409 assertFalse(token.hasNested());
410
411
412 token.setNested(Arrays.asList(new Token("child")));
413 assertTrue(token.hasNested());
414
415
416 token.setNested(Arrays.asList(new Token("child1"), new Token("child2")));
417 assertTrue(token.hasNested());
418 }
419
420
421
422
423
424 @Test void e01_roundTripTests() {
425
426 assertRoundTrip("foo");
427 assertRoundTrip("foo,bar,baz");
428
429
430 assertRoundTrip("foo{a,b}");
431 assertRoundTrip("foo{a,b},bar{c,d}");
432
433
434 assertRoundTrip("root{level1{level2{a,b}}}");
435
436
437 assertRoundTrip("user{name,email},config{timeout,retries}");
438 }
439
440 @Test void e02_performanceTest() {
441
442 var sb = new StringBuilder();
443 for (int i = 0; i < 1000; i++) {
444 if (i > 0) sb.append(",");
445 sb.append("token").append(i);
446 if (i % 10 == 0) {
447 sb.append("{nested").append(i).append(",value").append(i).append("}");
448 }
449 }
450
451 var start = System.currentTimeMillis();
452 var tokens = tokenize(sb.toString());
453 var elapsed = System.currentTimeMillis() - start;
454
455 assertTrue(tokens.size() > 900);
456 assertTrue(elapsed < 1000);
457 }
458
459
460
461
462
463
464
465
466 private Token token(String value) {
467 return new Token(value);
468 }
469
470
471
472
473 private void assertToken(Token actual, String expectedValue, String... expectedNested) {
474 assertEquals(expectedValue, actual.getValue());
475 if (expectedNested.length == 0) {
476 assertFalse(actual.hasNested());
477 } else {
478 assertTrue(actual.hasNested());
479 assertEquals(expectedNested.length, actual.getNested().size());
480 for (int i = 0; i < expectedNested.length; i++) {
481 assertEquals(expectedNested[i], actual.getNested().get(i).getValue());
482 }
483 }
484 }
485
486
487
488
489 private void assertRoundTrip(String input) {
490 var tokens = tokenize(input);
491 var rebuilt = tokens.stream()
492 .map(Token::toString)
493 .collect(java.util.stream.Collectors.joining(","));
494 assertEquals(input, rebuilt);
495 }
496 }