dd6302374730316eab90fdd826aabcf2079021c1
[yangtools.git] / yang / yang-parser-impl / src / test / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / Bug5410Test.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
9
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;
14
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;
30
31 public class Bug5410Test {
32     private static final String FOO_NS = "foo";
33
34     @Test
35     public void testJavaRegexFromXSD() {
36         testPattern("^[^:]+$", "^\\^[^:]+\\$$", ImmutableList.of("^a$", "^abc$"),
37                 ImmutableList.of("abc$", "^abc", "^a:bc$"));
38         testPattern("^[$^]$", "^\\^[$^]\\$$", ImmutableList.of("^^$", "^$$"), ImmutableList.of("^^", "^$", "$^", "$$"));
39         testPattern("[$-%]+", "^[$-%]+$", ImmutableList.of("$", "%", "%$"), ImmutableList.of("$-", "$-%", "-", "^"));
40         testPattern("[$-&]+", "^[$-&]+$", ImmutableList.of("$", "%&", "%$", "$%&"), ImmutableList.of("#", "$-&", "'"));
41
42         testPattern("[a-z&&[^m-p]]+", "^[a-z&&[^m-p]]+$", ImmutableList.of("a", "z", "az"),
43                 ImmutableList.of("m", "anz", "o"));
44         testPattern("^[\\[-b&&[^^-a]]+$", "^\\^[\\[-b&&[^^-a]]+\\$$", ImmutableList.of("^[$", "^\\$", "^]$", "^b$"),
45                 ImmutableList.of("^a$", "^^$", "^_$"));
46
47         testPattern("[^^-~&&[^$-^]]", "^[^^-~&&[^$-^]]$", ImmutableList.of("!", "\"", "#"),
48                 ImmutableList.of("a", "A", "z", "Z", "$", "%", "^", "}"));
49         testPattern("\\\\\\[^[^^-~&&[^$-^]]", "^\\\\\\[\\^[^^-~&&[^$-^]]$",
50                 ImmutableList.of("\\[^ ", "\\[^!", "\\[^\"", "\\[^#"),
51                 ImmutableList.of("\\[^a", "\\[^A", "\\[^z", "\\[^Z", "\\[^$", "\\[^%", "\\[^^", "\\[^}"));
52         testPattern("^\\[^\\\\[^^-b&&[^\\[-\\]]]\\]^", "^\\^\\[\\^\\\\[^^-b&&[^\\[-\\]]]\\]\\^$",
53                 ImmutableList.of("^[^\\c]^", "^[^\\Z]^"),
54                 ImmutableList.of("^[^\\[]^", "^[^\\\\]^", "^[^\\]]^", "^[^\\^]^", "^[^\\_]^", "^[^\\b]^"));
55         testPattern("[\\^]$", "^[\\^]\\$$", ImmutableList.of("^$"),
56                 ImmutableList.of("^", "$", "$^", "\\", "\\^", "\\^\\", "\\^\\$"));
57     }
58
59     @Test
60     public void testInvalidXSDRegexes() throws UnsupportedEncodingException {
61         testInvalidPattern("$^a^[$^\\]", "Unclosed character class");
62         testInvalidPattern("$(\\)", "Unclosed group");
63     }
64
65     @Test
66     public void testJavaPattern() {
67         testPattern("^[$^]+$", ImmutableList.of("$^", "^", "$"), ImmutableList.of("\\", "a"));
68         testPattern("^[^$-^]$", ImmutableList.of("a", "_", "#"), ImmutableList.of("%", "^", "$", "]", "\\"));
69     }
70
71     @Test
72     public void testYangPattern() throws Exception {
73         final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5410");
74         assertNotNull(context);
75
76         final PatternConstraint pattern = getPatternConstraintOf(context, "leaf-with-pattern");
77
78         final String rawRegex = pattern.getRegularExpressionString();
79         final String expectedYangRegex = "$0$.*|$1$[a-zA-Z0-9./]{1,8}$[a-zA-Z0-9./]{22}|$5$(rounds=\\d+$)?"
80                 + "[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);
82
83         final String javaRegexFromYang = pattern.getJavaPatternString();
84         final String expectedJavaRegex = "^\\$0\\$.*|\\$1\\$[a-zA-Z0-9./]{1,8}\\$[a-zA-Z0-9./]{22}|\\$5\\$"
85                 + "(rounds=\\d+\\$)?[a-zA-Z0-9./]{1,16}\\$[a-zA-Z0-9./]{43}|\\$6\\$(rounds=\\d+\\$)?"
86                 + "[a-zA-Z0-9./]{1,16}\\$[a-zA-Z0-9./]{86}$";
87         assertEquals(expectedJavaRegex, javaRegexFromYang);
88
89         final String value = "$6$AnrKGc0V$B/0/A.pWg4HrrA6YiEJOtFGibQ9Fmm5.4rI/"
90                 + "00gEz3QeB7joSxBU3YtbHDm6NSkS1dKTQy3BWhwKKDS8nB5S//";
91         testPattern(javaRegexFromYang, ImmutableList.of(value), ImmutableList.of());
92     }
93
94     @Test
95     public void testCaret() {
96         testPattern("^", "\\^");
97     }
98
99     @Test
100     public void testTextCaret() {
101         testPattern("abc^", "abc\\^");
102     }
103
104     @Test
105     public void testTextDollar() {
106         testPattern("abc$", "abc\\$");
107     }
108
109     @Test
110     public void testCaretCaret() {
111         testPattern("^^", "\\^\\^");
112     }
113
114     @Test
115     public void testCaretDollar() {
116         testPattern("^$", "\\^\\$");
117     }
118
119     @Test
120     public void testDot() {
121         testPattern(".", ".");
122     }
123
124     @Test
125     public void testNotColon() {
126         testPattern("[^:]+", "[^:]+");
127     }
128
129     @Test
130     public void testDollar() {
131         testPattern("$", "\\$");
132     }
133
134     @Test
135     public void testDollarOneDollar() {
136         testPattern("$1$", "\\$1\\$");
137     }
138
139     @Test
140     public void testDollarPercentRange() {
141         testPattern("[$-%]+", "[$-%]+");
142     }
143
144     @Test
145     public void testDollarRange() {
146         testPattern("[$$]+", "[$$]+");
147     }
148
149     @Test
150     public void testDollarCaretRange() {
151         testPattern("[$^]+", "[$^]+");
152     }
153
154     @Test
155     public void testSimple() {
156         testPattern("abc", "abc");
157     }
158
159     @Test
160     public void testDotPlus() {
161         testPattern(".+", ".+");
162     }
163
164     @Test
165     public void testDotStar() {
166         testPattern(".*", ".*");
167     }
168
169     @Test
170     public void testSimpleOptional() {
171         testPattern("a?", "a?");
172     }
173
174     @Test
175     public void testRangeOptional() {
176         testPattern("[a-z]?", "[a-z]?");
177     }
178
179     private static void testPattern(final String xsdRegex, final String expectedJavaRegex,
180             final List<String> positiveMatches, final List<String> negativeMatches) {
181         final String javaRegexFromXSD = javaRegexFromXSD(xsdRegex);
182         assertEquals(expectedJavaRegex, javaRegexFromXSD);
183
184         for (final String value : positiveMatches) {
185             assertTrue("Value '" + value + "' does not match java regex '" + javaRegexFromXSD + "'",
186                     testMatch(javaRegexFromXSD, value));
187         }
188         for (final String value : negativeMatches) {
189             assertFalse("Value '" + value + "' matches java regex '" + javaRegexFromXSD + "'",
190                     testMatch(javaRegexFromXSD, value));
191         }
192     }
193
194     private static void testPattern(final String javaRegex, final List<String> positiveMatches,
195             final List<String> negativeMatches) {
196         for (final String value : positiveMatches) {
197             assertTrue("Value '" + value + "' does not match java regex '" + javaRegex + "'",
198                     testMatch(javaRegex, value));
199         }
200         for (final String value : negativeMatches) {
201             assertFalse("Value '" + value + "' matches java regex '" + javaRegex + "'", testMatch(javaRegex, value));
202         }
203     }
204
205     private static void testPattern(final String xsdRegex, final String unanchoredJavaRegex) {
206         testPattern(xsdRegex, '^' + unanchoredJavaRegex + '$', ImmutableList.of(), ImmutableList.of());
207     }
208
209     private static boolean testMatch(final String javaRegex, final String value) {
210         return value.matches(javaRegex);
211     }
212
213     private static String javaRegexFromXSD(final String xsdRegex) {
214         return RegexUtils.getJavaRegexFromXSD(xsdRegex);
215     }
216
217     private static PatternConstraint getPatternConstraintOf(final SchemaContext context, final String leafName) {
218         final DataSchemaNode dataChildByName = context.getDataChildByName(foo(leafName));
219         assertTrue(dataChildByName instanceof LeafSchemaNode);
220         final LeafSchemaNode leaf = (LeafSchemaNode) dataChildByName;
221         final TypeDefinition<? extends TypeDefinition<?>> type = leaf.getType();
222         assertTrue(type instanceof StringTypeDefinition);
223         final StringTypeDefinition strType = (StringTypeDefinition) type;
224         return strType.getPatternConstraints().iterator().next();
225     }
226
227     private static QName foo(final String localName) {
228         return QName.create(FOO_NS, localName);
229     }
230
231     @SuppressWarnings("checkstyle:regexpSinglelineJava")
232     private static void testInvalidPattern(final String xsdRegex, final String expectedMessage)
233             throws UnsupportedEncodingException {
234         final PrintStream stdout = System.out;
235         final ByteArrayOutputStream output = new ByteArrayOutputStream();
236         System.setOut(new PrintStream(output, true, "UTF-8"));
237
238         javaRegexFromXSD(xsdRegex);
239
240         final String testLog = output.toString();
241         assertTrue(testLog.contains(expectedMessage));
242         System.setOut(stdout);
243     }
244 }