Bug 6869: [Yang 1.1] Allow if-feature in bit, enum, refine & identity 42/49242/9
authorPeter Kajsa <pkajsa@cisco.com>
Mon, 12 Dec 2016 12:23:45 +0000 (13:23 +0100)
committerRobert Varga <nite@hq.sk>
Sat, 17 Dec 2016 13:23:56 +0000 (13:23 +0000)
Allow "if-feature" in "bit", "enum", "identity" and "refine"
statements. Presence of an "if-feature" statement in a "bit"
statement does not affect the automatically assigned position.

Change-Id: I487620bc08fc4f57c51172821087feaad04db5fe
Signed-off-by: Peter Kajsa <pkajsa@cisco.com>
14 files changed:
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/BitStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/EnumStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/IdentityStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/RefineStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/UsesStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/BitStatementRfc7950Support.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/EnumStatementRfc7950Support.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/IdentityStatementRfc7950Support.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/RefineStatementRfc7950Support.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/Bug6869Test.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/StmtTestUtils.java
yang/yang-parser-impl/src/test/resources/rfc7950/bug6869/foo.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6869/invalid10.yang [new file with mode: 0644]

index c062ff10b2789fba5a8bcdd72cea073c648b86e7..7bb4cfe544a3d5ccb26d61668f9889a2cfb42f2f 100644 (file)
@@ -7,12 +7,14 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
+import java.util.Collection;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.BitStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.PositionStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
@@ -81,6 +83,12 @@ public class BitStatementImpl extends AbstractDeclaredStatement<QName> implement
         return firstDeclared(DescriptionStatement.class);
     }
 
+    @Nonnull
+    @Override
+    public Collection<? extends IfFeatureStatement> getIfFeatures() {
+        return allDeclared(IfFeatureStatement.class);
+    }
+
     @Override
     public ReferenceStatement getReference() {
         return firstDeclared(ReferenceStatement.class);
index afa17be9b11ba6f6bf4fb29810610139c8a19a4b..74b0ee896ddc0577bccd756deab63152257bf370 100644 (file)
@@ -7,11 +7,13 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
+import java.util.Collection;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.EnumStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ValueStatement;
@@ -81,6 +83,12 @@ public class EnumStatementImpl extends AbstractDeclaredStatement<String> impleme
         return firstDeclared(DescriptionStatement.class);
     }
 
+    @Nonnull
+    @Override
+    public Collection<? extends IfFeatureStatement> getIfFeatures() {
+        return allDeclared(IfFeatureStatement.class);
+    }
+
     @Override
     public ReferenceStatement getReference() {
         return firstDeclared(ReferenceStatement.class);
index a4fa2a9e5acb0d3989633db88bf0263751ea2f5e..32373d8ee58614161b93a9b022e7f9bff05be75f 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
+import java.util.Collection;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
@@ -14,6 +15,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.BaseStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.IdentityStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
 import org.opendaylight.yangtools.yang.parser.spi.IdentityNamespace;
@@ -89,6 +91,12 @@ public class IdentityStatementImpl extends AbstractDeclaredStatement<QName>
         return firstDeclared(DescriptionStatement.class);
     }
 
+    @Nonnull
+    @Override
+    public Collection<? extends IfFeatureStatement> getIfFeatures() {
+        return allDeclared(IfFeatureStatement.class);
+    }
+
     @Override
     public ReferenceStatement getReference() {
         return firstDeclared(ReferenceStatement.class);
index 5da200a7e5b834721d9232bfe35bd66d42173f83..3bd6ada915c3bbc4899c9f74315e857a1eb3a516 100644 (file)
@@ -8,10 +8,13 @@
 
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
+import java.util.Collection;
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
@@ -86,6 +89,12 @@ public class RefineStatementImpl extends AbstractDeclaredStatement<SchemaNodeIde
         return firstDeclared(DescriptionStatement.class);
     }
 
