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