2 * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
15 import com.google.common.collect.ImmutableList;
16 import java.io.ByteArrayOutputStream;
17 import java.io.PrintStream;
18 import java.io.UnsupportedEncodingException;
19 import java.util.List;
20 import org.junit.Test;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
25 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
27 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.util.RegexUtils;
29 import org.opendaylight.yangtools.yang.stmt.StmtTestUtils;
31 public class Bug5410Test {
32 private static final String FOO_NS = "foo";
33 private static final String FOO_REV = "1970-01-01";
36 public void testJavaRegexFromXSD() {
37 testPattern("^[^:]+$", "^\\^[^:]+\\$$", ImmutableList.of("^a$", "^abc$"),
38 ImmutableList.of("abc$", "^abc", "^a:bc$"));
39 testPattern("^[$^]$", "^\\^[$^]\\$$", ImmutableList.of("^^$", "^$$"), ImmutableList.of("^^", "^$", "$^", "$$"));
40 testPattern("[$-%]+", "^[$-%]+$", ImmutableList.of("$", "%", "%$"), ImmutableList.of("$-", "$-%", "-", "^"));
41 testPattern("[$-&]+", "^[$-&]+$", ImmutableList.of("$", "%&", "%$", "$%&"), ImmutableList.of("#", "$-&", "'"));
43 testPattern("[a-z&&[^m-p]]+", "^[a-z&&[^m-p]]+$", ImmutableList.of("a", "z", "az"),
44 ImmutableList.of("m", "anz", "o"));
45 testPattern("^[\\[-b&&[^^-a]]+$", "^\\^[\\[-b&&[^^-a]]+\\$$", ImmutableList.of("^[$", "^\\$", "^]$", "^b$"),
46 ImmutableList.of("^a$", "^^$", "^_$"));
48 testPattern("[^^-~&&[^$-^]]", "^[^^-~&&[^$-^]]$", ImmutableList.of("!", "\"", "#"),
49 ImmutableList.of("a", "A", "z", "Z", "$", "%", "^", "}"));
50 testPattern("\\\\\\[^[^^-~&&[^$-^]]", "^\\\\\\[\\^[^^-~&&[^$-^]]$",
51 ImmutableList.of("\\[^ ", "\\[^!", "\\[^\"", "\\[^#"),
52 ImmutableList.of("\\[^a", "\\[^A", "\\[^z", "\\[^Z", "\\[^$", "\\[^%", "\\[^^", "\\[^}"));
53 testPattern("^\\[^\\\\[^^-b&&[^\\[-\\]]]\\]^", "^\\^\\[\\^\\\\[^^-b&&[^\\[-\\]]]\\]\\^$",
54 ImmutableList.of("^[^\\c]^", "^[^\\Z]^"),
55 ImmutableList.of("^[^\\[]^", "^[^\\\\]^", "^[^\\]]^", "^[^\\^]^", "^[^\\_]^", "^[^\\b]^"));
56 testPattern("[\\^]$", "^[\\^]\\$$", ImmutableList.of("^$"),
57 ImmutableList.of("^", "$", "$^", "\\", "\\^", "\\^\\", "\\^\\$"));
61 public void testInvalidXSDRegexes() throws UnsupportedEncodingException {
62 testInvalidPattern("$^a^[$^\\]", "Unclosed character class");
63 testInvalidPattern("$(\\)", "Unclosed group");
67 public void testJavaPattern() {
68 testPattern("^[$^]+$", ImmutableList.of("$^", "^", "$"), ImmutableList.of("\\", "a"));
69 testPattern("^[^$-^]$", ImmutableList.of("a", "_", "#"), ImmutableList.of("%", "^", "$", "]", "\\"));
73 public void testYangPattern() throws Exception {
74 final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5410");
75 assertNotNull(context);
77 final PatternConstraint pattern = getPatternConstraintOf(context, "leaf-with-pattern");
79 final String rawRegex = pattern.getRawRegularExpression();
80 final String expectedYangRegex = "$0$.*|$1$[a-zA-Z0-9./]{1,8}$[a-zA-Z0-9./]{22}|$5$(rounds=\\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{43}|$6$(rounds=\\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{86}";
81 assertEquals(expectedYangRegex, rawRegex);
83 final String javaRegexFromYang = pattern.getRegularExpression();
84 final String expectedJavaRegex = "^\\$0\\$.*|\\$1\\$[a-zA-Z0-9./]{1,8}\\$[a-zA-Z0-9./]{22}|\\$5\\$(rounds=\\d+\\$)?[a-zA-Z0-9./]{1,16}\\$[a-zA-Z0-9./]{43}|\\$6\\$(rounds=\\d+\\$)?[a-zA-Z0-9./]{1,16}\\$[a-zA-Z0-9./]{86}$";
85 assertEquals(expectedJavaRegex, javaRegexFromYang);
87 final String value = "$6$AnrKGc0V$B/0/A.pWg4HrrA6YiEJOtFGibQ9Fmm5.4rI/00gEz3QeB7joSxBU3YtbHDm6NSkS1dKTQy3BWhwKKDS8nB5S//";
88 testPattern(javaRegexFromYang, ImmutableList.of(value), ImmutableList.of());
92 public void testCaret() {
93 testPattern("^", "\\^");
97 public void testTextCaret() {
98 testPattern("abc^", "abc\\^");
102 public void testTextDollar() {
103 testPattern("abc$", "abc\\$");
107 public void testCaretCaret() {
108 testPattern("^^", "\\^\\^");
112 public void testCaretDollar() {
113 testPattern("^$", "\\^\\$");
117 public void testDot() {
118 testPattern(".", ".");
122 public void testNotColon() {
123 testPattern("[^:]+", "[^:]+");
127 public void testDollar() {
128 testPattern("$", "\\$");
132 public void testDollarOneDollar() {
133 testPattern("$1$", "\\$1\\$");
137 public void testDollarPercentRange() {
138 testPattern("[$-%]+", "[$-%]+");
142 public void testDollarRange() {
143 testPattern("[$$]+", "[$$]+");
147 public void testDollarCaretRange() {
148 testPattern("[$^]+", "[$^]+");
152 public void testSimple() {
153 testPattern("abc", "abc");
157 public void testDotPlus() {
158 testPattern(".+", ".+");
162 public void testDotStar() {
163 testPattern(".*", ".*");
167 public void testSimpleOptional() {
168 testPattern("a?", "a?");
172 public void testRangeOptional() {
173 testPattern("[a-z]?", "[a-z]?");
176 private static void testPattern(final String xsdRegex, final String expectedJavaRegex,
177 final List<String> positiveMatches, final List<String> negativeMatches) {
178 final String javaRegexFromXSD = javaRegexFromXSD(xsdRegex);
179 assertEquals(expectedJavaRegex, javaRegexFromXSD);
181 for (final String value : positiveMatches) {
182 assertTrue("Value '" + value + "' does not match java regex '" + javaRegexFromXSD + "'",
183 testMatch(javaRegexFromXSD, value));
185 for (final String value : negativeMatches) {
186 assertFalse("Value '" + value + "' matches java regex '" + javaRegexFromXSD + "'",
187 testMatch(javaRegexFromXSD, value));
191 private static void testPattern(final String javaRegex, final List<String> positiveMatches,
192 final List<String> negativeMatches) {
193 for (final String value : positiveMatches) {
194 assertTrue("Value '" + value + "' does not match java regex '" + javaRegex + "'",
195 testMatch(javaRegex, value));
197 for (final String value : negativeMatches) {
198 assertFalse("Value '" + value + "' matches java regex '" + javaRegex + "'", testMatch(javaRegex, value));
202 private static String javaRegexFromXSD(final String xsdRegex) {
203 return RegexUtils.getJavaRegexFromXSD(xsdRegex);
206 private static boolean testMatch(final String javaRegex, final String value) {
207 return value.matches(javaRegex);
210 private static void testPattern(final String xsdRegex, final String unanchoredJavaRegex) {
211 testPattern(xsdRegex, '^' + unanchoredJavaRegex + '$', ImmutableList.of(), ImmutableList.of());
214 private static PatternConstraint getPatternConstraintOf(final SchemaContext context, final String leafName) {
215 final DataSchemaNode dataChildByName = context.getDataChildByName(foo(leafName));
216 assertTrue(dataChildByName instanceof LeafSchemaNode);
217 final LeafSchemaNode leaf = (LeafSchemaNode) dataChildByName;
218 final TypeDefinition<? extends TypeDefinition<?>> type = leaf.getType();
219 assertTrue(type instanceof StringTypeDefinition);
220 final StringTypeDefinition strType = (StringTypeDefinition) type;
221 return strType.getPatternConstraints().iterator().next();
224 private static QName foo(final String localName) {
225 return QName.create(FOO_NS, FOO_REV, localName);
228 private static void testInvalidPattern(final String xsdRegex, final String expectedMessage) throws UnsupportedEncodingException {
229 final PrintStream stdout = System.out;
230 final ByteArrayOutputStream output = new ByteArrayOutputStream();
231 System.setOut(new PrintStream(output, true, "UTF-8"));
233 javaRegexFromXSD(xsdRegex);
235 final String testLog = output.toString();
236 assertTrue(testLog.contains(expectedMessage));
237 System.setOut(stdout);