Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
RELEASE_TYPE: minor

This release changes the default value of `fullmatch` in `fromRegex` from `false` to `true`.
8 changes: 5 additions & 3 deletions src/main/java/dev/hegel/Generators.java
Original file line number Diff line number Diff line change
Expand Up @@ -590,12 +590,14 @@ public static DurationGenerator durations() {
}

/**
* Generates strings matching a (Python-compatible) regular expression.
* Generates strings matching a (Python-compatible) regular expression. By default the entire
* string matches the pattern; use {@link RegexGenerator#fullmatch(boolean) fullmatch(false)}
* to generate strings that merely contain a match.
*
* @param pattern the regex pattern
* @return a regex generator
*/
public static Generator<String> fromRegex(String pattern) {
return new RegexGenerator(pattern);
public static RegexGenerator fromRegex(String pattern) {
return new RegexGenerator(pattern, true);
}
}
21 changes: 17 additions & 4 deletions src/main/java/dev/hegel/generators/RegexGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,33 @@
import dev.hegel.Generator;

/**
* Generates strings matching a (Python-compatible) regular expression. Always basic (one engine
* call).
* Generates strings matching a (Python-compatible) regular expression. By default the entire
* string matches the pattern; use {@link #fullmatch(boolean) fullmatch(false)} to generate strings
* that merely contain a match. Always basic (one engine call).
*/
public final class RegexGenerator implements Generator<String> {
private final String pattern;
private final boolean fullmatch;

public RegexGenerator(String pattern) {
public RegexGenerator(String pattern, boolean fullmatch) {
this.pattern = pattern;
this.fullmatch = fullmatch;
}

/**
* @param fullmatch whether the entire string must match the pattern (the default), or merely
* contain a match somewhere within it
* @return a copy with the fullmatch behaviour set
*/
public RegexGenerator fullmatch(boolean fullmatch) {
return new RegexGenerator(pattern, fullmatch);
}

/** @hidden */
@Override
public BasicGenerator<String> asBasic() {
CBORObject schema = CBORObject.NewMap().Add("type", "regex").Add("pattern", pattern);
CBORObject schema =
CBORObject.NewMap().Add("type", "regex").Add("pattern", pattern).Add("fullmatch", fullmatch);
return new BasicGenerator<>(schema, Cbor::asString);
}
}
14 changes: 13 additions & 1 deletion src/test/java/dev/hegel/ConformanceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.time.ZoneOffset;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import org.junit.jupiter.api.Test;

/** Behaviour/conformance suite exercising every generator against the real engine. */
Expand Down Expand Up @@ -194,7 +195,18 @@ void formatGenerators() {
assertAllExamples(ipAddresses().v6(), s -> s.contains(":"));
assertAllExamples(ipAddresses(), s -> s.contains(".") || s.contains(":"));
assertAllExamples(uuids(), Objects::nonNull);
assertAllExamples(fromRegex("[0-9]{3}"), s -> s.matches(".*[0-9]{3}.*"));
}

@Test
void regexDefaultsToFullmatch() {
// By default the entire string matches the pattern (String.matches is a full match).
assertAllExamples(fromRegex("[0-9]{3}"), s -> s.matches("[0-9]{3}"));
// fullmatch(false) relaxes to contains-a-match: every example contains a match...
assertAllExamples(
fromRegex("[0-9]{3}").fullmatch(false),
s -> Pattern.compile("[0-9]{3}").matcher(s).find());
// ...and surrounding characters genuinely occur (findAny throws if no such example exists).
findAny(fromRegex("[0-9]{3}").fullmatch(false), s -> !s.matches("[0-9]{3}"));
}

@Test
Expand Down
Loading