Bug 6887: [Yang 1.1] Allow enumerations and bits to be subtyped 53/51453/8
authorIgor Foltin <ifoltin@cisco.com>
Mon, 6 Feb 2017 07:40:48 +0000 (08:40 +0100)
committerRobert Varga <nite@hq.sk>
Thu, 23 Feb 2017 09:47:10 +0000 (09:47 +0000)
Starting with YANG 1.1, enumeration and bits types
can be restricted

An enumeration type can be restricted with one or more
"enum" statements, which enumerate a subset of the values
for the base type.

A bits type can be restricted with one or more "bit"
statements, which enumerate a subset of the values for
the base type.

Change-Id: If46991b858a2a9153a60de85645f6ec301fcb33f
Signed-off-by: Igor Foltin <ifoltin@cisco.com>
24 files changed:
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/BitsTypeBuilder.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/EnumerationTypeBuilder.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RestrictedBitsType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RestrictedEnumerationType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RestrictedTypes.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/BitsTypeEffectiveStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/EnumTypeEffectiveStatementImpl.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/Bug6887Test.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-2.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-3.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-4.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-invalid-2.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-invalid.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-valid.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-2.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-3.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-4.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-invalid-2.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-invalid.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-valid.yang [new file with mode: 0644]

index 082b182709a42a33713f1c8cc9532f4d21c098ba..362f2b8681cfa47d6e8e87a0fd8cde7073aa4a1c 100644 (file)
@@ -16,20 +16,50 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
 
