/*
* 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.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 Exception {
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 Exception {
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 Exception {
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 Exception {
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 Exception {
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 Exception {
final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/foo10-valid.yang");
assertNotNull(schemaContext);
}
@Test
public void testInvalidYang10RestrictedEnumeration() throws Exception {
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 Exception {
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 Exception {
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 Exception {
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 Exception {
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 Exception {
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 Exception {
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 Exception {
final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6887/bar10-valid.yang");
assertNotNull(schemaContext);
}
@Test
public void testInvalidYang10RestrictedBits() throws Exception {
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 Exception {
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, final 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, final 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);
}
}