import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
* type body
* @return list of pattern constraints
*/
- private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx) {
+ private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx, final String moduleName) {
List<PatternConstraint> patterns = new ArrayList<>();
for (int i = 0; i < ctx.getChildCount(); i++) {
for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
ParseTree lengthChild = stringRestrChild.getChild(j);
if (lengthChild instanceof Pattern_stmtContext) {
- patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild));
+ final PatternConstraint constraint = parsePatternConstraint((Pattern_stmtContext) lengthChild,
+ moduleName);
+ if (constraint != null) {
+ patterns.add(constraint);
+ }
}
}
}
* pattern context
* @return PatternConstraint object
*/
- private static PatternConstraint parsePatternConstraint(final Pattern_stmtContext ctx) {
+ private static PatternConstraint parsePatternConstraint(final Pattern_stmtContext ctx, final String moduleName) {
Optional<String> description = Optional.absent();
Optional<String> reference = Optional.absent();
for (int i = 0; i < ctx.getChildCount(); i++) {
reference = Optional.of(stringFromNode(child));
}
}
- String pattern = parsePatternString(ctx);
- return BaseConstraints.newPatternConstraint(pattern, description, reference);
+ final String rawPattern = parsePatternString(ctx);
+ final String pattern = wrapPattern(rawPattern);
+ if (isValidPattern(pattern, ctx, moduleName)) {
+ return BaseConstraints.newPatternConstraint(pattern, description, reference);
+ }
+ return null;
+ }
+
+ private static String wrapPattern(String rawPattern) {
+ final StringBuilder wrapPatternBuilder = new StringBuilder(rawPattern.length() + 2);
+ wrapPatternBuilder.append('^');
+ wrapPatternBuilder.append(rawPattern);
+ wrapPatternBuilder.append('$');
+ return wrapPatternBuilder.toString();
+ }
+
+ private static boolean isValidPattern(final String pattern, final Pattern_stmtContext ctx, final String moduleName) {
+ try {
+ Pattern.compile(pattern);
+ return true;
+ } catch (PatternSyntaxException ex) {
+ LOG.warn("Unable to compile pattern defined in module {} at line {}. Error message: {}",
+ moduleName, ctx.getStart().getLine(), ex.getMessage());
+ }
+ return false;
}
/**
List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleBuilder.getName());
List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleBuilder.getName());
- List<PatternConstraint> patternStatements = getPatternConstraint(typeBody);
+ List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleBuilder.getName());
Integer fractionDigits = getFractionDigits(typeBody, moduleBuilder.getName());
if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
Integer fractionDigits = getFractionDigits(typeBody, moduleName);
List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleName);
- List<PatternConstraint> patternStatements = getPatternConstraint(typeBody);
+ List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleName);
List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleName);
TypeConstraints constraints = new TypeConstraints(moduleName, line);
Set<Module> modules = TestUtils.loadModules(getClass().getResource("/model").toURI());
Module bar = TestUtils.findModule(modules, "bar");
Set<TypeDefinition<?>> typedefs = bar.getTypeDefinitions();
- String[] expectedOrder = new String[] { "int32-ext1", "int32-ext2", "my-decimal-type", "my-union",
- "my-union-ext", "nested-union2", "string-ext1", "string-ext2", "string-ext3", "string-ext4" };
+ String[] expectedOrder = new String[] { "int32-ext1", "int32-ext2", "invalid-string-pattern",
+ "multiple-pattern-string", "my-decimal-type", "my-union", "my-union-ext", "nested-union2",
+ "string-ext1", "string-ext2", "string-ext3", "string-ext4" };
String[] actualOrder = new String[typedefs.size()];
int i = 0;
Module foo = TestUtils.findModule(modules, "foo");
Collection<DataSchemaNode> childNodes = foo.getChildNodes();
- String[] expectedOrder = new String[] { "int32-leaf", "string-leaf", "length-leaf", "decimal-leaf",
- "decimal-leaf2", "ext", "union-leaf", "custom-union-leaf", "transfer", "datas", "mycont", "data",
- "how", "address", "port", "addresses", "peer", "id", "foo-id","sub-ext", "sub-transfer", "sub-datas" };
+ String[] expectedOrder = new String[] { "int32-leaf", "string-leaf", "invalid-pattern-string-leaf",
+ "invalid-direct-string-pattern-def-leaf", "multiple-pattern-string-leaf",
+ "multiple-pattern-direct-string-def-leaf", "length-leaf", "decimal-leaf", "decimal-leaf2", "ext",
+ "union-leaf", "custom-union-leaf", "transfer", "datas", "mycont", "data", "how", "address", "port",
+ "addresses", "peer", "id", "foo-id","sub-ext", "sub-transfer", "sub-datas" };
String[] actualOrder = new String[childNodes.size()];
int i = 0;
ExtendedType ipv4 = (ExtendedType) unionTypes.get(0);
assertTrue(ipv4.getBaseType() instanceof StringTypeDefinition);
- String expectedPattern = "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}"
- + "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" + "(%[\\p{N}\\p{L}]+)?";
+ String expectedPattern = "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}"
+ + "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" + "(%[\\p{N}\\p{L}]+)?$";
assertEquals(expectedPattern, ipv4.getPatternConstraints().get(0).getRegularExpression());
ExtendedType ipv6 = (ExtendedType) unionTypes.get(1);
assertTrue(ipv6.getBaseType() instanceof StringTypeDefinition);
List<PatternConstraint> ipv6Patterns = ipv6.getPatternConstraints();
- expectedPattern = "((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}"
+ expectedPattern = "^((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}"
+ "((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|" + "(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}"
- + "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))" + "(%[\\p{N}\\p{L}]+)?";
+ + "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))" + "(%[\\p{N}\\p{L}]+)?$";
assertEquals(expectedPattern, ipv6Patterns.get(0).getRegularExpression());
- expectedPattern = "(([^:]+:){6}(([^:]+:[^:]+)|(.*\\..*)))|" + "((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)"
- + "(%.+)?";
+ expectedPattern = "^(([^:]+:){6}(([^:]+:[^:]+)|(.*\\..*)))|" + "((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)"
+ + "(%.+)?$";
assertEquals(expectedPattern, ipv6Patterns.get(1).getRegularExpression());
}
assertTrue(type.getBaseType() instanceof StringTypeDefinition);
List<PatternConstraint> patterns = type.getPatternConstraints();
assertEquals(1, patterns.size());
- String expectedPattern = "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*"
- + "([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)" + "|\\.";
+ String expectedPattern = "^((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*"
+ + "([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)" + "|\\.$";
assertEquals(expectedPattern, patterns.get(0).getRegularExpression());
List<LengthConstraint> lengths = type.getLengthConstraints();
List<PatternConstraint> patterns = testedType.getPatternConstraints();
assertEquals(1, patterns.size());
PatternConstraint pattern = patterns.get(0);
- assertEquals("\\d*(\\.\\d*){1,127}", pattern.getRegularExpression());
+ assertEquals("^\\d*(\\.\\d*){1,127}$", pattern.getRegularExpression());
QName testedTypeQName = testedType.getQName();
assertEquals(URI.create("urn:ietf:params:xml:ns:yang:ietf-yang-types"), testedTypeQName.getNamespace());
assertEquals(1, patterns.size());
pattern = patterns.get(0);
- assertEquals("(([0-1](\\.[1-3]?[0-9]))|(2\\.(0|([1-9]\\d*))))(\\.(0|([1-9]\\d*)))*",
+ assertEquals("^(([0-1](\\.[1-3]?[0-9]))|(2\\.(0|([1-9]\\d*))))(\\.(0|([1-9]\\d*)))*$",
pattern.getRegularExpression());
QName testedTypeBaseQName = testedTypeBase.getQName();
List<PatternConstraint> patterns = type.getPatternConstraints();
assertEquals(1, patterns.size());
PatternConstraint pattern = patterns.iterator().next();
- assertEquals("[e-z]*", pattern.getRegularExpression());
+ assertEquals("^[e-z]*$", pattern.getRegularExpression());
assertTrue(type.getLengthConstraints().isEmpty());
assertTrue(type.getRangeConstraints().isEmpty());
patterns = baseType1.getPatternConstraints();
assertEquals(1, patterns.size());
pattern = patterns.iterator().next();
- assertEquals("[b-u]*", pattern.getRegularExpression());
+ assertEquals("^[b-u]*$", pattern.getRegularExpression());
assertTrue(baseType1.getLengthConstraints().isEmpty());
assertTrue(baseType1.getRangeConstraints().isEmpty());
patterns = baseType3.getPatternConstraints();
assertEquals(1, patterns.size());
pattern = patterns.iterator().next();
- assertEquals("[a-k]*", pattern.getRegularExpression());
+ assertEquals("^[a-k]*$", pattern.getRegularExpression());
List<LengthConstraint> baseType3Lengths = baseType3.getLengthConstraints();
assertEquals(1, baseType3Lengths.size());
length = baseType3Lengths.get(0);
assertTrue(baseType3.getBaseType() instanceof StringType);
}
+ @Test
+ public void testTypedefInvalidPatternsResolving() {
+ Module foo = TestUtils.findModule(modules, "foo");
+ final LeafSchemaNode invalidPatternStringLeaf = (LeafSchemaNode) foo.getDataChildByName("invalid-pattern-string-leaf");
+ ExtendedType type = (ExtendedType) invalidPatternStringLeaf.getType();
+ QName typeQName = type.getQName();
+ assertEquals("invalid-string-pattern", typeQName.getLocalName());
+ assertEquals(barNS, typeQName.getNamespace());
+ assertEquals(barRev, typeQName.getRevision());
+ assertNull(type.getUnits());
+ assertNull(type.getDefaultValue());
+ List<PatternConstraint> patterns = type.getPatternConstraints();
+ assertTrue(patterns.isEmpty());
+
+ final LeafSchemaNode invalidDirectStringPatternDefLeaf = (LeafSchemaNode) foo.getDataChildByName("invalid-direct-string-pattern-def-leaf");
+ type = (ExtendedType) invalidDirectStringPatternDefLeaf.getType();
+ typeQName = type.getQName();
+ assertEquals("string", typeQName.getLocalName());
+ assertEquals(fooNS, typeQName.getNamespace());
+ assertEquals(fooRev, typeQName.getRevision());
+ assertNull(type.getUnits());
+ assertNull(type.getDefaultValue());
+ patterns = type.getPatternConstraints();
+ assertTrue(patterns.isEmpty());
+
+ final LeafSchemaNode multiplePatternStringLeaf = (LeafSchemaNode) foo.getDataChildByName("multiple-pattern-string-leaf");
+ type = (ExtendedType) multiplePatternStringLeaf.getType();
+ typeQName = type.getQName();
+ assertEquals("multiple-pattern-string", typeQName.getLocalName());
+ assertEquals(barNS, typeQName.getNamespace());
+ assertEquals(barRev, typeQName.getRevision());
+ assertNull(type.getUnits());
+ assertNull(type.getDefaultValue());
+ patterns = type.getPatternConstraints();
+ assertTrue(!patterns.isEmpty());
+ assertEquals(1, patterns.size());
+ PatternConstraint pattern = patterns.iterator().next();
+ assertEquals("^[e-z]*$", pattern.getRegularExpression());
+ assertTrue(type.getLengthConstraints().isEmpty());
+ assertTrue(type.getRangeConstraints().isEmpty());
+
+ final LeafSchemaNode multiplePatternDirectStringDefLeaf = (LeafSchemaNode) foo.getDataChildByName("multiple-pattern-direct-string-def-leaf");
+ type = (ExtendedType) multiplePatternDirectStringDefLeaf.getType();
+ typeQName = type.getQName();
+ assertEquals("string", typeQName.getLocalName());
+ assertEquals(fooNS, typeQName.getNamespace());
+ assertEquals(fooRev, typeQName.getRevision());
+ assertNull(type.getUnits());
+ assertNull(type.getDefaultValue());
+ patterns = type.getPatternConstraints();
+ assertTrue(!patterns.isEmpty());
+ assertEquals(2, patterns.size());
+
+ boolean isEZPattern = false;
+ boolean isADPattern = false;
+ for (final PatternConstraint patternConstraint : patterns) {
+ if (patternConstraint.getRegularExpression().equals("^[e-z]*$")) {
+ isEZPattern = true;
+ } else if (patternConstraint.getRegularExpression().equals("^[a-d]*$")) {
+ isADPattern = true;
+ }
+ }
+ assertTrue(isEZPattern);
+ assertTrue( isADPattern);
+ }
+
@Test
public void testTypedefLengthsResolving() {
Module foo = TestUtils.findModule(modules, "foo");
List<PatternConstraint> patterns = baseType2.getPatternConstraints();
assertEquals(1, patterns.size());
PatternConstraint pattern = patterns.iterator().next();
- assertEquals("[a-k]*", pattern.getRegularExpression());
+ assertEquals("^[a-k]*$", pattern.getRegularExpression());
List<LengthConstraint> baseType3Lengths = baseType2.getLengthConstraints();
assertEquals(1, baseType3Lengths.size());
length = baseType3Lengths.get(0);
}
}
+ typedef invalid-string-pattern {
+ type string {
+ pattern "[[A-1*-%22!^^}";
+ }
+ }
+
+ typedef multiple-pattern-string {
+ type string {
+ pattern "[[A-1*-%22!^^}";
+ pattern "[e-z]*";
+ }
+ }
+
typedef my-decimal-type {
type decimal64 {
fraction-digits 6;
type br:string-ext4;
}
+ leaf invalid-pattern-string-leaf {
+ type br:invalid-string-pattern;
+ }
+
+ leaf invalid-direct-string-pattern-def-leaf {
+ type string {
+ pattern "[[A-1*-%22!^^}";
+ }
+ }
+
+ leaf multiple-pattern-string-leaf {
+ type br:multiple-pattern-string;
+ }
+
+ leaf multiple-pattern-direct-string-def-leaf {
+ type string {
+ pattern "[e-z]*";
+ pattern "[[A-1*-%22!^^}";
+ pattern "[a-d]*";
+ }
+ }
+
leaf length-leaf {
type br:string-ext2 {
length "7..max";