-public final class BitsTypeBuilder extends TypeBuilder<BitsTypeDefinition> {
+public final class BitsTypeBuilder extends AbstractRestrictedTypeBuilder<BitsTypeDefinition> {
     private final Builder<String, Bit> builder = ImmutableMap.builder();
 
     BitsTypeBuilder(final SchemaPath path) {
         super(null, path);
     }
 
+    BitsTypeBuilder(final BitsTypeDefinition baseType, final SchemaPath path) {
+        super(baseType, path);
+    }
+
     public BitsTypeBuilder addBit(@Nonnull final Bit item) {
+        // in case we are dealing with a restricted bits type, validate if the bit is a subset of its base type
+        if (getBaseType() != null) {
+            validateRestrictedBit(item);
+        }
+
         builder.put(item.getName(), item);
+        touch();
         return this;
     }
 
+    private void validateRestrictedBit(@Nonnull final Bit item) {
+        boolean isASubsetOfBaseBits = false;
+        for (Bit baseTypeBit : getBaseType().getBits()) {
+            if (item.getName().equals(baseTypeBit.getName())) {
+                if (item.getPosition() != baseTypeBit.getPosition()) {
+                    throw new InvalidBitDefinitionException(item, "Position of bit '%s' must be the same as the " +
+                            "position of corresponding bit in the base bits type %s.", item.getName(),
+                            getBaseType().getQName());
+                }
+                isASubsetOfBaseBits = true;
+                break;
+            }
+        }
+
+        if (!isASubsetOfBaseBits) {
+            throw new InvalidBitDefinitionException(item, "Bit '%s' is not a subset of its base bits type %s.",
+                    item.getName(), getBaseType().getQName());
+        }
+    }
+
     @Override
-    public BitsTypeDefinition build() {
+    public BitsTypeDefinition buildType() {
         final Map<String, Bit> map = builder.build();
         final Map<Long, Bit> positionMap = new TreeMap<>();
 
@@ -40,6 +70,10 @@ public final class BitsTypeBuilder extends TypeBuilder<BitsTypeDefinition> {
             }
         }
 
-        return new BaseBitsType(getPath(), getUnknownSchemaNodes(), positionMap.values());
+        if (getBaseType() == null) {
+            return new BaseBitsType(getPath(), getUnknownSchemaNodes(), positionMap.values());
+        } else {
+            return new RestrictedBitsType(getBaseType(), getPath(), getUnknownSchemaNodes(), positionMap.values());
+        }
     }
 }
index fa272b84f4ba299a4942fac1155246093f356a1b..c0d368ed23617a967071d78ed257566fd7cadbce 100644 (file)
@@ -16,20 +16,50 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
 
-public final class EnumerationTypeBuilder extends TypeBuilder<EnumTypeDefinition> {
+public final class EnumerationTypeBuilder extends AbstractRestrictedTypeBuilder<EnumTypeDefinition> {
     private final Builder<String, EnumPair> builder = ImmutableMap.builder();
 
     EnumerationTypeBuilder(final SchemaPath path) {
         super(null, path);
     }
 
+    EnumerationTypeBuilder(final EnumTypeDefinition baseType, final SchemaPath path) {
+        super(baseType, path);
+    }
+
     public EnumerationTypeBuilder addEnum(@Nonnull final EnumPair item) {
+        // in case we are dealing with a restricted enumeration type, validate if the enum is a subset of its base type
+        if (getBaseType() != null) {
+            validateRestrictedEnum(item);
+        }
+
         builder.put(item.getName(), item);
+        touch();
         return this;
     }
 
+    private void validateRestrictedEnum(@Nonnull final EnumPair item) {
+        boolean isASubsetOfBaseEnums = false;
+        for (EnumPair baseTypeEnumPair : getBaseType().getValues()) {
+            if (item.getName().equals(baseTypeEnumPair.getName())) {
+                if (item.getValue() != baseTypeEnumPair.getValue()) {
+                    throw new InvalidEnumDefinitionException(item, "Value of enum '%s' must be the same as the value" +
+                            " of corresponding enum in the base enumeration type %s.", item.getName(),
+                            getBaseType().getQName());
+                }
+                isASubsetOfBaseEnums = true;
+                break;
+            }
+        }
+
+        if (!isASubsetOfBaseEnums) {
+            throw new InvalidEnumDefinitionException(item, "Enum '%s' is not a subset of its base enumeration type %s.",
+                    item.getName(), getBaseType().getQName());
+        }
+    }
+
     @Override
-    public EnumTypeDefinition build() {
+    public EnumTypeDefinition buildType() {
         final Map<String, EnumPair> map = builder.build();
         final Map<Integer, EnumPair> positionMap = new HashMap<>();
 
@@ -40,6 +70,10 @@ public final class EnumerationTypeBuilder extends TypeBuilder<EnumTypeDefinition
             }
         }
 
-        return new BaseEnumerationType(getPath(), getUnknownSchemaNodes(), map.values());
+        if (getBaseType() == null) {
+            return new BaseEnumerationType(getPath(), getUnknownSchemaNodes(), map.values());
+        } else {
+            return new RestrictedEnumerationType(getBaseType(), getPath(), getUnknownSchemaNodes(), map.values());
+        }
     }
 }
index e24dc3f7f717e11e39db0cd84a1e3729ad684ca9..b8e85427df43032e50621b22571da4962836da48 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.util.type;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 import java.util.List;
 import javax.annotation.Nonnull;
@@ -15,15 +17,18 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 
 final class RestrictedBitsType extends AbstractRestrictedType<BitsTypeDefinition> implements BitsTypeDefinition {
+    private final List<Bit> bits;
+
     RestrictedBitsType(final BitsTypeDefinition baseType, final SchemaPath path,
-            final Collection<UnknownSchemaNode> unknownSchemaNodes) {
+            final Collection<UnknownSchemaNode> unknownSchemaNodes, final Collection<Bit> bits) {
         super(baseType, path, unknownSchemaNodes);
+        this.bits = ImmutableList.copyOf(Preconditions.checkNotNull(bits));
     }
 
     @Nonnull
     @Override
     public List<Bit> getBits() {
-        return getBaseType().getBits();
+        return bits;
     }
 
     @Override
index e86d3fe3a0745026c53a56cdd99282b871a79555..eeb4e083fe4a1ed31c91e07d91e85cbd9708120d 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.util.type;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 import java.util.List;
 import javax.annotation.Nonnull;
@@ -15,15 +17,18 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
 
 final class RestrictedEnumerationType extends AbstractRestrictedType<EnumTypeDefinition> implements EnumTypeDefinition {
+    private final List<EnumPair> values;
+
     RestrictedEnumerationType(final EnumTypeDefinition baseType, final SchemaPath path,
-            final Collection<UnknownSchemaNode> unknownSchemaNodes) {
+            final Collection<UnknownSchemaNode> unknownSchemaNodes, final Collection<EnumPair> values) {
         super(baseType, path, unknownSchemaNodes);
+        this.values = ImmutableList.copyOf(Preconditions.checkNotNull(values));
     }
 
     @Nonnull
     @Override
     public List<EnumPair> getValues() {
-        return getBaseType().getValues();
+        return values;
     }
 
     @Override
index fe31615fcbf5fb04d42695701391fefe831c7ef7..3e3200e465412528bb0297e5f0d6e6078bc690fe 100644 (file)
@@ -85,13 +85,8 @@ public final class RestrictedTypes {
         };
     }
 
-    public static TypeBuilder<BitsTypeDefinition> newBitsBuilder(final BitsTypeDefinition baseType, final SchemaPath path) {
-        return new AbstractRestrictedTypeBuilder<BitsTypeDefinition>(baseType, path) {
-            @Override
-            BitsTypeDefinition buildType() {
-                return new RestrictedBitsType(getBaseType(), getPath(), getUnknownSchemaNodes());
-            }
-        };
+    public static BitsTypeBuilder newBitsBuilder(final BitsTypeDefinition baseType, final SchemaPath path) {
+        return new BitsTypeBuilder(baseType, path);
     }
 
     public static TypeBuilder<BooleanTypeDefinition> newBooleanBuilder(@Nonnull final BooleanTypeDefinition baseType, @Nonnull final SchemaPath path) {
@@ -122,13 +117,8 @@ public final class RestrictedTypes {
         };
     }
 
-    public static TypeBuilder<EnumTypeDefinition> newEnumerationBuilder(final EnumTypeDefinition baseType, final SchemaPath path) {
-        return new AbstractRestrictedTypeBuilder<EnumTypeDefinition>(baseType, path) {
-            @Override
-            EnumTypeDefinition buildType() {
-                return new RestrictedEnumerationType(getBaseType(), getPath(), getUnknownSchemaNodes());
-            }
-        };
+    public static EnumerationTypeBuilder newEnumerationBuilder(final EnumTypeDefinition baseType, final SchemaPath path) {
+        return new EnumerationTypeBuilder(baseType, path);
     }
 
     public static TypeBuilder<IdentityrefTypeDefinition> newIdentityrefBuilder(final IdentityrefTypeDefinition baseType, final SchemaPath path) {
index a7fc6ec81fb37aea52ef6d8d764a6570798878b3..6d775b12c99360e62ebbd0b58a9a5ec12255c5b2 100644 (file)
@@ -8,17 +8,76 @@
 
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type;
 
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
+import org.opendaylight.yangtools.yang.model.util.type.BitBuilder;
+import org.opendaylight.yangtools.yang.model.util.type.BitsTypeBuilder;
 import org.opendaylight.yangtools.yang.model.util.type.RestrictedTypes;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.UnknownEffectiveStatementImpl;
+
+public final class BitsTypeEffectiveStatementImpl extends DeclaredEffectiveStatementBase<String, TypeStatement>
+        implements TypeEffectiveStatement<TypeStatement> {
+
+    private final BitsTypeDefinition typeDefinition;
 
-public final class BitsTypeEffectiveStatementImpl extends AbstractTypeEffectiveStatement<BitsTypeDefinition> {
     public BitsTypeEffectiveStatementImpl(
             final StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx,
             final BitsTypeDefinition baseType) {
-        super(ctx, RestrictedTypes.newBitsBuilder(baseType, TypeUtils.typeEffectiveSchemaPath(ctx)));
+        super(ctx);
+
+        final BitsTypeBuilder builder = RestrictedTypes.newBitsBuilder(baseType, ctx.getSchemaPath().get());
+
+        final YangVersion yangVersion = ctx.getRootVersion();
+        for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
+            if (stmt instanceof BitEffectiveStatementImpl) {
+                SourceException.throwIf(yangVersion != YangVersion.VERSION_1_1, ctx.getStatementSourceReference(),
+                        "Restricted bits type is allowed only in YANG 1.1 version.");
+                final BitEffectiveStatementImpl bitSubStmt = (BitEffectiveStatementImpl) stmt;
+
+                final long effectivePos;
+                if (bitSubStmt.getDeclaredPosition() == null) {
+                    effectivePos = getBaseTypeBitPosition(bitSubStmt.getName(), baseType, ctx);
+                } else {
+                    effectivePos = bitSubStmt.getDeclaredPosition();
+                }
+
+                final Bit b = BitBuilder.create(bitSubStmt.getPath(), effectivePos)
+                        .setDescription(bitSubStmt.getDescription()).setReference(bitSubStmt.getReference())
+                        .setStatus(bitSubStmt.getStatus()).setUnknownSchemaNodes(bitSubStmt.getUnknownSchemaNodes())
+                        .build();
+
+                builder.addBit(b);
+            } else if (stmt instanceof UnknownEffectiveStatementImpl) {
+                builder.addUnknownSchemaNode((UnknownEffectiveStatementImpl) stmt);
+            }
+        }
+
+        typeDefinition = builder.build();
+    }
+
+    private static long getBaseTypeBitPosition(final String bitName, final BitsTypeDefinition baseType,
+            final StmtContext<?, ?, ?> ctx) {
+        for (Bit baseTypeBit : baseType.getBits()) {
+            if (bitName.equals(baseTypeBit.getName())) {
+                return baseTypeBit.getPosition();
+            }
+        }
+
+        throw new SourceException(ctx.getStatementSourceReference(),
+                "Bit '%s' is not a subset of its base bits type %s.", bitName, baseType.getQName());
+    }
+
+    @Nonnull
+    @Override
+    public BitsTypeDefinition getTypeDefinition() {
+        return typeDefinition;
     }
 }
index e5f53ef9b571444b566dbad6ec702caa6dbabb1a..9408310214a6f169faca9a9e80fbe7a5a1d90e0f 100644 (file)
@@ -8,17 +8,78 @@
 
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type;
 
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.yangtools.yang.model.util.type.EnumPairBuilder;
+import org.opendaylight.yangtools.yang.model.util.type.EnumerationTypeBuilder;
 import org.opendaylight.yangtools.yang.model.util.type.RestrictedTypes;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.UnknownEffectiveStatementImpl;
+
+public final class EnumTypeEffectiveStatementImpl extends DeclaredEffectiveStatementBase<String, TypeStatement>
+        implements TypeEffectiveStatement<TypeStatement> {
+
+    private final EnumTypeDefinition typeDefinition;
 
-public final class EnumTypeEffectiveStatementImpl extends AbstractTypeEffectiveStatement<EnumTypeDefinition> {
     public EnumTypeEffectiveStatementImpl(
             final StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx,
             final EnumTypeDefinition baseType) {
-        super(ctx, RestrictedTypes.newEnumerationBuilder(baseType, TypeUtils.typeEffectiveSchemaPath(ctx)));
+        super(ctx);
+
+        final EnumerationTypeBuilder builder = RestrictedTypes.newEnumerationBuilder(baseType,
+                ctx.getSchemaPath().get());
+
+        final YangVersion yangVersion = ctx.getRootVersion();
+        for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
+            if (stmt instanceof EnumEffectiveStatementImpl) {
+                SourceException.throwIf(yangVersion != YangVersion.VERSION_1_1, ctx.getStatementSourceReference(),
+                        "Restricted enumeration type is allowed only in YANG 1.1 version.");
+
+                final EnumEffectiveStatementImpl enumSubStmt = (EnumEffectiveStatementImpl) stmt;
+
+                final int effectiveValue;
+                if (enumSubStmt.getDeclaredValue() == null) {
+                    effectiveValue = getBaseTypeEnumValue(enumSubStmt.getName(), baseType, ctx);
+                } else {
+                    effectiveValue = enumSubStmt.getDeclaredValue();
+                }
+
+                final EnumPair p = EnumPairBuilder.create(enumSubStmt.getName(), effectiveValue)
+                        .setDescription(enumSubStmt.getDescription()).setReference(enumSubStmt.getReference())
+                        .setStatus(enumSubStmt.getStatus()).setUnknownSchemaNodes(enumSubStmt.getUnknownSchemaNodes())
+                        .build();
+
+                builder.addEnum(p);
+            } else if (stmt instanceof UnknownEffectiveStatementImpl) {
+                builder.addUnknownSchemaNode((UnknownEffectiveStatementImpl) stmt);
+            }
+        }
+
+        typeDefinition = builder.build();
+    }
+
+    private static int getBaseTypeEnumValue(final String enumName, final EnumTypeDefinition baseType,
+            final StmtContext<?, ?, ?> ctx) {
+        for (EnumPair baseTypeEnumPair : baseType.getValues()) {
+            if (enumName.equals(baseTypeEnumPair.getName())) {
+                return baseTypeEnumPair.getValue();
+            }
+        }
+
+        throw new SourceException(ctx.getStatementSourceReference(),
+                "Enum '%s' is not a subset of its base enumeration type %s.", enumName, baseType.getQName());
+    }
+
+    @Nonnull
+    @Override
+    public EnumTypeDefinition getTypeDefinition() {
+        return typeDefinition;
     }
 }
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/Bug6887Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/Bug6887Test.java
new file mode 100644 (file)
index 0000000..c19277e
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2017 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.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.text.ParseException;
+import java.util.Date;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+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.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.yangtools.yang.model.util.type.BitBuilder;
+import org.opendaylight.yangtools.yang.model.util.type.EnumPairBuilder;
+import org.opendaylight.yangtools.yang.model.util.type.InvalidBitDefinitionException;
+import org.opendaylight.yangtools.yang.model.util.type.InvalidEnumDefinitionException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.stmt.StmtTestUtils;
+
+public class Bug6887Test {
+
+    @Test
+    public void testRestrictedEnumeration() throws ReactorException, FileNotFoundException, URISyntaxException,
+            ParseException {
+        final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo.yang");
+        assertNotNull(schemaContext);
+
+        final Date revision = SimpleDateFormatUtil.getRevisionFormat().parse("2017-01-26");
+
+        final Module foo = schemaContext.findModuleByName("foo", revision);
+        assertNotNull(foo);
+
+        final LeafSchemaNode myEnumerationLeaf = (LeafSchemaNode) foo.getDataChildByName(
+                QName.create(foo.getQNameModule(), "my-enumeration-leaf"));
+        assertNotNull(myEnumerationLeaf);
+
+        EnumTypeDefinition enumerationType = (EnumTypeDefinition) myEnumerationLeaf.getType();
+
+        List<EnumPair> enums = enumerationType.getValues();
+        assertEquals(2, enums.size());
+        final EnumPair yellowEnum = createEnumPair("yellow", 2);
+        final EnumPair redEnum = createEnumPair("red", 3);
+        assertContainsEnums(enums, yellowEnum, redEnum);
+
+        enumerationType = enumerationType.getBaseType();
+        enums = enumerationType.getValues();
+        assertEquals(3, enums.size());
+        final EnumPair blackEnum = createEnumPair("black", 4);
+        assertContainsEnums(enums, yellowEnum, redEnum, blackEnum);
+
+        enumerationType = enumerationType.getBaseType();
+        enums = enumerationType.getValues();
+        assertEquals(4, enums.size());
+        final EnumPair whiteEnum = createEnumPair("white", 1);
+        assertContainsEnums(enums, whiteEnum, yellowEnum, redEnum, blackEnum);
+
+        final LeafSchemaNode myEnumerationLeaf2 = (LeafSchemaNode) foo.getDataChildByName(
+                QName.create(foo.getQNameModule(), "my-enumeration-leaf-2"));
+        assertNotNull(myEnumerationLeaf2);
+
+        enumerationType = (EnumTypeDefinition) myEnumerationLeaf2.getType();
+        enums = enumerationType.getValues();
+        assertEquals(3, enums.size());
+        assertContainsEnums(enums, yellowEnum, redEnum, blackEnum);
+    }
+
+    @Test
+    public void testInvalidRestrictedEnumeration() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo-invalid.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith("Enum 'purple' is not a subset of its base enumeration type" +
+                    " (foo?revision=2017-02-02)my-derived-enumeration-type."));
+        }
+    }
+
+    @Test
+    public void testInvalidRestrictedEnumeration2() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo-invalid-2.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof InvalidEnumDefinitionException);
+            assertTrue(cause.getMessage().startsWith("Enum 'magenta' is not a subset of its base enumeration type" +
+                    " (foo?revision=2017-02-02)my-base-enumeration-type."));
+        }
+    }
+
+    @Test
+    public void testInvalidRestrictedEnumeration3() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo-invalid-3.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof InvalidEnumDefinitionException);
+            assertTrue(cause.getMessage().startsWith("Value of enum 'red' must be the same as the value of " +
+                    "corresponding enum in the base enumeration type (foo?revision=2017-02-02)" +
+                    "my-derived-enumeration-type."));
+        }
+    }
+
+    @Test
+    public void testInvalidRestrictedEnumeration4() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo-invalid-4.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof InvalidEnumDefinitionException);
+            assertTrue(cause.getMessage().startsWith("Value of enum 'black' must be the same as the value of " +
+                    "corresponding enum in the base enumeration type (foo?revision=2017-02-02)" +
+                    "my-base-enumeration-type."));
+        }
+    }
+
+    @Test
+    public void testValidYang10EnumerationWithUnknownStatements() throws ReactorException, FileNotFoundException,
+            URISyntaxException {
+        final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo10-valid.yang");
+        assertNotNull(schemaContext);
+    }
+
+    @Test
+    public void testInvalidYang10RestrictedEnumeration() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo10-invalid.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith("Restricted enumeration type is allowed only in YANG 1.1 version."));
+        }
+    }
+
+    @Test
+    public void testInvalidYang10RestrictedEnumeration2() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo10-invalid-2.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith("Restricted enumeration type is allowed only in YANG 1.1 version."));
+        }
+    }
+
+    @Test
+    public void testRestrictedBits() throws ReactorException, FileNotFoundException, URISyntaxException,
+            ParseException {
+        final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar.yang");
+        assertNotNull(schemaContext);
+
+        final Date revision = SimpleDateFormatUtil.getRevisionFormat().parse("2017-02-02");
+
+        final Module bar = schemaContext.findModuleByName("bar", revision);
+        assertNotNull(bar);
+
+        final LeafSchemaNode myBitsLeaf = (LeafSchemaNode) bar.getDataChildByName(
+                QName.create(bar.getQNameModule(), "my-bits-leaf"));
+        assertNotNull(myBitsLeaf);
+
+        BitsTypeDefinition bitsType = (BitsTypeDefinition) myBitsLeaf.getType();
+
+        List<Bit> bits = bitsType.getBits();
+        assertEquals(2, bits.size());
+        Bit bitB = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-bits-leaf",
+                "my-derived-bits-type", "bit-b")), 2);
+        Bit bitC = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-bits-leaf",
+                "my-derived-bits-type", "bit-c")), 3);
+        assertContainsBits(bits, bitB, bitC);
+
+        bitsType = bitsType.getBaseType();
+        bits = bitsType.getBits();
+        assertEquals(3, bits.size());
+        bitB = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
+                "my-base-bits-type", "bit-b")), 2);
+        bitC = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
+                "my-base-bits-type", "bit-c")), 3);
+        Bit bitD = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
+                "my-base-bits-type", "bit-d")), 4);
+        assertContainsBits(bits, bitB, bitC, bitD);
+
+        bitsType = bitsType.getBaseType();
+        bits = bitsType.getBits();
+        assertEquals(4, bits.size());
+        Bit bitA = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-base-bits-type",
+                "bits", "bit-a")), 1);
+        bitB = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-base-bits-type",
+                "bits", "bit-b")), 2);
+        bitC = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-base-bits-type",
+                "bits", "bit-c")), 3);
+        bitD = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-base-bits-type",
+                "bits", "bit-d")), 4);
+        assertContainsBits(bits, bitA, bitB, bitC, bitD);
+
+        final LeafSchemaNode myBitsLeaf2 = (LeafSchemaNode) bar.getDataChildByName(
+                QName.create(bar.getQNameModule(), "my-bits-leaf-2"));
+        assertNotNull(myBitsLeaf2);
+
+        bitsType = (BitsTypeDefinition) myBitsLeaf2.getType();
+        bits = bitsType.getBits();
+        assertEquals(3, bits.size());
+        bitB = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
+                "my-base-bits-type", "bit-b")), 2);
+        bitC = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
+                "my-base-bits-type", "bit-c")), 3);
+        bitD = createBit(createSchemaPath(true, bar.getQNameModule(), ImmutableList.of("my-derived-bits-type",
+                "my-base-bits-type", "bit-d")), 4);
+        assertContainsBits(bits, bitB, bitC, bitD);
+    }
+
+    @Test
+    public void testInvalidRestrictedBits() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar-invalid.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith("Bit 'bit-w' is not a subset of its base bits type" +
+                    " (bar?revision=2017-02-02)my-derived-bits-type."));
+        }
+    }
+
+    @Test
+    public void testInvalidRestrictedBits2() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar-invalid-2.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof InvalidBitDefinitionException);
+            assertTrue(cause.getMessage().startsWith("Bit 'bit-x' is not a subset of its base bits type" +
+                    " (bar?revision=2017-02-02)my-base-bits-type."));
+        }
+    }
+
+    @Test
+    public void testInvalidRestrictedBits3() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar-invalid-3.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof InvalidBitDefinitionException);
+            assertTrue(cause.getMessage().startsWith("Position of bit 'bit-c' must be the same as the position of " +
+                    "corresponding bit in the base bits type (bar?revision=2017-02-02)my-derived-bits-type."));
+        }
+    }
+
+    @Test
+    public void testInvalidRestrictedBits4() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar-invalid-4.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof InvalidBitDefinitionException);
+            assertTrue(cause.getMessage().startsWith("Position of bit 'bit-d' must be the same as the position of " +
+                    "corresponding bit in the base bits type (bar?revision=2017-02-02)my-base-bits-type."));
+        }
+    }
+
+    @Test
+    public void testValidYang10BitsWithUnknownStatements() throws ReactorException, FileNotFoundException,
+            URISyntaxException {
+        final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar10-valid.yang");
+        assertNotNull(schemaContext);
+    }
+
+    @Test
+    public void testInvalidYang10RestrictedBits() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar10-invalid.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith("Restricted bits type is allowed only in YANG 1.1 version."));
+        }
+    }
+
+    @Test
+    public void testInvalidYang10RestrictedBits2() throws FileNotFoundException, URISyntaxException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar10-invalid-2.yang");
+            fail("An exception should have been thrown.");
+        } catch (final ReactorException ex) {
+            final Throwable cause = ex.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith("Restricted bits type is allowed only in YANG 1.1 version."));
+        }
+    }
+
+    private static EnumPair createEnumPair(final String name, int value) {
+        return EnumPairBuilder.create(name, value).build();
+    }
+
+    private static void assertContainsEnums(final List<EnumPair> enumList, final EnumPair... enumPairs) {
+        for (final EnumPair enumPair : enumPairs) {
+            assertTrue(enumList.contains(enumPair));
+        }
+    }
+
+    private static Bit createBit(final SchemaPath path, long position) {
+        return BitBuilder.create(path, position).build();
+    }
+
+    private static void assertContainsBits(final List<Bit> bitList, final Bit... bits) {
+        for (final Bit bit : bits) {
+            assertTrue(bitList.contains(bit));
+        }
+    }
+
+    private static SchemaPath createSchemaPath(final boolean absolute, final QNameModule qNameModule,
+            final Iterable<String> localNames) {
+        final Iterable<QName> qNames = Iterables.transform(localNames,
+                localName -> QName.create(qNameModule, localName));
+        return SchemaPath.create(qNames, true);
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-2.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-2.yang
new file mode 100644 (file)
index 0000000..a7e1085
--- /dev/null
@@ -0,0 +1,46 @@
+module bar {
+    namespace bar;
+    prefix bar;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-bits-type {
+        type bits {
+            bit bit-a {
+                position 1;
+            }
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    typedef my-derived-bits-type {
+        type my-base-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+            bit bit-x {
+                position 10;
+            }
+        }
+    }
+
+    leaf my-bits-leaf {
+        type my-derived-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-3.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-3.yang
new file mode 100644 (file)
index 0000000..d803144
--- /dev/null
@@ -0,0 +1,43 @@
+module bar {
+    namespace bar;
+    prefix bar;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-bits-type {
+        type bits {
+            bit bit-a {
+                position 1;
+            }
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    typedef my-derived-bits-type {
+        type my-base-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    leaf my-bits-leaf {
+        type my-derived-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 5;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-4.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid-4.yang
new file mode 100644 (file)
index 0000000..6013c3a
--- /dev/null
@@ -0,0 +1,43 @@
+module bar {
+    namespace bar;
+    prefix bar;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-bits-type {
+        type bits {
+            bit bit-a {
+                position 1;
+            }
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    typedef my-derived-bits-type {
+        type my-base-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 6;
+            }
+        }
+    }
+
+    leaf my-bits-leaf {
+        type my-derived-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar-invalid.yang
new file mode 100644 (file)
index 0000000..548835c
--- /dev/null
@@ -0,0 +1,44 @@
+module bar {
+    namespace bar;
+    prefix bar;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-bits-type {
+        type bits {
+            bit bit-a {
+                position 1;
+            }
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    typedef my-derived-bits-type {
+        type my-base-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    leaf my-bits-leaf {
+        type my-derived-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-w;
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar.yang
new file mode 100644 (file)
index 0000000..5eef206
--- /dev/null
@@ -0,0 +1,49 @@
+module bar {
+    namespace bar;
+    prefix bar;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-bits-type {
+        type bits {
+            bit bit-a {
+                position 1;
+            }
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    typedef my-derived-bits-type {
+        type my-base-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    leaf my-bits-leaf {
+        type my-derived-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+        }
+    }
+
+    leaf my-bits-leaf-2 {
+        type my-derived-bits-type {
+            // inherits bits from the base type
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-invalid-2.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-invalid-2.yang
new file mode 100644 (file)
index 0000000..41f771b
--- /dev/null
@@ -0,0 +1,30 @@
+module bar {
+    namespace bar;
+    prefix bar;
+
+    revision 2017-02-02;
+
+    typedef my-base-bits-type {
+        type bits {
+            bit bit-a {
+                position 1;
+            }
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    leaf my-bits-leaf {
+        type my-base-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-invalid.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-invalid.yang
new file mode 100644 (file)
index 0000000..4bf7f77
--- /dev/null
@@ -0,0 +1,33 @@
+module bar {
+    namespace bar;
+    prefix bar;
+
+    revision 2017-02-02;
+
+    typedef my-base-bits-type {
+        type bits {
+            bit bit-a {
+                position 1;
+            }
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    typedef my-derived-bits-type {
+        type my-base-bits-type {
+            bit bit-b;
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-valid.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/bar10-valid.yang
new file mode 100644 (file)
index 0000000..dd87930
--- /dev/null
@@ -0,0 +1,31 @@
+module bar {
+    namespace bar;
+    prefix bar;
+
+    revision 2017-02-21;
+
+    extension ext;
+
+    typedef my-base-bits-type {
+        type bits {
+            bit bit-a {
+                position 1;
+            }
+            bit bit-b {
+                position 2;
+            }
+            bit bit-c {
+                position 3;
+            }
+            bit bit-d {
+                position 4;
+            }
+        }
+    }
+
+    leaf my-bits-leaf {
+        type my-base-bits-type {
+            bar:ext;
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-2.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-2.yang
new file mode 100644 (file)
index 0000000..482688f
--- /dev/null
@@ -0,0 +1,50 @@
+module foo {
+    namespace foo;
+    prefix foo;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-enumeration-type {
+        type enumeration {
+            enum white {
+                value 1;
+            }
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    typedef my-derived-enumeration-type {
+        type my-base-enumeration-type {
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+            enum magenta {
+                value 10;
+            }
+        }
+    }
+
+    leaf my-enumeration-leaf {
+        type my-derived-enumeration-type {
+            enum yellow;
+            enum red {
+                value 3;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-3.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-3.yang
new file mode 100644 (file)
index 0000000..0a61ae5
--- /dev/null
@@ -0,0 +1,47 @@
+module foo {
+    namespace foo;
+    prefix foo;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-enumeration-type {
+        type enumeration {
+            enum white {
+                value 1;
+            }
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    typedef my-derived-enumeration-type {
+        type my-base-enumeration-type {
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    leaf my-enumeration-leaf {
+        type my-derived-enumeration-type {
+            enum yellow;
+            enum red {
+                value 5;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-4.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid-4.yang
new file mode 100644 (file)
index 0000000..06ed492
--- /dev/null
@@ -0,0 +1,47 @@
+module foo {
+    namespace foo;
+    prefix foo;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-enumeration-type {
+        type enumeration {
+            enum white {
+                value 1;
+            }
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    typedef my-derived-enumeration-type {
+        type my-base-enumeration-type {
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 6;
+            }
+        }
+    }
+
+    leaf my-enumeration-leaf {
+        type my-derived-enumeration-type {
+            enum yellow;
+            enum red {
+                value 3;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo-invalid.yang
new file mode 100644 (file)
index 0000000..3b3be05
--- /dev/null
@@ -0,0 +1,48 @@
+module foo {
+    namespace foo;
+    prefix foo;
+    yang-version 1.1;
+
+    revision 2017-02-02;
+
+    typedef my-base-enumeration-type {
+        type enumeration {
+            enum white {
+                value 1;
+            }
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    typedef my-derived-enumeration-type {
+        type my-base-enumeration-type {
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    leaf my-enumeration-leaf {
+        type my-derived-enumeration-type {
+            enum yellow;
+            enum red {
+                value 3;
+            }
+            enum purple;
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo.yang
new file mode 100644 (file)
index 0000000..50ff568
--- /dev/null
@@ -0,0 +1,49 @@
+module foo {
+    namespace foo;
+    prefix foo;
+    yang-version 1.1;
+
+    revision 2017-01-26;
+
+    typedef my-base-enumeration-type {
+        type enumeration {
+            enum white {
+                value 1;
+            }
+            enum yellow;
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    typedef my-derived-enumeration-type {
+        type my-base-enumeration-type {
+            enum yellow;
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    leaf my-enumeration-leaf {
+        type my-derived-enumeration-type {
+            enum yellow;
+            enum red {
+                value 3;
+            }
+        }
+    }
+
+    leaf my-enumeration-leaf-2 {
+        type my-derived-enumeration-type {
+            // inherits enums from the base type
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-invalid-2.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-invalid-2.yang
new file mode 100644 (file)
index 0000000..cfa900e
--- /dev/null
@@ -0,0 +1,30 @@
+module foo {
+    namespace foo;
+    prefix foo;
+
+    revision 2017-02-02;
+
+    typedef my-base-enumeration-type {
+        type enumeration {
+            enum white {
+                value 1;
+            }
+            enum yellow;
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    leaf my-enumeration-leaf {
+        type my-base-enumeration-type {
+            enum yellow;
+            enum red {
+                value 3;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-invalid.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-invalid.yang
new file mode 100644 (file)
index 0000000..36b245f
--- /dev/null
@@ -0,0 +1,33 @@
+module foo {
+    namespace foo;
+    prefix foo;
+
+    revision 2017-02-02;
+
+    typedef my-base-enumeration-type {
+        type enumeration {
+            enum white {
+                value 1;
+            }
+            enum yellow;
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    typedef my-derived-enumeration-type {
+        type my-base-enumeration-type {
+            enum yellow;
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-valid.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/bug6887/foo10-valid.yang
new file mode 100644 (file)
index 0000000..ed37030
--- /dev/null
@@ -0,0 +1,31 @@
+module foo {
+    namespace foo;
+    prefix foo;
+
+    revision 2017-02-21;
+
+    extension ext;
+
+    typedef my-base-enumeration-type {
+        type enumeration {
+            enum white {
+                value 1;
+            }
+            enum yellow {
+                value 2;
+            }
+            enum red {
+                value 3;
+            }
+            enum black {
+                value 4;
+            }
+        }
+    }
+
+    leaf my-enumeration-leaf {
+        type my-base-enumeration-type {
+            foo:ext;
+        }
+    }
+}
\ No newline at end of file