fe35284c30b49cba41b214e979e92bbe3dadf4b5
[yangtools.git] / parser / yang-parser-rfc7950 / src / test / java / org / opendaylight / yangtools / yang / stmt / GroupingTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.stmt;
9
10 import static org.junit.Assert.assertNull;
11 import static org.junit.jupiter.api.Assertions.assertEquals;
12 import static org.junit.jupiter.api.Assertions.assertFalse;
13 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
14 import static org.junit.jupiter.api.Assertions.assertNotEquals;
15 import static org.junit.jupiter.api.Assertions.assertNotNull;
16 import static org.junit.jupiter.api.Assertions.assertTrue;
17
18 import com.google.common.collect.Iterables;
19 import java.util.List;
20 import java.util.Optional;
21 import org.junit.jupiter.api.Test;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.common.QNameModule;
24 import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
28 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
30 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
33 import org.opendaylight.yangtools.yang.model.api.stmt.RefineEffectiveStatement;
34 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Descendant;
35 import org.opendaylight.yangtools.yang.model.api.stmt.UnrecognizedStatement;
36
37 class GroupingTest extends AbstractModelTest {
38     @Test
39     void testRefine() {
40         final var peer = assertInstanceOf(ContainerSchemaNode.class, FOO.dataChildByName(fooQName("peer")));
41         final var destination = assertInstanceOf(ContainerSchemaNode.class,
42             peer.dataChildByName(fooQName("destination")));
43
44         final var usesNodes = destination.getUses();
45         assertEquals(1, usesNodes.size());
46         final var usesNode = usesNodes.iterator().next();
47         final var refines = usesNode.getRefines();
48         assertEquals(4, refines.size());
49
50         assertEquals(List.of(
51             Descendant.of(fooQName("address")),
52             Descendant.of(fooQName("port")),
53             Descendant.of(fooQName("addresses")),
54             Descendant.of(fooQName("addresses"), fooQName("id"))),
55             List.copyOf(usesNode.getRefines()));
56
57         // leaf address
58         final var refineLeaf = assertInstanceOf(LeafSchemaNode.class, destination.dataChildByName(fooQName("address")));
59         assertEquals(Optional.of("IP address of target node"), refineLeaf.getDescription());
60         assertEquals(Optional.of("address reference added by refine"), refineLeaf.getReference());
61         assertEquals(Optional.of(Boolean.FALSE), refineLeaf.effectiveConfig());
62         assertFalse(refineLeaf.isMandatory());
63         final var leafMustConstraints = refineLeaf.getMustConstraints();
64         assertEquals(1, leafMustConstraints.size());
65         final var leafMust = leafMustConstraints.iterator().next();
66         assertEquals("ifType != 'ethernet' or (ifType = 'ethernet' and ifMTU = 1500)", leafMust.getXpath().toString());
67         assertEquals(0, refineLeaf.getUnknownSchemaNodes().size());
68         assertEquals(1, usesNode.asEffectiveStatement()
69             .findFirstEffectiveSubstatement(RefineEffectiveStatement.class).orElseThrow().getDeclared()
70             .declaredSubstatements(UnrecognizedStatement.class).size());
71
72         // container port
73         final var refineContainer = assertInstanceOf(ContainerSchemaNode.class,
74             destination.dataChildByName(fooQName("port")));
75
76         final var mustConstraints = refineContainer.getMustConstraints();
77         assertTrue(mustConstraints.isEmpty());
78         assertEquals(Optional.of("description of port defined by refine"), refineContainer.getDescription());
79         assertEquals(Optional.of("port reference added by refine"), refineContainer.getReference());
80         assertEquals(Optional.of(Boolean.FALSE), refineContainer.effectiveConfig());
81         assertTrue(refineContainer.isPresenceContainer());
82
83 //      // list addresses
84         final var refineList = assertInstanceOf(ListSchemaNode.class,
85             destination.dataChildByName(fooQName("addresses")));
86         assertEquals(Optional.of("description of addresses defined by refine"), refineList.getDescription());
87         assertEquals(Optional.of("addresses reference added by refine"), refineList.getReference());
88         assertEquals(Optional.of(Boolean.FALSE), refineList.effectiveConfig());
89
90         final var constraint = refineList.getElementCountConstraint().orElseThrow();
91         assertEquals(2, constraint.getMinElements());
92         assertNull(constraint.getMaxElements());
93
94         // leaf id
95         final var refineInnerLeaf = assertInstanceOf(LeafSchemaNode.class, refineList.dataChildByName(fooQName("id")));
96         assertEquals(Optional.of("id of address"), refineInnerLeaf.getDescription());
97     }
98
99     @Test
100     void testGrouping() {
101         final var groupings = BAZ.getGroupings();
102         assertEquals(1, groupings.size());
103         final var grouping = groupings.iterator().next();
104         final var children = grouping.getChildNodes();
105         assertEquals(5, children.size());
106     }
107
108     @Test
109     void testUses() {
110         // suffix _u = added by uses
111         // suffix _g = defined in grouping
112
113         // get grouping
114         final var groupings = BAZ.getGroupings();
115         assertEquals(1, groupings.size());
116         final var grouping = groupings.iterator().next();
117
118         // get node containing uses
119         final var peer = assertInstanceOf(ContainerSchemaNode.class, FOO.dataChildByName(fooQName("peer")));
120         final var destination = assertInstanceOf(ContainerSchemaNode.class,
121             peer.dataChildByName(fooQName("destination")));
122
123         // check uses
124         final var uses = destination.getUses();
125         assertEquals(1, uses.size());
126
127         // check uses process
128         final var data_u = assertInstanceOf(AnyxmlSchemaNode.class, destination.dataChildByName(fooQName("data")));
129         assertTrue(data_u.isAddedByUses());
130
131         final var data_g = assertInstanceOf(AnyxmlSchemaNode.class, grouping.dataChildByName(bazQName("data")));
132         assertFalse(data_g.isAddedByUses());
133         assertNotEquals(data_u, data_g);
134
135         final var how_u = assertInstanceOf(ChoiceSchemaNode.class, destination.dataChildByName(fooQName("how")));
136         assertIsAddedByUses(how_u, true);
137         assertEquals(2, how_u.getCases().size());
138
139         final var how_g = assertInstanceOf(ChoiceSchemaNode.class, grouping.dataChildByName(bazQName("how")));
140         assertIsAddedByUses(how_g, false);
141         assertEquals(2, how_g.getCases().size());
142         assertNotEquals(how_u, how_g);
143
144         final var address_u = assertInstanceOf(LeafSchemaNode.class, destination.dataChildByName(fooQName("address")));
145         assertEquals(Optional.of("1.2.3.4"), address_u.getType().getDefaultValue());
146         assertEquals(Optional.of("IP address of target node"), address_u.getDescription());
147         assertEquals(Optional.of("address reference added by refine"), address_u.getReference());
148         assertEquals(Optional.of(Boolean.FALSE), address_u.effectiveConfig());
149         assertTrue(address_u.isAddedByUses());
150         assertFalse(address_u.isMandatory());
151
152         final var address_g = assertInstanceOf(LeafSchemaNode.class, grouping.dataChildByName(bazQName("address")));
153         assertFalse(address_g.isAddedByUses());
154         assertEquals(Optional.empty(), address_g.getType().getDefaultValue());
155         assertEquals(Optional.of("Target IP address"), address_g.getDescription());
156         assertEquals(Optional.empty(), address_g.getReference());
157         assertEquals(Optional.empty(), address_g.effectiveConfig());
158         assertTrue(address_g.isMandatory());
159         assertNotEquals(address_u, address_g);
160
161         final var port_u = assertInstanceOf(ContainerSchemaNode.class, destination.dataChildByName(fooQName("port")));
162         assertIsAddedByUses(port_u, true);
163
164         final var port_g = assertInstanceOf(ContainerSchemaNode.class, grouping.dataChildByName(bazQName("port")));
165         assertIsAddedByUses(port_g, false);
166         assertNotEquals(port_u, port_g);
167
168         final var addresses_u = assertInstanceOf(ListSchemaNode.class,
169             destination.dataChildByName(fooQName("addresses")));
170         assertIsAddedByUses(addresses_u, true);
171
172         final var addresses_g = assertInstanceOf(ListSchemaNode.class, grouping.dataChildByName(bazQName("addresses")));
173         assertIsAddedByUses(addresses_g, false);
174         assertNotEquals(addresses_u, addresses_g);
175
176         // grouping defined by 'uses'
177         final var groupings_u = destination.getGroupings();
178         assertEquals(0, groupings_u.size());
179
180         // grouping defined in 'grouping' node
181         final var groupings_g = grouping.getGroupings();
182         assertEquals(1, groupings_g.size());
183         final var grouping_g = groupings_g.iterator().next();
184         assertIsAddedByUses(grouping_g, false);
185
186         assertEquals(0, destination.getUnknownSchemaNodes().size());
187         assertEquals(1,
188             grouping.asEffectiveStatement().getDeclared().declaredSubstatements(UnrecognizedStatement.class).size());
189     }
190
191     @Test
192     void testUsesUnderModule() {
193         // suffix _u = added by uses
194         // suffix _g = defined in grouping
195
196         // get grouping
197         final var groupings = BAZ.getGroupings();
198         assertEquals(1, groupings.size());
199         final var grouping = groupings.iterator().next();
200
201         // check uses
202         final var uses = FOO.getUses();
203         assertEquals(1, uses.size());
204
205         // check uses process
206         final var data_u = assertInstanceOf(AnyxmlSchemaNode.class, FOO.dataChildByName(fooQName("data")));
207         assertTrue(data_u.isAddedByUses());
208
209         final var data_g = assertInstanceOf(AnyxmlSchemaNode.class, grouping.dataChildByName(bazQName("data")));
210         assertFalse(data_g.isAddedByUses());
211         assertNotEquals(data_u, data_g);
212
213         final var how_u = assertInstanceOf(ChoiceSchemaNode.class, FOO.dataChildByName(fooQName("how")));
214         assertIsAddedByUses(how_u, true);
215         assertFalse(how_u.isAugmenting());
216         final var cases_u = how_u.getCases();
217         assertEquals(2, cases_u.size());
218         final var interval = how_u.findCaseNodes("interval").iterator().next();
219         assertFalse(interval.isAugmenting());
220         final var name = assertInstanceOf(LeafSchemaNode.class, interval.dataChildByName(fooQName("name")));
221         assertTrue(name.isAugmenting());
222         final var intervalLeaf = assertInstanceOf(LeafSchemaNode.class, interval.dataChildByName(fooQName("interval")));
223         assertFalse(intervalLeaf.isAugmenting());
224
225         final var how_g = assertInstanceOf(ChoiceSchemaNode.class, grouping.dataChildByName(bazQName("how")));
226         assertIsAddedByUses(how_g, false);
227         assertNotEquals(how_u, how_g);
228
229         final var address_u = assertInstanceOf(LeafSchemaNode.class, FOO.dataChildByName(fooQName("address")));
230         assertEquals(Optional.empty(), address_u.getType().getDefaultValue());
231         assertEquals(Optional.of("Target IP address"), address_u.getDescription());
232         assertFalse(address_u.getReference().isPresent());
233         assertEquals(Optional.empty(), address_u.effectiveConfig());
234         assertTrue(address_u.isAddedByUses());
235
236         final var address_g = assertInstanceOf(LeafSchemaNode.class, grouping.dataChildByName(bazQName("address")));
237         assertFalse(address_g.isAddedByUses());
238         assertEquals(Optional.empty(), address_g.getType().getDefaultValue());
239         assertEquals(Optional.of("Target IP address"), address_g.getDescription());
240         assertFalse(address_g.getReference().isPresent());
241         assertEquals(Optional.empty(), address_g.effectiveConfig());
242         assertNotEquals(address_u, address_g);
243
244         final var port_u = assertInstanceOf(ContainerSchemaNode.class, FOO.dataChildByName(fooQName("port")));
245         assertIsAddedByUses(port_u, true);
246
247         final var port_g = assertInstanceOf(ContainerSchemaNode.class, grouping.dataChildByName(bazQName("port")));
248         assertIsAddedByUses(port_g, false);
249         assertNotEquals(port_u, port_g);
250
251         final var addresses_u = assertInstanceOf(ListSchemaNode.class, FOO.dataChildByName(fooQName("addresses")));
252         assertIsAddedByUses(addresses_u, true);
253
254         final var addresses_g = assertInstanceOf(ListSchemaNode.class, grouping.dataChildByName(bazQName("addresses")));
255         assertIsAddedByUses(addresses_g, false);
256         assertNotEquals(addresses_u, addresses_g);
257
258         // grouping defined by 'uses'
259         final var groupings_u = FOO.getGroupings();
260         assertEquals(0, groupings_u.size());
261
262         // grouping defined in 'grouping' node
263         final var groupings_g = grouping.getGroupings();
264         assertEquals(1, groupings_g.size());
265         final var grouping_g = groupings_g.iterator().next();
266         assertIsAddedByUses(grouping_g, false);
267
268         assertEquals(0, grouping.getUnknownSchemaNodes().size());
269         assertEquals(1, grouping.asEffectiveStatement().getDeclared().declaredSubstatements(UnrecognizedStatement.class)
270             .size());
271
272         final var un = uses.iterator().next();
273         final var usesAugments = un.getAugmentations();
274         assertEquals(1, usesAugments.size());
275         final var augment = usesAugments.iterator().next();
276         assertEquals(Optional.of("inner augment"), augment.getDescription());
277         final var children = augment.getChildNodes();
278         assertEquals(1, children.size());
279         final var leaf = assertInstanceOf(LeafSchemaNode.class, children.iterator().next());
280         assertEquals("name", leaf.getQName().getLocalName());
281     }
282
283     @Test
284     void testCascadeUses() throws Exception {
285         final var loadModules = TestUtils.parseYangSource("/grouping-test/cascade-uses.yang");
286         assertEquals(1, loadModules.getModules().size());
287
288         final var testModule =  Iterables.getOnlyElement(loadModules.findModules("cascade-uses"));
289         final var namespace = testModule.getQNameModule();
290         final var groupings = testModule.getGroupings();
291
292         GroupingDefinition gu = null;
293         GroupingDefinition gv = null;
294         GroupingDefinition gx = null;
295         GroupingDefinition gy = null;
296         GroupingDefinition gz = null;
297         GroupingDefinition gzz = null;
298         for (var gd : groupings) {
299             final String name = gd.getQName().getLocalName();
300             switch (name) {
301                 case "grouping-U":
302                     gu = gd;
303                     break;
304                 case "grouping-V":
305                     gv = gd;
306                     break;
307                 case "grouping-X":
308                     gx = gd;
309                     break;
310                 case "grouping-Y":
311                     gy = gd;
312                     break;
313                 case "grouping-Z":
314                     gz = gd;
315                     break;
316                 case "grouping-ZZ":
317                     gzz = gd;
318                     break;
319                 default:
320                     break;
321             }
322         }
323         assertNotNull(gu);
324         assertNotNull(gv);
325         assertNotNull(gx);
326         assertNotNull(gy);
327         assertNotNull(gz);
328         assertNotNull(gzz);
329
330         final var expectedModule = QNameModule.of("urn:grouping:cascade-uses", "2013-07-18");
331
332         // grouping-U
333         var childNodes = gu.getChildNodes();
334         assertEquals(7, childNodes.size());
335
336         final var leafGroupingU = assertInstanceOf(LeafSchemaNode.class, gu.dataChildByName(
337             QName.create(namespace, "leaf-grouping-U")));
338         assertFalse(leafGroupingU.isAddedByUses());
339
340         for (var childNode : childNodes) {
341             if (!childNode.getQName().equals(leafGroupingU.getQName())) {
342                 assertIsAddedByUses(childNode, true);
343             }
344         }
345
346         // grouping-V
347         childNodes = gv.getChildNodes();
348         assertEquals(4, childNodes.size());
349         LeafSchemaNode leafGroupingV = null;
350         ContainerSchemaNode containerGroupingV = null;
351         for (var childNode : childNodes) {
352             if ("leaf-grouping-V".equals(childNode.getQName().getLocalName())) {
353                 leafGroupingV = assertInstanceOf(LeafSchemaNode.class, childNode);
354             } else if ("container-grouping-V".equals(childNode.getQName().getLocalName())) {
355                 containerGroupingV = assertInstanceOf(ContainerSchemaNode.class, childNode);
356             } else {
357                 assertIsAddedByUses(childNode, true);
358             }
359         }
360         assertNotNull(leafGroupingV);
361         assertFalse(leafGroupingV.isAddedByUses());
362
363         // grouping-V/container-grouping-V
364         assertNotNull(containerGroupingV);
365         assertFalse(containerGroupingV.isAddedByUses());
366         assertEquals(QName.create(expectedModule, "container-grouping-V"), containerGroupingV.getQName());
367         childNodes = containerGroupingV.getChildNodes();
368         assertEquals(2, childNodes.size());
369         for (var childNode : childNodes) {
370             assertIsAddedByUses(childNode, true);
371         }
372
373         // grouping-V/container-grouping-V/leaf-grouping-X
374         final var leafXinContainerV = assertInstanceOf(LeafSchemaNode.class, containerGroupingV.dataChildByName(
375             QName.create(namespace, "leaf-grouping-X")));
376         assertEquals(QName.create(expectedModule, "leaf-grouping-X"), leafXinContainerV.getQName());
377         // grouping-V/container-grouping-V/leaf-grouping-Y
378         final var leafYinContainerV = assertInstanceOf(LeafSchemaNode.class, containerGroupingV.dataChildByName(
379             QName.create(namespace, "leaf-grouping-Y")));
380         assertEquals(QName.create(expectedModule, "leaf-grouping-Y"), leafYinContainerV.getQName());
381
382         // grouping-X
383         childNodes = gx.getChildNodes();
384         assertEquals(2, childNodes.size());
385
386         // grouping-X/leaf-grouping-X
387         final var leafXinGX = assertInstanceOf(LeafSchemaNode.class, gx.dataChildByName(
388             QName.create(namespace, "leaf-grouping-X")));
389         assertFalse(leafXinGX.isAddedByUses());
390         assertEquals(QName.create(expectedModule, "leaf-grouping-X"), leafXinGX.getQName());
391
392         // grouping-X/leaf-grouping-Y
393         final var leafYinGX = assertInstanceOf(LeafSchemaNode.class, gx.dataChildByName(
394             QName.create(namespace, "leaf-grouping-Y")));
395         assertTrue(leafYinGX.isAddedByUses());
396         assertEquals(QName.create(expectedModule, "leaf-grouping-Y"), leafYinGX.getQName());
397
398         // grouping-Y
399         childNodes = gy.getChildNodes();
400         assertEquals(1, childNodes.size());
401
402         // grouping-Y/leaf-grouping-Y
403         final var leafYinGY = assertInstanceOf(LeafSchemaNode.class, gy.dataChildByName(
404             QName.create(namespace, "leaf-grouping-Y")));
405         assertFalse(leafYinGY.isAddedByUses());
406         assertEquals(QName.create(expectedModule, "leaf-grouping-Y"), leafYinGY.getQName());
407
408         // grouping-Z
409         childNodes = gz.getChildNodes();
410         assertEquals(1, childNodes.size());
411
412         // grouping-Z/leaf-grouping-Z
413         final var leafZinGZ = assertInstanceOf(LeafSchemaNode.class, gz.dataChildByName(
414             QName.create(namespace, "leaf-grouping-Z")));
415         assertFalse(leafZinGZ.isAddedByUses());
416         assertEquals(QName.create(expectedModule, "leaf-grouping-Z"), leafZinGZ.getQName());
417
418         // grouping-ZZ
419         childNodes = gzz.getChildNodes();
420         assertEquals(1, childNodes.size());
421
422         // grouping-ZZ/leaf-grouping-ZZ
423         final var leafZZinGZZ = assertInstanceOf(LeafSchemaNode.class, gzz.dataChildByName(
424             QName.create(namespace, "leaf-grouping-ZZ")));
425         assertFalse(leafZZinGZZ.isAddedByUses());
426         assertEquals(QName.create(expectedModule, "leaf-grouping-ZZ"), leafZZinGZZ.getQName());
427     }
428
429     @Test
430     void testAddedByUsesLeafTypeQName() throws Exception {
431         final var loadModules = assertEffectiveModelDir("/added-by-uses-leaf-test");
432         assertEquals(2, loadModules.getModules().size());
433
434         final var foo = Iterables.getOnlyElement(loadModules.findModules("foo"));
435         final var imp = Iterables.getOnlyElement(loadModules.findModules("import-module"));
436
437         final var leaf = assertInstanceOf(LeafSchemaNode.class,
438             assertInstanceOf(ContainerSchemaNode.class, foo.dataChildByName(
439                 QName.create(foo.getQNameModule(), "my-container")))
440             .dataChildByName(QName.create(foo.getQNameModule(), "my-leaf")));
441
442         TypeDefinition<?> impType = null;
443         for (var typeDefinition : imp.getTypeDefinitions()) {
444             if (typeDefinition.getQName().getLocalName().equals("imp-type")) {
445                 impType = typeDefinition;
446                 break;
447             }
448         }
449
450         assertNotNull(impType);
451         assertEquals(leaf.getType().getQName(), impType.getQName());
452     }
453
454     private static void assertIsAddedByUses(final GroupingDefinition node, final boolean expected) {
455         assertEquals(expected, node.isAddedByUses());
456         for (var child : node.getChildNodes()) {
457             assertIsAddedByUses(child, expected);
458         }
459     }
460
461     /**
462      * Check if node has addedByUses flag set to expected value. In case this is
463      * DataNodeContainer/ChoiceNode, check its child nodes/case nodes too.
464      *
465      * @param node node to check
466      * @param expected expected value
467      */
468     private static void assertIsAddedByUses(final DataSchemaNode node, final boolean expected) {
469         assertEquals(expected, node.isAddedByUses());
470         if (node instanceof DataNodeContainer container) {
471             for (var child : container.getChildNodes()) {
472                 assertIsAddedByUses(child, expected);
473             }
474         } else if (node instanceof ChoiceSchemaNode choice) {
475             for (var caseNode : choice.getCases()) {
476                 assertIsAddedByUses(caseNode, expected);
477             }
478         }
479     }
480 }