From 092e3656c2276fb4559b336264339e8fb6f38ae9 Mon Sep 17 00:00:00 2001 From: Peter Kajsa Date: Thu, 8 Sep 2016 16:25:48 +0200 Subject: [PATCH] Bug 6669: Mandatory nodes cannot be added to node from another module via augment Yang parser allowed to add mandatory nodes to target node from another module via augmentations in some cases. This patch fixes this according to the rules defined in RFC6020 (https://tools.ietf.org/html/rfc6020#section-3.1, https://tools.ietf.org/html/rfc6020#section-7.15). Change-Id: I699fc3c1014583b85ea47504f9a102d06e0b9011 Signed-off-by: Peter Kajsa --- .../parser/spi/meta/StmtContextUtils.java | 69 ++++++++++++ .../parser/stmt/rfc6020/AugmentUtils.java | 35 ++++-- .../yang/parser/stmt/rfc6020/Utils.java | 18 ---- .../yangtools/yang/stmt/Bug5335Test.java | 54 +++++----- .../yangtools/yang/stmt/Bug6669Test.java | 100 ++++++++++++++++++ .../yang/stmt/YangParserNegativeTest.java | 74 ++++++------- .../bugs/bug6669/invalid/test1/bar.yang | 19 ++++ .../bugs/bug6669/invalid/test1/foo.yang | 9 ++ .../bugs/bug6669/invalid/test2/bar.yang | 30 ++++++ .../bugs/bug6669/invalid/test2/foo.yang | 9 ++ .../bugs/bug6669/invalid/test3/bar.yang | 29 +++++ .../bugs/bug6669/invalid/test3/foo.yang | 9 ++ .../bugs/bug6669/valid/test1/bar.yang | 20 ++++ .../bugs/bug6669/valid/test1/foo.yang | 9 ++ .../bugs/bug6669/valid/test2/bar.yang | 31 ++++++ .../bugs/bug6669/valid/test2/foo.yang | 9 ++ .../bugs/bug6669/valid/test3/bar.yang | 30 ++++++ .../bugs/bug6669/valid/test3/foo.yang | 9 ++ 18 files changed, 470 insertions(+), 93 deletions(-) create mode 100644 yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug6669Test.java create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test1/bar.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test1/foo.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test2/bar.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test2/foo.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test3/bar.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test3/foo.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test1/bar.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test1/foo.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test2/bar.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test2/foo.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test3/bar.yang create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test3/foo.yang diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java index ddb1b35d2e..2d5924ff24 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java @@ -18,6 +18,9 @@ import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping; import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; import org.opendaylight.yangtools.yang.model.api.stmt.KeyStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.PresenceStatement; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.IfFeaturePredicates; import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace; @@ -252,4 +255,70 @@ public final class StmtContextUtils { return !containsIfFeature || isSupported; } + + /** + * Checks whether statement context is a presence container or not. + * + * @param stmtCtx + * statement context + * @return true if it is a presence container + */ + public static boolean isPresenceContainer(final StatementContextBase stmtCtx) { + return stmtCtx.getPublicDefinition() == Rfc6020Mapping.CONTAINER && containsPresenceSubStmt(stmtCtx); + } + + /** + * Checks whether statement context is a non-presence container or not. + * + * @param stmtCtx + * statement context + * @return true if it is a non-presence container + */ + public static boolean isNonPresenceContainer(final StatementContextBase stmtCtx) { + return stmtCtx.getPublicDefinition() == Rfc6020Mapping.CONTAINER && !containsPresenceSubStmt(stmtCtx); + } + + private static boolean containsPresenceSubStmt(final StatementContextBase stmtCtx) { + return findFirstSubstatement(stmtCtx, PresenceStatement.class) != null; + } + + /** + * Checks whether statement context is a mandatory node according to RFC6020 + * or not. + * + * @param stmtCtx + * statement context + * @return true if it is a mandatory node according to RFC6020 + */ + public static boolean isMandatoryNode(final StatementContextBase stmtCtx) { + return isMandatoryListOrLeafList(stmtCtx) || isMandatoryLeafChoiceOrAnyXML(stmtCtx); + } + + private static boolean isMandatoryLeafChoiceOrAnyXML(final StatementContextBase stmtCtx) { + if (!(stmtCtx.getPublicDefinition() instanceof Rfc6020Mapping)) { + return false; + } + switch ((Rfc6020Mapping) stmtCtx.getPublicDefinition()) { + case LEAF: + case CHOICE: + case ANYXML: + return Boolean.TRUE.equals(firstSubstatementAttributeOf(stmtCtx, MandatoryStatement.class)); + default: + return false; + } + } + + private static boolean isMandatoryListOrLeafList(final StatementContextBase stmtCtx) { + if (!(stmtCtx.getPublicDefinition() instanceof Rfc6020Mapping)) { + return false; + } + switch ((Rfc6020Mapping) stmtCtx.getPublicDefinition()) { + case LIST: + case LEAF_LIST: + final Integer minElements = firstSubstatementAttributeOf(stmtCtx, MinElementsStatement.class); + return minElements != null && minElements > 0; + default: + return false; + } + } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentUtils.java index 09e78b4b42..159b473370 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentUtils.java @@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -17,7 +18,6 @@ import java.util.Set; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping; import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryStatement; import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement; import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement; import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; @@ -89,15 +89,7 @@ public final class AugmentUtils { } if (typeOfCopy == CopyType.ADDED_BY_AUGMENTATION && reguiredCheckOfMandatoryNodes(sourceCtx, targetCtx)) { - final List> sourceSubStatements = new Builder>() - .addAll(sourceCtx.declaredSubstatements()).addAll(sourceCtx.effectiveSubstatements()).build(); - - for (final StatementContextBase sourceSubStatement : sourceSubStatements) { - InferenceException.throwIf(MandatoryStatement.class.equals(sourceSubStatement.getPublicDefinition() - .getDeclaredRepresentationClass()), sourceCtx.getStatementSourceReference(), - "An augment cannot add node '%s' because it is mandatory and in module different from target", - sourceCtx.rawStatementArgument()); - } + checkForMandatoryNodes(sourceCtx); } final List> targetSubStatements = new Builder>() @@ -118,6 +110,27 @@ public final class AugmentUtils { } } + private static void checkForMandatoryNodes(final StatementContextBase sourceCtx) { + if (StmtContextUtils.isNonPresenceContainer(sourceCtx)) { + /* + * We need to iterate over both declared and effective sub-statements, + * because a mandatory node can be: + * a) declared in augment body + * b) added to augment body also via uses of a grouping and + * such sub-statements are stored in effective sub-statements collection. + */ + for (final StatementContextBase sourceSubStatement : Iterables.concat( + sourceCtx.declaredSubstatements(), sourceCtx.declaredSubstatements())) { + checkForMandatoryNodes(sourceSubStatement); + } + } + + InferenceException.throwIf(StmtContextUtils.isMandatoryNode(sourceCtx), + sourceCtx.getStatementSourceReference(), + "An augment cannot add node '%s' because it is mandatory and in module different than target", + sourceCtx.rawStatementArgument()); + } + private static boolean reguiredCheckOfMandatoryNodes(final StatementContextBase sourceCtx, StatementContextBase targetCtx) { /* @@ -146,7 +159,7 @@ public final class AugmentUtils { * the same module, return false and skip mandatory nodes * validation */ - if (Utils.isPresenceContainer(targetCtx)) { + if (StmtContextUtils.isPresenceContainer(targetCtx)) { return false; } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java index ac6ad4afcb..38620a1e7b 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java @@ -14,7 +14,6 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableSet; @@ -41,7 +40,6 @@ import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; import org.opendaylight.yangtools.yang.model.api.DeviateKind; import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath; -import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping; import org.opendaylight.yangtools.yang.model.api.Status; import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement; @@ -681,22 +679,6 @@ public final class Utils { return false; } - public static boolean isPresenceContainer(final StatementContextBase targetCtx) { - if (!targetCtx.getPublicDefinition().equals(Rfc6020Mapping.CONTAINER)) { - return false; - } - - final List> targetSubStatements = new ImmutableList.Builder>() - .addAll(targetCtx.declaredSubstatements()).addAll(targetCtx.effectiveSubstatements()).build(); - for (final StatementContextBase subStatement : targetSubStatements) { - if (subStatement.getPublicDefinition().equals(Rfc6020Mapping.PRESENCE)) { - return true; - } - } - - return false; - } - public static SourceIdentifier createSourceIdentifier(final RootStatementContext root) { final QNameModule qNameModule = root.getFromNamespace(ModuleCtxToModuleQName.class, root); if (qNameModule != null) { diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug5335Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug5335Test.java index fed98bf20a..ccaab3750b 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug5335Test.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug5335Test.java @@ -56,86 +56,86 @@ public class Bug5335Test { @Test public void incorrectTest1() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException { - SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/incorrect/case-1"); + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/incorrect/case-1"); assertNotNull(context); - SchemaPath schemaPath = SchemaPath.create(true, ROOT, NON_PRESENCE_CONTAINER_B, MANDATORY_LEAF_B); - SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); + final SchemaPath schemaPath = SchemaPath.create(true, ROOT, NON_PRESENCE_CONTAINER_B, MANDATORY_LEAF_B); + final SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); assertNull(mandatoryLeaf); - String testLog = output.toString(); + final String testLog = output.toString(); assertTrue(testLog - .contains("An augment cannot add node 'mandatory-leaf' because it is mandatory and in module different from target")); + .contains("An augment cannot add node 'mandatory-leaf' because it is mandatory and in module different than target")); } @Test public void incorrectTest2() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException { - SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/incorrect/case-2"); + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/incorrect/case-2"); assertNotNull(context); - SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_F, MANDATORY_LEAF_B); - SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); + final SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_F, MANDATORY_LEAF_B); + final SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); assertNull(mandatoryLeaf); - String testLog = output.toString(); + final String testLog = output.toString(); assertTrue(testLog - .contains("An augment cannot add node 'mandatory-leaf' because it is mandatory and in module different from target")); + .contains("An augment cannot add node 'mandatory-leaf' because it is mandatory and in module different than target")); } @Test public void incorrectTest3() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException { - SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/incorrect/case-2"); + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/incorrect/case-2"); assertNotNull(context); - SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_F, NON_PRESENCE_CONTAINER_B, + final SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_F, NON_PRESENCE_CONTAINER_B, MANDATORY_LEAF_B); - SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); + final SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); assertNull(mandatoryLeaf); - String testLog = output.toString(); + final String testLog = output.toString(); assertTrue(testLog - .contains("An augment cannot add node 'mandatory-leaf' because it is mandatory and in module different from target")); + .contains("An augment cannot add node 'mandatory-leaf' because it is mandatory and in module different than target")); } @Test public void correctTest1() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException { - SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-1"); + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-1"); assertNotNull(context); - SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_B, MANDATORY_LEAF_B); - SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); + final SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_B, MANDATORY_LEAF_B); + final SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); assertTrue(mandatoryLeaf instanceof LeafSchemaNode); } @Test public void correctTest2() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException { - SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-2"); + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-2"); assertNotNull(context); - SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_B, NON_PRESENCE_CONTAINER_B, + final SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_B, NON_PRESENCE_CONTAINER_B, MANDATORY_LEAF_B); - SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); + final SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); assertTrue(mandatoryLeaf instanceof LeafSchemaNode); } @Test public void correctTest3() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException { - SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-3"); + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-3"); assertNotNull(context); - SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_B, NON_PRESENCE_CONTAINER_B, + final SchemaPath schemaPath = SchemaPath.create(true, ROOT, PRESENCE_CONTAINER_B, NON_PRESENCE_CONTAINER_B, MANDATORY_LEAF_B); - SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); + final SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); assertTrue(mandatoryLeaf instanceof LeafSchemaNode); } @Test public void correctTest4() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException { - SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-4"); + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-4"); assertNotNull(context); - SchemaPath schemaPath = SchemaPath.create(true, ROOT, NON_PRESENCE_CONTAINER_F, MANDATORY_LEAF_F); - SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); + final SchemaPath schemaPath = SchemaPath.create(true, ROOT, NON_PRESENCE_CONTAINER_F, MANDATORY_LEAF_F); + final SchemaNode mandatoryLeaf = SchemaContextUtil.findDataSchemaNode(context, schemaPath); assertTrue(mandatoryLeaf instanceof LeafSchemaNode); } } diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug6669Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug6669Test.java new file mode 100644 index 0000000000..8254cd419d --- /dev/null +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug6669Test.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.stmt; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.FileNotFoundException; +import java.net.URISyntaxException; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; + +public class Bug6669Test { + private static final String REV = "2016-09-08"; + private static final String FOO_NS = "foo"; + private static final String BAR_NS = "bar"; + private static final QName ROOT = QName.create(FOO_NS, REV, "root"); + private static final QName BAR = QName.create(BAR_NS, REV, "bar"); + private static final QName BAR_1 = QName.create(BAR_NS, REV, "bar1"); + private static final QName BAR_2 = QName.create(BAR_NS, REV, "bar2"); + private static final QName M = QName.create(BAR_NS, REV, "m"); + private static final QName L = QName.create(BAR_NS, REV, "l"); + + @Test + public void testInvalidAugment() throws SourceException, ReactorException, FileNotFoundException, + URISyntaxException { + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug6669/invalid/test1"); + assertNotNull(context); + + final SchemaNode findDataSchemaNode = SchemaContextUtil.findDataSchemaNode(context, + SchemaPath.create(true, ROOT, BAR, BAR_1, M)); + assertNull(findDataSchemaNode); + } + + @Test + public void testInvalidAugment2() throws SourceException, ReactorException, FileNotFoundException, + URISyntaxException { + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug6669/invalid/test2"); + assertNotNull(context); + + final SchemaNode findDataSchemaNode = SchemaContextUtil.findDataSchemaNode(context, + SchemaPath.create(true, ROOT, BAR, BAR_1, BAR_2, M)); + assertNull(findDataSchemaNode); + } + + @Test + public void testInvalidAugment3() throws SourceException, ReactorException, FileNotFoundException, + URISyntaxException { + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug6669/invalid/test3"); + assertNotNull(context); + + final SchemaNode findDataSchemaNode = SchemaContextUtil.findDataSchemaNode(context, + SchemaPath.create(true, ROOT, BAR, BAR_1, BAR_2, L)); + assertNull(findDataSchemaNode); + } + + @Test + public void testValidAugment() throws SourceException, ReactorException, FileNotFoundException, URISyntaxException { + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug6669/valid/test1"); + assertNotNull(context); + + final SchemaNode findDataSchemaNode = SchemaContextUtil.findDataSchemaNode(context, + SchemaPath.create(true, ROOT, BAR, BAR_1, M)); + assertTrue(findDataSchemaNode instanceof LeafSchemaNode); + } + + @Test + public void testValidAugment2() throws SourceException, ReactorException, FileNotFoundException, URISyntaxException { + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug6669/valid/test2"); + assertNotNull(context); + + final SchemaNode findDataSchemaNode = SchemaContextUtil.findDataSchemaNode(context, + SchemaPath.create(true, ROOT, BAR, BAR_1, BAR_2, M)); + assertTrue(findDataSchemaNode instanceof LeafSchemaNode); + } + + @Test + public void testValidAugment3() throws SourceException, ReactorException, FileNotFoundException, URISyntaxException { + final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug6669/valid/test3"); + assertNotNull(context); + + final SchemaNode findDataSchemaNode = SchemaContextUtil.findDataSchemaNode(context, + SchemaPath.create(true, ROOT, BAR, BAR_1, BAR_2, L)); + assertTrue(findDataSchemaNode instanceof ListSchemaNode); + } +} diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/YangParserNegativeTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/YangParserNegativeTest.java index 7224332480..6330790c51 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/YangParserNegativeTest.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/YangParserNegativeTest.java @@ -46,14 +46,14 @@ public class YangParserNegativeTest { @Test public void testInvalidImport() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/testfile1.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/testfile1.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("SomeModifiersUnresolvedException should be thrown"); } - } catch (SomeModifiersUnresolvedException e) { - Throwable rootCause = Throwables.getRootCause(e); + } catch (final SomeModifiersUnresolvedException e) { + final Throwable rootCause = Throwables.getRootCause(e); assertTrue(rootCause instanceof InferenceException); assertTrue(rootCause.getMessage().startsWith("Imported module")); assertTrue(rootCause.getMessage().contains("was not found.")); @@ -62,14 +62,14 @@ public class YangParserNegativeTest { @Test public void testTypeNotFound() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/testfile2.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/testfile2.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("InferenceException should be thrown"); } - } catch (SomeModifiersUnresolvedException e) { - Throwable rootCause = Throwables.getRootCause(e); + } catch (final SomeModifiersUnresolvedException e) { + final Throwable rootCause = Throwables.getRootCause(e); assertTrue(rootCause instanceof InferenceException); assertTrue(rootCause.getMessage() .startsWith("Type [(urn:simple.types.data.demo?revision=2013-02-27)int-ext] was not found.")); @@ -78,8 +78,8 @@ public class YangParserNegativeTest { @Test public void testInvalidAugmentTarget() throws Exception { - File yang1 = new File(getClass().getResource("/negative-scenario/testfile0.yang").toURI()); - File yang2 = new File(getClass().getResource("/negative-scenario/testfile3.yang").toURI()); + final File yang1 = new File(getClass().getResource("/negative-scenario/testfile0.yang").toURI()); + final File yang2 = new File(getClass().getResource("/negative-scenario/testfile3.yang").toURI()); try { final List streams = new ArrayList<>(2); try (InputStream testFile0 = new NamedFileInputStream(yang1, yang1.getPath())) { @@ -91,7 +91,7 @@ public class YangParserNegativeTest { fail("SomeModifiersUnresolvedException should be thrown"); } } - } catch (SomeModifiersUnresolvedException e) { + } catch (final SomeModifiersUnresolvedException e) { final Throwable rootCause = Throwables.getRootCause(e); assertTrue(rootCause instanceof InferenceException); assertTrue(rootCause.getMessage().startsWith( @@ -101,13 +101,13 @@ public class YangParserNegativeTest { @Test public void testInvalidRefine() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/testfile4.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/testfile4.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("SourceException should be thrown"); } - } catch (ReactorException e) { + } catch (final ReactorException e) { assertTrue(e.getCause().getMessage().contains("Error in module 'test4' in the refine of uses " + "'Relative{path=[(urn:simple.container.demo?revision=1970-01-01)node]}': can not perform refine of 'PRESENCE' for" + " the target 'LEAF_LIST'.")); @@ -116,40 +116,40 @@ public class YangParserNegativeTest { @Test public void testInvalidLength() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/testfile5.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/testfile5.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("YangParseException should be thrown"); } - } catch (ReactorException e) { + } catch (final ReactorException e) { assertTrue(e.getCause().getMessage().contains("Invalid length constraint: <4, 10>")); } } @Test public void testInvalidRange() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/testfile6.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/testfile6.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("Exception should be thrown"); } - } catch (ReactorException e) { + } catch (final ReactorException e) { assertTrue(e.getCause().getMessage().contains("Invalid range constraint: <5, 20>")); } } @Test public void testDuplicateContainer() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/duplicity/container.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/duplicity/container.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("SourceException should be thrown"); } - } catch (ReactorException e) { - String expected = "Error in module 'container': cannot add '(urn:simple.container" + + } catch (final ReactorException e) { + final String expected = "Error in module 'container': cannot add '(urn:simple.container" + ".demo?revision=1970-01-01)foo'. Node name collision: '(urn:simple.container" + ".demo?revision=1970-01-01)foo' already declared."; assertTrue(e.getCause().getMessage().contains(expected)); @@ -158,14 +158,14 @@ public class YangParserNegativeTest { @Test public void testDuplicateContainerList() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/duplicity/container-list.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/duplicity/container-list.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("SourceException should be thrown"); } - } catch (ReactorException e) { - String expected = "Error in module 'container-list': cannot add '(urn:simple.container" + + } catch (final ReactorException e) { + final String expected = "Error in module 'container-list': cannot add '(urn:simple.container" + ".demo?revision=1970-01-01)foo'. Node name collision: '(urn:simple.container" + ".demo?revision=1970-01-01)foo' already declared."; assertTrue(e.getCause().getMessage().contains(expected)); @@ -174,14 +174,14 @@ public class YangParserNegativeTest { @Test public void testDuplicateContainerLeaf() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/duplicity/container-leaf.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/duplicity/container-leaf.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("SourceException should be thrown"); } - } catch (ReactorException e) { - String expected = "Error in module 'container-leaf': cannot add '(urn:simple.container" + + } catch (final ReactorException e) { + final String expected = "Error in module 'container-leaf': cannot add '(urn:simple.container" + ".demo?revision=1970-01-01)foo'. Node name collision: '(urn:simple.container" + ".demo?revision=1970-01-01)foo' already declared."; assertTrue(e.getCause().getMessage().contains(expected)); @@ -190,14 +190,14 @@ public class YangParserNegativeTest { @Test public void testDuplicateTypedef() throws Exception { - File yang = new File(getClass().getResource("/negative-scenario/duplicity/typedef.yang").toURI()); + final File yang = new File(getClass().getResource("/negative-scenario/duplicity/typedef.yang").toURI()); try { try (InputStream stream = new NamedFileInputStream(yang, yang.getPath())) { TestUtils.loadModule(stream); fail("SourceException should be thrown"); } - } catch (ReactorException e) { - String expected = "Error in module 'typedef': cannot add '(urn:simple.container" + + } catch (final ReactorException e) { + final String expected = "Error in module 'typedef': cannot add '(urn:simple.container" + ".demo?revision=1970-01-01)int-ext'. Node name collision: '(urn:simple.container" + ".demo?revision=1970-01-01)int-ext' already declared."; assertTrue(e.getCause().getMessage().startsWith(expected)); @@ -206,8 +206,8 @@ public class YangParserNegativeTest { @Test public void testDuplicityInAugmentTarget1() throws Exception { - File yang1 = new File(getClass().getResource("/negative-scenario/duplicity/augment0.yang").toURI()); - File yang2 = new File(getClass().getResource("/negative-scenario/duplicity/augment1.yang").toURI()); + final File yang1 = new File(getClass().getResource("/negative-scenario/duplicity/augment0.yang").toURI()); + final File yang2 = new File(getClass().getResource("/negative-scenario/duplicity/augment1.yang").toURI()); try (InputStream stream1 = new NamedFileInputStream(yang1, yang1.getPath()); InputStream stream2 = new NamedFileInputStream(yang2, yang2.getPath())) { TestUtils.loadModules(Arrays.asList(stream1, stream2)); @@ -218,8 +218,8 @@ public class YangParserNegativeTest { @Test public void testDuplicityInAugmentTarget2() throws Exception { - File yang1 = new File(getClass().getResource("/negative-scenario/duplicity/augment0.yang").toURI()); - File yang2 = new File(getClass().getResource("/negative-scenario/duplicity/augment2.yang").toURI()); + final File yang1 = new File(getClass().getResource("/negative-scenario/duplicity/augment0.yang").toURI()); + final File yang2 = new File(getClass().getResource("/negative-scenario/duplicity/augment2.yang").toURI()); try (InputStream stream1 = new NamedFileInputStream(yang1, yang1.getPath()); InputStream stream2 = new NamedFileInputStream(yang2, yang2.getPath())) { TestUtils.loadModules(Arrays.asList(stream1, stream2)); @@ -230,27 +230,27 @@ public class YangParserNegativeTest { @Test public void testMandatoryInAugment() throws Exception { - File yang1 = new File(getClass().getResource("/negative-scenario/testfile8.yang").toURI()); - File yang2 = new File(getClass().getResource("/negative-scenario/testfile7.yang").toURI()); + final File yang1 = new File(getClass().getResource("/negative-scenario/testfile8.yang").toURI()); + final File yang2 = new File(getClass().getResource("/negative-scenario/testfile7.yang").toURI()); try (InputStream stream1 = new NamedFileInputStream(yang1, yang1.getPath()); InputStream stream2 = new NamedFileInputStream(yang2, yang2.getPath())) { TestUtils.loadModules(Arrays.asList(stream1, stream2)); testLog = output.toString(); assertTrue(testLog.contains( - "An augment cannot add node 'linkleaf' because it is mandatory and in module different from target")); + "An augment cannot add node 'linkleaf' because it is mandatory and in module different than target")); } } @Test public void testInvalidListKeyDefinition() throws Exception { - File yang1 = new File(getClass().getResource("/negative-scenario/invalid-list-key-def.yang").toURI()); + final File yang1 = new File(getClass().getResource("/negative-scenario/invalid-list-key-def.yang").toURI()); try { try (InputStream stream1 = new NamedFileInputStream(yang1, yang1.getPath())) { TestUtils.loadModule(stream1); fail("InferenceException should be thrown"); } - } catch (ReactorException e) { - String expected = "Key 'rib-id' misses node 'rib-id' in list '(invalid:list:key:def?revision=1970-01-01)" + + } catch (final ReactorException e) { + final String expected = "Key 'rib-id' misses node 'rib-id' in list '(invalid:list:key:def?revision=1970-01-01)" + "application-map'"; assertTrue(e.getCause().getMessage().startsWith(expected)); } diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test1/bar.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test1/bar.yang new file mode 100644 index 0000000000..5fea1b1d28 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test1/bar.yang @@ -0,0 +1,19 @@ +module bar { + namespace "bar"; + prefix bar; + + import foo { prefix foo; revision-date 2016-09-08; } + + revision 2016-09-08; + + augment /foo:root { + container bar { + container bar1 { + leaf m { + mandatory true; + type empty; + } + } + } + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test1/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test1/foo.yang new file mode 100644 index 0000000000..3c1f0310ef --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test1/foo.yang @@ -0,0 +1,9 @@ +module foo { + namespace "foo"; + prefix foo; + + revision 2016-09-08; + + container root { + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test2/bar.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test2/bar.yang new file mode 100644 index 0000000000..197ed30230 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test2/bar.yang @@ -0,0 +1,30 @@ +module bar { + namespace "bar"; + prefix bar; + + import foo { prefix foo; revision-date 2016-09-08; } + + revision 2016-09-08; + + augment /foo:root { + container bar { + } + } + + augment /foo:root/bar:bar { + container bar1 { + } + } + + augment /foo:root/bar:bar/bar:bar1 { + container bar2 { + } + } + + augment /foo:root/bar:bar/bar:bar1/bar:bar2 { + leaf m { + mandatory true; + type empty; + } + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test2/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test2/foo.yang new file mode 100644 index 0000000000..3c1f0310ef --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test2/foo.yang @@ -0,0 +1,9 @@ +module foo { + namespace "foo"; + prefix foo; + + revision 2016-09-08; + + container root { + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test3/bar.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test3/bar.yang new file mode 100644 index 0000000000..3bbc37104e --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test3/bar.yang @@ -0,0 +1,29 @@ +module bar { + namespace "bar"; + prefix bar; + + import foo { prefix foo; revision-date 2016-09-08; } + + revision 2016-09-08; + + augment /foo:root { + container bar { + } + } + + augment /foo:root/bar:bar { + container bar1 { + } + } + + augment /foo:root/bar:bar/bar:bar1 { + container bar2 { + } + } + + augment /foo:root/bar:bar/bar:bar1/bar:bar2 { + list l { + min-elements 1; + } + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test3/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test3/foo.yang new file mode 100644 index 0000000000..3c1f0310ef --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/invalid/test3/foo.yang @@ -0,0 +1,9 @@ +module foo { + namespace "foo"; + prefix foo; + + revision 2016-09-08; + + container root { + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test1/bar.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test1/bar.yang new file mode 100644 index 0000000000..1f9aa87d5d --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test1/bar.yang @@ -0,0 +1,20 @@ +module bar { + namespace "bar"; + prefix bar; + + import foo { prefix foo; revision-date 2016-09-08; } + + revision 2016-09-08; + + augment /foo:root { + container bar { + container bar1 { + presence "presence container"; + leaf m { + mandatory true; + type empty; + } + } + } + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test1/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test1/foo.yang new file mode 100644 index 0000000000..3c1f0310ef --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test1/foo.yang @@ -0,0 +1,9 @@ +module foo { + namespace "foo"; + prefix foo; + + revision 2016-09-08; + + container root { + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test2/bar.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test2/bar.yang new file mode 100644 index 0000000000..5a9cd60eb7 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test2/bar.yang @@ -0,0 +1,31 @@ +module bar { + namespace "bar"; + prefix bar; + + import foo { prefix foo; revision-date 2016-09-08; } + + revision 2016-09-08; + + augment /foo:root { + container bar { + } + } + + augment /foo:root/bar:bar { + container bar1 { + presence "presence container"; + } + } + + augment /foo:root/bar:bar/bar:bar1 { + container bar2 { + } + } + + augment /foo:root/bar:bar/bar:bar1/bar:bar2 { + leaf m { + mandatory true; + type empty; + } + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test2/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test2/foo.yang new file mode 100644 index 0000000000..3c1f0310ef --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test2/foo.yang @@ -0,0 +1,9 @@ +module foo { + namespace "foo"; + prefix foo; + + revision 2016-09-08; + + container root { + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test3/bar.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test3/bar.yang new file mode 100644 index 0000000000..52107deb1d --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test3/bar.yang @@ -0,0 +1,30 @@ +module bar { + namespace "bar"; + prefix bar; + + import foo { prefix foo; revision-date 2016-09-08; } + + revision 2016-09-08; + + augment /foo:root { + container bar { + } + } + + augment /foo:root/bar:bar { + container bar1 { + presence "presence container"; + } + } + + augment /foo:root/bar:bar/bar:bar1 { + container bar2 { + } + } + + augment /foo:root/bar:bar/bar:bar1/bar:bar2 { + list l { + min-elements 1; + } + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test3/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test3/foo.yang new file mode 100644 index 0000000000..3c1f0310ef --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug6669/valid/test3/foo.yang @@ -0,0 +1,9 @@ +module foo { + namespace "foo"; + prefix foo; + + revision 2016-09-08; + + container root { + } +} -- 2.36.6