1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration2.tree;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertSame;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.util.Arrays;
26 import java.util.List;
27
28 import org.apache.commons.lang3.StringUtils;
29 import org.junit.jupiter.api.BeforeAll;
30 import org.junit.jupiter.api.BeforeEach;
31 import org.junit.jupiter.api.Test;
32
33
34
35
36 public class TestDefaultExpressionEngine {
37
38 private static final String[] tables = {"users", "documents"};
39
40
41 private static final String[] tabTypes = {"system", "application"};
42
43
44 private static final String[][] fields = {{"uid", "uname", "firstName", "lastName", "email"}, {"docid", "name", "creationDate", "authorID", "version"}};
45
46
47 private static ImmutableNode root;
48
49
50 private static NodeHandler<ImmutableNode> handler;
51
52
53
54
55
56
57
58 private static ImmutableNode createFieldNode(final String name) {
59 final ImmutableNode.Builder nodeFieldBuilder = new ImmutableNode.Builder(1);
60 nodeFieldBuilder.addChild(createNode("name", name));
61 return nodeFieldBuilder.name("field").create();
62 }
63
64
65
66
67
68
69
70
71 private static ImmutableNode createNode(final String name, final Object value) {
72 return new ImmutableNode.Builder().name(name).value(value).create();
73 }
74
75 @BeforeAll
76 public static void setUpBeforeClass() {
77 root = setUpNodes();
78 handler = new InMemoryNodeModel(root).getNodeHandler();
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 private static ImmutableNode setUpNodes() {
98 final ImmutableNode.Builder nodeTablesBuilder = new ImmutableNode.Builder(tables.length);
99 nodeTablesBuilder.name("tables");
100 for (int i = 0; i < tables.length; i++) {
101 final ImmutableNode.Builder nodeTableBuilder = new ImmutableNode.Builder(2);
102 nodeTableBuilder.name("table");
103 nodeTableBuilder.addChild(new ImmutableNode.Builder().name("name").value(tables[i]).create());
104 nodeTableBuilder.addAttribute("type", tabTypes[i]);
105
106 final ImmutableNode.Builder nodeFieldsBuilder = new ImmutableNode.Builder(fields[i].length);
107 for (int j = 0; j < fields[i].length; j++) {
108 nodeFieldsBuilder.addChild(createFieldNode(fields[i][j]));
109 }
110 nodeTableBuilder.addChild(nodeFieldsBuilder.name("fields").create());
111 nodeTablesBuilder.addChild(nodeTableBuilder.create());
112 }
113
114 final ImmutableNode.Builder rootBuilder = new ImmutableNode.Builder();
115 rootBuilder.addChild(nodeTablesBuilder.create());
116 final ImmutableNode.Builder nodeConnBuilder = new ImmutableNode.Builder();
117 nodeConnBuilder.name("connection.settings");
118 nodeConnBuilder.addChild(createNode("usr.name", "scott"));
119 nodeConnBuilder.addChild(createNode("usr.pwd", "tiger"));
120 rootBuilder.addAttribute("test", "true");
121 rootBuilder.addChild(nodeConnBuilder.create());
122
123 return rootBuilder.create();
124 }
125
126
127 private DefaultExpressionEngine engine;
128
129
130
131
132
133
134
135
136 private void checkAttributeValue(final String key, final String attr, final Object expValue) {
137 final List<QueryResult<ImmutableNode>> results = checkKey(key, attr, 1);
138 final QueryResult<ImmutableNode> result = results.get(0);
139 assertTrue(result.isAttributeResult());
140 assertEquals(expValue, result.getAttributeValue(handler), "Wrong attribute value for key " + key);
141 }
142
143
144
145
146
147
148
149
150
151
152 private List<QueryResult<ImmutableNode>> checkKey(final String key, final String name, final int count) {
153 final List<QueryResult<ImmutableNode>> nodes = query(key, count);
154 for (final QueryResult<ImmutableNode> result : nodes) {
155 if (result.isAttributeResult()) {
156 assertEquals(name, result.getAttributeName(), "Wrong attribute name for key " + key);
157 } else {
158 assertEquals(name, result.getNode().getNodeName(), "Wrong result node for key " + key);
159 }
160 }
161 return nodes;
162 }
163
164
165
166
167
168
169
170
171
172 private void checkKeyValue(final String key, final String name, final String value) {
173 final List<QueryResult<ImmutableNode>> results = checkKey(key, name, 1);
174 final QueryResult<ImmutableNode> result = results.get(0);
175 assertFalse(result.isAttributeResult());
176 assertEquals(value, result.getNode().getValue(), "Wrong value for key " + key);
177 }
178
179
180
181
182
183
184
185 private void checkNodePath(final NodeAddData<ImmutableNode> data, final String... expected) {
186 assertEquals(Arrays.asList(expected), data.getPathNodes());
187 }
188
189
190
191
192
193
194 private void checkQueryRootNode(final String key) {
195 final List<QueryResult<ImmutableNode>> results = checkKey(key, null, 1);
196 final QueryResult<ImmutableNode> result = results.get(0);
197 assertFalse(result.isAttributeResult());
198 assertSame(root, result.getNode());
199 }
200
201
202
203
204
205
206
207 private ImmutableNode fetchNode(final String key) {
208 final QueryResult<ImmutableNode> result = query(key, 1).get(0);
209 assertFalse(result.isAttributeResult());
210 return result.getNode();
211 }
212
213
214
215
216
217
218
219
220 private List<QueryResult<ImmutableNode>> query(final String key, final int expCount) {
221 final List<QueryResult<ImmutableNode>> nodes = engine.query(root, key, handler);
222 assertEquals(expCount, nodes.size());
223 return nodes;
224 }
225
226 @BeforeEach
227 public void setUp() throws Exception {
228 engine = DefaultExpressionEngine.INSTANCE;
229 }
230
231
232
233
234
235 private void setUpAlternativeMatcher() {
236 final NodeMatcher<String> matcher = new NodeMatcher<String>() {
237 @Override
238 public <T> boolean matches(final T node, final NodeHandler<T> handler, final String criterion) {
239 return handler.nodeName(node).equals(StringUtils.remove(criterion, '_'));
240 }
241 };
242 engine = new DefaultExpressionEngine(engine.getSymbols(), matcher);
243 }
244
245
246
247
248 private void setUpAlternativeSyntax() {
249 final DefaultExpressionEngineSymbols symbols = new DefaultExpressionEngineSymbols.Builder().setAttributeEnd(null).setAttributeStart("@")
250 .setPropertyDelimiter("/").setEscapedDelimiter(null).setIndexStart("[").setIndexEnd("]").create();
251 engine = new DefaultExpressionEngine(symbols);
252 }
253
254
255
256
257 @Test
258 public void testAttributeKey() {
259 assertEquals("tables.table[@type]", engine.attributeKey("tables.table", "type"));
260 }
261
262
263
264
265 @Test
266 public void testAttributeKeyNoParent() {
267 assertEquals("[@test]", engine.attributeKey(null, "test"));
268 }
269
270
271
272
273 @Test
274 public void testAttributeKeyRoot() {
275 assertEquals("[@test]", engine.attributeKey("", "test"));
276 }
277
278
279
280
281 @Test
282 public void testAttributeKeyWithAlternativeSyntax() {
283 setUpAlternativeSyntax();
284 assertEquals("@test", engine.attributeKey("", "test"));
285 }
286
287
288
289
290 @Test
291 public void testCanonicalKeyNoDuplicates() {
292 final ImmutableNode node = fetchNode("tables.table(0).name");
293 assertEquals("table.name(0)", engine.canonicalKey(node, "table", handler));
294 }
295
296
297
298
299 @Test
300 public void testCanonicalKeyNoParentKey() {
301 final ImmutableNode node = fetchNode("tables.table(0).fields.field(1).name");
302 assertEquals("name(0)", engine.canonicalKey(node, null, handler));
303 }
304
305
306
307
308 @Test
309 public void testCanonicalKeyRootNoParentKey() {
310 assertEquals("", engine.canonicalKey(root, null, handler));
311 }
312
313
314
315
316 @Test
317 public void testCanonicalKeyRootWithParentKey() {
318 assertEquals("parent", engine.canonicalKey(root, "parent", handler));
319 }
320
321
322
323
324 @Test
325 public void testCanonicalKeyWithDuplicates() {
326 final ImmutableNode tab1 = fetchNode("tables.table(0)");
327 final ImmutableNode tab2 = fetchNode("tables.table(1)");
328 assertEquals("tables.table(0)", engine.canonicalKey(tab1, "tables", handler));
329 assertEquals("tables.table(1)", engine.canonicalKey(tab2, "tables", handler));
330 }
331
332
333
334
335 @Test
336 public void testDefaultSymbols() {
337 assertSame(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS, engine.getSymbols());
338 }
339
340
341
342
343 @Test
344 public void testInitNoSymbols() {
345 assertThrows(IllegalArgumentException.class, () -> new DefaultExpressionEngine(null));
346 }
347
348
349
350
351 @Test
352 public void testNodeKey() {
353 final ImmutableNode node = root.getChildren().get(0);
354 assertEquals("tables", engine.nodeKey(node, "", handler));
355 assertEquals("test.tables", engine.nodeKey(node, "test", handler));
356 assertEquals("a.full.parent.key.tables", engine.nodeKey(node, "a.full.parent.key", handler));
357 }
358
359
360
361
362 @Test
363 public void testNodeKeyWithAlternativeSyntax() {
364 setUpAlternativeSyntax();
365 assertEquals("tables/table", engine.nodeKey(root.getChildren().get(0).getChildren().get(0), "tables", handler));
366 }
367
368
369
370
371
372 @Test
373 public void testNodeKeyWithAlternativeSyntaxAttributePropertyDelimiter() {
374 setUpAlternativeSyntax();
375 final DefaultExpressionEngineSymbols symbols = new DefaultExpressionEngineSymbols.Builder(engine.getSymbols())
376 .setAttributeStart(engine.getSymbols().getPropertyDelimiter()).create();
377 engine = new DefaultExpressionEngine(symbols);
378 assertEquals("/test", engine.attributeKey("", "test"));
379 }
380
381
382
383
384 @Test
385 public void testNodeKeyWithEscapedDelimiters() {
386 final ImmutableNode node = root.getChildren().get(1);
387 assertEquals("connection..settings", engine.nodeKey(node, "", handler));
388 assertEquals("connection..settings.usr..name", engine.nodeKey(node.getChildren().get(0), engine.nodeKey(node, "", handler), handler));
389 }
390
391
392
393
394 @Test
395 public void testNodeKeyWithRoot() {
396 assertEquals("", engine.nodeKey(root, null, handler));
397 assertEquals("test", engine.nodeKey(root, "test", handler));
398 }
399
400
401
402
403 @Test
404 public void testPrepareAddAttribute() {
405 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "tables.table(0)[@tableSpace]", handler);
406 assertEquals(tables[0], data.getParent().getChildren().get(0).getValue());
407 assertEquals("tableSpace", data.getNewNodeName());
408 assertTrue(data.isAttribute());
409 assertTrue(data.getPathNodes().isEmpty());
410 }
411
412
413
414
415 @Test
416 public void testPrepareAddAttributeRoot() {
417 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "[@newAttr]", handler);
418 assertSame(root, data.getParent());
419 assertEquals("newAttr", data.getNewNodeName());
420 assertTrue(data.isAttribute());
421 }
422
423
424
425
426 @Test
427 public void testPrepareAddDirectly() {
428 NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "newNode", handler);
429 assertSame(root, data.getParent());
430 assertTrue(data.getPathNodes().isEmpty());
431 assertEquals("newNode", data.getNewNodeName());
432 assertFalse(data.isAttribute());
433
434 data = engine.prepareAdd(root, "tables.table.fields.field.name", handler);
435 assertEquals("name", data.getNewNodeName());
436 assertTrue(data.getPathNodes().isEmpty());
437 assertEquals("field", data.getParent().getNodeName());
438 final ImmutableNode nd = data.getParent().getChildren().get(0);
439 assertEquals("name", nd.getNodeName());
440 assertEquals("version", nd.getValue());
441 }
442
443 @Test
444 public void testPrepareAddEmptyKey() {
445 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, "", handler));
446 }
447
448
449
450
451 @Test
452 public void testPrepareAddInvalidKey() {
453 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, "tables.table(0)[@type].new", handler));
454 }
455
456 @Test
457 public void testPrepareAddInvalidKeyAttribute() {
458 assertThrows(IllegalArgumentException.class,
459 () -> engine.prepareAdd(root, "a.complete.new.path.with.an[@attribute].at.a.non.allowed[@position]", handler));
460 }
461
462 @Test
463 public void testPrepareAddNullKey() {
464 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, null, handler));
465 }
466
467
468
469
470 @Test
471 public void testPrepareAddWithAlternativeMatcher() {
472 setUpAlternativeMatcher();
473 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "tables_.table._fields__._field.name", handler);
474 assertEquals("name", data.getNewNodeName());
475 assertTrue(data.getPathNodes().isEmpty());
476 }
477
478
479
480
481 @Test
482 public void testPrepareAddWithAlternativeSyntax() {
483 setUpAlternativeSyntax();
484 NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "tables/table[0]/test", handler);
485 assertEquals("test", data.getNewNodeName());
486 assertFalse(data.isAttribute());
487 assertEquals(tables[0], data.getParent().getChildren().get(0).getValue());
488
489 data = engine.prepareAdd(root, "a/complete/new/path@attr", handler);
490 assertEquals("attr", data.getNewNodeName());
491 checkNodePath(data, "a", "complete", "new", "path");
492 assertSame(root, data.getParent());
493 }
494
495
496
497
498 @Test
499 public void testPrepareAddWithIndex() {
500 NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "tables.table(0).tableSpace", handler);
501 assertEquals("tableSpace", data.getNewNodeName());
502 assertTrue(data.getPathNodes().isEmpty());
503 assertEquals("table", data.getParent().getNodeName());
504 final ImmutableNode node = data.getParent().getChildren().get(0);
505 assertEquals(tables[0], node.getValue());
506
507 data = engine.prepareAdd(root, "tables.table(1).fields.field(2).alias", handler);
508 assertEquals("alias", data.getNewNodeName());
509 assertEquals("field", data.getParent().getNodeName());
510 assertEquals("creationDate", data.getParent().getChildren().get(0).getValue());
511 }
512
513
514
515
516 @Test
517 public void testPrepareAddWithPath() {
518 NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "tables.table(1).fields.field(-1).name", handler);
519 assertEquals("name", data.getNewNodeName());
520 checkNodePath(data, "field");
521 assertEquals("fields", data.getParent().getNodeName());
522
523 data = engine.prepareAdd(root, "tables.table(-1).name", handler);
524 assertEquals("name", data.getNewNodeName());
525 checkNodePath(data, "table");
526 assertEquals("tables", data.getParent().getNodeName());
527
528 data = engine.prepareAdd(root, "a.complete.new.path", handler);
529 assertEquals("path", data.getNewNodeName());
530 checkNodePath(data, "a", "complete", "new");
531 assertSame(root, data.getParent());
532 }
533
534
535
536
537
538 @Test
539 public void testPrepareAddWithSameAttributeDelimiter() {
540 final DefaultExpressionEngineSymbols symbols = new DefaultExpressionEngineSymbols.Builder(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS)
541 .setAttributeEnd(null).setAttributeStart(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS.getPropertyDelimiter()).create();
542 engine = new DefaultExpressionEngine(symbols);
543
544 NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "tables.table(0).test", handler);
545 assertEquals("test", data.getNewNodeName());
546 assertFalse(data.isAttribute());
547 assertEquals("table", data.getParent().getNodeName());
548
549 data = engine.prepareAdd(root, "a.complete.new.path", handler);
550 assertFalse(data.isAttribute());
551 checkNodePath(data, "a", "complete", "new");
552 }
553
554
555
556
557 @Test
558 public void testQueryAlternativeSyntax() {
559 setUpAlternativeSyntax();
560 checkKeyValue("tables/table[1]/name", "name", tables[1]);
561 checkAttributeValue("tables/table[0]@type", "type", tabTypes[0]);
562 checkAttributeValue("@test", "test", "true");
563 checkKeyValue("connection.settings/usr.name", "usr.name", "scott");
564 }
565
566
567
568
569 @Test
570 public void testQueryAttributeEmulation() {
571 final DefaultExpressionEngineSymbols symbols = new DefaultExpressionEngineSymbols.Builder(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS)
572 .setAttributeEnd(null).setAttributeStart(DefaultExpressionEngineSymbols.DEFAULT_PROPERTY_DELIMITER).create();
573 engine = new DefaultExpressionEngine(symbols);
574 checkKeyValue("tables.table(0).name", "name", tables[0]);
575 checkAttributeValue("tables.table(0).type", "type", tabTypes[0]);
576 checkKey("tables.table.type", "type", 2);
577 }
578
579
580
581
582 @Test
583 public void testQueryEscapedKeys() {
584 checkKeyValue("connection..settings.usr..name", "usr.name", "scott");
585 checkKeyValue("connection..settings.usr..pwd", "usr.pwd", "tiger");
586 }
587
588
589
590
591 @Test
592 public void testQueryKeys() {
593 checkKey("tables.table.name", "name", 2);
594 checkKey("tables.table.fields.field.name", "name", 10);
595 checkKey("tables.table[@type]", "type", 2);
596 checkKey("tables.table(0).fields.field.name", "name", 5);
597 checkKey("tables.table(1).fields.field.name", "name", 5);
598 checkKey("tables.table.fields.field(1).name", "name", 2);
599 }
600
601
602
603
604 @Test
605 public void testQueryKeyWithAlternativeMatcher() {
606 setUpAlternativeMatcher();
607 checkKey("tables_._table_.name_", "name", 2);
608 }
609
610
611
612
613 @Test
614 public void testQueryNodes() {
615 for (int i = 0; i < tables.length; i++) {
616 checkKeyValue("tables.table(" + i + ").name", "name", tables[i]);
617 checkAttributeValue("tables.table(" + i + ")[@type]", "type", tabTypes[i]);
618
619 for (int j = 0; j < fields[i].length; j++) {
620 checkKeyValue("tables.table(" + i + ").fields.field(" + j + ").name", "name", fields[i][j]);
621 }
622 }
623 }
624
625
626
627
628 @Test
629 public void testQueryNonExistingKeys() {
630 checkKey("tables.tablespace.name", null, 0);
631 checkKey("tables.table(2).name", null, 0);
632 checkKey("a complete unknown key", null, 0);
633 checkKey("tables.table(0).fields.field(-1).name", null, 0);
634 checkKey("tables.table(0).fields.field(28).name", null, 0);
635 checkKey("tables.table(0).fields.field().name", null, 0);
636 checkKey("connection.settings.usr.name", null, 0);
637 checkKey("tables.table(0)[@type].additional", null, 0);
638 }
639
640
641
642
643 @Test
644 public void testQueryRootAttribute() {
645 checkAttributeValue("[@test]", "test", "true");
646 }
647
648
649
650
651 @Test
652 public void testQueryRootNodeEmptyKey() {
653 checkQueryRootNode("");
654 }
655
656
657
658
659 @Test
660 public void testQueryRootNodeNullKey() {
661 checkQueryRootNode(null);
662 }
663 }