diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..4924614 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,3 @@ +RELEASE_TYPE: minor + +This release changes the default value of `fullmatch` in `fromRegex` from `false` to `true`. diff --git a/src/main/java/dev/hegel/Generators.java b/src/main/java/dev/hegel/Generators.java index d476cc6..e5d4c13 100644 --- a/src/main/java/dev/hegel/Generators.java +++ b/src/main/java/dev/hegel/Generators.java @@ -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 fromRegex(String pattern) { - return new RegexGenerator(pattern); + public static RegexGenerator fromRegex(String pattern) { + return new RegexGenerator(pattern, true); } } diff --git a/src/main/java/dev/hegel/generators/RegexGenerator.java b/src/main/java/dev/hegel/generators/RegexGenerator.java index f0c2aa3..21eb868 100644 --- a/src/main/java/dev/hegel/generators/RegexGenerator.java +++ b/src/main/java/dev/hegel/generators/RegexGenerator.java @@ -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 { 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 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); } } diff --git a/src/test/java/dev/hegel/ConformanceTest.java b/src/test/java/dev/hegel/ConformanceTest.java index 8289867..556e0f1 100644 --- a/src/test/java/dev/hegel/ConformanceTest.java +++ b/src/test/java/dev/hegel/ConformanceTest.java @@ -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. */ @@ -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