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<>();
}
}
- 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());
+ }
}
}
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<>();
}
}
- 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());
+ }
}
}
*/
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;
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
*/
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;
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
};
}
- 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) {
};
}
- 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) {
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;
}
}
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;
}
}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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;
+ }
+ }
+ }
+}
--- /dev/null
+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