+    @Nonnull
+    @Override
+    public Collection<? extends IfFeatureStatement> getIfFeatures() {
+        return allDeclared(IfFeatureStatement.class);
+    }
+
     @Nullable
     @Override
     public ReferenceStatement getReference() {
index 61860be3d3e0aa2fca750f41428d23e8b5cfdc95..e97a9771beffaf6eac04478a8d89e00eba4499fb 100644 (file)
@@ -15,6 +15,7 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
@@ -267,12 +268,21 @@ public class UsesStatementImpl extends AbstractDeclaredStatement<QName> implemen
             final Mutable<QName, UsesStatement, EffectiveStatement<QName, UsesStatement>> usesNode,
             final StatementContextBase<?, ?, ?> targetNodeStmtCtx) {
         for (final StatementContextBase<?, ?, ?> subStmtCtx : usesNode.declaredSubstatements()) {
-            if (StmtContextUtils.producesDeclared(subStmtCtx, RefineStatement.class)) {
+            if (StmtContextUtils.producesDeclared(subStmtCtx, RefineStatement.class)
+                    && areFeaturesSupported(subStmtCtx)) {
                 performRefine(subStmtCtx, targetNodeStmtCtx);
             }
         }
     }
 
+    private static boolean areFeaturesSupported(final StatementContextBase<?, ?, ?> subStmtCtx) {
+        /*
+         * In case of Yang 1.1, checks whether features are supported.
+         */
+        return !YangVersion.VERSION_1_1.equals(subStmtCtx.getRootVersion()) || StmtContextUtils
+                .areFeaturesSupported(subStmtCtx);
+    }
+
     private static void performRefine(final StatementContextBase<?, ?, ?> refineCtx,
             final StatementContextBase<?, ?, ?> usesParentCtx) {
 
index cf844977fa6267defd94e1a824511d72dfe6fc49..4b746b2376912a498637b5410180929f6d488fb1 100644 (file)
@@ -63,10 +63,13 @@ import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementR
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ActionStatementImpl;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.AnydataStatementImpl;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.AugmentStatementRfc7950Support;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.BitStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.CaseStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ChoiceStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ContainerStatementRfc7950Support;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.EnumStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.GroupingStatementRfc7950Support;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.IdentityStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ImportStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.IncludeStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.InputStatementRfc7950Support;
@@ -74,6 +77,7 @@ import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ListStatementRfc7950S
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ModuleStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.NotificationStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.OutputStatementRfc7950Support;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.RefineStatementRfc7950Support;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.SubmoduleStatementRfc7950Support;
 
 public final class YangInferencePipeline {
@@ -147,16 +151,19 @@ public final class YangInferencePipeline {
             .addSupport(global(ExtensionNamespace.class))
             .addSupport(new TypedefStatementImpl.Definition())
             .addSupport(treeScoped(TypeNamespace.class))
-            .addSupport(new IdentityStatementImpl.Definition())
+            .addVersionSpecificSupport(VERSION_1, new IdentityStatementImpl.Definition())
+            .addVersionSpecificSupport(VERSION_1_1, new IdentityStatementRfc7950Support())
             .addSupport(global(IdentityNamespace.class))
             .addSupport(new DefaultStatementImpl.Definition())
             .addSupport(new StatusStatementImpl.Definition())
             .addSupport(new TypeStatementImpl.Definition())
             .addSupport(new UnitsStatementImpl.Definition())
             .addSupport(new RequireInstanceStatementImpl.Definition())
-            .addSupport(new BitStatementImpl.Definition())
+            .addVersionSpecificSupport(VERSION_1, new BitStatementImpl.Definition())
+            .addVersionSpecificSupport(VERSION_1_1, new BitStatementRfc7950Support())
             .addSupport(new PathStatementImpl.Definition())
-            .addSupport(new EnumStatementImpl.Definition())
+            .addVersionSpecificSupport(VERSION_1, new EnumStatementImpl.Definition())
+            .addVersionSpecificSupport(VERSION_1_1, new EnumStatementRfc7950Support())
             .addSupport(new LengthStatementImpl.Definition())
             .addSupport(new PatternStatementImpl.Definition())
             .addSupport(new RangeStatementImpl.Definition())
@@ -210,7 +217,8 @@ public final class YangInferencePipeline {
             .addVersionSpecificSupport(VERSION_1, new AugmentStatementImpl.Definition())
             .addVersionSpecificSupport(VERSION_1_1, new AugmentStatementRfc7950Support())
             .addSupport(treeScoped(AugmentToChoiceNamespace.class))
-            .addSupport(new RefineStatementImpl.Definition())
+            .addVersionSpecificSupport(VERSION_1, new RefineStatementImpl.Definition())
+            .addVersionSpecificSupport(VERSION_1_1, new RefineStatementRfc7950Support())
             .addSupport(new FeatureStatementImpl.Definition())
             .addSupport(new PositionStatementImpl.Definition())
             .addSupport(new ValueStatementImpl.Definition())
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/BitStatementRfc7950Support.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/BitStatementRfc7950Support.java
new file mode 100644 (file)
index 0000000..2ec80d0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.parser.stmt.rfc7950;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.BitStatementImpl;
+
+/**
+ * Class providing necessary support for processing YANG 1.1 Bit statement.
+ */
+@Beta
+public final class BitStatementRfc7950Support extends BitStatementImpl.Definition {
+    private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
+            .BIT)
+            .addOptional(YangStmtMapping.DESCRIPTION)
+            .addAny(YangStmtMapping.IF_FEATURE)
+            .addOptional(YangStmtMapping.REFERENCE)
+            .addOptional(YangStmtMapping.STATUS)
+            .addOptional(YangStmtMapping.POSITION)
+            .build();
+
+    @Override
+    protected SubstatementValidator getSubstatementValidator() {
+        return SUBSTATEMENT_VALIDATOR;
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/EnumStatementRfc7950Support.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/EnumStatementRfc7950Support.java
new file mode 100644 (file)
index 0000000..a3dddbd
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.parser.stmt.rfc7950;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.EnumStatementImpl;
+
+/**
+ * Class providing necessary support for processing YANG 1.1 Enum statement.
+ */
+@Beta
+public final class EnumStatementRfc7950Support extends EnumStatementImpl.Definition {
+    private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
+            .ENUM)
+            .addOptional(YangStmtMapping.DESCRIPTION)
+            .addAny(YangStmtMapping.IF_FEATURE)
+            .addOptional(YangStmtMapping.REFERENCE)
+            .addOptional(YangStmtMapping.STATUS)
+            .addOptional(YangStmtMapping.VALUE)
+            .build();
+
+    @Override
+    protected SubstatementValidator getSubstatementValidator() {
+        return SUBSTATEMENT_VALIDATOR;
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/IdentityStatementRfc7950Support.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/IdentityStatementRfc7950Support.java
new file mode 100644 (file)
index 0000000..f711464
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.parser.stmt.rfc7950;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.IdentityStatementImpl;
+
+/**
+ * Class providing necessary support for processing YANG 1.1 Identity statement.
+ */
+@Beta
+public final class IdentityStatementRfc7950Support extends IdentityStatementImpl.Definition {
+    private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
+            .IDENTITY)
+            .addOptional(YangStmtMapping.BASE)
+            .addOptional(YangStmtMapping.DESCRIPTION)
+            .addAny(YangStmtMapping.IF_FEATURE)
+            .addOptional(YangStmtMapping.REFERENCE)
+            .addOptional(YangStmtMapping.STATUS)
+            .build();
+
+    @Override
+    protected SubstatementValidator getSubstatementValidator() {
+        return SUBSTATEMENT_VALIDATOR;
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/RefineStatementRfc7950Support.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/RefineStatementRfc7950Support.java
new file mode 100644 (file)
index 0000000..f242416
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.parser.stmt.rfc7950;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.RefineStatementImpl;
+
+/**
+ * Class providing necessary support for processing YANG 1.1 Refine statement.
+ */
+@Beta
+public final class RefineStatementRfc7950Support extends RefineStatementImpl.Definition {
+    private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
+            .REFINE)
+            .addOptional(YangStmtMapping.DEFAULT)
+            .addOptional(YangStmtMapping.DESCRIPTION)
+            .addOptional(YangStmtMapping.REFERENCE)
+            .addOptional(YangStmtMapping.CONFIG)
+            .addAny(YangStmtMapping.IF_FEATURE)
+            .addOptional(YangStmtMapping.MANDATORY)
+            .addOptional(YangStmtMapping.PRESENCE)
+            .addAny(YangStmtMapping.MUST)
+            .addOptional(YangStmtMapping.MIN_ELEMENTS)
+            .addOptional(YangStmtMapping.MAX_ELEMENTS)
+            .build();
+
+    @Override
+    protected SubstatementValidator getSubstatementValidator() {
+        return SUBSTATEMENT_VALIDATOR;
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/Bug6869Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/Bug6869Test.java
new file mode 100644 (file)
index 0000000..5228b79
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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.parser.stmt.rfc7950;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+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.meta.SomeModifiersUnresolvedException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.stmt.StmtTestUtils;
+
+public class Bug6869Test {
+    private static final String FOO_NS = "foo";
+    private static final String FOO_REV = "1970-01-01";
+
+    @Test
+    public void identityNoFeaureTest() throws ReactorException, SourceException, FileNotFoundException,
+            URISyntaxException {
+        final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6869/foo.yang",
+                createIfFeaturesPredicate("no-feature"));
+        assertNotNull(schemaContext);
+
+        final Set<IdentitySchemaNode> identities = getIdentities(schemaContext);
+        assertEquals(0, identities.size());
+
+        final SchemaNode findNode = findNode(schemaContext, ImmutableList.of("root", "grp-leaf"));
+        assertTrue(findNode instanceof LeafSchemaNode);
+        final LeafSchemaNode grpLeaf = (LeafSchemaNode) findNode;
+        assertFalse(grpLeaf.getConstraints().isMandatory());
+    }
+
+    @Test
+    public void identityAllFeauresTest() throws ReactorException, SourceException, FileNotFoundException,
+            URISyntaxException {
+        final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6869/foo.yang",
+                createIfFeaturesPredicate("identity-feature", "mandatory-leaf", "tls", "ssh", "two", "three"));
+        assertNotNull(schemaContext);
+
+        final Set<IdentitySchemaNode> identities = getIdentities(schemaContext);
+        assertEquals(1, identities.size());
+
+        final SchemaNode findNode = findNode(schemaContext, ImmutableList.of("root", "grp-leaf"));
+        assertTrue(findNode instanceof LeafSchemaNode);
+        final LeafSchemaNode grpLeaf = (LeafSchemaNode) findNode;
+        assertTrue(grpLeaf.getConstraints().isMandatory());
+    }
+
+    private static Set<IdentitySchemaNode> getIdentities(final SchemaContext schemaContext) {
+        final Set<Module> modules = schemaContext.getModules();
+        assertEquals(1, modules.size());
+        final Module module = modules.iterator().next();
+        return module.getIdentities();
+    }
+
+    private static Predicate<QName> createIfFeaturesPredicate(final String... featureNames) {
+        final Predicate<QName> ifFeaturesPredicate = qName -> {
+            final Set<QName> supportedFeatures = new HashSet<>();
+            for (final String featureName : featureNames) {
+                supportedFeatures.add(QName.create(FOO_NS, FOO_REV, featureName));
+            }
+            return supportedFeatures.contains(qName);
+        };
+        return ifFeaturesPredicate;
+    }
+
+    private static SchemaNode findNode(final SchemaContext context, final Iterable<String> localNamesPath) {
+        final Iterable<QName> qNames = Iterables.transform(localNamesPath,
+                localName -> QName.create(FOO_NS, FOO_REV, localName));
+        return SchemaContextUtil.findDataSchemaNode(context, SchemaPath.create(qNames, true));
+    }
+
+    @Test
+    public void invalidYang10Test() throws ReactorException, SourceException, FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6869/invalid10.yang");
+            fail("Test should fail due to invalid Yang 1.0");
+        } catch (final SomeModifiersUnresolvedException e) {
+            assertTrue(e.getCause().getMessage().startsWith("IF_FEATURE is not valid for IDENTITY"));
+        }
+    }
+}
\ No newline at end of file
index e6336f273b31e682bd4119f82315136a95944a53..a3435cabc5203c3d1b1cbf55dd8906ac4dbae51b 100644 (file)
@@ -17,11 +17,14 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Predicate;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.IfFeaturePredicates;
 import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
@@ -98,13 +101,13 @@ public class StmtTestUtils {
 
     public static SchemaContext parseYangSources(final StatementStreamSource... sources) throws SourceException,
             ReactorException {
-        return parseYangSources(StatementParserMode.DEFAULT_MODE, sources);
+        return parseYangSources(StatementParserMode.DEFAULT_MODE, IfFeaturePredicates.ALL_FEATURES, sources);
     }
 
-    public static SchemaContext parseYangSources(final StatementParserMode statementParserMode, final StatementStreamSource... sources)
+    public static SchemaContext parseYangSources(final StatementParserMode statementParserMode, final Predicate<QName> ifFeaturePredicate, final StatementStreamSource... sources)
             throws SourceException, ReactorException {
 
-        final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(statementParserMode);
+        final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(statementParserMode, ifFeaturePredicate);
         reactor.addSources(sources);
 
         return reactor.buildEffective();
@@ -112,10 +115,10 @@ public class StmtTestUtils {
 
     public static SchemaContext parseYangSources(final File... files) throws SourceException, ReactorException,
             FileNotFoundException {
-        return parseYangSources(StatementParserMode.DEFAULT_MODE, files);
+        return parseYangSources(StatementParserMode.DEFAULT_MODE, IfFeaturePredicates.ALL_FEATURES, files);
     }
 
-    public static SchemaContext parseYangSources(final StatementParserMode statementParserMode, final File... files) throws SourceException,
+    public static SchemaContext parseYangSources(final StatementParserMode statementParserMode, final Predicate<QName> ifFeaturePredicate, final File... files) throws SourceException,
             ReactorException, FileNotFoundException {
 
         final StatementStreamSource[] sources = new StatementStreamSource[files.length];
@@ -124,7 +127,7 @@ public class StmtTestUtils {
             sources[i] = new YangStatementSourceImpl(new NamedFileInputStream(files[i], files[i].getPath()));
         }
 
-        return parseYangSources(statementParserMode, sources);
+        return parseYangSources(statementParserMode, ifFeaturePredicate, sources);
     }
 
     public static SchemaContext parseYangSources(final Collection<File> files) throws SourceException, ReactorException,
@@ -134,7 +137,7 @@ public class StmtTestUtils {
 
     public static SchemaContext parseYangSources(final Collection<File> files, final StatementParserMode statementParserMode)
             throws SourceException, ReactorException, FileNotFoundException {
-        return parseYangSources(statementParserMode, files.toArray(new File[files.size()]));
+        return parseYangSources(statementParserMode, IfFeaturePredicates.ALL_FEATURES, files.toArray(new File[files.size()]));
     }
 
     public static SchemaContext parseYangSources(final String yangSourcesDirectoryPath) throws SourceException,
@@ -144,14 +147,20 @@ public class StmtTestUtils {
 
     public static SchemaContext parseYangSource(final String yangSourcePath) throws SourceException, ReactorException,
             FileNotFoundException, URISyntaxException {
-        return parseYangSource(yangSourcePath, StatementParserMode.DEFAULT_MODE);
+        return parseYangSource(yangSourcePath, StatementParserMode.DEFAULT_MODE, IfFeaturePredicates.ALL_FEATURES);
+    }
+
+    public static SchemaContext parseYangSource(final String yangSourcePath, final Predicate<QName> ifFeaturesPredicate)
+            throws SourceException, FileNotFoundException, ReactorException, URISyntaxException {
+        return parseYangSource(yangSourcePath, StatementParserMode.DEFAULT_MODE, ifFeaturesPredicate);
     }
 
-    public static SchemaContext parseYangSource(final String yangSourcePath, final StatementParserMode statementParserMode)
+    public static SchemaContext parseYangSource(final String yangSourcePath,
+            final StatementParserMode statementParserMode, final Predicate<QName> ifFeaturePredicate)
             throws SourceException, ReactorException, FileNotFoundException, URISyntaxException {
         final URL source = StmtTestUtils.class.getResource(yangSourcePath);
         final File sourceFile = new File(source.toURI());
-        return parseYangSources(statementParserMode, sourceFile);
+        return parseYangSources(statementParserMode, ifFeaturePredicate, sourceFile);
     }
 
     public static SchemaContext parseYangSources(final String yangSourcesDirectoryPath, final StatementParserMode statementParserMode)
@@ -160,7 +169,7 @@ public class StmtTestUtils {
         final URL resourceDir = StmtTestUtils.class.getResource(yangSourcesDirectoryPath);
         final File testSourcesDir = new File(resourceDir.toURI());
 
-        return parseYangSources(statementParserMode, testSourcesDir.listFiles(YANG_FILE_FILTER));
+        return parseYangSources(statementParserMode, IfFeaturePredicates.ALL_FEATURES, testSourcesDir.listFiles(YANG_FILE_FILTER));
     }
 
     public static SchemaContext parseYinSources(final String yinSourcesDirectoryPath, final StatementParserMode statementParserMode)
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6869/foo.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6869/foo.yang
new file mode 100644 (file)
index 0000000..b1b4b5b
--- /dev/null
@@ -0,0 +1,48 @@
+module foo {
+    namespace "foo";
+    prefix foo;
+    yang-version 1.1;
+
+    identity my-identity {
+        if-feature identity-feature;
+    }
+
+    container root {
+        uses grp {
+            refine grp-leaf {
+                if-feature mandatory-leaf;
+                mandatory true;
+            }
+        }
+    }
+
+    grouping grp {
+        leaf grp-leaf {
+            type empty;
+        }
+    }
+
+    typedef my-enum {
+        type enumeration {
+            enum tcp;
+            enum ssh {
+                if-feature ssh;
+            }
+            enum tls {
+                if-feature tls;
+            }
+        }
+    }
+
+    typedef my-bits {
+        type bits {
+            bit one;
+            bit two {
+                if-feature two;
+            }
+            bit three {
+                if-feature three;
+            }
+        }
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6869/invalid10.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6869/invalid10.yang
new file mode 100644 (file)
index 0000000..026e9e3
--- /dev/null
@@ -0,0 +1,8 @@
+module foo {
+    namespace "foo";
+    prefix foo;
+
+    identity foo {
+        if-feature foo-identity;
+    }
+}