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