BUG-4688: Rework SchemaContext module lookups
[yangtools.git] / yang / yang-parser-impl / src / test / java / org / opendaylight / yangtools / yang / parser / stmt / rfc7950 / Bug6887Test.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
9 package org.opendaylight.yangtools.yang.parser.stmt.rfc7950;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15
16 import com.google.common.collect.ImmutableList;
17 import com.google.common.collect.Iterables;
18 import java.util.List;
19 import org.junit.Test;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.common.QNameModule;
22 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.Module;
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
25 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
26 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
28 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
30 import org.opendaylight.yangtools.yang.model.util.type.BitBuilder;
31 import org.opendaylight.yangtools.yang.model.util.type.EnumPairBuilder;
32 import org.opendaylight.yangtools.yang.model.util.type.InvalidBitDefinitionException;
33 import org.opendaylight.yangtools.yang.model.util.type.InvalidEnumDefinitionException;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
35 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
36 import org.opendaylight.yangtools.yang.stmt.StmtTestUtils;
37
38 public class Bug6887Test {
39
40     @Test
41     public void testRestrictedEnumeration() throws Exception {
42         final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo.yang");
43         assertNotNull(schemaContext);
44
45         final Module foo = schemaContext.findModule("foo", QName.parseRevision("2017-01-26")).get();
46         final LeafSchemaNode myEnumerationLeaf = (LeafSchemaNode) foo.getDataChildByName(
47                 QName.create(foo.getQNameModule(), "my-enumeration-leaf"));
48         assertNotNull(myEnumerationLeaf);
49
50         EnumTypeDefinition enumerationType = (EnumTypeDefinition) myEnumerationLeaf.getType();
51
52         List<EnumPair> enums = enumerationType.getValues();
53         assertEquals(2, enums.size());
54         final EnumPair yellowEnum = createEnumPair("yellow", 2);
55         final EnumPair redEnum = createEnumPair("red", 3);
56         assertContainsEnums(enums, yellowEnum, redEnum);
57
58         enumerationType = enumerationType.getBaseType();
59         enums = enumerationType.getValues();
60         assertEquals(3, enums.size());
61         final EnumPair blackEnum = createEnumPair("black", 4);
62         assertContainsEnums(enums, yellowEnum, redEnum, blackEnum);
63
64         enumerationType = enumerationType.getBaseType();
65         enums = enumerationType.getValues();
66         assertEquals(4, enums.size());
67         final EnumPair whiteEnum = createEnumPair("white", 1);
68         assertContainsEnums(enums, whiteEnum, yellowEnum, redEnum, blackEnum);
69
70         final LeafSchemaNode myEnumerationLeaf2 = (LeafSchemaNode) foo.getDataChildByName(
71                 QName.create(foo.getQNameModule(), "my-enumeration-leaf-2"));
72         assertNotNull(myEnumerationLeaf2);
73
74         enumerationType = (EnumTypeDefinition) myEnumerationLeaf2.getType();
75         enums = enumerationType.getValues();
76         assertEquals(3, enums.size());
77         assertContainsEnums(enums, yellowEnum, redEnum, blackEnum);
78     }
79
80     @Test
81     public void testInvalidRestrictedEnumeration() throws Exception {
82         try {
83             StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo-invalid.yang");
84             fail("An exception should have been thrown.");
85         } catch (final ReactorException ex) {
86             final Throwable cause = ex.getCause();
87             assertTrue(cause instanceof SourceException);
88             assertTrue(cause.getMessage().startsWith("Enum 'purple' is not a subset of its base enumeration type "
89                     + "(foo?revision=2017-02-02)my-derived-enumeration-type."));
90         }
91     }
92
93     @Test
94     public void testInvalidRestrictedEnumeration2() throws Exception {
95         try {
96             StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo-invalid-2.yang");
97             fail("An exception should have been thrown.");
98         } catch (final ReactorException ex) {
99             final Throwable cause = ex.getCause();
100             assertTrue(cause instanceof InvalidEnumDefinitionException);
101             assertTrue(cause.getMessage().startsWith("Enum 'magenta' is not a subset of its base enumeration type "
102                     + "(foo?revision=2017-02-02)my-base-enumeration-type."));
103         }
104     }
105
106     @Test
107     public void testInvalidRestrictedEnumeration3() throws Exception {
108         try {
109             StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo-invalid-3.yang");
110             fail("An exception should have been thrown.");
111         } catch (final ReactorException ex) {
112             final Throwable cause = ex.getCause();
113             assertTrue(cause instanceof InvalidEnumDefinitionException);
114             assertTrue(cause.getMessage().startsWith("Value of enum 'red' must be the same as the value of "
115                     + "corresponding enum in the base enumeration type (foo?revision=2017-02-02)"
116                     + "my-derived-enumeration-type."));
117         }
118     }
119
120     @Test
121     public void testInvalidRestrictedEnumeration4() throws Exception {
122         try {
123             StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo-invalid-4.yang");
124             fail("An exception should have been thrown.");
125         } catch (final ReactorException ex) {
126             final Throwable cause = ex.getCause();
127             assertTrue(cause instanceof InvalidEnumDefinitionException);
128             assertTrue(cause.getMessage().startsWith("Value of enum 'black' must be the same as the value of "
129                     + "corresponding enum in the base enumeration type (foo?revision=2017-02-02)"
130                     + "my-base-enumeration-type."));
131         }
132     }
133
134     @Test
135     public void testValidYang10EnumerationWithUnknownStatements() throws Exception {
136         final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo10-valid.yang");
137         assertNotNull(schemaContext);
138     }
139
140     @Test
141     public void testInvalidYang10RestrictedEnumeration() throws Exception {
142         try {
143             StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo10-invalid.yang");
144             fail("An exception should have been thrown.");
145         } catch (final ReactorException ex) {
146             final Throwable cause = ex.getCause();
147             assertTrue(cause instanceof SourceException);
148             assertTrue(cause.getMessage().startsWith(
149                 "Restricted enumeration type is allowed only in YANG 1.1 version."));
150         }
151     }
152
153     @Test
154     public void testInvalidYang10RestrictedEnumeration2() throws Exception {
155         try {
156             StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo10-invalid-2.yang");
157             fail("An exception should have been thrown.");
158         } catch (final ReactorException ex) {
159             final Throwable cause = ex.getCause();
160             assertTrue(cause instanceof SourceException);
161             assertTrue(cause.getMessage().startsWith(
162                 "Restricted enumeration type is allowed only in YANG 1.1 version."));
163         }
164     }
165
166     @Test
167     public void testRestrictedBits() throws Exception {
168         final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar.yang");
169         assertNotNull(schemaContext);
170
171         final Module bar = schemaContext.findModule("bar", QName.parseRevision("2017-02-02")).get();
172         final LeafSchemaNode myBitsLeaf = (LeafSchemaNode) bar.getDataChildByName(
173                 QName.create(bar.getQNameModule(), "my-bits-leaf"));
174         assertNotNull(myBitsLeaf);
175
176         BitsTypeDefinition bitsType = (BitsTypeDefinition) myBitsLeaf.getType();
177
178         List<Bit> bits = bitsType.getBits();
179         assertEquals(2, bits.size());
180         Bit bitB = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-bits-leaf",
181                 "my-derived-bits-type", "bit-b")), 2);
182         Bit bitC = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-bits-leaf",
183                 "my-derived-bits-type", "bit-c")), 3);
184         assertContainsBits(bits, bitB, bitC);
185
186         bitsType = bitsType.getBaseType();
187         bits = bitsType.getBits();
188         assertEquals(3, bits.size());
189         bitB = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
190                 "my-base-bits-type", "bit-b")), 2);
191         bitC = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
192                 "my-base-bits-type", "bit-c")), 3);
193         Bit bitD = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
194                 "my-base-bits-type", "bit-d")), 4);
195         assertContainsBits(bits, bitB, bitC, bitD);
196
197         bitsType = bitsType.getBaseType();
198         bits = bitsType.getBits();
199         assertEquals(4, bits.size());
200         final Bit bitA = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-base-bits-type",
201                 "bits", "bit-a")), 1);
202         bitB = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-base-bits-type",
203                 "bits", "bit-b")), 2);
204         bitC = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-base-bits-type",
205                 "bits", "bit-c")), 3);
206         bitD = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-base-bits-type",
207                 "bits", "bit-d")), 4);
208         assertContainsBits(bits, bitA, bitB, bitC, bitD);
209
210         final LeafSchemaNode myBitsLeaf2 = (LeafSchemaNode) bar.getDataChildByName(
211                 QName.create(bar.getQNameModule(), "my-bits-leaf-2"));
212         assertNotNull(myBitsLeaf2);
213
214         bitsType = (BitsTypeDefinition) myBitsLeaf2.getType();
215         bits = bitsType.getBits();
216         assertEquals(3, bits.size());
217         bitB = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
218                 "my-base-bits-type", "bit-b")), 2);
219         bitC = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
220                 "my-base-bits-type", "bit-c")), 3);
221         bitD = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
222                 "my-base-bits-type", "bit-d")), 4);
223         assertContainsBits(bits, bitB, bitC, bitD);
224     }
225
226     @Test
227     public void testInvalidRestrictedBits() throws Exception {
228         try {
229             StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar-invalid.yang");
230             fail("An exception should have been thrown.");
231         } catch (final ReactorException ex) {
232             final Throwable cause = ex.getCause();
233             assertTrue(cause instanceof SourceException);
234             assertTrue(cause.getMessage().startsWith("Bit 'bit-w' is not a subset of its base bits type "
235                     + "(bar?revision=2017-02-02)my-derived-bits-type."));
236         }
237     }
238
239     @Test
240     public void testInvalidRestrictedBits2() throws Exception {
241         try {
242             StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar-invalid-2.yang");
243             fail("An exception should have been thrown.");
244         } catch (final ReactorException ex) {
245             final Throwable cause = ex.getCause();
246             assertTrue(cause instanceof InvalidBitDefinitionException);
247             assertTrue(cause.getMessage().startsWith("Bit 'bit-x' is not a subset of its base bits type "
248                     + "(bar?revision=2017-02-02)my-base-bits-type."));
249         }
250     }
251
252     @Test
253     public void testInvalidRestrictedBits3() throws Exception {
254         try {
255             StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar-invalid-3.yang");
256             fail("An exception should have been thrown.");
257         } catch (final ReactorException ex) {
258             final Throwable cause = ex.getCause();
259             assertTrue(cause instanceof InvalidBitDefinitionException);
260             assertTrue(cause.getMessage().startsWith("Position of bit 'bit-c' must be the same as the position of "
261                     + "corresponding bit in the base bits type (bar?revision=2017-02-02)my-derived-bits-type."));
262         }
263     }
264
265     @Test
266     public void testInvalidRestrictedBits4() throws Exception {
267         try {
268             StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar-invalid-4.yang");
269             fail("An exception should have been thrown.");
270         } catch (final ReactorException ex) {
271             final Throwable cause = ex.getCause();
272             assertTrue(cause instanceof InvalidBitDefinitionException);
273             assertTrue(cause.getMessage().startsWith("Position of bit 'bit-d' must be the same as the position of "
274                     + "corresponding bit in the base bits type (bar?revision=2017-02-02)my-base-bits-type."));
275         }
276     }
277
278     @Test
279     public void testValidYang10BitsWithUnknownStatements() throws Exception {
280         final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar10-valid.yang");
281         assertNotNull(schemaContext);
282     }
283
284     @Test
285     public void testInvalidYang10RestrictedBits() throws Exception {
286         try {
287             StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar10-invalid.yang");
288             fail("An exception should have been thrown.");
289         } catch (final ReactorException ex) {
290             final Throwable cause = ex.getCause();
291             assertTrue(cause instanceof SourceException);
292             assertTrue(cause.getMessage().startsWith("Restricted bits type is allowed only in YANG 1.1 version."));
293         }
294     }
295
296     @Test
297     public void testInvalidYang10RestrictedBits2() throws Exception {
298         try {
299             StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar10-invalid-2.yang");
300             fail("An exception should have been thrown.");
301         } catch (final ReactorException ex) {
302             final Throwable cause = ex.getCause();
303             assertTrue(cause instanceof SourceException);
304             assertTrue(cause.getMessage().startsWith("Restricted bits type is allowed only in YANG 1.1 version."));
305         }
306     }
307
308     private static EnumPair createEnumPair(final String name, final int value) {
309         return EnumPairBuilder.create(name, value).build();
310     }
311
312     private static void assertContainsEnums(final List<EnumPair> enumList, final EnumPair... enumPairs) {
313         for (final EnumPair enumPair : enumPairs) {
314             assertTrue(enumList.contains(enumPair));
315         }
316     }
317
318     private static Bit createBit(final SchemaPath path, final long position) {
319         return BitBuilder.create(path, position).build();
320     }
321
322     private static void assertContainsBits(final List<Bit> bitList, final Bit... bits) {
323         for (final Bit bit : bits) {
324             assertTrue(bitList.contains(bit));
325         }
326     }
327
328     private static SchemaPath createSchemaPath(final boolean absolute, final QNameModule qnameModule,
329             final Iterable<String> localNames) {
330         return SchemaPath.create(Iterables.transform(localNames,
331             localName -> QName.create(qnameModule, localName)), true);
332     }
333 }