Refactor yang-model-api child traversal return types
[yangtools.git] / yang / yang-parser-rfc7950 / src / test / java / org / opendaylight / yangtools / yang / stmt / YangParserTest.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.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.opendaylight.yangtools.yang.stmt.StmtTestUtils.sourceForResource;
16
17 import com.google.common.collect.Range;
18 import com.google.common.collect.RangeSet;
19 import java.io.IOException;
20 import java.net.URI;
21 import java.net.URISyntaxException;
22 import java.text.ParseException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Optional;
28 import java.util.Set;
29 import java.util.SortedMap;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.opendaylight.yangtools.yang.common.QName;
33 import org.opendaylight.yangtools.yang.common.QNameModule;
34 import org.opendaylight.yangtools.yang.common.Revision;
35 import org.opendaylight.yangtools.yang.common.YangConstants;
36 import org.opendaylight.yangtools.yang.common.YangVersion;
37 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.DeviateKind;
43 import org.opendaylight.yangtools.yang.model.api.Deviation;
44 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
45 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
46 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
47 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.Module;
50 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
51 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
52 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
53 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
54 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
55 import org.opendaylight.yangtools.yang.model.api.Status;
56 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
57 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
58 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
59 import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition;
60 import org.opendaylight.yangtools.yang.model.api.type.Int32TypeDefinition;
61 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
62 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
63 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
64 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
65 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
66 import org.opendaylight.yangtools.yang.model.util.type.BaseTypes;
67 import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.RFC7950Reactors;
68 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
69 import org.opendaylight.yangtools.yang.parser.spi.meta.SomeModifiersUnresolvedException;
70 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
71 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
72 import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor.BuildAction;
73
74 public class YangParserTest {
75     private static final QNameModule FOO = QNameModule.create(URI.create("urn:opendaylight.foo"),
76         Revision.of("2013-02-27"));
77     private static final QNameModule BAR = QNameModule.create(URI.create("urn:opendaylight.bar"),
78         Revision.of("2013-07-03"));
79     private static final QNameModule BAZ = QNameModule.create(URI.create("urn:opendaylight.baz"),
80         Revision.of("2013-02-27"));
81
82     private SchemaContext context;
83     private Module foo;
84     private Module bar;
85     private Module baz;
86
87     @Before
88     public void init() throws Exception {
89         context = TestUtils.loadModules(getClass().getResource("/model").toURI());
90         foo = TestUtils.findModule(context, "foo").get();
91         bar = TestUtils.findModule(context, "bar").get();
92         baz = TestUtils.findModule(context, "baz").get();
93     }
94
95     @Test
96     public void testHeaders() throws ParseException {
97         assertEquals("foo", foo.getName());
98         assertEquals(YangVersion.VERSION_1, foo.getYangVersion());
99         assertEquals(FOO.getNamespace(), foo.getNamespace());
100         assertEquals("foo", foo.getPrefix());
101
102         final Collection<? extends ModuleImport> imports = foo.getImports();
103         assertEquals(2, imports.size());
104
105         final ModuleImport import2 = TestUtils.findImport(imports, "br");
106         assertEquals("bar", import2.getModuleName());
107         assertEquals(BAR.getRevision(), import2.getRevision());
108
109         final ModuleImport import3 = TestUtils.findImport(imports, "bz");
110         assertEquals("baz", import3.getModuleName());
111         assertEquals(BAZ.getRevision(), import3.getRevision());
112
113         assertEquals(Optional.of("opendaylight"), foo.getOrganization());
114         assertEquals(Optional.of("http://www.opendaylight.org/"), foo.getContact());
115         assertEquals(Revision.ofNullable("2013-02-27"), foo.getRevision());
116         assertFalse(foo.getReference().isPresent());
117     }
118
119     @Test
120     public void testParseList() {
121         final ContainerSchemaNode interfaces = (ContainerSchemaNode) bar.getDataChildByName(QName.create(
122             bar.getQNameModule(), "interfaces"));
123
124         final ListSchemaNode ifEntry = (ListSchemaNode) interfaces.getDataChildByName(QName.create(bar.getQNameModule(),
125             "ifEntry"));
126         // test SchemaNode args
127         assertEquals(QName.create(BAR, "ifEntry"), ifEntry.getQName());
128
129         final SchemaPath expectedPath = TestUtils.createPath(true, BAR, "interfaces", "ifEntry");
130         assertEquals(expectedPath, ifEntry.getPath());
131         assertFalse(ifEntry.getDescription().isPresent());
132         assertFalse(ifEntry.getReference().isPresent());
133         assertEquals(Status.CURRENT, ifEntry.getStatus());
134         assertEquals(0, ifEntry.getUnknownSchemaNodes().size());
135         // test DataSchemaNode args
136         assertFalse(ifEntry.isAugmenting());
137         assertTrue(ifEntry.isConfiguration());
138         // :TODO augment to ifEntry have when condition and so in consequence
139         // ifEntry should be a context node ?
140         // assertNull(constraints.getWhenCondition());
141         assertEquals(0, ifEntry.getMustConstraints().size());
142         ElementCountConstraint constraints = ifEntry.getElementCountConstraint().get();
143         assertEquals(1, constraints.getMinElements().intValue());
144         assertEquals(11, constraints.getMaxElements().intValue());
145         // test AugmentationTarget args
146         final Collection<? extends AugmentationSchemaNode> availableAugmentations = ifEntry.getAvailableAugmentations();
147         assertEquals(2, availableAugmentations.size());
148         // test ListSchemaNode args
149         final List<QName> expectedKey = new ArrayList<>();
150         expectedKey.add(QName.create(BAR, "ifIndex"));
151         assertEquals(expectedKey, ifEntry.getKeyDefinition());
152         assertFalse(ifEntry.isUserOrdered());
153         // test DataNodeContainer args
154         assertEquals(0, ifEntry.getTypeDefinitions().size());
155         assertEquals(4, ifEntry.getChildNodes().size());
156         assertEquals(0, ifEntry.getGroupings().size());
157         assertEquals(0, ifEntry.getUses().size());
158
159         final LeafSchemaNode ifIndex = (LeafSchemaNode) ifEntry.getDataChildByName(QName.create(bar.getQNameModule(),
160             "ifIndex"));
161         assertEquals(ifEntry.getKeyDefinition().get(0), ifIndex.getQName());
162         assertTrue(ifIndex.getType() instanceof Uint32TypeDefinition);
163         assertEquals(Optional.of("minutes"), ifIndex.getType().getUnits());
164         final LeafSchemaNode ifMtu = (LeafSchemaNode) ifEntry.getDataChildByName(QName.create(bar.getQNameModule(),
165             "ifMtu"));
166         assertEquals(BaseTypes.int32Type(), ifMtu.getType());
167     }
168
169     @Test
170     public void testTypedefRangesResolving() throws ParseException {
171         final LeafSchemaNode int32Leaf = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
172             "int32-leaf"));
173
174         final Int32TypeDefinition leafType = (Int32TypeDefinition) int32Leaf.getType();
175         assertEquals(QName.create(FOO, "int32-ext2"), leafType.getQName());
176         assertEquals(Optional.of("mile"), leafType.getUnits());
177         assertEquals(Optional.of("11"), leafType.getDefaultValue());
178
179         final RangeSet<? extends Number> rangeset = leafType.getRangeConstraint().get().getAllowedRanges();
180         final Set<? extends Range<? extends Number>> ranges = rangeset.asRanges();
181         assertEquals(1, ranges.size());
182
183         final Range<? extends Number> range = ranges.iterator().next();
184         assertEquals(12, range.lowerEndpoint().intValue());
185         assertEquals(20, range.upperEndpoint().intValue());
186
187         final Int32TypeDefinition firstBaseType = leafType.getBaseType();
188         assertEquals(QName.create(BAR, "int32-ext2"), firstBaseType.getQName());
189         assertEquals(Optional.of("mile"), firstBaseType.getUnits());
190         assertEquals(Optional.of("11"), firstBaseType.getDefaultValue());
191
192         final RangeSet<? extends Number> firstRangeset = firstBaseType.getRangeConstraint().get().getAllowedRanges();
193         final Set<? extends Range<? extends Number>> baseRanges = firstRangeset.asRanges();
194         assertEquals(2, baseRanges.size());
195
196         final Iterator<? extends Range<? extends Number>> it = baseRanges.iterator();
197         final Range<? extends Number> baseTypeRange1 = it.next();
198         assertEquals(3, baseTypeRange1.lowerEndpoint().intValue());
199         assertEquals(9, baseTypeRange1.upperEndpoint().intValue());
200         final Range<? extends Number> baseTypeRange2 = it.next();
201         assertEquals(11, baseTypeRange2.lowerEndpoint().intValue());
202         assertEquals(20, baseTypeRange2.upperEndpoint().intValue());
203
204         final Int32TypeDefinition secondBaseType = firstBaseType.getBaseType();
205         final QName baseQName = secondBaseType.getQName();
206         assertEquals("int32-ext1", baseQName.getLocalName());
207         assertEquals(BAR, baseQName.getModule());
208         assertEquals(Optional.empty(), secondBaseType.getUnits());
209         assertEquals(Optional.empty(), secondBaseType.getDefaultValue());
210
211         final Set<? extends Range<? extends Number>> secondRanges = secondBaseType.getRangeConstraint().get()
212                 .getAllowedRanges().asRanges();
213         assertEquals(1, secondRanges.size());
214         final Range<? extends Number> secondRange = secondRanges.iterator().next();
215         assertEquals(2, secondRange.lowerEndpoint().intValue());
216         assertEquals(20, secondRange.upperEndpoint().intValue());
217
218         assertEquals(BaseTypes.int32Type(), secondBaseType.getBaseType());
219     }
220
221     @Test
222     public void testTypedefPatternsResolving() {
223         final LeafSchemaNode stringleaf = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
224             "string-leaf"));
225
226         assertTrue(stringleaf.getType() instanceof StringTypeDefinition);
227         final StringTypeDefinition type = (StringTypeDefinition) stringleaf.getType();
228         final QName typeQName = type.getQName();
229         assertEquals("string-ext4", typeQName.getLocalName());
230         assertEquals(BAR, typeQName.getModule());
231         assertEquals(Optional.empty(), type.getUnits());
232         assertEquals(Optional.empty(), type.getDefaultValue());
233         List<PatternConstraint> patterns = type.getPatternConstraints();
234         assertEquals(1, patterns.size());
235         PatternConstraint pattern = patterns.iterator().next();
236         assertEquals("^(?:[e-z]*)$", pattern.getJavaPatternString());
237         assertEquals(1, type.getLengthConstraint().get().getAllowedRanges().asRanges().size());
238
239         final StringTypeDefinition baseType1 = type.getBaseType();
240         final QName baseType1QName = baseType1.getQName();
241         assertEquals("string-ext3", baseType1QName.getLocalName());
242         assertEquals(BAR, baseType1QName.getModule());
243         assertEquals(Optional.empty(), baseType1.getUnits());
244         assertEquals(Optional.empty(), baseType1.getDefaultValue());
245         patterns = baseType1.getPatternConstraints();
246         assertEquals(1, patterns.size());
247         pattern = patterns.iterator().next();
248         assertEquals("^(?:[b-u]*)$", pattern.getJavaPatternString());
249         assertEquals(1, baseType1.getLengthConstraint().get().getAllowedRanges().asRanges().size());
250
251         final StringTypeDefinition baseType2 = baseType1.getBaseType();
252         final QName baseType2QName = baseType2.getQName();
253         assertEquals("string-ext2", baseType2QName.getLocalName());
254         assertEquals(BAR, baseType2QName.getModule());
255         assertEquals(Optional.empty(), baseType2.getUnits());
256         assertEquals(Optional.empty(), baseType2.getDefaultValue());
257         assertTrue(baseType2.getPatternConstraints().isEmpty());
258         final RangeSet<Integer> baseType2Lengths = baseType2.getLengthConstraint().get().getAllowedRanges();
259         assertEquals(1, baseType2Lengths.asRanges().size());
260         Range<Integer> length = baseType2Lengths.span();
261         assertEquals(6, length.lowerEndpoint().intValue());
262         assertEquals(10, length.upperEndpoint().intValue());
263
264         final StringTypeDefinition baseType3 = baseType2.getBaseType();
265         assertEquals(QName.create(BAR, "string-ext1"), baseType3.getQName());
266         assertEquals(Optional.empty(), baseType3.getUnits());
267         assertEquals(Optional.empty(), baseType3.getDefaultValue());
268         patterns = baseType3.getPatternConstraints();
269         assertEquals(1, patterns.size());
270         pattern = patterns.iterator().next();
271         assertEquals("^(?:[a-k]*)$", pattern.getJavaPatternString());
272         final RangeSet<Integer> baseType3Lengths = baseType3.getLengthConstraint().get().getAllowedRanges();
273         assertEquals(1, baseType3Lengths.asRanges().size());
274         length = baseType3Lengths.span();
275         assertEquals(5, length.lowerEndpoint().intValue());
276         assertEquals(11, length.upperEndpoint().intValue());
277
278         assertEquals(BaseTypes.stringType(), baseType3.getBaseType());
279     }
280
281     @Test
282     public void testTypedefInvalidPatternsResolving() {
283         final LeafSchemaNode invalidPatternStringLeaf = (LeafSchemaNode) foo
284                 .getDataChildByName(QName.create(foo.getQNameModule(), "invalid-pattern-string-leaf"));
285         StringTypeDefinition type = (StringTypeDefinition) invalidPatternStringLeaf.getType();
286         assertEquals(QName.create(BAR, "invalid-string-pattern"), type.getQName());
287         assertEquals(Optional.empty(), type.getUnits());
288         assertEquals(Optional.empty(), type.getDefaultValue());
289         List<PatternConstraint> patterns = type.getPatternConstraints();
290         assertTrue(patterns.isEmpty());
291
292         final LeafSchemaNode invalidDirectStringPatternDefLeaf = (LeafSchemaNode) foo
293                 .getDataChildByName(QName.create(foo.getQNameModule(), "invalid-direct-string-pattern-def-leaf"));
294         type = (StringTypeDefinition) invalidDirectStringPatternDefLeaf.getType();
295
296         assertEquals(QName.create(YangConstants.RFC6020_YANG_MODULE, "string"), type.getQName());
297         assertEquals(Optional.empty(), type.getUnits());
298         assertEquals(Optional.empty(), type.getDefaultValue());
299         patterns = type.getPatternConstraints();
300         assertTrue(patterns.isEmpty());
301
302         final LeafSchemaNode multiplePatternStringLeaf = (LeafSchemaNode) foo
303                 .getDataChildByName(QName.create(foo.getQNameModule(), "multiple-pattern-string-leaf"));
304         type = (StringTypeDefinition) multiplePatternStringLeaf.getType();
305         assertEquals(QName.create(BAR, "multiple-pattern-string"), type.getQName());
306         assertEquals(Optional.empty(), type.getUnits());
307         assertEquals(Optional.empty(), type.getDefaultValue());
308         patterns = type.getPatternConstraints();
309         assertTrue(!patterns.isEmpty());
310         assertEquals(1, patterns.size());
311         final PatternConstraint pattern = patterns.iterator().next();
312         assertEquals("^(?:[e-z]*)$", pattern.getJavaPatternString());
313         assertEquals(1, type.getLengthConstraint().get().getAllowedRanges().asRanges().size());
314
315         final LeafSchemaNode multiplePatternDirectStringDefLeaf = (LeafSchemaNode) foo
316                 .getDataChildByName(QName.create(foo.getQNameModule(), "multiple-pattern-direct-string-def-leaf"));
317         type = (StringTypeDefinition) multiplePatternDirectStringDefLeaf.getType();
318         assertEquals(QName.create(FOO, "string"), type.getQName());
319         assertEquals(Optional.empty(), type.getUnits());
320         assertEquals(Optional.empty(), type.getDefaultValue());
321         patterns = type.getPatternConstraints();
322         assertTrue(!patterns.isEmpty());
323         assertEquals(2, patterns.size());
324
325         boolean isEZPattern = false;
326         boolean isADPattern = false;
327         for (final PatternConstraint patternConstraint : patterns) {
328             if (patternConstraint.getJavaPatternString().equals("^(?:[e-z]*)$")) {
329                 isEZPattern = true;
330             } else if (patternConstraint.getJavaPatternString().equals("^(?:[a-d]*)$")) {
331                 isADPattern = true;
332             }
333         }
334         assertTrue(isEZPattern);
335         assertTrue(isADPattern);
336     }
337
338     @Test
339     public void testTypedefLengthsResolving() {
340         final LeafSchemaNode lengthLeaf = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
341             "length-leaf"));
342         final StringTypeDefinition type = (StringTypeDefinition) lengthLeaf.getType();
343
344         assertEquals(QName.create(FOO, "string-ext2"), type.getQName());
345         assertEquals(Optional.empty(), type.getUnits());
346         assertEquals(Optional.empty(), type.getDefaultValue());
347         assertTrue(type.getPatternConstraints().isEmpty());
348         final RangeSet<Integer> typeLengths = type.getLengthConstraint().get().getAllowedRanges();
349         assertEquals(1, typeLengths.asRanges().size());
350         Range<Integer> length = typeLengths.span();
351         assertEquals(7, length.lowerEndpoint().intValue());
352         assertEquals(10, length.upperEndpoint().intValue());
353
354         final StringTypeDefinition baseType1 = type.getBaseType();
355         assertEquals(QName.create(BAR, "string-ext2"), baseType1.getQName());
356         assertEquals(Optional.empty(), baseType1.getUnits());
357         assertEquals(Optional.empty(), baseType1.getDefaultValue());
358         assertTrue(baseType1.getPatternConstraints().isEmpty());
359         final RangeSet<Integer> baseType2Lengths = baseType1.getLengthConstraint().get().getAllowedRanges();
360         assertEquals(1, baseType2Lengths.asRanges().size());
361         length = baseType2Lengths.span();
362         assertEquals(6, length.lowerEndpoint().intValue());
363         assertEquals(10, length.upperEndpoint().intValue());
364
365         final StringTypeDefinition baseType2 = baseType1.getBaseType();
366         assertEquals(QName.create(BAR, "string-ext1"), baseType2.getQName());
367         assertEquals(Optional.empty(), baseType2.getUnits());
368         assertEquals(Optional.empty(), baseType2.getDefaultValue());
369         final List<PatternConstraint> patterns = baseType2.getPatternConstraints();
370         assertEquals(1, patterns.size());
371         final PatternConstraint pattern = patterns.iterator().next();
372         assertEquals("^(?:[a-k]*)$", pattern.getJavaPatternString());
373         final RangeSet<Integer> baseType3Lengths = baseType2.getLengthConstraint().get().getAllowedRanges();
374         assertEquals(1, baseType3Lengths.asRanges().size());
375         length = baseType3Lengths.span();
376         assertEquals(5, length.lowerEndpoint().intValue());
377         assertEquals(11, length.upperEndpoint().intValue());
378
379         assertEquals(BaseTypes.stringType(), baseType2.getBaseType());
380     }
381
382     @Test
383     public void testTypedefDecimal1() {
384         final LeafSchemaNode testleaf = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
385             "decimal-leaf"));
386
387         assertTrue(testleaf.getType() instanceof DecimalTypeDefinition);
388         final DecimalTypeDefinition type = (DecimalTypeDefinition) testleaf.getType();
389         assertEquals(QName.create(BAR, "my-decimal-type"), type.getQName());
390         assertEquals(Optional.empty(), type.getUnits());
391         assertEquals(Optional.empty(), type.getDefaultValue());
392         assertEquals(6, type.getFractionDigits());
393         assertEquals(1, type.getRangeConstraint().get().getAllowedRanges().asRanges().size());
394
395         final DecimalTypeDefinition typeBase = type.getBaseType();
396         assertEquals(QName.create(BAR, "decimal64"), typeBase.getQName());
397         assertEquals(Optional.empty(), typeBase.getUnits());
398         assertEquals(Optional.empty(), typeBase.getDefaultValue());
399         assertEquals(6, typeBase.getFractionDigits());
400         assertEquals(1, typeBase.getRangeConstraint().get().getAllowedRanges().asRanges().size());
401
402         assertNull(typeBase.getBaseType());
403     }
404
405     @Test
406     public void testTypedefDecimal2() {
407         final LeafSchemaNode testleaf = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
408             "decimal-leaf2"));
409
410         assertTrue(testleaf.getType() instanceof DecimalTypeDefinition);
411         final DecimalTypeDefinition type = (DecimalTypeDefinition) testleaf.getType();
412         assertEquals(QName.create(BAR, "my-decimal-type"), type.getQName());
413         assertEquals(Optional.empty(), type.getUnits());
414         assertEquals(Optional.empty(), type.getDefaultValue());
415         assertEquals(6, type.getFractionDigits());
416         assertEquals(1, type.getRangeConstraint().get().getAllowedRanges().asRanges().size());
417
418         final DecimalTypeDefinition baseTypeDecimal = type.getBaseType();
419         assertEquals(6, baseTypeDecimal.getFractionDigits());
420     }
421
422     @Test
423     public void testTypedefUnion() {
424         final LeafSchemaNode unionleaf = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
425             "union-leaf"));
426
427         assertTrue(unionleaf.getType() instanceof UnionTypeDefinition);
428         final UnionTypeDefinition type = (UnionTypeDefinition) unionleaf.getType();
429         assertEquals(QName.create(BAR, "my-union-ext"), type.getQName());
430         assertEquals(Optional.empty(), type.getUnits());
431         assertEquals(Optional.empty(), type.getDefaultValue());
432
433         final UnionTypeDefinition baseType = type.getBaseType();
434         assertEquals(QName.create(BAR, "my-union"), baseType.getQName());
435         assertEquals(Optional.empty(), baseType.getUnits());
436         assertEquals(Optional.empty(), baseType.getDefaultValue());
437
438         final UnionTypeDefinition unionType = baseType.getBaseType();
439         final List<TypeDefinition<?>> unionTypes = unionType.getTypes();
440         assertEquals(2, unionTypes.size());
441
442         final Int16TypeDefinition unionType1 = (Int16TypeDefinition) unionTypes.get(0);
443         assertEquals(QName.create(BAR, "my-union"), baseType.getQName());
444         assertEquals(Optional.empty(), unionType1.getUnits());
445         assertEquals(Optional.empty(), unionType1.getDefaultValue());
446
447         final RangeConstraint<?> ranges = unionType1.getRangeConstraint().get();
448         assertEquals(1, ranges.getAllowedRanges().asRanges().size());
449         final Range<?> range = ranges.getAllowedRanges().span();
450         assertEquals((short)1, range.lowerEndpoint());
451         assertEquals((short)100, range.upperEndpoint());
452         assertEquals(BaseTypes.int16Type(), unionType1.getBaseType());
453
454         assertEquals(BaseTypes.int32Type(), unionTypes.get(1));
455     }
456
457     @Test
458     public void testNestedUnionResolving() {
459         final LeafSchemaNode testleaf = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
460             "custom-union-leaf"));
461
462         assertTrue(testleaf.getType() instanceof UnionTypeDefinition);
463         final UnionTypeDefinition type = (UnionTypeDefinition) testleaf.getType();
464         assertEquals(QName.create(BAZ, "union1"), type.getQName());
465         assertEquals(Optional.empty(), type.getUnits());
466         assertEquals(Optional.empty(), type.getDefaultValue());
467
468         final UnionTypeDefinition typeBase = type.getBaseType();
469         assertEquals(QName.create(BAZ, "union2"), typeBase.getQName());
470         assertEquals(Optional.empty(), typeBase.getUnits());
471         assertEquals(Optional.empty(), typeBase.getDefaultValue());
472
473         final UnionTypeDefinition union = typeBase.getBaseType();
474         final List<TypeDefinition<?>> unionTypes = union.getTypes();
475         assertEquals(2, unionTypes.size());
476         assertEquals(BaseTypes.int32Type(), unionTypes.get(0));
477         assertTrue(unionTypes.get(1) instanceof UnionTypeDefinition);
478
479         final UnionTypeDefinition unionType1 = (UnionTypeDefinition) unionTypes.get(1);
480         assertEquals(QName.create(BAR, "nested-union2"), unionType1.getQName());
481         assertEquals(Optional.empty(), unionType1.getUnits());
482         assertEquals(Optional.empty(), unionType1.getDefaultValue());
483
484         final UnionTypeDefinition nestedUnion = unionType1.getBaseType();
485         final List<TypeDefinition<?>> nestedUnion2Types = nestedUnion.getTypes();
486         assertEquals(2, nestedUnion2Types.size());
487         assertTrue(nestedUnion2Types.get(1) instanceof StringTypeDefinition);
488         assertTrue(nestedUnion2Types.get(0) instanceof UnionTypeDefinition);
489
490         final UnionTypeDefinition myUnionExt = (UnionTypeDefinition) nestedUnion2Types.get(0);
491         assertEquals(QName.create(BAR, "my-union-ext"), myUnionExt.getQName());
492         assertEquals(Optional.empty(), myUnionExt.getUnits());
493         assertEquals(Optional.empty(), myUnionExt.getDefaultValue());
494
495
496         final UnionTypeDefinition myUnion = myUnionExt.getBaseType();
497         assertEquals(QName.create(BAR, "my-union"), myUnion.getQName());
498         assertEquals(Optional.empty(), myUnion.getUnits());
499         assertEquals(Optional.empty(), myUnion.getDefaultValue());
500
501         final UnionTypeDefinition myUnionBase = myUnion.getBaseType();
502         final List<TypeDefinition<?>> myUnionBaseTypes = myUnionBase.getTypes();
503         assertEquals(2, myUnionBaseTypes.size());
504         assertTrue(myUnionBaseTypes.get(0) instanceof Int16TypeDefinition);
505         assertEquals(BaseTypes.int32Type(), myUnionBaseTypes.get(1));
506
507         final Int16TypeDefinition int16Ext = (Int16TypeDefinition) myUnionBaseTypes.get(0);
508         assertEquals(QName.create(BAR, "int16"), int16Ext.getQName());
509         assertEquals(Optional.empty(), int16Ext.getUnits());
510         assertEquals(Optional.empty(), int16Ext.getDefaultValue());
511         final Set<? extends Range<? extends Number>> ranges = int16Ext.getRangeConstraint().get().getAllowedRanges()
512                 .asRanges();
513         assertEquals(1, ranges.size());
514         final Range<? extends Number> range = ranges.iterator().next();
515         assertEquals(1, range.lowerEndpoint().intValue());
516         assertEquals(100, range.upperEndpoint().intValue());
517
518         assertEquals(BaseTypes.int16Type(), int16Ext.getBaseType());
519     }
520
521     @Test
522     public void testChoice() {
523         final ContainerSchemaNode transfer = (ContainerSchemaNode) foo.getDataChildByName(
524             QName.create(foo.getQNameModule(), "transfer"));
525         final ChoiceSchemaNode how = (ChoiceSchemaNode) transfer.getDataChildByName(
526             QName.create(foo.getQNameModule(), "how"));
527         final SortedMap<QName, CaseSchemaNode> cases = how.getCases();
528         assertEquals(5, cases.size());
529         CaseSchemaNode input = null;
530         CaseSchemaNode output = null;
531         for (final CaseSchemaNode caseNode : cases.values()) {
532             if ("input".equals(caseNode.getQName().getLocalName())) {
533                 input = caseNode;
534             } else if ("output".equals(caseNode.getQName().getLocalName())) {
535                 output = caseNode;
536             }
537         }
538         assertNotNull(input);
539         assertNotNull(input.getPath());
540         assertNotNull(output);
541         assertNotNull(output.getPath());
542     }
543
544     @Test
545     public void testDeviation() {
546         final Collection<? extends Deviation> deviations = foo.getDeviations();
547         assertEquals(1, deviations.size());
548         final Deviation dev = deviations.iterator().next();
549         assertEquals(Optional.of("system/user ref"), dev.getReference());
550
551         final SchemaPath expectedPath = SchemaPath.create(true,
552             QName.create(BAR, "interfaces"),
553             QName.create(BAR, "ifEntry"));
554
555         assertEquals(expectedPath, dev.getTargetPath());
556         assertEquals(DeviateKind.ADD, dev.getDeviates().iterator().next().getDeviateType());
557     }
558
559     @Test
560     public void testUnknownNode() {
561         final ContainerSchemaNode network = (ContainerSchemaNode) baz.getDataChildByName(
562             QName.create(baz.getQNameModule(), "network"));
563         final Collection<? extends UnknownSchemaNode> unknownNodes = network.getUnknownSchemaNodes();
564         assertEquals(1, unknownNodes.size());
565         final UnknownSchemaNode unknownNode = unknownNodes.iterator().next();
566         assertNotNull(unknownNode.getNodeType());
567         assertEquals("point", unknownNode.getNodeParameter());
568     }
569
570     @Test
571     public void testFeature() {
572         final Collection<? extends FeatureDefinition> features = baz.getFeatures();
573         assertEquals(3, features.size());
574     }
575
576     @Test
577     public void testExtension() {
578         final Collection<? extends ExtensionDefinition> extensions = baz.getExtensionSchemaNodes();
579         assertEquals(1, extensions.size());
580         final ExtensionDefinition extension = extensions.iterator().next();
581         assertEquals("name", extension.getArgument());
582         assertEquals(
583             Optional.of("Takes as argument a name string. Makes the code generator use the given name in the #define."),
584                 extension.getDescription());
585         assertTrue(extension.isYinElement());
586     }
587
588     @Test
589     public void testNotification() {
590         final Collection<? extends NotificationDefinition> notifications = baz.getNotifications();
591         assertEquals(1, notifications.size());
592
593         final NotificationDefinition notification = notifications.iterator().next();
594         // test SchemaNode args
595         assertEquals(QName.create(BAZ, "event"), notification.getQName());
596         final SchemaPath expectedPath = SchemaPath.create(true,  QName.create(BAZ, "event"));
597         assertEquals(expectedPath, notification.getPath());
598         assertFalse(notification.getDescription().isPresent());
599         assertFalse(notification.getReference().isPresent());
600         assertEquals(Status.CURRENT, notification.getStatus());
601         assertEquals(0, notification.getUnknownSchemaNodes().size());
602         // test DataNodeContainer args
603         assertEquals(0, notification.getTypeDefinitions().size());
604         assertEquals(3, notification.getChildNodes().size());
605         assertEquals(0, notification.getGroupings().size());
606         assertEquals(0, notification.getUses().size());
607
608         final LeafSchemaNode eventClass = (LeafSchemaNode) notification.getDataChildByName(
609             QName.create(baz.getQNameModule(), "event-class"));
610         assertTrue(eventClass.getType() instanceof StringTypeDefinition);
611         final LeafSchemaNode severity = (LeafSchemaNode) notification.getDataChildByName(
612             QName.create(baz.getQNameModule(), "severity"));
613         assertTrue(severity.getType() instanceof StringTypeDefinition);
614     }
615
616     @Test
617     public void testRpc() {
618         final Collection<? extends RpcDefinition> rpcs = baz.getRpcs();
619         assertEquals(1, rpcs.size());
620
621         final RpcDefinition rpc = rpcs.iterator().next();
622         assertEquals(Optional.of("Retrieve all or part of a specified configuration."), rpc.getDescription());
623         assertEquals(Optional.of("RFC 6241, Section 7.1"), rpc.getReference());
624     }
625
626     @Test
627     public void testTypePath() throws ParseException {
628         final Collection<? extends TypeDefinition<?>> types = bar.getTypeDefinitions();
629
630         // int32-ext1
631         final Int32TypeDefinition int32ext1 = (Int32TypeDefinition) TestUtils.findTypedef(types, "int32-ext1");
632         final QName int32TypedefQName = QName.create(BAR, "int32-ext1");
633         assertEquals(int32TypedefQName, int32ext1.getQName());
634
635         final SchemaPath typeSchemaPath = int32ext1.getPath();
636         final Iterable<QName> typePath = typeSchemaPath.getPathFromRoot();
637         final Iterator<QName> typePathIt = typePath.iterator();
638         assertEquals(int32TypedefQName, typePathIt.next());
639         assertFalse(typePathIt.hasNext());
640
641         // int32-ext1/int32
642         final Int32TypeDefinition int32 = int32ext1.getBaseType();
643         assertEquals(BaseTypes.int32Type(), int32);
644     }
645
646     @Test
647     public void testTypePath2() throws ParseException {
648         final Collection<? extends TypeDefinition<?>> types = bar.getTypeDefinitions();
649
650         // my-decimal-type
651         final DecimalTypeDefinition myDecType = (DecimalTypeDefinition) TestUtils.findTypedef(types, "my-decimal-type");
652         final QName myDecTypeQName = myDecType.getQName();
653
654         assertEquals(BAR, myDecTypeQName.getModule());
655         assertEquals("my-decimal-type", myDecTypeQName.getLocalName());
656
657         final SchemaPath typeSchemaPath = myDecType.getPath();
658         final Iterable<QName> typePath = typeSchemaPath.getPathFromRoot();
659         final Iterator<QName> typePathIt = typePath.iterator();
660         assertEquals(myDecTypeQName, typePathIt.next());
661         assertFalse(typePathIt.hasNext());
662
663         // my-base-int32-type/int32
664         final DecimalTypeDefinition dec64 = myDecType.getBaseType();
665         final QName dec64QName = dec64.getQName();
666
667         assertEquals(BAR, dec64QName.getModule());
668         assertEquals("decimal64", dec64QName.getLocalName());
669
670         final SchemaPath dec64SchemaPath = dec64.getPath();
671         final Iterable<QName> dec64Path = dec64SchemaPath.getPathFromRoot();
672         final Iterator<QName> dec64PathIt = dec64Path.iterator();
673         assertEquals(myDecTypeQName, dec64PathIt.next());
674         assertEquals(dec64QName, dec64PathIt.next());
675         assertFalse(dec64PathIt.hasNext());
676     }
677
678     private static void checkOrder(final Collection<Module> modules) {
679         final Iterator<Module> it = modules.iterator();
680         Module module = it.next();
681         assertEquals("m2", module.getName());
682         module = it.next();
683         assertEquals("m4", module.getName());
684         module = it.next();
685         assertEquals("m6", module.getName());
686         module = it.next();
687         assertEquals("m8", module.getName());
688         module = it.next();
689         assertEquals("m7", module.getName());
690         module = it.next();
691         assertEquals("m5", module.getName());
692         module = it.next();
693         assertEquals("m3", module.getName());
694         module = it.next();
695         assertEquals("m1", module.getName());
696     }
697
698     private static void assertSetEquals(final Set<Module> s1, final Set<Module> s2) {
699         assertEquals(s1, s2);
700         final Iterator<Module> it = s1.iterator();
701         for (final Module m : s2) {
702             assertEquals(m, it.next());
703         }
704     }
705
706     @Test
707     public void testSubmodules() {
708         final DataSchemaNode id = foo.getDataChildByName(QName.create(foo.getQNameModule(), "id"));
709         assertNotNull(id);
710         final DataSchemaNode subExt = foo.getDataChildByName(QName.create(foo.getQNameModule(), "sub-ext"));
711         assertNotNull(subExt);
712         final DataSchemaNode subTransfer = foo.getDataChildByName(QName.create(foo.getQNameModule(), "sub-transfer"));
713         assertNotNull(subTransfer);
714
715         assertEquals(2, foo.getExtensionSchemaNodes().size());
716         assertEquals(2, foo.getAugmentations().size());
717     }
718
719     @Test
720     public void unknownStatementInSubmoduleHeaderTest() throws IOException, URISyntaxException, ReactorException {
721         final StatementStreamSource yang1 = sourceForResource("/yang-grammar-test/revisions-extension.yang");
722         final StatementStreamSource yang2 = sourceForResource("/yang-grammar-test/submodule-header-extension.yang");
723         TestUtils.parseYangSources(yang1, yang2);
724     }
725
726     @Test
727     public void unknownStatementBetweenRevisionsTest() throws ReactorException {
728         final SchemaContext result = RFC7950Reactors.defaultReactor().newBuild()
729                 .addSource(sourceForResource("/yang-grammar-test/revisions-extension.yang"))
730                 .addSource(sourceForResource("/yang-grammar-test/submodule-header-extension.yang"))
731                 .buildEffective();
732         assertNotNull(result);
733     }
734
735     @Test
736     public void unknownStatementsInStatementsTest() {
737
738         final StatementStreamSource yangFile1 = sourceForResource(
739                 "/yang-grammar-test/stmtsep-in-statements.yang");
740         final StatementStreamSource yangFile2 = sourceForResource(
741                 "/yang-grammar-test/stmtsep-in-statements2.yang");
742         final StatementStreamSource yangFile3 = sourceForResource(
743                 "/yang-grammar-test/stmtsep-in-statements-sub.yang");
744
745         final BuildAction reactor = RFC7950Reactors.defaultReactor().newBuild()
746                 .addSources(yangFile1, yangFile2, yangFile3);
747         // TODO: change test or create new module in order to respect new statement parser validations
748         try {
749             final SchemaContext result = reactor.buildEffective();
750         } catch (final ReactorException e) {
751             assertEquals(SomeModifiersUnresolvedException.class, e.getClass());
752             assertTrue(e.getCause() instanceof SourceException);
753             assertTrue(e.getCause().getMessage().startsWith("aaa is not a YANG statement or use of extension"));
754         }
755     }
756
757 }