Skip to content

Commit 06311c6

Browse files
authored
Fix test filter greediness for method names (#93)
The present change aims at preventing the `MyTest#testSomething` pattern from matching the `testSomethingElse` method in the following example: ```java public class MyTest { @test void testSomething() { } @test void testSomethingElse() { } ``` With `asPredicate`, the test filter matches test methods _starting with_ the given method name: > Creates a predicate that tests if this pattern is found in a given > input string. Unless the pattern doesn't encompass a method name, appending a `$` to the input pattern makes sure only exact method names are considered. Note: think about filter greediness for class names.
1 parent d315d8f commit 06311c6

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

java/src/com/github/bazel_contrib/contrib_rules_jvm/junit5/PatternFilter.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.util.function.Predicate;
44
import java.util.regex.Pattern;
5+
import java.util.stream.Collectors;
6+
import java.util.stream.Stream;
57
import org.junit.platform.engine.FilterResult;
68
import org.junit.platform.engine.TestDescriptor;
79
import org.junit.platform.engine.TestSource;
@@ -59,10 +61,19 @@ public FilterResult apply(TestDescriptor object) {
5961
return FilterResult.excluded("Did not match " + rawPattern);
6062
}
6163

64+
/**
65+
* Converts comma-separated selections in patterns like:
66+
*
67+
* <ul>
68+
* <li>classes: "path.to.SomeTest,path.to.AnotherTest" -> "path.to.SomeTest|path.to.AnotherTest"
69+
* <li>methods: "path.to.SomeTest#testSomething,testSomethingElse" ->
70+
* "path.to.SomeTest#testSomething$|path.to.SomeTest#testSomethingElse$"
71+
* </ul>
72+
*/
6273
private static String convertCommaSeparatedSelections(String pattern) {
6374
var selections = pattern.split(",");
6475
if (selections.length == 1) {
65-
return pattern;
76+
return ensureExactMethodName(pattern);
6677
}
6778
var precedingClassSelection = selections[0];
6879
var precedingHashIndex = precedingClassSelection.indexOf('#');
@@ -76,6 +87,13 @@ private static String convertCommaSeparatedSelections(String pattern) {
7687
selections[i] = precedingClassSelection.substring(0, precedingHashIndex + 1) + selection;
7788
}
7889
}
79-
return String.join("|", selections);
90+
return Stream.of(selections)
91+
.map(PatternFilter::ensureExactMethodName)
92+
.collect(Collectors.joining("|"));
93+
}
94+
95+
/** Appends '$' to patterns like "class#method" or "#method", unless already done. */
96+
private static String ensureExactMethodName(String pattern) {
97+
return pattern.matches(".*#.*[^$]$") ? pattern + '$' : pattern;
8098
}
8199
}

java/test/com/github/bazel_contrib/contrib_rules_jvm/junit5/FilteringTest.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public void shouldIncludeATestMethodIfTheFilterIsJustTheClassName() {
134134
assertTrue(siblingTestResult.included());
135135

136136
FilterResult nestedTestResult = filter.apply(nestedTestMethodTestDescriptor);
137-
assertFalse(nestedTestResult.included(), "nested class should not be matched");
137+
assertFalse(nestedTestResult.included(), "method in nested class should not be matched");
138138
}
139139

140140
@Test
@@ -143,10 +143,10 @@ public void shouldIncludeANestedTestMethodIfTheFilterIsJustTheNestedClassName()
143143
new PatternFilter(JUnit5StyleTest.NestedTest.class.getName().replace("$", "\\$") + "#");
144144

145145
FilterResult testResult = filter.apply(testMethodTestDescriptor);
146-
assertFalse(testResult.included(), "enclosing class should not be matched");
146+
assertFalse(testResult.included(), "method in enclosing class should not be matched");
147147

148148
FilterResult siblingTestResult = filter.apply(siblingTestMethodTestDescriptor);
149-
assertFalse(siblingTestResult.included(), "enclosing class should not be matched");
149+
assertFalse(siblingTestResult.included(), "method in enclosing class should not be matched");
150150

151151
FilterResult nestedTestResult = filter.apply(nestedTestMethodTestDescriptor);
152152
assertTrue(nestedTestResult.included());
@@ -186,11 +186,25 @@ public void shouldNotIncludeATestMethodIfTheFilterDoesNotMatchTheMethodName() {
186186
}
187187

188188
@Test
189-
public void shouldIncludeATestMethodIfTheFilterMatchesTheMethodName() {
189+
public void shouldIncludeATestMethodIfTheFilterMatchesTheExactShortMethodName() {
190+
PatternFilter filter = new PatternFilter("#alwaysPasses");
191+
192+
FilterResult testResult = filter.apply(testMethodTestDescriptor);
193+
assertTrue(testResult.included());
194+
195+
FilterResult siblingTestResult = filter.apply(siblingTestMethodTestDescriptor);
196+
assertFalse(siblingTestResult.included(), "longer method name should not be matched");
197+
198+
FilterResult nestedTestResult = filter.apply(nestedTestMethodTestDescriptor);
199+
assertFalse(nestedTestResult.included(), "longer method name should not be matched");
200+
}
201+
202+
@Test
203+
public void shouldIncludeATestMethodIfTheFilterMatchesTheExactLongMethodName() {
190204
PatternFilter filter = new PatternFilter("#alwaysPassesToo");
191205

192206
FilterResult testResult = filter.apply(testMethodTestDescriptor);
193-
assertFalse(testResult.included(), "different method name should not be matched");
207+
assertFalse(testResult.included(), "shorter method name should not be matched");
194208

195209
FilterResult siblingTestResult = filter.apply(siblingTestMethodTestDescriptor);
196210
assertTrue(siblingTestResult.included());

0 commit comments

Comments
 (0)