2 * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.rfc7950.stmt.pattern;
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertFalse;
12 import static org.junit.jupiter.api.Assertions.assertTrue;
14 import java.io.ByteArrayOutputStream;
15 import java.io.PrintStream;
16 import java.io.UnsupportedEncodingException;
17 import java.nio.charset.StandardCharsets;
18 import java.util.List;
19 import org.junit.jupiter.api.Test;
24 testPattern("^", "\\^");
28 void testTextCaret() {
29 testPattern("abc^", "abc\\^");
33 void testTextDollar() {
34 testPattern("abc$", "abc\\$");
38 void testCaretCaret() {
39 testPattern("^^", "\\^\\^");
43 void testCaretDollar() {
44 testPattern("^$", "\\^\\$");
49 testPattern(".", ".");
54 testPattern("[^:]+", "[^:]+");
59 testPattern("$", "\\$");
63 void testDollarOneDollar() {
64 testPattern("$1$", "\\$1\\$");
68 void testDollarPercentRange() {
69 testPattern("[$-%]+", "[$-%]+");
73 void testDollarRange() {
74 testPattern("[$$]+", "[$$]+");
78 void testDollarCaretRange() {
79 testPattern("[$^]+", "[$^]+");
84 testPattern("abc", "abc");
89 testPattern(".+", ".+");
94 testPattern(".*", ".*");
98 void testSimpleOptional() {
99 testPattern("a?", "a?");
103 void testRangeOptional() {
104 testPattern("[a-z]?", "[a-z]?");
108 void testInvalidXSDRegexes() throws UnsupportedEncodingException {
109 testInvalidPattern("$^a^[$^\\]", "Unclosed character class");
110 testInvalidPattern("$(\\)", "Unclosed group");
114 void testJavaPattern() {
115 testPattern("^[$^]+$", List.of("$^", "^", "$"), List.of("\\", "a"));
116 testPattern("^[^$-^]$", List.of("a", "_", "#"), List.of("%", "^", "$", "]", "\\"));
120 void testJavaRegexFromXSD() {
121 testPattern("^[^:]+$", "^(?:\\^[^:]+\\$)$", List.of("^a$", "^abc$"), List.of("abc$", "^abc", "^a:bc$"));
122 testPattern("^[$^]$", "^(?:\\^[$^]\\$)$", List.of("^^$", "^$$"), List.of("^^", "^$", "$^", "$$"));
123 testPattern("[$-%]+", "^(?:[$-%]+)$", List.of("$", "%", "%$"), List.of("$-", "$-%", "-", "^"));
124 testPattern("[$-&]+", "^(?:[$-&]+)$", List.of("$", "%&", "%$", "$%&"), List.of("#", "$-&", "'"));
126 testPattern("[a-z&&[^m-p]]+", "^(?:[a-z&&[^m-p]]+)$", List.of("a", "z", "az"), List.of("m", "anz", "o"));
127 testPattern("^[\\[-b&&[^^-a]]+$", "^(?:\\^[\\[-b&&[^^-a]]+\\$)$",
128 List.of("^[$", "^\\$", "^]$", "^b$"), List.of("^a$", "^^$", "^_$"));
130 // FIXME: YANGTOOLS-887: these patterns are not translated correctly, "&&" is a different construct in XSD
131 // testPattern("[^^-~&&[^$-^]]", "^(?:[^^-~&&[^$-^]])$",
132 // List.of("!", "\"", "#"), List.of("a", "A", "z", "Z", "$", "%", "^", "}"));
133 // testPattern("\\\\\\[^[^^-~&&[^$-^]]", "^(?:\\\\\\[\\^[^^-~&&[^$-^]])$",
134 // List.of("\\[^ ", "\\[^!", "\\[^\"", "\\[^#"),
135 // List.of("\\[^a", "\\[^A", "\\[^z", "\\[^Z", "\\[^$", "\\[^%", "\\[^^", "\\[^}"));
136 // testPattern("^\\[^\\\\[^^-b&&[^\\[-\\]]]\\]^", "^(?:\\^\\[\\^\\\\[^^-b&&[^\\[-\\]]]\\]\\^)$",
137 // List.of("^[^\\c]^", "^[^\\Z]^"),
138 // List.of("^[^\\[]^", "^[^\\\\]^", "^[^\\]]^", "^[^\\^]^", "^[^\\_]^", "^[^\\b]^"));
139 // testPattern("[\\^]$", "^(?:[\\^]\\$)$",
140 // List.of("^$"), List.of("^", "$", "$^", "\\", "\\^", "\\^\\", "\\^\\$"));
143 @SuppressWarnings("checkstyle:regexpSinglelineJava")
144 private static void testInvalidPattern(final String xsdRegex, final String expectedMessage) {
145 final PrintStream stdout = System.out;
146 final ByteArrayOutputStream output = new ByteArrayOutputStream();
147 System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
149 RegexUtils.getJavaRegexFromXSD(xsdRegex);
151 final String testLog = output.toString();
152 assertTrue(testLog.contains(expectedMessage));
153 System.setOut(stdout);
156 private static boolean testMatch(final String javaRegex, final String value) {
157 return value.matches(javaRegex);
160 private static void testPattern(final String xsdRegex, final String unanchoredJavaRegex) {
161 testPattern(xsdRegex, "^(?:" + unanchoredJavaRegex + ")$", List.of(), List.of());
164 private static void testPattern(final String javaRegex, final List<String> positiveMatches,
165 final List<String> negativeMatches) {
166 for (var value : positiveMatches) {
167 assertTrue(testMatch(javaRegex, value),
168 "Value '" + value + "' does not match java regex '" + javaRegex + "'");
170 for (var value : negativeMatches) {
171 assertFalse(testMatch(javaRegex, value), "Value '" + value + "' matches java regex '" + javaRegex + "'");
175 private static void testPattern(final String xsdRegex, final String expectedJavaRegex,
176 final List<String> positiveMatches, final List<String> negativeMatches) {
177 final String javaRegexFromXSD = RegexUtils.getJavaRegexFromXSD(xsdRegex);
178 assertEquals(expectedJavaRegex, javaRegexFromXSD);
180 for (var value : positiveMatches) {
181 assertTrue(testMatch(javaRegexFromXSD, value),
182 "Value '" + value + "' does not match java regex '" + javaRegexFromXSD + "'");
184 for (var value : negativeMatches) {
185 assertFalse(testMatch(javaRegexFromXSD, value),
186 "Value '" + value + "' matches java regex '" + javaRegexFromXSD + "'");