Skip to content

Commit 2838bc2

Browse files
authored
Preserve Pattern flags when used in conditions (#2304)
With this PR, we no longer lose pattern flags when using them with strict and lenient collection matches. This fixes #2298 and keeps the original behavior of Groovy's `==~` and `=~` operators intact by calling Groovy's original logic.
1 parent 14afa54 commit 2838bc2

3 files changed

Lines changed: 34 additions & 11 deletions

File tree

docs/release_notes.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ include::include.adoc[]
66

77
== 2.5 (tbd)
88

9+
=== Misc
10+
11+
* Fix Pattern flags being dropped when `java.util.regex.Pattern` instances are used in Spock regex conditions spockIssue:2298[]
12+
913
== 2.4 (2025-12-11)
1014

1115
_This is a summary of the highlights of the milestone releases_

spock-core/src/main/java/org/spockframework/runtime/SpockRuntime.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@
1818
import groovy.lang.Closure;
1919
import groovy.lang.DelegatesTo;
2020
import groovy.transform.stc.ClosureParams;
21-
import groovy.transform.stc.FirstParam;
2221
import groovy.transform.stc.FromString;
22+
import org.codehaus.groovy.runtime.InvokerHelper;
2323
import org.hamcrest.CoreMatchers;
2424
import org.hamcrest.Matcher;
2525
import org.hamcrest.collection.IsIterableContainingInAnyOrder;
2626
import org.opentest4j.MultipleFailuresError;
2727
import spock.lang.Specification;
2828

29-
import org.spockframework.lang.ISpecificationContext;
3029
import org.spockframework.runtime.extension.IBlockListener;
3130
import org.spockframework.runtime.model.BlockInfo;
3231
import org.spockframework.runtime.model.ExpressionInfo;
@@ -39,7 +38,6 @@
3938
import java.util.*;
4039
import java.util.function.Consumer;
4140
import java.util.function.Function;
42-
import java.util.regex.Pattern;
4341
import java.util.stream.Collectors;
4442
import java.util.stream.StreamSupport;
4543

@@ -154,8 +152,7 @@ public static Object matchCollectionsAsSet(Object left, Object right) {
154152
} else if ((left == null) || (right == null)) {
155153
return (left == null) && (right == null);
156154
} else {
157-
Pattern pattern = Pattern.compile(String.valueOf(right));
158-
return pattern.matcher(String.valueOf(left));
155+
return InvokerHelper.findRegex(left, right);
159156
}
160157
}
161158

@@ -173,10 +170,7 @@ public static boolean matchCollectionsInAnyOrder(Object left, Object right) {
173170
} else if ((left == null) || (right == null)) {
174171
return (left == null) && (right == null);
175172
} else {
176-
Pattern pattern = Pattern.compile(String.valueOf(right));
177-
java.util.regex.Matcher matcher = pattern.matcher(String.valueOf(left));
178-
179-
return matcher.matches();
173+
return InvokerHelper.matchRegex(left, right);
180174
}
181175
}
182176

@@ -392,8 +386,7 @@ void verify(ErrorCollector errorCollector, @Nullable List<Object> values, @Nulla
392386
}
393387
values.set(3, false);
394388
} else {
395-
Pattern pattern = Pattern.compile(String.valueOf(right));
396-
java.util.regex.Matcher matcher = pattern.matcher(String.valueOf(left));
389+
java.util.regex.Matcher matcher = InvokerHelper.findRegex(left, right);
397390

398391
values.set(idxActual, left);
399392
values.set(idxExpected, right);

spock-specs/src/test/groovy/org/spockframework/smoke/condition/ConditionEvaluation.groovy

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import spock.lang.Issue
2424
import spock.lang.Snapshot
2525
import spock.lang.Snapshotter
2626

27+
import java.util.regex.Matcher
28+
import java.util.regex.Pattern
29+
2730
import static java.lang.Integer.MAX_VALUE
2831
import static java.lang.Math.max
2932
import static java.lang.Math.min
@@ -443,6 +446,29 @@ class ConditionEvaluation extends EmbeddedSpecification {
443446
a =~ b
444447
}
445448
449+
@Issue("https://github.com/spockframework/spock/issues/2298")
450+
def "Groovy regex conditions still work"() {
451+
given:
452+
def patternWithFlags = Pattern.compile(/[abc]oo/, Pattern.CASE_INSENSITIVE)
453+
def patternWithInlineFlags = ~/(?i)[abc]oo/
454+
def patternWithPartialMatchAndFlags = Pattern.compile(/[abc]o/, Pattern.CASE_INSENSITIVE)
455+
def patternWithPartialMatchAndInlineFlags = ~/(?i)[abc]o/
456+
457+
expect: "The strict collection match still works as regex match"
458+
"BOO" ==~ patternWithFlags
459+
"BOO" ==~ patternWithInlineFlags
460+
461+
and: "The lenient collection match still builds a matcher"
462+
("boo" =~ patternWithPartialMatchAndFlags) instanceof Matcher
463+
("boo" =~ patternWithPartialMatchAndInlineFlags) instanceof Matcher
464+
("BOO" =~ /[ABC]o/) instanceof Matcher
465+
466+
and: "Groovy truth applies to the returned matcher"
467+
"boo" =~ patternWithPartialMatchAndFlags
468+
"boo" =~ patternWithPartialMatchAndInlineFlags
469+
"BOO" =~ /[ABC]O/
470+
}
471+
446472
@FailsWith(ConditionFailedWithExceptionError)
447473
def "regular implicit condition"() {
448474
expect:

0 commit comments

Comments
 (0)