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.apache.commons.configuration2.tree.NodeStructureHelper.ROOT_AUTHORS_TREE;
20 import static org.apache.commons.configuration2.tree.NodeStructureHelper.ROOT_PERSONAE_TREE;
21 import static org.apache.commons.configuration2.tree.NodeStructureHelper.nodeForKey;
22 import static org.apache.commons.configuration2.tree.NodeStructureHelper.nodePathWithEndNode;
23 import static org.junit.jupiter.api.Assertions.assertEquals;
24 import static org.junit.jupiter.api.Assertions.assertFalse;
25 import static org.junit.jupiter.api.Assertions.assertNotEquals;
26 import static org.junit.jupiter.api.Assertions.assertNotNull;
27 import static org.junit.jupiter.api.Assertions.assertNull;
28 import static org.junit.jupiter.api.Assertions.assertSame;
29 import static org.junit.jupiter.api.Assertions.assertThrows;
30 import static org.junit.jupiter.api.Assertions.assertTrue;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.ArgumentMatchers.eq;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.when;
35
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.NoSuchElementException;
45 import java.util.Set;
46 import java.util.concurrent.CountDownLatch;
47 import java.util.regex.Matcher;
48 import java.util.regex.Pattern;
49
50 import org.junit.jupiter.api.Test;
51
52
53
54
55 public class TestInMemoryNodeModel {
56
57
58 private static final String KEY = "aTestKey";
59
60
61
62
63
64
65
66
67 private static void checkPathToRoot(final InMemoryNodeModel model, ImmutableNode node, final String... path) {
68 final NodeHandler<ImmutableNode> handler = model.getNodeHandler();
69 for (int i = path.length - 1; i >= 0; i--) {
70 node = handler.getParent(node);
71 assertEquals(path[i], node.getNodeName());
72 }
73 assertSame(model.getRootNode(), handler.getParent(node));
74 }
75
76
77
78
79
80
81 @SuppressWarnings("unchecked")
82 private static NodeKeyResolver<ImmutableNode> createResolver() {
83 return mock(NodeKeyResolver.class);
84 }
85
86
87
88
89
90
91 private void checkAddNodesNoNodes(final Collection<ImmutableNode> newNodes) {
92 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
93 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_AUTHORS_TREE);
94
95 model.addNodes(KEY, newNodes, resolver);
96 assertSame(NodeStructureHelper.ROOT_AUTHORS_TREE, model.getRootNode());
97 }
98
99
100
101
102
103
104
105 private void checkClearTreeUpdatedParentMapping(final String pathToRemove, final ImmutableNode nodeToCheck) {
106 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
107 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
108 final QueryResult<ImmutableNode> result = QueryResult.createNodeResult(nodeForKey(model, pathToRemove));
109
110 when(resolver.resolveKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(result));
111
112 model.clearTree(KEY, resolver);
113 final NodeHandler<ImmutableNode> nodeHandler = model.getNodeHandler();
114 assertThrows(IllegalArgumentException.class, () -> nodeHandler.getParent(nodeToCheck));
115 }
116
117
118
119
120 @Test
121 void testAddNodesEmptyCollection() {
122 checkAddNodesNoNodes(Collections.<ImmutableNode>emptySet());
123 }
124
125
126
127
128 @Test
129 void testAddNodesNullCollection() {
130 checkAddNodesNoNodes(null);
131 }
132
133
134
135
136 @Test
137 void testAddNodesToAttribute() {
138 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
139 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_AUTHORS_TREE);
140 when(resolver.resolveKey(NodeStructureHelper.ROOT_AUTHORS_TREE, KEY, model.getNodeHandler()))
141 .thenReturn(Collections.singletonList(QueryResult.createAttributeResult(nodeForKey(model, NodeStructureHelper.author(1)), "test")));
142
143 final ImmutableNode newNode = new ImmutableNode.Builder().name("newNode").create();
144 final Set<ImmutableNode> nodes = Collections.singleton(newNode);
145 assertThrows(IllegalArgumentException.class, () -> model.addNodes(KEY, nodes, resolver));
146 }
147
148
149
150
151 @Test
152 void testAddNodesToExistingNode() {
153 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
154 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_AUTHORS_TREE);
155 final String key = NodeStructureHelper.author(0);
156 final ImmutableNode newWork1 = new ImmutableNode.Builder().name("King Lear").create();
157 final ImmutableNode newWork2 = new ImmutableNode.Builder().name("The Taming of the Shrew").create();
158 when(resolver.resolveKey(NodeStructureHelper.ROOT_AUTHORS_TREE, KEY, model.getNodeHandler()))
159 .thenReturn(Collections.singletonList(QueryResult.createNodeResult(nodeForKey(model, key))));
160
161 model.addNodes(KEY, Arrays.asList(newWork1, newWork2), resolver);
162 final ImmutableNode node = nodeForKey(model, key);
163 final int size = node.getChildren().size();
164 assertSame(newWork1, node.getChildren().get(size - 2));
165 assertSame(newWork2, node.getChildren().get(size - 1));
166 }
167
168
169
170
171 @Test
172 void testAddNodesToNewAttributeKey() {
173 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
174 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_AUTHORS_TREE);
175 when(resolver.resolveKey(NodeStructureHelper.ROOT_AUTHORS_TREE, KEY, model.getNodeHandler()))
176 .thenReturn(Collections.<QueryResult<ImmutableNode>>emptyList());
177 when(resolver.resolveAddKey(NodeStructureHelper.ROOT_AUTHORS_TREE, KEY, model.getNodeHandler()))
178 .thenReturn(new NodeAddData<>(NodeStructureHelper.ROOT_AUTHORS_TREE, "test", true, null));
179
180 final ImmutableNode newNode = new ImmutableNode.Builder().name("newNode").create();
181 final Set<ImmutableNode> nodes = Collections.singleton(newNode);
182 assertThrows(IllegalArgumentException.class, () -> model.addNodes(KEY, nodes, resolver));
183 }
184
185
186
187
188 @Test
189 void testAddNodesToNewNode() {
190 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
191 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_AUTHORS_TREE);
192 final String newAuthor = "Goethe";
193 final String newWork = "Faust";
194 final String newPersona = "Mephisto";
195
196 when(resolver.resolveKey(NodeStructureHelper.ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(new ArrayList<>(0));
197 when(resolver.resolveAddKey(NodeStructureHelper.ROOT_AUTHORS_TREE, KEY, model.getNodeHandler()))
198 .thenReturn(new NodeAddData<>(NodeStructureHelper.ROOT_AUTHORS_TREE, newWork, false, Arrays.asList(newAuthor)));
199
200 final ImmutableNode personaNode = new ImmutableNode.Builder().name(newPersona).create();
201 model.addNodes(KEY, Collections.singleton(personaNode), resolver);
202 assertSame(personaNode, nodeForKey(model, newAuthor + "/" + newWork + "/" + newPersona));
203 }
204
205
206
207
208 @Test
209 void testAddPropertyAttributeNoPathNodes() {
210 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
211 final NodeAddData<ImmutableNode> addData = new NodeAddData<>(nodeForKey(ROOT_AUTHORS_TREE, "Shakespeare/The Tempest"), "year", true, null);
212 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
213
214 when(resolver.resolveAddKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(addData);
215
216 model.addProperty(KEY, Collections.singleton(1611), resolver);
217 final ImmutableNode node = nodeForKey(model, "Shakespeare/The Tempest");
218 assertEquals(1611, node.getAttributes().get("year"));
219 }
220
221
222
223
224 @Test
225 void testAddPropertyAttributeWithPathNodes() {
226 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
227 final NodeAddData<ImmutableNode> addData = new NodeAddData<>(nodeForKey(ROOT_AUTHORS_TREE, "Homer/Ilias"), "number", true,
228 Arrays.asList("scenes", "scene"));
229 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
230
231 when(resolver.resolveAddKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(addData);
232
233 model.addProperty(KEY, Collections.singleton(1), resolver);
234 final ImmutableNode node = nodeForKey(model, "Homer/Ilias/scenes/scene");
235 assertEquals(1, node.getAttributes().get("number"));
236 }
237
238
239
240
241 @Test
242 void testAddPropertyAttributeWithSinglePathNode() {
243 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
244 final NodeAddData<ImmutableNode> addData = new NodeAddData<>(nodeForKey(ROOT_AUTHORS_TREE, NodeStructureHelper.author(0)), "year", true,
245 Arrays.asList("dateOfBirth"));
246 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
247
248 when(resolver.resolveAddKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(addData);
249
250 final Integer year = 1564;
251 model.addProperty(KEY, Collections.singleton(year), resolver);
252 final ImmutableNode node = nodeForKey(model, "Shakespeare/dateOfBirth");
253 assertEquals(year, node.getAttributes().get("year"));
254 }
255
256
257
258
259 @Test
260 void testAddPropertyNoPathNodes() {
261 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
262 final NodeAddData<ImmutableNode> addData = new NodeAddData<>(nodeForKey(ROOT_AUTHORS_TREE, "Homer"), "work", false, null);
263 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
264
265 when(resolver.resolveAddKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(addData);
266
267 model.addProperty(KEY, Collections.singleton("Odyssee"), resolver);
268 final ImmutableNode node = nodeForKey(model, "Homer/work");
269 assertEquals("Odyssee", node.getValue());
270 assertNotNull(nodeForKey(model, "Homer/Ilias/Hektor"));
271 }
272
273
274
275
276 @Test
277 void testAddPropertyNoValues() {
278 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
279 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
280
281 model.addProperty(KEY, Collections.emptySet(), resolver);
282 assertSame(ROOT_AUTHORS_TREE, model.getRootNode());
283 }
284
285
286
287
288 @Test
289 void testAddPropertyUpdateParentReferences() {
290 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
291 final NodeAddData<ImmutableNode> addData = new NodeAddData<>(nodeForKey(ROOT_AUTHORS_TREE, "Homer/Ilias"), "location", false,
292 Collections.singleton("locations"));
293 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
294
295 when(resolver.resolveAddKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(addData);
296
297 final String[] locations = {"Troja", "Beach", "Olympos"};
298
299 model.addProperty(KEY, Arrays.asList(locations), resolver);
300 final String[] path = {"Homer", "Ilias", "locations"};
301 final ImmutableNode node = nodeForKey(model, nodePathWithEndNode("location(1)", path));
302 checkPathToRoot(model, node, path);
303 }
304
305
306
307
308 @Test
309 void testAddPropertyWithPathNodes() {
310 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
311 final NodeAddData<ImmutableNode> addData = new NodeAddData<>(nodeForKey(ROOT_AUTHORS_TREE, "Homer/Ilias"), "location", false,
312 Collections.singleton("locations"));
313 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
314
315 when(resolver.resolveAddKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(addData);
316
317 final String[] locations = {"Troja", "Beach", "Olympos"};
318
319 model.addProperty(KEY, Arrays.asList(locations), resolver);
320 final ImmutableNode nodeLocs = nodeForKey(model, "Homer/Ilias/locations");
321 assertEquals(locations.length, nodeLocs.getChildren().size());
322 int idx = 0;
323 for (final ImmutableNode c : nodeLocs) {
324 assertEquals("location", c.getNodeName());
325 assertEquals(locations[idx], c.getValue());
326 assertTrue(c.getChildren().isEmpty());
327 assertTrue(c.getAttributes().isEmpty());
328 idx++;
329 }
330 assertNotNull(nodeForKey(model, "Homer/Ilias/Hektor"));
331 }
332
333
334
335
336 @Test
337 void testClear() {
338 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
339 model.clear(createResolver());
340 assertFalse(model.getNodeHandler().isDefined(model.getRootNode()));
341 assertEquals(ROOT_AUTHORS_TREE.getNodeName(), model.getRootNode().getNodeName());
342 }
343
344
345
346
347 @Test
348 void testClearPropertyAttribute() {
349 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
350 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_PERSONAE_TREE);
351 final String nodeKey = "Prospero/The Tempest/" + NodeStructureHelper.ELEM_ORG_VALUE;
352
353 when(resolver.resolveKey(model.getRootNode(), KEY, model.getNodeHandler()))
354 .thenReturn(Collections.singletonList(QueryResult.createAttributeResult(nodeForKey(model, nodeKey), NodeStructureHelper.ATTR_TESTED)));
355
356 model.clearProperty(KEY, resolver);
357 final ImmutableNode node = nodeForKey(model, nodeKey);
358 assertTrue(node.getAttributes().isEmpty());
359 }
360
361
362
363
364 @Test
365 void testClearPropertyNode() {
366 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
367 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_PERSONAE_TREE);
368 final String nodeKey = "Ariel/The Tempest/" + NodeStructureHelper.ELEM_ORG_VALUE;
369 when(resolver.resolveKey(model.getRootNode(), KEY, model.getNodeHandler()))
370 .thenReturn(Collections.singletonList(QueryResult.createNodeResult(nodeForKey(model, nodeKey))));
371
372 model.clearProperty(KEY, resolver);
373 final ImmutableNode node = nodeForKey(model, nodeKey);
374 assertNull(node.getValue());
375 }
376
377
378
379
380 @Test
381 void testClearPropertyNonExisting() {
382 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
383 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_PERSONAE_TREE);
384
385 when(resolver.resolveKey(model.getRootNode(), KEY, model.getNodeHandler())).thenReturn(Collections.<QueryResult<ImmutableNode>>emptyList());
386
387 final TreeData treeDataOld = model.getTreeData();
388 model.clearProperty(KEY, resolver);
389 assertNotNull(model.getNodeHandler().getRootNode());
390 assertSame(treeDataOld, model.getTreeData());
391 }
392
393
394
395
396 @Test
397 void testClearTreeAttribute() {
398 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
399 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_PERSONAE_TREE);
400 final String nodeName = "Puck";
401 final QueryResult<ImmutableNode> result = QueryResult.createAttributeResult(nodeForKey(model, nodeName), NodeStructureHelper.ATTR_AUTHOR);
402
403 when(resolver.resolveKey(ROOT_PERSONAE_TREE, KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(result));
404
405 final List<QueryResult<ImmutableNode>> removed = model.clearTree(KEY, resolver);
406 final ImmutableNode node = nodeForKey(model, nodeName);
407 assertTrue(node.getAttributes().isEmpty());
408 assertEquals(1, removed.size());
409 assertTrue(removed.contains(result));
410 }
411
412
413
414
415 @Test
416 void testClearTreeChildrenRemovedFromParentMapping() {
417 final String path = "Homer/Ilias";
418 checkClearTreeUpdatedParentMapping(path, nodeForKey(ROOT_AUTHORS_TREE, path + "/Achilles"));
419 }
420
421
422
423
424 @Test
425 void testClearTreeNodeRemovedFromParentMapping() {
426 final String path = "Homer/Ilias/Achilles";
427 checkClearTreeUpdatedParentMapping(path, nodeForKey(ROOT_AUTHORS_TREE, path));
428 }
429
430
431
432
433 @Test
434 void testClearTreeNodes() {
435 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
436 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
437 final QueryResult<ImmutableNode> result = QueryResult.createNodeResult(nodeForKey(model, "Homer/Ilias/Achilles"));
438
439 when(resolver.resolveKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(result));
440
441 final List<QueryResult<ImmutableNode>> removed = model.clearTree(KEY, resolver);
442 final ImmutableNode node = nodeForKey(model, "Homer/Ilias");
443 assertEquals(2, node.getChildren().size());
444 for (final ImmutableNode c : node) {
445 assertNotEquals(result.getNode().getNodeName(), c.getNodeName());
446 }
447 assertEquals(1, removed.size());
448 assertTrue(removed.contains(result));
449 }
450
451
452
453
454
455 @Test
456 void testClearTreeNodesAndAttributes() {
457 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
458 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_PERSONAE_TREE);
459 final String nodeName = "Puck";
460 final ImmutableNode orgNode = nodeForKey(model, nodeName);
461 final List<QueryResult<ImmutableNode>> results = new ArrayList<>(2);
462 results.add(QueryResult.createAttributeResult(orgNode, NodeStructureHelper.ATTR_AUTHOR));
463 results.add(QueryResult.createNodeResult(orgNode.getChildren().get(0)));
464
465 when(resolver.resolveKey(ROOT_PERSONAE_TREE, KEY, model.getNodeHandler())).thenReturn(results);
466
467 model.clearTree(KEY, resolver);
468 assertThrows(NoSuchElementException.class, () -> nodeForKey(model, nodeName));
469 }
470
471
472
473
474 @Test
475 void testClearTreeNonExistingKey() {
476 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
477 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_PERSONAE_TREE);
478
479 when(resolver.resolveKey(ROOT_PERSONAE_TREE, KEY, model.getNodeHandler())).thenReturn(Collections.<QueryResult<ImmutableNode>>emptyList());
480
481 final TreeData treeDataOld = model.getTreeData();
482 assertTrue(model.clearTree(KEY, resolver).isEmpty());
483 assertNotNull(model.getNodeHandler().getRootNode());
484 assertSame(treeDataOld, model.getTreeData());
485 }
486
487
488
489
490 @Test
491 void testClearTreeRemoveUndefinedNodes() {
492 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
493 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
494 final ImmutableNode node = nodeForKey(model, "Homer/Ilias");
495 final List<QueryResult<ImmutableNode>> results = new ArrayList<>(node.getChildren().size());
496 for (final ImmutableNode child : node) {
497 results.add(QueryResult.createNodeResult(child));
498 }
499
500 when(resolver.resolveKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(results);
501
502 model.clearTree(KEY, resolver);
503 assertEquals(NodeStructureHelper.authorsLength() - 1, model.getRootNode().getChildren().size());
504 for (final ImmutableNode child : model.getRootNode()) {
505 assertNotEquals("Homer", child.getNodeName());
506 }
507 }
508
509
510
511
512 @Test
513 void testClearTreeResultIsEmpty() {
514 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
515 final ImmutableNode child = new ImmutableNode.Builder().name("child").value("test").create();
516 final ImmutableNode root = new ImmutableNode.Builder(1).addChild(child).create();
517 final InMemoryNodeModel model = new InMemoryNodeModel(root);
518
519 when(resolver.resolveKey(root, KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(QueryResult.createNodeResult(child)));
520
521 model.clearTree(KEY, resolver);
522 assertFalse(model.getNodeHandler().isDefined(model.getRootNode()));
523 }
524
525
526
527
528 @Test
529 void testClearTreeRootNode() {
530 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
531 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
532 final List<QueryResult<ImmutableNode>> results = new ArrayList<>(2);
533 results.add(QueryResult.createNodeResult(nodeForKey(model, NodeStructureHelper.author(0))));
534 results.add(QueryResult.createNodeResult(ROOT_AUTHORS_TREE));
535
536 when(resolver.resolveKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(results);
537
538 model.clearTree(KEY, resolver);
539 assertFalse(model.getNodeHandler().isDefined(model.getRootNode()));
540 }
541
542
543
544
545 @Test
546 void testClearTreeUpdateParentReferences() {
547 final String[] path = {"Homer", "Ilias"};
548 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
549 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
550 final QueryResult<ImmutableNode> result = QueryResult.createNodeResult(nodeForKey(model, nodePathWithEndNode("Achilles", path)));
551
552 when(resolver.resolveKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(Collections.singletonList(result));
553
554 model.clearTree(KEY, resolver);
555 checkPathToRoot(model, nodeForKey(model, nodePathWithEndNode("Hektor", path)), path);
556 }
557
558
559
560
561 @Test
562 void testCompactReplacementMapping() {
563 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
564 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
565 final int numberOfOperations = 200;
566 final String key = "Homer/Ilias";
567 for (int i = 0; i < numberOfOperations; i++) {
568 final int index = i;
569 when(resolver.resolveAddKey(any(), eq(KEY), any())).thenAnswer(invocation -> {
570 assertSame(model.getRootNode(), invocation.getArgument(0));
571 final ImmutableNode addParent = nodeForKey(model, key);
572 return new NodeAddData<>(addParent, "Warrior" + index, false, null);
573 });
574 }
575
576 for (int i = 0; i < numberOfOperations; i++) {
577 model.addProperty(KEY, Collections.singleton(i), resolver);
578 }
579 final ImmutableNode orgNode = nodeForKey(ROOT_AUTHORS_TREE, key);
580 final ImmutableNode changedNode = nodeForKey(model, key);
581 assertEquals(orgNode.getChildren().size() + numberOfOperations, changedNode.getChildren().size());
582 final Map<ImmutableNode, ImmutableNode> replacementMapping = model.getTreeData().copyReplacementMapping();
583 assertTrue(replacementMapping.size() < numberOfOperations);
584 }
585
586
587
588
589
590 @Test
591 void testConcurrentUpdate() throws InterruptedException {
592 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
593 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_AUTHORS_TREE);
594
595 when(resolver.resolveAddKey(any(), eq(KEY), any())).thenAnswer(invocation -> {
596 final ImmutableNode addParent = invocation.getArgument(0, ImmutableNode.class);
597 return new NodeAddData<>(addParent, "name", false, Collections.singleton("author"));
598 });
599
600 final CountDownLatch latch = new CountDownLatch(1);
601 final String authorPrefix = "newAuthor";
602 final int threadCount = 32;
603 final Thread[] threads = new Thread[threadCount];
604 for (int i = 0; i < threadCount; i++) {
605 final String authorName = authorPrefix + i;
606 threads[i] = new Thread(() -> {
607 try {
608 latch.await();
609 model.addProperty(KEY, Collections.singleton(authorName), resolver);
610 } catch (final InterruptedException iex) {
611
612 }
613 });
614 threads[i].start();
615 }
616 latch.countDown();
617 for (final Thread t : threads) {
618 t.join();
619 }
620
621 final Pattern patternAuthorName = Pattern.compile(Pattern.quote(authorPrefix) + "(\\d+)");
622 final Set<Integer> indices = new HashSet<>();
623 for (int i = 0; i < threadCount; i++) {
624 final ImmutableNode node = nodeForKey(model, "author(" + i + ")/name");
625 final Matcher m = patternAuthorName.matcher(String.valueOf(node.getValue()));
626 assertTrue(m.matches(), "Wrong value: " + node.getValue());
627 final int idx = Integer.parseInt(m.group(1));
628 assertTrue(idx >= 0 && idx < threadCount, "Invalid index: " + idx);
629 indices.add(idx);
630 }
631 assertEquals(threadCount, indices.size());
632 }
633
634
635
636
637 @Test
638 void testGetInMemoryRepresentation() {
639 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_AUTHORS_TREE);
640 assertSame(NodeStructureHelper.ROOT_AUTHORS_TREE, model.getInMemoryRepresentation());
641 }
642
643
644
645
646 @Test
647 void testGetNodeHandler() {
648 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_PERSONAE_TREE);
649 assertSame(model.getTreeData(), model.getNodeHandler());
650 }
651
652
653
654
655 @Test
656 void testGetRootNodeFromConstructor() {
657 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
658 assertSame(ROOT_AUTHORS_TREE, model.getRootNode());
659 }
660
661
662
663
664 @Test
665 void testInitDefaultRoot() {
666 final InMemoryNodeModel model = new InMemoryNodeModel();
667 final ImmutableNode root = model.getRootNode();
668 assertNull(root.getNodeName());
669 assertNull(root.getValue());
670 assertTrue(root.getChildren().isEmpty());
671 assertTrue(root.getAttributes().isEmpty());
672 }
673
674
675
676
677 @Test
678 void testSetPropertyChangedValues() {
679 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
680 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_PERSONAE_TREE);
681 final String nodeKey = "Ariel/The Tempest/" + NodeStructureHelper.ELEM_ORG_VALUE;
682 final Map<QueryResult<ImmutableNode>, Object> changedValues = new HashMap<>();
683 final String newValue = "of course";
684 final ImmutableNode changedNode = nodeForKey(model, nodeKey);
685 changedValues.put(QueryResult.createAttributeResult(changedNode, NodeStructureHelper.ATTR_TESTED), newValue);
686 changedValues.put(QueryResult.createNodeResult(changedNode), newValue);
687 final NodeUpdateData<ImmutableNode> updateData = new NodeUpdateData<>(changedValues, null, null, null);
688
689 when(resolver.resolveUpdateKey(NodeStructureHelper.ROOT_PERSONAE_TREE, KEY, this, model.getNodeHandler())).thenReturn(updateData);
690
691 model.setProperty(KEY, this, resolver);
692 final ImmutableNode node = nodeForKey(model, nodeKey);
693 assertEquals(newValue, node.getAttributes().get(NodeStructureHelper.ATTR_TESTED));
694 assertEquals(newValue, node.getValue());
695 }
696
697
698
699
700 @Test
701 void testSetPropertyClearValues() {
702 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
703 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_PERSONAE_TREE);
704 final String nodeKey = "Ariel/The Tempest/" + NodeStructureHelper.ELEM_ORG_VALUE;
705 final NodeUpdateData<ImmutableNode> updateData = new NodeUpdateData<>(null, null,
706 Collections.singletonList(QueryResult.createNodeResult(nodeForKey(model, nodeKey))), null);
707
708 when(resolver.resolveUpdateKey(NodeStructureHelper.ROOT_PERSONAE_TREE, KEY, this, model.getNodeHandler())).thenReturn(updateData);
709
710 model.setProperty(KEY, this, resolver);
711 final ImmutableNode node = nodeForKey(model, nodeKey);
712 assertNull(node.getValue());
713 }
714
715
716
717
718 @Test
719 void testSetPropertyNewValues() {
720 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
721 final NodeAddData<ImmutableNode> addData = new NodeAddData<>(nodeForKey(ROOT_AUTHORS_TREE, "Homer"), "work", false, null);
722 final NodeUpdateData<ImmutableNode> updateData = new NodeUpdateData<>(null, Collections.<Object>singleton("Odyssee"), null, KEY);
723 final InMemoryNodeModel model = new InMemoryNodeModel(ROOT_AUTHORS_TREE);
724
725 when(resolver.resolveUpdateKey(ROOT_AUTHORS_TREE, KEY, this, model.getNodeHandler())).thenReturn(updateData);
726 when(resolver.resolveAddKey(ROOT_AUTHORS_TREE, KEY, model.getNodeHandler())).thenReturn(addData);
727
728 model.setProperty(KEY, this, resolver);
729 final ImmutableNode node = nodeForKey(model, "Homer/work");
730 assertEquals("Odyssee", node.getValue());
731 assertNotNull(nodeForKey(model, "Homer/Ilias/Hektor"));
732 }
733
734
735
736
737 @Test
738 void testSetPropertyNoChanges() {
739 final NodeKeyResolver<ImmutableNode> resolver = createResolver();
740 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_PERSONAE_TREE);
741
742 when(resolver.resolveUpdateKey(NodeStructureHelper.ROOT_PERSONAE_TREE, KEY, this, model.getNodeHandler()))
743 .thenReturn(new NodeUpdateData<>(null, null, null, null));
744
745 model.setProperty(KEY, this, resolver);
746 assertSame(NodeStructureHelper.ROOT_PERSONAE_TREE, model.getRootNode());
747 }
748
749
750
751
752 @Test
753 void testSetRoot() {
754 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_PERSONAE_TREE);
755 model.setRootNode(NodeStructureHelper.ROOT_AUTHORS_TREE);
756 assertSame(NodeStructureHelper.ROOT_AUTHORS_TREE, model.getRootNode());
757 final ImmutableNode node = nodeForKey(model, "Homer/Ilias");
758 assertEquals(nodeForKey(model, "Homer"), model.getNodeHandler().getParent(node));
759 }
760
761
762
763
764 @Test
765 void testSetRootNull() {
766 final InMemoryNodeModel model = new InMemoryNodeModel(NodeStructureHelper.ROOT_PERSONAE_TREE);
767 model.setRootNode(null);
768 final ImmutableNode rootNode = model.getRootNode();
769 assertTrue(rootNode.getChildren().isEmpty());
770 }
771 }