Skip to content

Commit

Permalink
Handled double quoted patterns
Browse files Browse the repository at this point in the history
This addresses TypeFox#239

Signed-off-by: Siddharth Sharma <[email protected]>
  • Loading branch information
esmasth committed Sep 7, 2024
1 parent 3697fbd commit 6121909
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ import io.typefox.yang.yang.BelongsTo
import org.apache.xerces.impl.xpath.regex.ParseException

/**
* This class contains custom validation rules for the YANG language.
* This class contains custom validation rules for the YANG language.
*/
@Singleton
class YangValidator extends AbstractYangValidator {
Expand Down Expand Up @@ -111,7 +111,7 @@ class YangValidator extends AbstractYangValidator {
];
validAugmentStatements.put(CHOICE, CASE);
// https://tools.ietf.org/html/rfc7950#section-7.9.2
// Shorthand "case" statement.
// Shorthand "case" statement.
validShorthandStatements = ImmutableList.copyOf(#[ANYDATA, ANYXML, CHOICE, CONTAINER, LEAF, LIST, LEAF_LIST]);
}

Expand Down Expand Up @@ -152,22 +152,22 @@ class YangValidator extends AbstractYangValidator {
];
}
}

@Check
def void checkVersionConsistency(Submodule subModule) {
val submoduleVersion = subModule.yangVersion
subModule
.substatementsOfType(BelongsTo)
.filter[module?.eResource !== null && !module.eIsProxy]
.forEach [ belongsTo |
.forEach [ belongsTo |
val baseModuleVersion = belongsTo.module.yangVersion
if(submoduleVersion != baseModuleVersion) {
val message = '''A version «submoduleVersion» submodule cannot be included in a version «baseModuleVersion» module.''';
error(message, belongsTo, BELONGS_TO__MODULE, BAD_INCLUDE_YANG_VERSION);
}
]
}


@Check
def void checkSubstatements(Statement it) {
Expand Down Expand Up @@ -215,7 +215,7 @@ class YangValidator extends AbstractYangValidator {
@Check
def checkIdentityrefType(Type it) {
if (identityref) {
// The "base" statement, which is a sub-statement to the "type" statement,
// The "base" statement, which is a sub-statement to the "type" statement,
// must be present at least once if the type is "identityref".
// https://tools.ietf.org/html/rfc7950#section-9.10.2
if (substatementsOfType(Base).nullOrEmpty) {
Expand Down Expand Up @@ -260,7 +260,7 @@ class YangValidator extends AbstractYangValidator {
val fractionDigits = firstSubstatementsOfType(FractionDigits);
val fractionDigitsExist = fractionDigits !== null;
// Note, only the decimal type definition MUST have the `fraction-digits` statement.
// It is not mandatory for types that are derived from decimal built-ins.
// It is not mandatory for types that are derived from decimal built-ins.
val decimalBuiltin = decimal;
if (decimalBuiltin) {
if (fractionDigitsExist) {
Expand All @@ -287,6 +287,7 @@ class YangValidator extends AbstractYangValidator {
@Check
def checkPattern(Pattern it) {
// https://tools.ietf.org/html/rfc7950#section-9.4.5
// If 'it' is double quoted replace all '\\' with '\'
if (eContainer instanceof Type) {
val type = eContainer as Type;
if (type.subtypeOfString) {
Expand Down Expand Up @@ -348,8 +349,8 @@ class YangValidator extends AbstractYangValidator {
try {
revisionDateFormat.parse(revisionFile);
val revisionStatement = substatementsOfType(Revision).head;
if(revisionStatement !== null
&& revisionStatement.revision !== null
if(revisionStatement !== null
&& revisionStatement.revision !== null
&& revisionStatement.revision != revisionFile) {
val message = '''The revision date in the file name does not match.''';
warning(message, revisionStatement, REVISION__REVISION, REVISION_MISMATCH);
Expand All @@ -364,7 +365,7 @@ class YangValidator extends AbstractYangValidator {
@Check
def checkTypedef(Typedef it) {
// The [1..*] type cardinality is checked by other rules.
// Also, the type name uniqueness is checked in the scoping.
// Also, the type name uniqueness is checked in the scoping.
// https://tools.ietf.org/html/rfc7950#section-7.3
if (name.builtinName) {
val message = '''Illegal type name "«name»".''';
Expand Down Expand Up @@ -421,7 +422,7 @@ class YangValidator extends AbstractYangValidator {

@Check
def checkKey(Key key) {
// https://tools.ietf.org/html/rfc7950#section-7.8.2
// https://tools.ietf.org/html/rfc7950#section-7.8.2
// A leaf identifier must not appear more than once in the key.
key.references.filter[!node?.name.nullOrEmpty].toMultimap[node.name].asMap.forEach [ name, nodesWithSameName |
if (nodesWithSameName.size > 1) {
Expand Down Expand Up @@ -510,7 +511,7 @@ class YangValidator extends AbstractYangValidator {
val message = '''The augment's target node must be either a «validTypes» node.''';
error(message, it, AUGMENT__PATH, INVALID_AUGMENTATION);
} else {
// As a shorthand, the "case" statement can be omitted if the branch contains a single "anydata", "anyxml",
// As a shorthand, the "case" statement can be omitted if the branch contains a single "anydata", "anyxml",
// "choice", "container", "leaf", "list", or "leaf-list" statement.
val schemaNodes = substatements.filter(SchemaNode);
if (target.eClass === CHOICE && schemaNodes.size === 1) {
Expand Down Expand Up @@ -539,7 +540,7 @@ class YangValidator extends AbstractYangValidator {
def void checkAction(Action it) {
// https://tools.ietf.org/html/rfc7950#section-7.15
// An action must not have any ancestor node that is a list node without a "key" statement.
// An action must not be defined within an rpc, another action, or a notification, i.e., an action node must
// An action must not be defined within an rpc, another action, or a notification, i.e., an action node must
// not have an rpc, action, or a notification node as one of its ancestors in the schema tree.
checkAncestors(SCHEMA_NODE__NAME);
}
Expand All @@ -548,7 +549,7 @@ class YangValidator extends AbstractYangValidator {
def void checkNotification(Notification it) {
// https://tools.ietf.org/html/rfc7950#section-7.16
// A notification must not have any ancestor node that is a list node without a "key" statement.
// A notification must not be defined within an rpc, another action, or a notification, i.e., a notification node must
// A notification must not be defined within an rpc, another action, or a notification, i.e., a notification node must
// not have an rpc, action, or a notification node as one of its ancestors in the schema tree.
checkAncestors(SCHEMA_NODE__NAME);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import org.junit.Assert

/**
* Validation test for the YANG language.
*
*
* @author akos.kitta
*/
class YangValidatorTest extends AbstractYangTest {
Expand Down Expand Up @@ -581,6 +581,23 @@ class YangValidatorTest extends AbstractYangTest {
assertError(EcoreUtil2.getAllContentsOfType(root, Type).head, TYPE_ERROR, 'int32');
}

@Test
def void checkPattern_04() {
val it = load('''
module foo {
yang-version 1.1;
namespace "urn:yang:types";
prefix "yang";
typedef my-base-type {
type int32 {
pattern "[a-zA-Z0-9!$%\\^()\\[\\]_\\-~{}.+]*";
}
}
}
''');
assertNoErrors;
}

@Test
def void checkEnumStatements() {
val it = load('''
Expand Down Expand Up @@ -1168,7 +1185,7 @@ class YangValidatorTest extends AbstractYangTest {
namespace "urn:example:my-crypto";
prefix mc;
identity eth-if-speed {
description
description
"Representing the configured or negotiated speed of an Ethernet interface. Definitions are only required for PHYs that can run at different speeds (e.g. BASE-T).";
}
leaf crypto {
Expand Down Expand Up @@ -1423,7 +1440,7 @@ class YangValidatorTest extends AbstractYangTest {
}
rpc run {
input { uses g; }
output {
output {
uses g {
augment l {
leaf xxx {
Expand All @@ -1445,15 +1462,15 @@ class YangValidatorTest extends AbstractYangTest {
module d {
namespace urn:d;
prefix d;
container x {
choice c {
leaf d {
type string;
}
}
}
deviation /x/c/d {
deviate «it»;
}
Expand All @@ -1469,15 +1486,15 @@ class YangValidatorTest extends AbstractYangTest {
module d {
namespace urn:d;
prefix d;
container x {
choice c {
leaf d {
type string;
}
}
}
deviation /x/c/d {
deviate blabla;
}
Expand All @@ -1493,7 +1510,7 @@ class YangValidatorTest extends AbstractYangTest {
module d {
namespace urn:d;
prefix d;
leaf Num1 {
type int32 {
range min..max;
Expand All @@ -1513,7 +1530,7 @@ class YangValidatorTest extends AbstractYangTest {
module d {
namespace urn:d;
prefix d;
leaf Num1 {
type int32 {
range min..max;
Expand All @@ -1525,7 +1542,7 @@ class YangValidatorTest extends AbstractYangTest {
''');
assertError(EcoreUtil2.getAllContentsOfType(root, Status).head, TYPE_ERROR);
}

@Test
def void checkUriToProblem_01() {
val model = loadWithSyntaxErrors('''
Expand All @@ -1534,7 +1551,7 @@ class YangValidatorTest extends AbstractYangTest {
namespace bug196;
leaf key-id {
type string;
when "/ctxsr6k:contexts/ctxr6k:context/ctxr6k:context-"
+ "name='local'" {
description
Expand All @@ -1544,7 +1561,7 @@ class YangValidatorTest extends AbstractYangTest {
}
}
''');

val issues = validator.validate(model)
val noUriIssues = issues.filter[it.uriToProblem === null].toList
Assert.assertEquals("Some issues has no uriToProblem set", 0, noUriIssues.size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,81 +7,100 @@ import org.junit.Test
import static io.typefox.yang.validation.IssueCodes.*

class RegexpTest extends AbstractYangTest {

@Test def void testLegalPattern_0() {
val foo = load('''
module foo {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:foo;
prefix foo;
typedef foo {
type string {
pattern [a-z0-9];
}
}
}
''')

validator.validate(foo)
assertNoErrors(foo.allContents.filter(Pattern).head, TYPE_ERROR)
}

@Test def void testLegalPattern_1() {
val foo = load('''
module foo {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:foo;
prefix foo;
typedef foo {
type string {
pattern [a-zA-_];
}
}
}
''')


validator.validate(foo)
assertNoErrors(foo.allContents.filter(Pattern).head, TYPE_ERROR)
}

@Test def void testLegalPattern_2() {
val foo = load('''
module foo {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:foo;
prefix foo;
typedef foo {
type string {
pattern "[a-zA-Z0-9!$%\\^()\\[\\]_\\-~{}.+]*";
}
}
}
''')

validator.validate(foo)
assertNoErrors(foo.allContents.filter(Pattern).head, TYPE_ERROR)
}

@Test def void testIllegalPattern_0() {
val foo = load('''
module foo {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:foo;
prefix foo;
typedef foo {
type string {
pattern [a-z-0];
}
}
}
''')

validator.validate(foo)
assertError(foo.allContents.filter(Pattern).head, TYPE_ERROR)
}

@Test def void testIllegalPattern_1() {
val foo = load('''
module foo {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:foo;
prefix foo;
typedef foo {
type string {
pattern [a-z-_];
}
}
}
''')

validator.validate(foo)
assertError(foo.allContents.filter(Pattern).head, TYPE_ERROR)
}
}

}

0 comments on commit 6121909

Please sign in to comment.