Do do not check unique in unsupported lists
[yangtools.git] / parser / yang-parser-rfc7950 / src / test / java / org / opendaylight / yangtools / yang / stmt / DeviationResolutionTest.java
1 /*
2  * Copyright (c) 2017 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.hamcrest.CoreMatchers.containsString;
11 import static org.hamcrest.CoreMatchers.startsWith;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.jupiter.api.Assertions.assertEquals;
14 import static org.junit.jupiter.api.Assertions.assertFalse;
15 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
16 import static org.junit.jupiter.api.Assertions.assertNotNull;
17 import static org.junit.jupiter.api.Assertions.assertNull;
18 import static org.junit.jupiter.api.Assertions.assertTrue;
19
20 import java.io.ByteArrayOutputStream;
21 import java.io.PrintStream;
22 import java.nio.charset.StandardCharsets;
23 import java.util.Optional;
24 import org.junit.jupiter.api.Test;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.common.Revision;
27 import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
32 import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.Module;
37 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
38 import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
40 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
41
42 class DeviationResolutionTest extends AbstractYangTest {
43     @Test
44     void testDeviateNotSupported() {
45         final var schemaContext = assertEffectiveModelDir("/deviation-resolution-test/deviation-not-supported");
46         assertNotNull(schemaContext);
47
48         final Module importedModule = schemaContext.findModule("imported", Revision.of("2017-01-20")).get();
49         final ContainerSchemaNode myContA = (ContainerSchemaNode) importedModule.getDataChildByName(
50             QName.create(importedModule.getQNameModule(), "my-cont-a"));
51         assertNotNull(myContA);
52
53         assertEquals(1, myContA.getChildNodes().size());
54         assertNotNull(myContA.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-a3")));
55
56         final ContainerSchemaNode myContB = (ContainerSchemaNode) importedModule.dataChildByName(
57             QName.create(importedModule.getQNameModule(), "my-cont-b"));
58         assertNull(myContB);
59
60         final ContainerSchemaNode myContC = (ContainerSchemaNode) importedModule.getDataChildByName(
61             QName.create(importedModule.getQNameModule(), "my-cont-c"));
62         assertNotNull(myContC);
63
64         assertEquals(2, myContC.getChildNodes().size());
65         assertNotNull(myContC.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-c1")));
66         assertNotNull(myContC.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-c2")));
67     }
68
69     @Test
70     void testDeviateAdd() {
71         final var schemaContext = assertEffectiveModel(
72             "/deviation-resolution-test/deviation-add/foo.yang",
73             "/deviation-resolution-test/deviation-add/bar.yang");
74
75         final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
76         final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
77             QName.create(barModule.getQNameModule(), "my-leaf-list"));
78         assertNotNull(myLeafList);
79
80         assertEquals(Optional.of(Boolean.FALSE), myLeafList.effectiveConfig());
81         assertEquals(3, myLeafList.getDefaults().size());
82
83         final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
84         assertEquals((Object) 10, constraint.getMaxElements());
85         assertEquals((Object) 5, constraint.getMinElements());
86         assertNotNull(myLeafList.getType().getUnits());
87
88         final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
89             QName.create(barModule.getQNameModule(), "my-list"));
90         assertNotNull(myList);
91         assertEquals(2, myList.getUniqueConstraints().size());
92
93         final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
94             QName.create(barModule.getQNameModule(), "my-choice"));
95         assertNotNull(myChoice);
96         assertEquals("c2", myChoice.getDefaultCase().get().getQName().getLocalName());
97
98         final RpcDefinition myRpc = barModule.getRpcs().iterator().next();
99         final InputSchemaNode input = myRpc.getInput();
100         assertEquals(2, input.getMustConstraints().size());
101         final OutputSchemaNode output = myRpc.getOutput();
102         assertEquals(2, output.getMustConstraints().size());
103
104         final NotificationDefinition myNotification = barModule.getNotifications().iterator().next();
105         assertEquals(2, myNotification.getMustConstraints().size());
106
107         final AnyxmlSchemaNode myAnyxml = (AnyxmlSchemaNode) barModule.getDataChildByName(
108             QName.create(barModule.getQNameModule(), "my-anyxml"));
109         assertNotNull(myAnyxml);
110         assertTrue(myAnyxml.isMandatory());
111
112         final AnydataSchemaNode myAnyData = (AnydataSchemaNode) barModule.findDataChildByName(
113             QName.create(barModule.getQNameModule(), "my-anydata")).orElse(null);
114         assertNotNull(myAnyData);
115         assertTrue(myAnyData.isMandatory());
116     }
117
118     @Test
119     void testDeviateReplace() throws Exception {
120         final var schemaContext = assertEffectiveModel(
121             "/deviation-resolution-test/deviation-replace/foo.yang",
122             "/deviation-resolution-test/deviation-replace/bar.yang");
123
124         final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
125         assertNotNull(barModule);
126
127         final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
128             QName.create(barModule.getQNameModule(), "my-leaf"));
129         assertNotNull(myLeaf);
130
131         assertInstanceOf(Uint32TypeDefinition.class, myLeaf.getType());
132         assertEquals(Optional.of("bytes"), myLeaf.getType().getUnits());
133         assertEquals(Optional.of("10"), myLeaf.getType().getDefaultValue());
134
135         final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
136             QName.create(barModule.getQNameModule(), "my-leaf-list-test"));
137         assertNotNull(myLeafList);
138
139         final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
140         assertEquals((Object) 6, constraint.getMaxElements());
141         assertEquals((Object) 3, constraint.getMinElements());
142         assertEquals(Optional.of(Boolean.TRUE), myLeafList.effectiveConfig());
143
144         final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
145             QName.create(barModule.getQNameModule(), "my-choice"));
146         assertNotNull(myChoice);
147
148         assertFalse(myChoice.isMandatory());
149         // FIXME: we need a supported extension to properly test this
150         assertEquals(0, myChoice.getUnknownSchemaNodes().size());
151
152         final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
153             QName.create(barModule.getQNameModule(), "my-cont"));
154         assertNotNull(myCont);
155
156         final LeafSchemaNode myAugLeaf = (LeafSchemaNode) myCont.getDataChildByName(
157             QName.create(barModule.getQNameModule(), "my-aug-leaf"));
158         assertNotNull(myAugLeaf);
159         assertInstanceOf(Uint32TypeDefinition.class, myAugLeaf.getType());
160         assertEquals(Optional.of("seconds"), myAugLeaf.getType().getUnits());
161         assertEquals(Optional.of("new-def-val"), myAugLeaf.getType().getDefaultValue());
162         // FIXME: we need a supported extension to properly test this
163         assertEquals(0, myAugLeaf.getUnknownSchemaNodes().size());
164
165         final LeafSchemaNode myUsedLeaf = (LeafSchemaNode) myCont.getDataChildByName(
166             QName.create(barModule.getQNameModule(), "my-used-leaf"));
167         assertNotNull(myUsedLeaf);
168         assertInstanceOf(Uint32TypeDefinition.class, myUsedLeaf.getType());
169         assertEquals(Optional.of("weeks"), myUsedLeaf.getType().getUnits());
170         assertEquals(Optional.of("new-def-val"), myUsedLeaf.getType().getDefaultValue());
171         // FIXME: we need a supported extension to properly test this
172         assertEquals(0, myUsedLeaf.getUnknownSchemaNodes().size());
173     }
174
175     @Test
176     void testDeviateDelete() throws Exception {
177         final var schemaContext = assertEffectiveModel(
178             "/deviation-resolution-test/deviation-delete/foo.yang",
179             "/deviation-resolution-test/deviation-delete/bar.yang");
180
181         final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
182         final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
183             QName.create(barModule.getQNameModule(), "my-leaf"));
184         assertNotNull(myLeaf);
185
186         assertEquals(Optional.empty(), myLeaf.getType().getDefaultValue());
187         assertEquals(Optional.empty(), myLeaf.getType().getUnits());
188         assertEquals(0, myLeaf.getUnknownSchemaNodes().size());
189
190         final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
191             QName.create(barModule.getQNameModule(), "my-leaf-list"));
192         assertNotNull(myLeafList);
193
194         assertEquals(0, myLeafList.getDefaults().size());
195         assertEquals(0, myLeafList.getMustConstraints().size());
196
197         final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
198             QName.create(barModule.getQNameModule(), "my-list"));
199         assertNotNull(myList);
200
201         assertEquals(0, myList.getUniqueConstraints().size());
202         assertEquals(0, myList.getUnknownSchemaNodes().size());
203
204         final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
205             QName.create(barModule.getQNameModule(), "my-cont"));
206         assertNotNull(myCont);
207
208         final LeafSchemaNode myAugLeaf = (LeafSchemaNode) myCont.getDataChildByName(
209             QName.create(barModule.getQNameModule(), "my-aug-leaf"));
210         assertNotNull(myAugLeaf);
211         assertEquals(Optional.empty(), myAugLeaf.getType().getDefaultValue());
212         assertEquals(Optional.empty(), myAugLeaf.getType().getUnits());
213         assertEquals(0, myAugLeaf.getMustConstraints().size());
214         assertEquals(0, myAugLeaf.getUnknownSchemaNodes().size());
215
216         final LeafSchemaNode myUsedLeaf = (LeafSchemaNode) myCont.getDataChildByName(
217             QName.create(barModule.getQNameModule(), "my-used-leaf"));
218         assertNotNull(myUsedLeaf);
219         assertEquals(Optional.empty(), myUsedLeaf.getType().getDefaultValue());
220         assertEquals(Optional.empty(), myUsedLeaf.getType().getUnits());
221         assertEquals(0, myUsedLeaf.getMustConstraints().size());
222         assertEquals(0, myUsedLeaf.getUnknownSchemaNodes().size());
223     }
224
225     @Test
226     void shouldFailOnInvalidYang10Model() {
227         assertInvalidSubstatementException(startsWith("Maximal count of DEFAULT for DEVIATE is 1, detected 2."),
228             "/deviation-resolution-test/deviation-add/foo10-invalid.yang",
229             "/deviation-resolution-test/deviation-add/bar10-invalid.yang");
230     }
231
232     @Test
233     void shouldFailOnInvalidYang10Model2() {
234         assertInvalidSubstatementException(startsWith("Maximal count of DEFAULT for DEVIATE is 1, detected 2."),
235             "/deviation-resolution-test/deviation-delete/foo10-invalid.yang",
236             "/deviation-resolution-test/deviation-delete/bar10-invalid.yang");
237     }
238
239     @Test
240     void shouldFailOnInvalidDeviationTarget() {
241         assertInferenceException(startsWith("(bar?revision=2017-01-20)my-cont is not a valid deviation "
242             + "target for substatement (urn:ietf:params:xml:ns:yang:yin:1)max-elements."),
243             "/deviation-resolution-test/foo-invalid-deviation-target.yang",
244             "/deviation-resolution-test/bar.yang");
245     }
246
247     @Test
248     void shouldFailOnInvalidDeviationPath() {
249         assertInferenceException(startsWith(
250             "Deviation target 'Absolute{qnames=[(bar?revision=2017-01-20)invalid, path]}' not found"),
251             "/deviation-resolution-test/foo-invalid-deviation-path.yang",
252             "/deviation-resolution-test/bar.yang");
253     }
254
255     @Test
256     void shouldFailOnInvalidDeviateAdd() {
257         assertInferenceException(startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
258             + ":yin:1)config to target node (bar?revision=2017-01-20)my-leaf because it is already defined in"
259             + " target and can appear only once."),
260             "/deviation-resolution-test/deviation-add/foo-invalid.yang",
261             "/deviation-resolution-test/deviation-add/bar-invalid.yang");
262     }
263
264     @Test
265     void shouldFailOnInvalidDeviateAdd2() {
266         assertInferenceException(startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
267             + ":yin:1)default to target node (bar?revision=2017-01-20)my-leaf because it is already defined in"
268             + " target and can appear only once."),
269             "/deviation-resolution-test/deviation-add/foo-invalid-2.yang",
270             "/deviation-resolution-test/deviation-add/bar-invalid-2.yang");
271     }
272
273     @Test
274     void shouldFailOnInvalidDeviateAdd3() {
275         assertInferenceException(startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
276             + ":yin:1)default to target node (bar?revision=2017-02-01)my-used-leaf because it is already "
277             + "defined in target and can appear only once."),
278             "/deviation-resolution-test/deviation-add/foo-invalid-4.yang",
279             "/deviation-resolution-test/deviation-add/bar-invalid-4.yang");
280     }
281
282     @Test
283     void shouldFailOnInvalidDeviateReplace() {
284         assertInferenceException(startsWith("Deviation cannot replace substatement "
285             + "(urn:ietf:params:xml:ns:yang:yin:1)units in target node (bar?revision=2017-01-20)my-leaf "
286             + "because it does not exist in target node."),
287             "/deviation-resolution-test/deviation-replace/foo-invalid.yang",
288             "/deviation-resolution-test/deviation-replace/bar-invalid.yang");
289     }
290
291     @Test
292     @SuppressWarnings("checkstyle:regexpSinglelineJava")
293     void shouldLogInvalidDeviateReplaceAttempt() throws Exception {
294         final PrintStream stdout = System.out;
295         final ByteArrayOutputStream output = new ByteArrayOutputStream();
296         final String testLog;
297
298         System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
299
300         TestUtils.parseYangSource(
301             "/deviation-resolution-test/deviation-replace/foo-invalid-2.yang",
302             "/deviation-resolution-test/deviation-replace/bar-invalid-2.yang");
303
304         testLog = output.toString();
305         System.setOut(stdout);
306         assertThat(testLog, containsString(
307             "Deviation cannot replace substatement (urn:ietf:params:xml:ns:yang:yin:1)default in target leaf-list "
308                 + "(bar?revision=2017-01-20)my-leaf-list because a leaf-list can have multiple "
309                 + "default statements."));
310     }
311
312     @Test
313     @SuppressWarnings("checkstyle:regexpSinglelineJava")
314     void shouldLogInvalidDeviateDeleteAttempt() throws Exception {
315         final PrintStream stdout = System.out;
316         final ByteArrayOutputStream output = new ByteArrayOutputStream();
317         final String testLog;
318
319         System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
320
321         TestUtils.parseYangSource(
322             "/deviation-resolution-test/deviation-delete/foo-invalid.yang",
323             "/deviation-resolution-test/deviation-delete/bar-invalid.yang");
324
325         testLog = output.toString();
326         System.setOut(stdout);
327         assertThat(testLog, containsString(
328             "Deviation cannot delete substatement (urn:ietf:params:xml:ns:yang:yin:1)units with argument 'seconds' in "
329                 + "target node (bar?revision=2017-01-20)my-leaf because it does not exist in the target node."));
330     }
331
332     @Test
333     void shouldFailOnInvalidDeviateAddSubstatement() {
334         assertInvalidSubstatementException(startsWith("TYPE is not valid for DEVIATE."),
335             "/deviation-resolution-test/deviation-add/foo-invalid-3.yang",
336             "/deviation-resolution-test/deviation-add/bar-invalid-3.yang");
337     }
338
339     @Test
340     void shouldFailOnInvalidDeviateReplaceSubstatement() {
341         assertInvalidSubstatementException(startsWith("MUST is not valid for DEVIATE."),
342             "/deviation-resolution-test/deviation-replace/foo-invalid-3.yang",
343             "/deviation-resolution-test/deviation-replace/bar-invalid-3.yang");
344     }
345
346     @Test
347     void shouldFailOnInvalidDeviateDeleteSubstatement() {
348         assertInvalidSubstatementException(startsWith("CONFIG is not valid for DEVIATE."),
349             "/deviation-resolution-test/deviation-delete/foo-invalid-2.yang",
350             "/deviation-resolution-test/deviation-delete/bar-invalid-2.yang");
351     }
352 }