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.assertInstanceOf;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNotSame;
24 import static org.junit.jupiter.api.Assertions.assertNull;
25 import static org.junit.jupiter.api.Assertions.assertSame;
26 import static org.junit.jupiter.api.Assertions.assertThrows;
27 import static org.junit.jupiter.api.Assertions.assertTrue;
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.ArgumentMatchers.eq;
30 import static org.mockito.Mockito.when;
31
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42
43 import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
44 import org.junit.jupiter.api.BeforeAll;
45 import org.junit.jupiter.api.BeforeEach;
46 import org.junit.jupiter.api.Test;
47
48
49
50
51 public class TestInMemoryNodeModelTrackedNodes {
52
53
54 private static final String NEW_FIELD = "newTableField";
55
56
57 private static final String TEST_KEY = "someTestKey";
58
59
60 private static final String SELECTOR_KEY = "tables.table(1)";
61
62
63 private static ImmutableNode root;
64
65
66 private static NodeSelector selector;
67
68
69
70
71
72
73
74 private static void checkedForChangedField(final ImmutableNode nodeFields, final int idx) {
75 assertEquals(NodeStructureHelper.fieldsLength(1), nodeFields.getChildren().size());
76 int childIndex = 0;
77 for (final ImmutableNode field : nodeFields) {
78 final String expName = childIndex == idx ? NEW_FIELD : NodeStructureHelper.field(1, childIndex);
79 checkFieldNode(field, expName);
80 childIndex++;
81 }
82 }
83
84
85
86
87
88
89
90 private static void checkFieldNode(final ImmutableNode nodeField, final String name) {
91 assertEquals("field", nodeField.getNodeName());
92 assertEquals(1, nodeField.getChildren().size());
93 final ImmutableNode nodeName = nodeField.getChildren().get(0);
94 assertEquals("name", nodeName.getNodeName());
95 assertEquals(name, nodeName.getValue());
96 }
97
98
99
100
101
102
103 private static void checkForAddedField(final ImmutableNode nodeFields) {
104 assertEquals(NodeStructureHelper.fieldsLength(1) + 1, nodeFields.getChildren().size());
105 final ImmutableNode nodeField = nodeFields.getChildren().get(NodeStructureHelper.fieldsLength(1));
106 checkFieldNode(nodeField, NEW_FIELD);
107 }
108
109
110
111
112
113
114
115 private static void checkForRemovedField(final ImmutableNode nodeFields, final int idx) {
116 assertEquals(NodeStructureHelper.fieldsLength(1) - 1, nodeFields.getChildren().size());
117 final Set<String> expectedNames = new HashSet<>();
118 final Set<String> actualNames = new HashSet<>();
119 for (int i = 0; i < NodeStructureHelper.fieldsLength(1); i++) {
120 if (idx != i) {
121 expectedNames.add(NodeStructureHelper.field(1, i));
122 }
123 }
124 for (final ImmutableNode field : nodeFields) {
125 final ImmutableNode nodeName = field.getChildren().get(0);
126 actualNames.add(String.valueOf(nodeName.getValue()));
127 }
128 assertEquals(expectedNames, actualNames);
129 }
130
131
132
133
134
135
136 private static NodeKeyResolver<ImmutableNode> createResolver() {
137 final NodeKeyResolver<ImmutableNode> resolver = NodeStructureHelper.createResolverMock();
138 NodeStructureHelper.prepareResolveKeyForQueries(resolver);
139 return resolver;
140 }
141
142
143
144
145
146
147
148 private static void prepareResolverForUpdateKeys(final NodeKeyResolver<ImmutableNode> resolver) {
149 when(resolver.resolveUpdateKey(any(), any(), any(), any())).thenAnswer(invocation -> {
150 final ImmutableNode root = invocation.getArgument(0, ImmutableNode.class);
151 final String key = invocation.getArgument(1, String.class);
152 final TreeData handler = invocation.getArgument(3, TreeData.class);
153 final List<QueryResult<ImmutableNode>> results = DefaultExpressionEngine.INSTANCE.query(root, key, handler);
154 assertEquals(1, results.size());
155 return new NodeUpdateData<>(Collections.singletonMap(results.get(0), invocation.getArgument(2)), null, null, null);
156 });
157 }
158
159 @BeforeAll
160 public static void setUpBeforeClass() throws Exception {
161 root = new ImmutableNode.Builder(1).addChild(NodeStructureHelper.ROOT_TABLES_TREE).create();
162 selector = new NodeSelector(SELECTOR_KEY);
163 }
164
165
166 private InMemoryNodeModel model;
167
168
169
170
171 private void checkReplaceTrackedNode() {
172 final ImmutableNode newNode = new ImmutableNode.Builder().name("newNode").create();
173 model.replaceTrackedNode(selector, newNode);
174 assertSame(newNode, model.getTrackedNode(selector));
175 assertTrue(model.isTrackedNodeDetached(selector));
176 }
177
178
179
180
181
182
183 private void checkTrackChildNodesNoResult(final List<ImmutableNode> queryResult) {
184 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
185 when(resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler())).thenReturn(queryResult);
186
187 final TreeData oldData = model.getTreeData();
188
189 assertTrue(model.trackChildNodes(TEST_KEY, resolver).isEmpty());
190 assertSame(oldData, model.getTreeData());
191 }
192
193
194
195
196
197
198 private void checkTrackChildNodeWithCreationInvalidKey(final List<ImmutableNode> queryResult) {
199 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
200 when(resolver.resolveNodeKey(model.getRootNode(), TEST_KEY, model.getNodeHandler())).thenReturn(queryResult);
201
202 assertThrows(ConfigurationRuntimeException.class, () -> model.trackChildNodeWithCreation(TEST_KEY, "someChild", resolver));
203 }
204
205
206
207
208
209
210 private ImmutableNode fieldsNodeFromModel() {
211 return NodeStructureHelper.nodeForKey(model, "tables/table(1)/fields");
212 }
213
214
215
216
217
218
219 private ImmutableNode fieldsNodeFromTrackedNode() {
220 return NodeStructureHelper.nodeForKey(model.getTrackedNode(selector), "fields");
221 }
222
223
224
225
226
227
228 private void initDetachedNode(final NodeKeyResolver<ImmutableNode> resolver) {
229 model.trackNode(selector, resolver);
230 model.clearTree("tables.table(0)", resolver);
231 }
232
233
234
235
236
237
238
239
240 private void prepareNodeKey(final NodeKeyResolver<ImmutableNode> resolver, final ImmutableNode node, final String key) {
241 final Map<ImmutableNode, String> cache = new HashMap<>();
242 when(resolver.nodeKey(node, cache, model.getNodeHandler())).thenReturn(key);
243 }
244
245 @BeforeEach
246 public void setUp() throws Exception {
247 model = new InMemoryNodeModel(root);
248 }
249
250
251
252
253 @Test
254 void testAddNodesOnDetachedNode() {
255 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
256 NodeStructureHelper.prepareResolveAddKeys(resolver);
257 model.trackNode(selector, resolver);
258 initDetachedNode(resolver);
259 final ImmutableNode rootNode = model.getRootNode();
260 model.addNodes("fields", selector, Collections.singleton(NodeStructureHelper.createFieldNode(NEW_FIELD)), resolver);
261 assertSame(rootNode, model.getRootNode());
262 checkForAddedField(fieldsNodeFromTrackedNode());
263 }
264
265
266
267
268 @Test
269 void testAddNodesOnTrackedNode() {
270 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
271 NodeStructureHelper.prepareResolveAddKeys(resolver);
272 model.trackNode(selector, resolver);
273 model.addNodes("fields", selector, Collections.singleton(NodeStructureHelper.createFieldNode(NEW_FIELD)), resolver);
274 checkForAddedField(fieldsNodeFromModel());
275 checkForAddedField(fieldsNodeFromTrackedNode());
276 }
277
278
279
280
281 @Test
282 void testAddPropertyOnDetachedNode() {
283 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
284 NodeStructureHelper.prepareResolveAddKeys(resolver);
285 model.trackNode(selector, resolver);
286 initDetachedNode(resolver);
287 final ImmutableNode rootNode = model.getRootNode();
288 model.addProperty("fields.field(-1).name", selector, Collections.singleton(NEW_FIELD), resolver);
289 assertSame(rootNode, model.getRootNode());
290 checkForAddedField(fieldsNodeFromTrackedNode());
291 }
292
293
294
295
296 @Test
297 void testAddPropertyOnTrackedNode() {
298 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
299 NodeStructureHelper.prepareResolveAddKeys(resolver);
300 model.trackNode(selector, resolver);
301 model.addProperty("fields.field(-1).name", selector, Collections.singleton(NEW_FIELD), resolver);
302 checkForAddedField(fieldsNodeFromModel());
303 checkForAddedField(fieldsNodeFromTrackedNode());
304 }
305
306
307
308
309 @Test
310 void testClearPropertyOnDetachedNode() {
311 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
312 initDetachedNode(resolver);
313 final ImmutableNode rootNode = model.getRootNode();
314 model.clearProperty("fields.field(0).name", selector, resolver);
315 assertSame(rootNode, model.getRootNode());
316 final ImmutableNode nodeFields = fieldsNodeFromTrackedNode();
317 checkForRemovedField(nodeFields, 0);
318 }
319
320
321
322
323 @Test
324 void testClearPropertyOnTrackedNode() {
325 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
326 model.trackNode(selector, resolver);
327 model.clearProperty("fields.field(0).name", selector, resolver);
328 final ImmutableNode nodeFields = fieldsNodeFromModel();
329 checkForRemovedField(nodeFields, 0);
330 }
331
332
333
334
335 @Test
336 void testClearTreeOnDetachedNode() {
337 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
338 initDetachedNode(resolver);
339 final ImmutableNode rootNode = model.getRootNode();
340 model.clearTree("fields.field(1)", selector, resolver);
341 assertSame(rootNode, model.getRootNode());
342 final ImmutableNode nodeFields = fieldsNodeFromTrackedNode();
343 checkForRemovedField(nodeFields, 1);
344 }
345
346
347
348
349 @Test
350 void testClearTreeOnTrackedNode() {
351 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
352 model.trackNode(selector, resolver);
353 model.clearTree("fields.field(1)", selector, resolver);
354 final ImmutableNode nodeFields = fieldsNodeFromModel();
355 checkForRemovedField(nodeFields, 1);
356 }
357
358
359
360
361 @Test
362 void testGetTrackedNodeAfterClear() {
363 final ImmutableNode node = NodeStructureHelper.nodeForKey(model, "tables/table(1)");
364 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
365 model.trackNode(selector, resolver);
366 model.clear(resolver);
367 assertSame(node, model.getTrackedNode(selector));
368 }
369
370
371
372
373 @Test
374 void testGetTrackedNodeAfterSetRootNode() {
375 final ImmutableNode node = NodeStructureHelper.nodeForKey(model, "tables/table(1)");
376 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
377 model.trackNode(selector, resolver);
378 model.setRootNode(root);
379 assertSame(node, model.getTrackedNode(selector));
380 }
381
382
383
384
385 @Test
386 void testGetTrackedNodeAfterUpdate() {
387 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
388 model.trackNode(selector, resolver);
389 model.clearProperty("tables.table(1).fields.field(1).name", resolver);
390 final ImmutableNode node = model.getTrackedNode(selector);
391 assertEquals(NodeStructureHelper.table(1), node.getChildren().get(0).getValue());
392 }
393
394
395
396
397 @Test
398 void testGetTrackedNodeAfterUpdateNoLongerExisting() {
399 final ImmutableNode node = NodeStructureHelper.nodeForKey(model, "tables/table(1)");
400 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
401 initDetachedNode(resolver);
402 assertSame(node, model.getTrackedNode(selector));
403 }
404
405
406
407
408 @Test
409 void testGetTrackedNodeExisting() {
410 final ImmutableNode node = NodeStructureHelper.nodeForKey(model, "tables/table(1)");
411 model.trackNode(selector, createResolver());
412 assertSame(node, model.getTrackedNode(selector));
413 }
414
415
416
417
418 @Test
419 void testGetTrackedNodeHandlerActive() {
420 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
421 model.trackNode(selector, resolver);
422 final NodeHandler<ImmutableNode> handler = model.getTrackedNodeHandler(selector);
423 final TrackedNodeHandler tnh = assertInstanceOf(TrackedNodeHandler.class, handler);
424 assertSame(model.getTrackedNode(selector), handler.getRootNode());
425 assertSame(model.getTreeData(), tnh.getParentHandler());
426 }
427
428
429
430
431 @Test
432 void testGetTrackedNodeHandlerDetached() {
433 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
434 model.trackNode(selector, resolver);
435 initDetachedNode(resolver);
436 final NodeHandler<ImmutableNode> handler = model.getTrackedNodeHandler(selector);
437 assertSame(model.getTrackedNode(selector), handler.getRootNode());
438 assertInstanceOf(TreeData.class, handler);
439 assertNotSame(model.getNodeHandler(), handler);
440 }
441
442
443
444
445 @Test
446 void testGetTrackedNodeNonExisting() {
447 assertThrows(ConfigurationRuntimeException.class, () -> model.getTrackedNode(selector));
448 }
449
450
451
452
453 @Test
454 void testIsDetachedAfterClear() {
455 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
456 model.trackNode(selector, resolver);
457 model.clear(resolver);
458 assertTrue(model.isTrackedNodeDetached(selector));
459 }
460
461
462
463
464 @Test
465 void testIsDetachedAfterSetRoot() {
466 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
467 model.trackNode(selector, resolver);
468 model.clearProperty("tables.table(1).fields.field(1).name", resolver);
469 model.setRootNode(root);
470 assertTrue(model.isTrackedNodeDetached(selector));
471 }
472
473
474
475
476 @Test
477 void testIsDetachedFalseAfterUpdate() {
478 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
479 model.trackNode(selector, resolver);
480 model.clearProperty("tables.table(1).fields.field(1).name", resolver);
481 assertFalse(model.isTrackedNodeDetached(selector));
482 }
483
484
485
486
487 @Test
488 void testIsDetachedFalseNoUpdates() {
489 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
490 model.trackNode(selector, resolver);
491 assertFalse(model.isTrackedNodeDetached(selector));
492 }
493
494
495
496
497 @Test
498 void testIsDetachedTrue() {
499 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
500 initDetachedNode(resolver);
501 assertTrue(model.isTrackedNodeDetached(selector));
502 }
503
504
505
506
507 @Test
508 void testReplaceTrackedNodeForActiveTrackedNode() {
509 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
510 model.trackNode(selector, resolver);
511 checkReplaceTrackedNode();
512 }
513
514
515
516
517 @Test
518 void testReplaceTrackedNodeForDetachedNode() {
519 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
520 model.trackNode(selector, resolver);
521 initDetachedNode(resolver);
522 checkReplaceTrackedNode();
523 }
524
525
526
527
528 @Test
529 void testReplaceTrackedNodeNull() {
530 model.trackNode(selector, createResolver());
531 assertThrows(IllegalArgumentException.class, () -> model.replaceTrackedNode(selector, null));
532 }
533
534
535
536
537 @Test
538 void testSelectAndTrackNodes() {
539 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
540 final String nodeKey1 = "tables/table(0)";
541 final String nodeKey2 = "tables/table(1)";
542 final ImmutableNode node1 = NodeStructureHelper.nodeForKey(root, nodeKey1);
543 final ImmutableNode node2 = NodeStructureHelper.nodeForKey(root, nodeKey2);
544
545 when(resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler())).thenReturn(Arrays.asList(node1, node2));
546 prepareNodeKey(resolver, node1, nodeKey1);
547 prepareNodeKey(resolver, node2, nodeKey2);
548
549 final Collection<NodeSelector> selectors = model.selectAndTrackNodes(TEST_KEY, resolver);
550 final Iterator<NodeSelector> it = selectors.iterator();
551 NodeSelector sel = it.next();
552 assertEquals(new NodeSelector(nodeKey1), sel);
553 assertSame(node1, model.getTrackedNode(sel));
554 sel = it.next();
555 assertEquals(new NodeSelector(nodeKey2), sel);
556 assertSame(node2, model.getTrackedNode(sel));
557 assertFalse(it.hasNext());
558 }
559
560
561
562
563 @Test
564 void testSelectAndTrackNodesNodeAlreadyTracked() {
565 NodeKeyResolver<ImmutableNode> resolver = createResolver();
566 model.trackNode(selector, resolver);
567 resolver = createResolver();
568 final ImmutableNode node = model.getTrackedNode(selector);
569
570 when(resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(node));
571 prepareNodeKey(resolver, node, SELECTOR_KEY);
572
573 final Collection<NodeSelector> selectors = model.selectAndTrackNodes(TEST_KEY, resolver);
574 assertEquals(1, selectors.size());
575 assertEquals(selector, selectors.iterator().next());
576 model.untrackNode(selector);
577 assertSame(node, model.getTrackedNode(selector));
578 }
579
580
581
582
583 @Test
584 void testSelectAndTrackNodesNoSelection() {
585 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
586
587 when(resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler())).thenReturn(Collections.<ImmutableNode>emptyList());
588
589 assertTrue(model.selectAndTrackNodes(TEST_KEY, resolver).isEmpty());
590 }
591
592
593
594
595 @Test
596 void testSetPropertyOnDetachedNode() {
597 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
598 prepareResolverForUpdateKeys(resolver);
599 model.trackNode(selector, resolver);
600 initDetachedNode(resolver);
601 final ImmutableNode rootNode = model.getRootNode();
602 model.setProperty("fields.field(0).name", selector, NEW_FIELD, resolver);
603 assertSame(rootNode, model.getRootNode());
604 checkedForChangedField(fieldsNodeFromTrackedNode(), 0);
605 }
606
607
608
609
610 @Test
611 void testSetPropertyOnTrackedNode() {
612 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
613 prepareResolverForUpdateKeys(resolver);
614 model.trackNode(selector, resolver);
615 model.setProperty("fields.field(0).name", selector, NEW_FIELD, resolver);
616 checkedForChangedField(fieldsNodeFromModel(), 0);
617 checkedForChangedField(fieldsNodeFromTrackedNode(), 0);
618 }
619
620
621
622
623 @Test
624 void testTrackChildNodes() {
625 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
626 final ImmutableNode node = NodeStructureHelper.nodeForKey(root, "tables");
627 final String[] keys = new String[node.getChildren().size()];
628
629 for (int i = 0; i < keys.length; i++) {
630 final ImmutableNode child = node.getChildren().get(i);
631 keys[i] = String.format("%s.%s(%d)", node.getNodeName(), child.getNodeName(), i);
632 prepareNodeKey(resolver, child, keys[i]);
633 }
634 when(resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(node));
635
636 final Collection<NodeSelector> selectors = model.trackChildNodes(TEST_KEY, resolver);
637 assertEquals(node.getChildren().size(), selectors.size());
638 int idx = 0;
639 for (final NodeSelector sel : selectors) {
640 assertEquals(new NodeSelector(keys[idx]), sel);
641 assertEquals(node.getChildren().get(idx), model.getTrackedNode(sel), "Wrong tracked node for " + sel);
642 idx++;
643 }
644 }
645
646
647
648
649 @Test
650 void testTrackChildNodesMultipleResults() {
651 checkTrackChildNodesNoResult(
652 Arrays.asList(NodeStructureHelper.nodeForKey(root, "tables/table(0)"), NodeStructureHelper.nodeForKey(root, "tables/table(1)")));
653 }
654
655
656
657
658 @Test
659 void testTrackChildNodesNodeWithNoChildren() {
660 checkTrackChildNodesNoResult(Collections.singletonList(NodeStructureHelper.nodeForKey(root, "tables/table(0)/name")));
661 }
662
663
664
665
666 @Test
667 void testTrackChildNodesNoResults() {
668 checkTrackChildNodesNoResult(Collections.<ImmutableNode>emptyList());
669 }
670
671
672
673
674 @Test
675 void testTrackChildNodeWithCreationExisting() {
676 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
677 final String childName = "name";
678 final String parentKey = "tables/table(0)";
679 final String childKey = parentKey + "/" + childName;
680 final ImmutableNode node = NodeStructureHelper.nodeForKey(model, parentKey);
681 final ImmutableNode child = NodeStructureHelper.nodeForKey(node, childName);
682
683 when(resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(node));
684 prepareNodeKey(resolver, child, childKey);
685
686 final NodeSelector childSelector = model.trackChildNodeWithCreation(TEST_KEY, childName, resolver);
687 assertEquals(new NodeSelector(childKey), childSelector);
688 assertSame(child, model.getTrackedNode(childSelector));
689 }
690
691
692
693
694 @Test
695 void testTrackChildNodeWithCreationMultipleResults() {
696 final List<ImmutableNode> nodes = Arrays.asList(NodeStructureHelper.nodeForKey(root, "tables/table(0)"),
697 NodeStructureHelper.nodeForKey(root, "tables/table(1)"));
698 checkTrackChildNodeWithCreationInvalidKey(nodes);
699 }
700
701
702
703
704 @Test
705 void testTrackChildNodeWithCreationNonExisting() {
706 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
707 final String childName = "space";
708 final String parentKey = "tables/table(0)";
709 final String childKey = parentKey + "/" + childName;
710 final ImmutableNode node = NodeStructureHelper.nodeForKey(model, parentKey);
711
712 when(resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(node));
713 when(resolver.nodeKey(any(), eq(new HashMap<>()), any())).thenReturn(childKey);
714
715 final NodeSelector childSelector = model.trackChildNodeWithCreation(TEST_KEY, childName, resolver);
716 assertEquals(new NodeSelector(childKey), childSelector);
717 final ImmutableNode child = model.getTrackedNode(childSelector);
718 assertEquals(childName, child.getNodeName());
719 assertNull(child.getValue());
720 final ImmutableNode parent = model.getNodeHandler().getParent(child);
721 assertEquals("table", parent.getNodeName());
722 assertEquals(child, NodeStructureHelper.nodeForKey(model, childKey));
723 }
724
725
726
727
728 @Test
729 void testTrackChildNodeWithCreationNoResults() {
730 checkTrackChildNodeWithCreationInvalidKey(new ArrayList<>());
731 }
732
733
734
735
736
737 @Test
738 void testTrackedNodeClearedInOperation() {
739 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
740 model.trackNode(selector, resolver);
741 model.clearTree(null, selector, resolver);
742 assertTrue(model.isTrackedNodeDetached(selector));
743 final ImmutableNode node = model.getTrackedNode(selector);
744 assertEquals("table", node.getNodeName());
745 assertFalse(model.getNodeHandler().isDefined(node));
746 }
747
748
749
750
751 @Test
752 void testTrackNodeKeyMultipleResults() {
753 final NodeSelector nodeSelector = new NodeSelector("tables.table.fields.field.name");
754 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
755 assertThrows(ConfigurationRuntimeException.class, () -> model.trackNode(nodeSelector, resolver));
756 }
757
758
759
760
761 @Test
762 void testTrackNodeKeyNoResults() {
763 final NodeSelector nodeSelector = new NodeSelector("tables.unknown");
764 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
765 assertThrows(ConfigurationRuntimeException.class, () -> model.trackNode(nodeSelector, resolver));
766 }
767
768
769
770
771 @Test
772 void testTrackNodeMultipleTimes() {
773 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
774 model.trackNode(selector, resolver);
775 model.trackNode(selector, resolver);
776 model.untrackNode(selector);
777 assertNotNull(model.getTrackedNode(selector));
778 }
779
780
781
782
783 @Test
784 void testUntrackNode() {
785 model.trackNode(selector, createResolver());
786 model.untrackNode(selector);
787 assertThrows(ConfigurationRuntimeException.class, () -> model.getTrackedNode(selector));
788 }
789
790
791
792
793 @Test
794 void testUntrackNodeNonExisting() {
795 assertThrows(ConfigurationRuntimeException.class, () -> model.untrackNode(selector));
796 }
797 }