diff --git a/README.md b/README.md
index 97145c2e..57ffe460 100644
--- a/README.md
+++ b/README.md
@@ -149,8 +149,8 @@ public class Main {
| `[...]` | Single character from ones that are inside brackets. `[a-zA-Z]` (dash) also supported |
| `[^...]` | Single character except the ones in brackets. `[^a]` - any symbol except 'a' |
| `()` | To group multiple characters for the repetitions |
-| `foo(?=bar)` and `(?<=foo)bar` | Positive lookahead and lookbehind. These are equivalent to `foobar` |
-| `foo(?!bar)` and `(?(a|b) | Alternatives |
| \\ | Escape character (use \\\\ (double backslash) to generate single \ character) |
diff --git a/pom.xml b/pom.xml
index e389afd6..05ac51c9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,21 +21,21 @@
3.6.1
- 5.10.0-M1
- 1.10.0-M1
- 1.36
+ 5.10.1
+ 1.10.1
+ 1.37
- 3.11.0
- 3.1.0
- 3.2.1
- 3.5.0
+ 3.12.1
+ 3.2.5
+ 3.3.0
+ 3.6.3
3.1.0
- 3.3.0
+ 3.4.1
1.6.13
- 2.15.0
+ 2.16.2
- 0.8.10
+ 0.8.11
diff --git a/src/main/java/com/github/curiousoddman/rgxgen/visitors/NotMatchingGenerationVisitor.java b/src/main/java/com/github/curiousoddman/rgxgen/visitors/NotMatchingGenerationVisitor.java
index 15fc9d1d..494f746f 100644
--- a/src/main/java/com/github/curiousoddman/rgxgen/visitors/NotMatchingGenerationVisitor.java
+++ b/src/main/java/com/github/curiousoddman/rgxgen/visitors/NotMatchingGenerationVisitor.java
@@ -72,12 +72,11 @@ public void visit(Choice node) {
int i = aRandom.nextInt(nodes.length);
nodes[i].visit(this);
// To match group values along with generated values - we need to prepend groups values before the generated
- } while (pattern.matcher(valuePrefixBuilder + aStringBuilder.substring(pos))
- .matches());
+ } while (pattern.matcher(valuePrefixBuilder + aStringBuilder.substring(pos)).matches());
}
/**
- * We need to add existing group values, so that we could later use it in a matching pattern
+ * Need to add existing group values, so that we could later use it in a matching pattern
*
* @param groupsBuilder
* @param valuePrefixBuilder
diff --git a/src/test/java/com/github/curiousoddman/rgxgen/CompleteTests.java b/src/test/java/com/github/curiousoddman/rgxgen/CompleteTests.java
index 0cb0b785..63ff3511 100644
--- a/src/test/java/com/github/curiousoddman/rgxgen/CompleteTests.java
+++ b/src/test/java/com/github/curiousoddman/rgxgen/CompleteTests.java
@@ -6,6 +6,8 @@
import org.junit.jupiter.params.provider.MethodSource;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
@@ -61,9 +63,11 @@ public static Stream getData() {
{"Periodic Table Elements", Boolean.FALSE, "\\b(?:A[cglmr-u]|B[aehikr]?|C[adefl-orsu]?|D[bsy]|E[rsu]|F[elmr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airuv]|M[dgont]|N[abdeiop]?|Os?|P[abdmortu]?|R[abe-hnu]|S[bcegimnr]?|T[abcehilm]|U(?:u[opst])?|V|W|Xe|Yb?|Z[nr])\\b"},
{"Russia Phone Number", Boolean.FALSE, "^((\\+7|7|8)+([0-9]){10})$|\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b"},
{"Brainfuck code", Boolean.FALSE, "^[+-<>.,\\[\\] \t\n\r]+$"},
- {"USA/Canada Zip codes", Boolean.FALSE, "(^\\d{5}(-\\d{4})?$)|(^[A-Z]{1}\\d{1}[A-Z]{1} *\\d{1}[A-Z]{1}\\d{1}$)"},
+ {"USA and Canada Zip codes", Boolean.FALSE, "(^\\d{5}(-\\d{4})?$)|(^[A-Z]{1}\\d{1}[A-Z]{1} *\\d{1}[A-Z]{1}\\d{1}$)"},
{"JS comments", Boolean.TRUE, "//(?![\\S]{2,}\\.[\\w]).*|/\\*(.|\n)+\\*/"},
{"2-5 letter palindromes", Boolean.FALSE, "\\b(\\w?)(\\w)\\w?\\2\\1"},
+ {"Morse code", Boolean.TRUE, "^[.-]{1,5}(?: +[.-]{1,5})*(?: +[.-]{1,5}(?: +[.-]{1,5})*)$"},
+ {"JWT", Boolean.TRUE, "^[A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]+\\.?[A-Za-z0-9-_.+/=]*$"},
})
.flatMap(arr -> IntStream.range(0, 100)
.mapToObj(index -> Arguments.of(arr[0], arr[1], arr[2], index)));
@@ -86,8 +90,11 @@ public void generateNotMatchingTest(String aName, boolean aUseFind, String aRege
assertFalse(matches(aRegex, s, aUseFind), "Text: '" + s + "'does not match pattern " + aRegex);
}
- private boolean matches(String aRegex, String text, boolean aUseFind) {
- Matcher matcher = Pattern.compile(aRegex).matcher(text);
+ private static Map PATTERN_CACHE = new HashMap<>();
+
+ private static boolean matches(String pattern, String text, boolean aUseFind) {
+ Pattern compiledPattern = PATTERN_CACHE.computeIfAbsent(pattern, k -> Pattern.compile(pattern));
+ Matcher matcher = compiledPattern.matcher(text);
return aUseFind ? matcher.find() : matcher.matches();
}
}
diff --git a/src/test/java/com/github/curiousoddman/rgxgen/GenerationConsistencyTests.java b/src/test/java/com/github/curiousoddman/rgxgen/GenerationConsistencyTests.java
index f16bb0a7..8c6216e3 100644
--- a/src/test/java/com/github/curiousoddman/rgxgen/GenerationConsistencyTests.java
+++ b/src/test/java/com/github/curiousoddman/rgxgen/GenerationConsistencyTests.java
@@ -4,7 +4,10 @@
import com.github.curiousoddman.rgxgen.config.RgxGenProperties;
import com.github.curiousoddman.rgxgen.data.TestPattern;
import com.github.curiousoddman.rgxgen.data.TestPatternCaseInsensitive;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.IOException;
@@ -15,13 +18,14 @@
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Random;
+import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.github.curiousoddman.rgxgen.testutil.TestingUtilities.newRandom;
import static java.util.Collections.singletonList;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.fail;
-import static org.junit.jupiter.api.Assumptions.assumeFalse;
/**
* The aim of these test is to show that the result of generation was changed by writing values generated with same seed into a text file.
@@ -45,12 +49,40 @@ public static Stream getPatterns() {
return Arrays.stream(TestPattern.values());
}
+ public static Stream getCompleteTestsPatterns() {
+ return CompleteTests.getData();
+ }
+
+ @BeforeAll
+ static void cleanupFiles() throws IOException {
+ try (Stream pathStream = Files.walk(caseInsensitivePath)) {
+ pathStream.filter(Files::isRegularFile)
+ .forEach(path -> {
+ try {
+ Files.delete(path);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ try (Stream pathStream = Files.walk(caseSensitivePath)) {
+ pathStream.filter(Files::isRegularFile)
+ .forEach(path -> {
+ try {
+ Files.delete(path);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+ }
+
@ParameterizedTest
@MethodSource("getCaseInsensitivePatterns")
void verifyThatAllCaseInsensitivePatternsStaysTheSameTest(TestPatternCaseInsensitive data) throws IOException {
String name = data.name();
- Path fileName = caseInsensitivePath.resolve("matching").resolve(name + ".txt").toAbsolutePath();
- Files.deleteIfExists(fileName);
+ Path fileName = caseInsensitivePath.resolve("matching").resolve(createFileName(name)).toAbsolutePath();
RgxGenProperties properties = new RgxGenProperties();
RgxGenOption.CASE_INSENSITIVE.setInProperties(properties, true);
RgxGen rgxGen = RgxGen.parse(properties, data.getPattern());
@@ -65,8 +97,7 @@ void verifyThatAllCaseInsensitivePatternsStaysTheSameTest(TestPatternCaseInsensi
@MethodSource("getCaseInsensitivePatterns")
void verifyThatAllCaseInsensitivePatternsStaysTheSameNotMatchingTest(TestPatternCaseInsensitive data) throws IOException {
String name = data.name();
- Path fileName = caseInsensitivePath.resolve("notmatching").resolve(name + ".txt").toAbsolutePath();
- Files.deleteIfExists(fileName);
+ Path fileName = caseInsensitivePath.resolve("notmatching").resolve(createFileName(name)).toAbsolutePath();
RgxGenProperties properties = new RgxGenProperties();
RgxGenOption.CASE_INSENSITIVE.setInProperties(properties, true);
RgxGen rgxGen = RgxGen.parse(properties, data.getPattern());
@@ -81,8 +112,7 @@ void verifyThatAllCaseInsensitivePatternsStaysTheSameNotMatchingTest(TestPattern
@MethodSource("getPatterns")
void verifyThatAllCaseSensitivePatternsStaysTheSameTest(TestPattern data) throws IOException {
String name = data.name();
- Path fileName = caseSensitivePath.resolve("matching").resolve(name + ".txt").toAbsolutePath();
- Files.deleteIfExists(fileName);
+ Path fileName = caseSensitivePath.resolve("matching").resolve(createFileName(name)).toAbsolutePath();
RgxGen rgxGen = RgxGen.parse(data.getPattern());
Random random = newRandom(17);
for (int i = 0; i < NUM_ITERATIONS; i++) {
@@ -96,8 +126,7 @@ void verifyThatAllCaseSensitivePatternsStaysTheSameTest(TestPattern data) throws
@MethodSource("getPatterns")
void verifyThatAllCaseSensitivePatternsStaysTheSameNotMatchingTest(TestPattern data) throws IOException {
String name = data.name();
- Path fileName = caseSensitivePath.resolve("notmatching").resolve(name + ".txt").toAbsolutePath();
- Files.deleteIfExists(fileName);
+ Path fileName = caseSensitivePath.resolve("notmatching").resolve(createFileName(name)).toAbsolutePath();
RgxGen rgxGen = RgxGen.parse(data.getPattern());
Random random = newRandom(17);
for (int i = 0; i < NUM_ITERATIONS; i++) {
@@ -112,4 +141,51 @@ void verifyThatAllCaseSensitivePatternsStaysTheSameNotMatchingTest(TestPattern d
}
}
}
+
+ @Test
+ void verifyCompletePatternsHaveDifferentNames() {
+ assertDoesNotThrow(() -> {
+ getCompleteTestsPatterns()
+ .filter(arguments -> (int) arguments.get()[3] == 0) // Seed is 0
+ .map(arguments -> arguments.get()[0])
+ .map(Object::toString)
+ .collect(Collectors.toMap(Function.identity(), Function.identity()));
+ });
+ }
+
+ @ParameterizedTest(name = "{index}: {0}")
+ @MethodSource("getCompleteTestsPatterns")
+ public void generateTest(String name, boolean aUseFind, String aRegex, int aSeed) throws IOException {
+ Path fileName = caseSensitivePath.resolve("matching").resolve(createFileName(name)).toAbsolutePath();
+ RgxGen rgxGen = RgxGen.parse(aRegex);
+ String generated = rgxGen.generate(newRandom(aSeed));
+ try {
+ Files.write(fileName, singletonList(generated), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
+ } catch (MalformedInputException e) {
+ System.out.println("Failed to write a text " + e.getMessage());
+ System.out.println(generated.chars().mapToObj(String::valueOf).collect(Collectors.toList()));
+ System.out.println(generated);
+ fail(e);
+ }
+ }
+
+ @ParameterizedTest(name = "{index}: {0}")
+ @MethodSource("getCompleteTestsPatterns")
+ public void generateNotMatchingTest(String name, boolean aUseFind, String aRegex, int aSeed) throws IOException {
+ Path fileName = caseSensitivePath.resolve("notmatching").resolve(createFileName(name)).toAbsolutePath();
+ RgxGen rgxGen = RgxGen.parse(aRegex);
+ String generated = rgxGen.generateNotMatching(newRandom(aSeed));
+ try {
+ Files.write(fileName, singletonList(generated), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
+ } catch (MalformedInputException e) {
+ System.out.println("Failed to write a text " + e.getMessage());
+ System.out.println(generated.chars().mapToObj(String::valueOf).collect(Collectors.toList()));
+ System.out.println(generated);
+ fail(e);
+ }
+ }
+
+ private static String createFileName(String name) {
+ return name.replace('/', '_').replace('\\', '_') + ".txt";
+ }
}
diff --git a/src/test/java/com/github/curiousoddman/rgxgen/TmpCompleteTests.java b/src/test/java/com/github/curiousoddman/rgxgen/TmpCompleteTests.java
index be047be0..41896513 100644
--- a/src/test/java/com/github/curiousoddman/rgxgen/TmpCompleteTests.java
+++ b/src/test/java/com/github/curiousoddman/rgxgen/TmpCompleteTests.java
@@ -1,6 +1,5 @@
package com.github.curiousoddman.rgxgen;
-import com.github.curiousoddman.rgxgen.testutil.TestingUtilities;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -12,6 +11,7 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;
+import static com.github.curiousoddman.rgxgen.testutil.TestingUtilities.newRandom;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -21,15 +21,20 @@ public class TmpCompleteTests {
public static Stream getTestData() {
return Arrays.stream(new Object[][]{
- //{"Test", Boolean.FALSE, "a\nb"}
- {"Morse code", Boolean.TRUE, "^[.-]{1,5}(?:[ \t]+[.-]{1,5})*(?:[ \t]+[.-]{1,5}(?:[ \t]+[.-]{1,5})*)*$"}, // Very slow not matching generation. + java.regex fails to parse..
- // {"Morse code", Boolean.TRUE, "^[.-]{1,5}(?: +[.-]{1,5})*(?: +[.-]{1,5}(?: +[.-]{1,5})*)*$"}, // Very slow not matching generation. + java.regex fails to parse..
- // {"Domain name", Boolean.TRUE, "(?!w{1,}\\.)(\\w+\\.?)([a-zA-Z]+)(\\.\\w+)"}, // Fails infrequently...
- // {"ISO-8601 Date", Boolean.TRUE, "^(?![+-]?\\d{4,5}-?(?:\\d{2}|W\\d{2})T)(?:|(\\d{4}|[+-]\\d{5})-?(?:|(0\\d|1[0-2])(?:|-?([0-2]\\d|3[0-1]))|([0-2]\\d{2}|3[0-5]\\d|36[0-6])|W([0-4]\\d|5[0-3])(?:|-?([1-7])))(?:(?!\\d)|T(?=\\d)))(?:|([01]\\d|2[0-4])(?:|:?([0-5]\\d)(?:|:?([0-5]\\d)(?:|\\.(\\d{3})))(?:|[zZ]|([+-](?:[01]\\d|2[0-4]))(?:|:?([0-5]\\d)))))$"}, // Something totally wrong
- // {"Unix Path", Boolean.TRUE, "/|((?=/)|\\.|\\.\\.|~|~(?=/))(/(?=[^/])[^/]+)*/?"}, // Not matching generation fails
- // {"Hashtags", Boolean.TRUE, "\\B#([a-z0-9]{2,})(?![~!@#$%^&*()=+_`\\-\\|\\/'\\[\\]\\{\\}]|[?.,]*\\w)"}, // This partially fails
- // {"HTML Tags", Boolean.FALSE, "()|(