Xeger can cause stackoverflow and doesn't understand \d \w \s
fixes gh-589, fixes gh-590
This commit is contained in:
@@ -31,11 +31,16 @@ import dk.brics.automaton.Transition;
|
||||
/**
|
||||
* An object that will generate text from a regular expression. In a way, it's the opposite of a regular expression
|
||||
* matcher: an instance of this class will produce text that is guaranteed to match the regular expression passed in.
|
||||
*
|
||||
* slight modifications by Marcin Grzejszczak
|
||||
*/
|
||||
public class Xeger {
|
||||
|
||||
private final Automaton automaton;
|
||||
private Random random;
|
||||
// Added by Marcin Grzejszczak
|
||||
// may lead to stackoverflow when regex is unbounded
|
||||
static int ITERATION_LIMIT = 200;
|
||||
|
||||
/**
|
||||
* Constructs a new instance, accepting the regular expression and the randomizer.
|
||||
@@ -47,7 +52,12 @@ public class Xeger {
|
||||
public Xeger(String regex, Random random) {
|
||||
assert regex != null;
|
||||
assert random != null;
|
||||
this.automaton = new RegExp(regex).toAutomaton();
|
||||
// https://stackoverflow.com/questions/1578789/how-do-i-generate-text-matching-a-regular-expression-from-a-regular-expression
|
||||
String pattern = regex
|
||||
.replace("\\d", "[0-9]") // Used d=Digit
|
||||
.replace("\\w", "[A-Za-z0-9_]") // Used =Word
|
||||
.replace("\\s", "[ \t\r\n]"); // Used s="White"Space
|
||||
this.automaton = new RegExp(pattern).toAutomaton();
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
@@ -67,11 +77,15 @@ public class Xeger {
|
||||
*/
|
||||
public String generate() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
generate(builder, this.automaton.getInitialState());
|
||||
int counter = 0;
|
||||
generate(builder, this.automaton.getInitialState(), counter);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void generate(StringBuilder builder, State state) {
|
||||
private void generate(StringBuilder builder, State state, int counter) {
|
||||
if (counter >= ITERATION_LIMIT) {
|
||||
return;
|
||||
}
|
||||
List<Transition> transitions = state.getSortedTransitions(false);
|
||||
if (transitions.size() == 0) {
|
||||
assert state.isAccept();
|
||||
@@ -85,7 +99,7 @@ public class Xeger {
|
||||
// Moving on to next transition
|
||||
Transition transition = transitions.get(option - (state.isAccept() ? 1 : 0));
|
||||
appendChoice(builder, transition);
|
||||
generate(builder, transition.getDest());
|
||||
generate(builder, transition.getDest(), ++counter);
|
||||
}
|
||||
|
||||
private void appendChoice(StringBuilder builder, Transition transition) {
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
*/
|
||||
package repackaged.nl.flotsam.xeger;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -38,6 +38,47 @@ public class XegerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotGenerateMoreThanTheLimit() {
|
||||
String regex = "[ab]{5}";
|
||||
Xeger.ITERATION_LIMIT = 1;
|
||||
Xeger generator = new Xeger(regex);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String text = generator.generate();
|
||||
assertTrue(text.length() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGenerateTextCorrectlyForDigitSign() {
|
||||
String regex = "\\d+";
|
||||
Xeger generator = new Xeger(regex);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String text = generator.generate();
|
||||
assertTrue(text.matches(regex));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGenerateTextCorrectlyForWordSign() {
|
||||
String regex = "\\w+";
|
||||
Xeger generator = new Xeger(regex);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String text = generator.generate();
|
||||
assertTrue(text.matches(regex));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGenerateTextCorrectlyForWhiteSpaceSign() {
|
||||
String regex = "\\s+";
|
||||
Xeger generator = new Xeger(regex);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String text = generator.generate();
|
||||
assertTrue(text.matches(regex));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRepeatableRegex() {
|
||||
for (int x = 0; x < 1000; x++) {
|
||||
|
||||
Reference in New Issue
Block a user