1
2
3
4
5
6 package dev.metaschema.core.metapath.item.node;
7
8 import static org.junit.jupiter.api.Assertions.assertEquals;
9 import static org.junit.jupiter.api.Assertions.assertNotNull;
10 import static org.junit.jupiter.api.Assertions.assertNull;
11 import static org.junit.jupiter.api.Assertions.assertTrue;
12
13 import org.junit.jupiter.api.Test;
14
15 import java.net.URI;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.stream.Collectors;
19
20 import dev.metaschema.core.mdm.IDMAssemblyNodeItem;
21 import dev.metaschema.core.mdm.IDMDocumentNodeItem;
22 import dev.metaschema.core.mdm.IDMFieldNodeItem;
23 import dev.metaschema.core.metapath.StaticContext;
24 import dev.metaschema.core.metapath.item.atomic.IStringItem;
25 import dev.metaschema.core.model.IAssemblyDefinition;
26 import dev.metaschema.core.model.IAssemblyInstance;
27 import dev.metaschema.core.model.IFieldInstance;
28 import dev.metaschema.core.model.IFlagInstance;
29 import dev.metaschema.core.model.IModule;
30 import dev.metaschema.core.model.ISource;
31 import dev.metaschema.core.qname.IEnhancedQName;
32 import dev.metaschema.core.testsupport.MockedModelTestSupport;
33 import dev.metaschema.core.testsupport.builder.IFieldBuilder;
34 import dev.metaschema.core.testsupport.builder.IModuleBuilder;
35 import dev.metaschema.core.util.ObjectUtils;
36
37
38
39
40 class NodeItemTraversalTest {
41
42 private static final String TEST_NAMESPACE = "http://example.com/ns/traversal-test";
43 private static final URI DOCUMENT_URI = URI.create("http://example.com/test-doc.xml");
44
45
46
47
48 @Test
49 void testCreateDocumentNodeItem() {
50 MockedModelTestSupport mocking = new MockedModelTestSupport();
51 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
52
53 IModule module = IModuleBuilder.builder()
54 .namespace(TEST_NAMESPACE)
55 .shortName("traversal-test")
56 .version("1.0.0")
57 .source(source)
58 .assembly(mocking.assembly()
59 .name("root-assembly")
60 .rootName("root-assembly"))
61 .toModule();
62
63 IAssemblyDefinition rootDef = module.getRootAssemblyDefinitions().iterator().next();
64 assertNotNull(rootDef, "Root assembly definition should exist");
65
66
67 IDMDocumentNodeItem document = IDMDocumentNodeItem.newInstance(DOCUMENT_URI, rootDef);
68
69 assertNotNull(document, "Document node item should be created");
70 assertEquals(INodeItem.NodeType.DOCUMENT, document.getNodeType(), "Should be a document node");
71 assertEquals(DOCUMENT_URI, document.getDocumentUri(), "Document URI should match");
72 assertNull(document.getParentNodeItem(), "Document should have no parent");
73
74 IRootAssemblyNodeItem rootAssembly = document.getRootAssemblyNodeItem();
75 assertNotNull(rootAssembly, "Root assembly should exist");
76 assertEquals(INodeItem.NodeType.ASSEMBLY, rootAssembly.getNodeType(), "Should be an assembly node");
77 assertEquals(document, rootAssembly.getParentNodeItem(), "Root assembly parent should be the document");
78 }
79
80
81
82
83 @Test
84 void testCreateAssemblyWithFlags() {
85 MockedModelTestSupport mocking = new MockedModelTestSupport();
86 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
87
88 IModule module = IModuleBuilder.builder()
89 .namespace(TEST_NAMESPACE)
90 .shortName("traversal-test")
91 .version("1.0.0")
92 .source(source)
93 .assembly(mocking.assembly()
94 .name("test-assembly")
95 .rootName("test-assembly")
96 .flags(List.of(
97 mocking.flag().namespace(TEST_NAMESPACE).name("flag1"),
98 mocking.flag().namespace(TEST_NAMESPACE).name("flag2"))))
99 .toModule();
100
101 IAssemblyDefinition assemblyDef = module.getRootAssemblyDefinitions().iterator().next();
102 StaticContext staticContext = StaticContext.instance();
103 IDMAssemblyNodeItem assembly = IDMAssemblyNodeItem.newInstance(assemblyDef, staticContext);
104
105
106 IFlagInstance flag1Instance = assemblyDef.getFlagInstanceByName(
107 IEnhancedQName.of(TEST_NAMESPACE, "flag1").getIndexPosition());
108 IFlagInstance flag2Instance = assemblyDef.getFlagInstanceByName(
109 IEnhancedQName.of(TEST_NAMESPACE, "flag2").getIndexPosition());
110 assertNotNull(flag1Instance, "flag1 instance should exist");
111 assertNotNull(flag2Instance, "flag2 instance should exist");
112
113 assembly.newFlag(flag1Instance, IStringItem.valueOf("value1"));
114 assembly.newFlag(flag2Instance, IStringItem.valueOf("value2"));
115
116
117 List<? extends IFlagNodeItem> flags = assembly.getFlags().stream().collect(Collectors.toList());
118 assertEquals(2, flags.size(), "Should have 2 flags");
119
120
121 IFlagNodeItem flag1 = assembly.getFlagByName(IEnhancedQName.of(TEST_NAMESPACE, "flag1"));
122 assertNotNull(flag1, "Flag1 should be found by name");
123 assertEquals("value1", flag1.toAtomicItem().asString(), "Flag1 value should match");
124
125 IFlagNodeItem flag2 = assembly.getFlagByName(IEnhancedQName.of(TEST_NAMESPACE, "flag2"));
126 assertNotNull(flag2, "Flag2 should be found by name");
127 assertEquals("value2", flag2.toAtomicItem().asString(), "Flag2 value should match");
128
129
130 assertEquals(assembly, flag1.getParentNodeItem(), "Flag parent should be the assembly");
131 assertEquals(INodeItem.NodeType.FLAG, flag1.getNodeType(), "Should be a flag node");
132 }
133
134
135
136
137 @Test
138 void testParentChildNavigation() {
139 MockedModelTestSupport mocking = new MockedModelTestSupport();
140 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
141
142 IModule module = IModuleBuilder.builder()
143 .namespace(TEST_NAMESPACE)
144 .shortName("traversal-test")
145 .version("1.0.0")
146 .source(source)
147 .assembly(mocking.assembly()
148 .name("parent-assembly")
149 .rootName("parent-assembly")
150 .modelInstances(List.of(
151 mocking.field().namespace(TEST_NAMESPACE).name("child-field"))))
152 .toModule();
153
154 IAssemblyDefinition assemblyDef = module.getRootAssemblyDefinitions().iterator().next();
155 StaticContext staticContext = StaticContext.instance();
156 IDMAssemblyNodeItem assembly = IDMAssemblyNodeItem.newInstance(assemblyDef, staticContext);
157
158
159 List<IFieldInstance> fieldInstances = new ArrayList<>(assemblyDef.getFieldInstances());
160 assertEquals(1, fieldInstances.size(), "Should have 1 field instance");
161
162 IDMFieldNodeItem field = assembly.newField(fieldInstances.get(0), IStringItem.valueOf("field-value"));
163
164
165 assertEquals(assembly, field.getParentNodeItem(), "Field parent should be the assembly");
166 assertEquals(assembly, field.getParentContentNodeItem(), "Field parent content node should be the assembly");
167
168 List<? extends IModelNodeItem<?, ?>> modelItems = assembly.modelItems().collect(Collectors.toList());
169 assertEquals(1, modelItems.size(), "Assembly should have 1 child model item");
170 assertEquals(field, modelItems.get(0), "Child should be the field we added");
171
172 assertEquals(INodeItem.NodeType.FIELD, field.getNodeType(), "Should be a field node");
173 assertEquals(INodeItem.NodeType.ASSEMBLY, assembly.getNodeType(), "Should be an assembly node");
174 }
175
176
177
178
179 @Test
180 void testAncestorAxis() {
181 MockedModelTestSupport mocking = new MockedModelTestSupport();
182 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
183
184 IModule module = IModuleBuilder.builder()
185 .namespace(TEST_NAMESPACE)
186 .shortName("traversal-test")
187 .version("1.0.0")
188 .source(source)
189 .assembly(mocking.assembly()
190 .name("grandparent-assembly")
191 .rootName("grandparent-assembly")
192 .modelInstances(List.of(
193 mocking.assemblyRef("child-assembly"))))
194 .assembly(mocking.assembly()
195 .name("child-assembly")
196 .modelInstances(List.of(
197 mocking.field().namespace(TEST_NAMESPACE).name("grandchild-field"))))
198 .toModule();
199
200 IAssemblyDefinition grandparentDef = module.getRootAssemblyDefinitions().iterator().next();
201 IDMDocumentNodeItem document = IDMDocumentNodeItem.newInstance(DOCUMENT_URI, grandparentDef);
202 IRootAssemblyNodeItem grandparent = document.getRootAssemblyNodeItem();
203
204
205 IAssemblyInstance childAssemblyInstance = grandparentDef.getAssemblyInstances().iterator().next();
206 IDMAssemblyNodeItem child = ((IDMAssemblyNodeItem) grandparent).newAssembly(childAssemblyInstance);
207
208
209 IFieldInstance grandchildFieldInstance = child.getDefinition().getFieldInstances().iterator().next();
210 IDMFieldNodeItem grandchild = child.newField(grandchildFieldInstance, IStringItem.valueOf("test-value"));
211
212
213
214 List<? extends INodeItem> ancestors = grandchild.ancestor().collect(Collectors.toList());
215 assertEquals(3, ancestors.size(), "Grandchild should have 3 ancestors: document, grandparent, child");
216
217 assertEquals(document, ancestors.get(0), "First ancestor should be the document (farthest)");
218 assertEquals(grandparent, ancestors.get(1), "Second ancestor should be the grandparent assembly");
219 assertEquals(child, ancestors.get(2), "Third ancestor should be the child assembly (nearest)");
220
221
222
223 List<? extends INodeItem> ancestorsOrSelf = grandchild.ancestorOrSelf().collect(Collectors.toList());
224 assertEquals(4, ancestorsOrSelf.size(), "Should have 4 items: 3 ancestors + self");
225 assertEquals(grandchild, ancestorsOrSelf.get(3), "Last item should be self");
226 }
227
228
229
230
231 @Test
232 void testDescendantAxis() {
233 MockedModelTestSupport mocking = new MockedModelTestSupport();
234 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
235
236 IModule module = IModuleBuilder.builder()
237 .namespace(TEST_NAMESPACE)
238 .shortName("traversal-test")
239 .version("1.0.0")
240 .source(source)
241 .assembly(mocking.assembly()
242 .name("parent-assembly")
243 .rootName("parent-assembly")
244 .modelInstances(List.of(
245 mocking.field().namespace(TEST_NAMESPACE).name("field1"),
246 mocking.field().namespace(TEST_NAMESPACE).name("field2"),
247 mocking.assemblyRef("child-assembly"))))
248 .assembly(mocking.assembly()
249 .name("child-assembly")
250 .modelInstances(List.of(
251 mocking.field().namespace(TEST_NAMESPACE).name("nested-field"))))
252 .toModule();
253
254 IAssemblyDefinition parentDef = module.getRootAssemblyDefinitions().iterator().next();
255 StaticContext staticContext = StaticContext.instance();
256 IDMAssemblyNodeItem parent = IDMAssemblyNodeItem.newInstance(parentDef, staticContext);
257
258
259 IFieldInstance field1Instance = parentDef.getModelInstances().stream()
260 .filter(instance -> instance instanceof IFieldInstance)
261 .map(instance -> (IFieldInstance) instance)
262 .filter(instance -> "field1".equals(instance.getName()))
263 .findFirst()
264 .orElseThrow(() -> new AssertionError("field1 instance not found"));
265 IFieldInstance field2Instance = parentDef.getModelInstances().stream()
266 .filter(instance -> instance instanceof IFieldInstance)
267 .map(instance -> (IFieldInstance) instance)
268 .filter(instance -> "field2".equals(instance.getName()))
269 .findFirst()
270 .orElseThrow(() -> new AssertionError("field2 instance not found"));
271
272 parent.newField(field1Instance, IStringItem.valueOf("value1"));
273 parent.newField(field2Instance, IStringItem.valueOf("value2"));
274
275 IAssemblyInstance childAssemblyInstance = parentDef.getAssemblyInstances().iterator().next();
276 IDMAssemblyNodeItem childAssembly = parent.newAssembly(childAssemblyInstance);
277
278 IFieldInstance nestedFieldInstance = childAssembly.getDefinition().getFieldInstances().iterator().next();
279 childAssembly.newField(nestedFieldInstance, IStringItem.valueOf("nested-value"));
280
281
282 List<? extends IModelNodeItem<?, ?>> descendants = parent.descendant().collect(Collectors.toList());
283 assertEquals(4, descendants.size(), "Should have 4 descendants: field1, field2, child-assembly, nested-field");
284
285
286 long fieldCount = descendants.stream()
287 .filter(item -> item.getNodeType() == INodeItem.NodeType.FIELD)
288 .count();
289 long assemblyCount = descendants.stream()
290 .filter(item -> item.getNodeType() == INodeItem.NodeType.ASSEMBLY)
291 .count();
292 assertEquals(3, fieldCount, "Should have 3 field descendants (field1, field2, nested-field)");
293 assertEquals(1, assemblyCount, "Should have 1 assembly descendant (child-assembly)");
294
295
296
297 IModelNodeItem<?, ?> nestedField = descendants.stream()
298 .filter(item -> item.getNodeType() == INodeItem.NodeType.FIELD)
299 .filter(item -> item.getParentNodeItem() != parent)
300 .findFirst()
301 .orElse(null);
302 assertNotNull(nestedField, "Should have a nested field under child-assembly");
303 assertEquals(INodeItem.NodeType.ASSEMBLY, nestedField.getParentNodeItem().getNodeType(),
304 "Nested field's parent should be the child assembly");
305
306
307 List<? extends INodeItem> descendantsOrSelf = parent.descendantOrSelf().collect(Collectors.toList());
308 assertEquals(5, descendantsOrSelf.size(), "Should have 5 items: self + 4 descendants");
309 assertEquals(parent, descendantsOrSelf.get(0), "First item should be self");
310 }
311
312
313
314
315 @Test
316 void testFlagAccessOnFieldsAndAssemblies() {
317 MockedModelTestSupport mocking = new MockedModelTestSupport();
318 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
319
320
321 IFieldBuilder fieldBuilder = mocking.field()
322 .namespace(TEST_NAMESPACE)
323 .name("test-field")
324 .source(source)
325 .flags(List.of(
326 mocking.flag().namespace(TEST_NAMESPACE).name("field-flag").source(source)));
327
328 IModule module = IModuleBuilder.builder()
329 .namespace(TEST_NAMESPACE)
330 .shortName("traversal-test")
331 .version("1.0.0")
332 .source(source)
333 .assembly(mocking.assembly()
334 .name("test-assembly")
335 .rootName("test-assembly")
336 .source(source)
337 .flags(List.of(
338 mocking.flag().namespace(TEST_NAMESPACE).name("assembly-flag").source(source)))
339 .modelInstances(List.of(fieldBuilder)))
340 .toModule();
341
342 IAssemblyDefinition assemblyDef = module.getRootAssemblyDefinitions().iterator().next();
343 StaticContext staticContext = StaticContext.instance();
344 IDMAssemblyNodeItem assembly = IDMAssemblyNodeItem.newInstance(assemblyDef, staticContext);
345
346
347 List<IFlagInstance> assemblyFlags = new ArrayList<>(assemblyDef.getFlagInstances());
348 assertEquals(1, assemblyFlags.size(), "Assembly should have 1 flag");
349 assembly.newFlag(assemblyFlags.get(0), IStringItem.valueOf("assembly-flag-value"));
350
351
352 IFieldInstance fieldInstance = assemblyDef.getFieldInstances().iterator().next();
353 IDMFieldNodeItem field = assembly.newField(fieldInstance, IStringItem.valueOf("field-value"));
354
355 List<IFlagInstance> fieldFlags = new ArrayList<>(fieldInstance.getDefinition().getFlagInstances());
356 assertEquals(1, fieldFlags.size(), "Field should have 1 flag");
357 field.newFlag(fieldFlags.get(0), IStringItem.valueOf("field-flag-value"));
358
359
360 List<? extends IFlagNodeItem> assemblyFlagItems = assembly.flags().collect(Collectors.toList());
361 assertEquals(1, assemblyFlagItems.size(), "Assembly should have 1 flag item");
362 assertEquals("assembly-flag-value", assemblyFlagItems.get(0).toAtomicItem().asString(),
363 "Assembly flag value should match");
364
365
366 List<? extends IFlagNodeItem> fieldFlagItems = field.flags().collect(Collectors.toList());
367 assertEquals(1, fieldFlagItems.size(), "Field should have 1 flag item");
368 assertEquals("field-flag-value", fieldFlagItems.get(0).toAtomicItem().asString(),
369 "Field flag value should match");
370 }
371
372
373
374
375 @Test
376 void testNodeTypeIdentification() {
377 MockedModelTestSupport mocking = new MockedModelTestSupport();
378 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
379
380 IModule module = IModuleBuilder.builder()
381 .namespace(TEST_NAMESPACE)
382 .shortName("traversal-test")
383 .version("1.0.0")
384 .source(source)
385 .assembly(mocking.assembly()
386 .name("test-assembly")
387 .rootName("test-assembly")
388 .flags(List.of(
389 mocking.flag().namespace(TEST_NAMESPACE).name("test-flag")))
390 .modelInstances(List.of(
391 mocking.field().namespace(TEST_NAMESPACE).name("test-field"))))
392 .toModule();
393
394 IAssemblyDefinition assemblyDef = module.getRootAssemblyDefinitions().iterator().next();
395 IDMDocumentNodeItem document = IDMDocumentNodeItem.newInstance(DOCUMENT_URI, assemblyDef);
396 IRootAssemblyNodeItem assembly = document.getRootAssemblyNodeItem();
397
398
399 List<IFlagInstance> flagInstances = new ArrayList<>(assemblyDef.getFlagInstances());
400 ((IDMAssemblyNodeItem) assembly).newFlag(flagInstances.get(0), IStringItem.valueOf("flag-value"));
401
402
403 IFieldInstance fieldInstance = assemblyDef.getFieldInstances().iterator().next();
404 IDMFieldNodeItem field = ((IDMAssemblyNodeItem) assembly).newField(fieldInstance,
405 IStringItem.valueOf("field-value"));
406
407
408 IFlagNodeItem flag = assembly.getFlagByName(IEnhancedQName.of(TEST_NAMESPACE, "test-flag"));
409 assertNotNull(flag, "Flag should exist");
410
411
412 assertEquals(INodeItem.NodeType.DOCUMENT, document.getNodeType(), "Should identify as document");
413 assertEquals(INodeItem.NodeType.ASSEMBLY, assembly.getNodeType(), "Should identify as assembly");
414 assertEquals(INodeItem.NodeType.FIELD, field.getNodeType(), "Should identify as field");
415 assertEquals(INodeItem.NodeType.FLAG, flag.getNodeType(), "Should identify as flag");
416 }
417
418
419
420
421 @Test
422 void testMetapathGeneration() {
423 MockedModelTestSupport mocking = new MockedModelTestSupport();
424 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
425
426 IModule module = IModuleBuilder.builder()
427 .namespace(TEST_NAMESPACE)
428 .shortName("traversal-test")
429 .version("1.0.0")
430 .source(source)
431 .assembly(mocking.assembly()
432 .name("root-assembly")
433 .rootName("root-assembly")
434 .modelInstances(List.of(
435 mocking.field().namespace(TEST_NAMESPACE).name("child-field"))))
436 .toModule();
437
438 IAssemblyDefinition assemblyDef = module.getRootAssemblyDefinitions().iterator().next();
439 IDMDocumentNodeItem document = IDMDocumentNodeItem.newInstance(DOCUMENT_URI, assemblyDef);
440 IRootAssemblyNodeItem assembly = document.getRootAssemblyNodeItem();
441
442
443 IFieldInstance fieldInstance = assemblyDef.getFieldInstances().iterator().next();
444 IDMFieldNodeItem field = ((IDMAssemblyNodeItem) assembly).newField(fieldInstance,
445 IStringItem.valueOf("field-value"));
446
447
448
449 String documentPath = document.getMetapath();
450 assertNotNull(documentPath, "Document should have a metapath (even if empty)");
451
452 String assemblyPath = assembly.getMetapath();
453 assertNotNull(assemblyPath, "Assembly should have a metapath");
454
455 assertTrue(assemblyPath.length() > 0, "Root assembly metapath should not be empty");
456
457 String fieldPath = field.getMetapath();
458 assertNotNull(fieldPath, "Field should have a metapath");
459 assertTrue(fieldPath.length() > 0, "Field metapath should not be empty");
460
461
462
463 assertTrue(fieldPath.length() >= assemblyPath.length(),
464 "Field metapath should be at least as long as assembly metapath");
465 }
466
467
468
469
470 @Test
471 void testModelItemsByName() {
472 MockedModelTestSupport mocking = new MockedModelTestSupport();
473 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
474
475 IModule module = IModuleBuilder.builder()
476 .namespace(TEST_NAMESPACE)
477 .shortName("traversal-test")
478 .version("1.0.0")
479 .source(source)
480 .assembly(mocking.assembly()
481 .name("test-assembly")
482 .rootName("test-assembly")
483 .modelInstances(List.of(
484 mocking.field().namespace(TEST_NAMESPACE).name("field1"),
485 mocking.field().namespace(TEST_NAMESPACE).name("field2"))))
486 .toModule();
487
488 IAssemblyDefinition assemblyDef = module.getRootAssemblyDefinitions().iterator().next();
489 StaticContext staticContext = StaticContext.instance();
490 IDMAssemblyNodeItem assembly = IDMAssemblyNodeItem.newInstance(assemblyDef, staticContext);
491
492
493 IFieldInstance field1Instance = assemblyDef.getModelInstances().stream()
494 .filter(instance -> instance instanceof IFieldInstance)
495 .map(instance -> (IFieldInstance) instance)
496 .filter(instance -> "field1".equals(instance.getName()))
497 .findFirst()
498 .orElseThrow(() -> new AssertionError("field1 instance not found"));
499 IFieldInstance field2Instance = assemblyDef.getModelInstances().stream()
500 .filter(instance -> instance instanceof IFieldInstance)
501 .map(instance -> (IFieldInstance) instance)
502 .filter(instance -> "field2".equals(instance.getName()))
503 .findFirst()
504 .orElseThrow(() -> new AssertionError("field2 instance not found"));
505
506 assembly.newField(field1Instance, IStringItem.valueOf("value1"));
507 assembly.newField(field2Instance, IStringItem.valueOf("value2"));
508
509
510 List<? extends IModelNodeItem<?, ?>> field1Items = assembly
511 .getModelItemsByName(IEnhancedQName.of(TEST_NAMESPACE, "field1"));
512 assertEquals(1, field1Items.size(), "Should find 1 item for field1");
513 assertEquals("value1", field1Items.get(0).toAtomicItem().asString(), "Field1 value should match");
514
515 List<? extends IModelNodeItem<?, ?>> field2Items = assembly
516 .getModelItemsByName(IEnhancedQName.of(TEST_NAMESPACE, "field2"));
517 assertEquals(1, field2Items.size(), "Should find 1 item for field2");
518 assertEquals("value2", field2Items.get(0).toAtomicItem().asString(), "Field2 value should match");
519
520
521 List<? extends IModelNodeItem<?, ?>> nonExistentItems = assembly
522 .getModelItemsByName(IEnhancedQName.of(TEST_NAMESPACE, "non-existent"));
523 assertTrue(nonExistentItems.isEmpty(), "Should return empty list for non-existent name");
524 }
525
526
527
528
529 @Test
530 void testComplexAssemblyHierarchy() {
531 MockedModelTestSupport mocking = new MockedModelTestSupport();
532 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
533
534 IModule module = IModuleBuilder.builder()
535 .namespace(TEST_NAMESPACE)
536 .shortName("traversal-test")
537 .version("1.0.0")
538 .source(source)
539 .assembly(mocking.assembly()
540 .name("level1")
541 .rootName("level1")
542 .modelInstances(List.of(
543 mocking.assemblyRef("level2"))))
544 .assembly(mocking.assembly()
545 .name("level2")
546 .modelInstances(List.of(
547 mocking.assemblyRef("level3"))))
548 .assembly(mocking.assembly()
549 .name("level3")
550 .modelInstances(List.of(
551 mocking.field().namespace(TEST_NAMESPACE).name("leaf-field"))))
552 .toModule();
553
554 IAssemblyDefinition level1Def = module.getRootAssemblyDefinitions().iterator().next();
555 IDMDocumentNodeItem document = IDMDocumentNodeItem.newInstance(DOCUMENT_URI, level1Def);
556 IRootAssemblyNodeItem level1 = document.getRootAssemblyNodeItem();
557
558
559 IAssemblyInstance level2Instance = level1Def.getAssemblyInstances().iterator().next();
560 IDMAssemblyNodeItem level2 = ((IDMAssemblyNodeItem) level1).newAssembly(level2Instance);
561
562
563 IAssemblyInstance level3Instance = level2.getDefinition().getAssemblyInstances().iterator().next();
564 IDMAssemblyNodeItem level3 = level2.newAssembly(level3Instance);
565
566
567 IFieldInstance leafFieldInstance = level3.getDefinition().getFieldInstances().iterator().next();
568 IDMFieldNodeItem leafField = level3.newField(leafFieldInstance, IStringItem.valueOf("leaf-value"));
569
570
571 assertEquals(level3, leafField.getParentNodeItem(), "Leaf field parent should be level3");
572 assertEquals(level2, level3.getParentNodeItem(), "Level3 parent should be level2");
573 assertEquals(level1, level2.getParentNodeItem(), "Level2 parent should be level1");
574 assertEquals(document, level1.getParentNodeItem(), "Level1 parent should be document");
575
576
577 List<? extends IModelNodeItem<?, ?>> allDescendants = level1.descendant().collect(Collectors.toList());
578 assertEquals(3, allDescendants.size(), "Should have 3 descendants from root: level2, level3, leaf-field");
579
580
581 List<? extends INodeItem> allAncestors = leafField.ancestor().collect(Collectors.toList());
582 assertEquals(4, allAncestors.size(), "Should have 4 ancestors from leaf: level3, level2, level1, document");
583 }
584
585
586
587
588 @Test
589 void testModuleNodeItem() {
590 MockedModelTestSupport mocking = new MockedModelTestSupport();
591 ISource source = ISource.externalSource(ObjectUtils.notNull(URI.create(TEST_NAMESPACE)));
592
593 IModule module = IModuleBuilder.builder()
594 .namespace(TEST_NAMESPACE)
595 .shortName("traversal-test")
596 .version("1.0.0")
597 .source(source)
598 .assembly(mocking.assembly()
599 .name("test-assembly")
600 .rootName("test-assembly"))
601 .toModule();
602
603
604 IModuleNodeItem moduleNode = INodeItemFactory.instance().newModuleNodeItem(module);
605
606 assertNotNull(moduleNode, "Module node item should be created");
607 assertEquals(INodeItem.NodeType.MODULE, moduleNode.getNodeType(), "Should be a module node");
608 assertNull(moduleNode.getParentNodeItem(), "Module node should have no parent");
609 assertEquals(module, moduleNode.getModule(), "Module should match");
610
611
612 List<? extends IModelNodeItem<?, ?>> modelItems = moduleNode.modelItems().collect(Collectors.toList());
613 assertTrue(modelItems.size() > 0, "Module should have model items for exported definitions");
614 }
615 }