Skip to content

Commit

Permalink
Add include matching to ClassNamePatternFilterUtils (junit-team#4115)
Browse files Browse the repository at this point in the history
Issue: junit-team#3717

---------

Signed-off-by: yongjunhong <[email protected]>
Co-authored-by: Marc Philipp <[email protected]>
  • Loading branch information
YongGoose and marcphilipp authored Nov 12, 2024
1 parent 37e6e09 commit 3214f05
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public final class Constants {
* @see #DEACTIVATE_CONDITIONS_PATTERN_PROPERTY_NAME
* @see org.junit.jupiter.api.extension.ExecutionCondition
*/
public static final String DEACTIVATE_ALL_CONDITIONS_PATTERN = ClassNamePatternFilterUtils.DEACTIVATE_ALL_PATTERN;
public static final String DEACTIVATE_ALL_CONDITIONS_PATTERN = ClassNamePatternFilterUtils.ALL_PATTERN;

/**
* Property name used to set the default display name generator class name: {@value}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private ClassNamePatternFilterUtils() {
/* no-op */
}

public static final String DEACTIVATE_ALL_PATTERN = "*";
public static final String ALL_PATTERN = "*";

/**
* Create a {@link Predicate} that can be used to exclude (i.e., filter out)
Expand All @@ -51,7 +51,7 @@ private ClassNamePatternFilterUtils() {
* @param patterns a comma-separated list of patterns
*/
public static <T> Predicate<T> excludeMatchingClasses(String patterns) {
return excludeMatchingClasses(patterns, object -> object.getClass().getName());
return matchingClasses(patterns, object -> object.getClass().getName(), FilterType.EXCLUDE);
}

/**
Expand All @@ -61,26 +61,57 @@ public static <T> Predicate<T> excludeMatchingClasses(String patterns) {
* @param patterns a comma-separated list of patterns
*/
public static Predicate<String> excludeMatchingClassNames(String patterns) {
return excludeMatchingClasses(patterns, Function.identity());
return matchingClasses(patterns, Function.identity(), FilterType.EXCLUDE);
}

private static <T> Predicate<T> excludeMatchingClasses(String patterns, Function<T, String> classNameGetter) {
/**
* Create a {@link Predicate} that can be used to include (i.e., filter in)
* objects of type {@code T} whose fully qualified class names match any of
* the supplied patterns.
*
* @param patterns a comma-separated list of patterns
*/
public static <T> Predicate<T> includeMatchingClasses(String patterns) {
return matchingClasses(patterns, object -> object.getClass().getName(), FilterType.INCLUDE);
}

/**
* Create a {@link Predicate} that can be used to include (i.e., filter in)
* fully qualified class names matching any of the supplied patterns.
*
* @param patterns a comma-separated list of patterns
*/
public static Predicate<String> includeMatchingClassNames(String patterns) {
return matchingClasses(patterns, Function.identity(), FilterType.INCLUDE);
}

private enum FilterType {
INCLUDE, EXCLUDE
}

private static <T> Predicate<T> matchingClasses(String patterns, Function<T, String> classNameProvider,
FilterType type) {
// @formatter:off
return Optional.ofNullable(patterns)
.filter(StringUtils::isNotBlank)
.map(String::trim)
.map(trimmedPatterns -> createPredicateFromPatterns(trimmedPatterns, classNameGetter))
.orElse(object -> true);
.map(trimmedPatterns -> createPredicateFromPatterns(trimmedPatterns, classNameProvider, type))
.orElse(type == FilterType.EXCLUDE ? __ -> true : __ -> false);
// @formatter:on
}

private static <T> Predicate<T> createPredicateFromPatterns(String patterns,
Function<T, String> classNameProvider) {
if (DEACTIVATE_ALL_PATTERN.equals(patterns)) {
return object -> false;
private static <T> Predicate<T> createPredicateFromPatterns(String patterns, Function<T, String> classNameProvider,
FilterType mode) {
if (ALL_PATTERN.equals(patterns)) {
return __ -> mode == FilterType.INCLUDE;
}

List<Pattern> patternList = convertToRegularExpressions(patterns);
return object -> patternList.stream().noneMatch(it -> it.matcher(classNameProvider.apply(object)).matches());
return object -> {
boolean isMatchingAnyPattern = patternList.stream().anyMatch(
pattern -> pattern.matcher(classNameProvider.apply(object)).matches());
return (mode == FilterType.INCLUDE) == isMatchingAnyPattern;
};
}

private static List<Pattern> convertToRegularExpressions(String patterns) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public class LauncherConstants {
* @see #DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME
* @see org.junit.platform.launcher.TestExecutionListener
*/
public static final String DEACTIVATE_ALL_LISTENERS_PATTERN = ClassNamePatternFilterUtils.DEACTIVATE_ALL_PATTERN;
public static final String DEACTIVATE_ALL_LISTENERS_PATTERN = ClassNamePatternFilterUtils.ALL_PATTERN;

/**
* Property name used to enable support for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,155 @@ void alwaysExcludedClassName(String pattern) {
.isEmpty();
}

//@formatter:off
@ValueSource(strings = {
"org.junit.jupiter.*",
"org.junit.platform.*.NonExistentClass",
"*.NonExistentClass*",
"*NonExistentClass*",
"AExecutionConditionClass, BExecutionConditionClass"
})
//@formatter:on
@ParameterizedTest
void neverIncludedConditions(String pattern) {
List<? extends ExecutionCondition> executionConditions = List.of(new AExecutionConditionClass(),
new BExecutionConditionClass());
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) //
.isEmpty();
}

//@formatter:off
@ValueSource(strings = {
"org.junit.platform.*",
"*.platform.*",
"*",
"*AExecutionConditionClass, *BExecutionConditionClass",
"*ExecutionConditionClass"
})
//@formatter:on
@ParameterizedTest
void alwaysIncludedConditions(String pattern) {
List<? extends ExecutionCondition> executionConditions = List.of(new AExecutionConditionClass(),
new BExecutionConditionClass());
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) //
.hasSize(2);
}

//@formatter:off
@ValueSource(strings = {
"org.junit.jupiter.*",
"org.junit.platform.*.NonExistentClass",
"*.NonExistentClass*",
"*NonExistentClass*",
"ATestExecutionListenerClass, BTestExecutionListenerClass"
})
//@formatter:on
@ParameterizedTest
void neverIncludedListeners(String pattern) {
List<? extends TestExecutionListener> executionConditions = List.of(new ATestExecutionListenerClass(),
new BTestExecutionListenerClass());
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) //
.isEmpty();
}

//@formatter:off
@ValueSource(strings = {
"org.junit.platform.*",
"*.platform.*",
"*",
"*ATestExecutionListenerClass, *BTestExecutionListenerClass",
"*TestExecutionListenerClass"
})
//@formatter:on
@ParameterizedTest
void alwaysIncludedListeners(String pattern) {
List<? extends TestExecutionListener> executionConditions = List.of(new ATestExecutionListenerClass(),
new BTestExecutionListenerClass());
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) //
.hasSize(2);
}

//@formatter:off
@ValueSource(strings = {
"org.junit.jupiter.*",
"org.junit.platform.*.NonExistentClass",
"*.NonExistentClass*",
"*NonExistentClass*",
"AVanillaEmpty, BVanillaEmpty"
})
//@formatter:on
@ParameterizedTest
void neverIncludedClass(String pattern) {
var executionConditions = List.of(new AVanillaEmpty(), new BVanillaEmpty());
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) //
.isEmpty();
}

//@formatter:off
@ValueSource(strings = {
"org.junit.platform.*",
"*.platform.*",
"*",
"*AVanillaEmpty, *BVanillaEmpty",
"*VanillaEmpty"
})
//@formatter:on
@ParameterizedTest
void alwaysIncludedClass(String pattern) {
var executionConditions = List.of(new AVanillaEmpty(), new BVanillaEmpty());
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) //
.hasSize(2);
}

//@formatter:off
@ValueSource(strings = {
"org.junit.jupiter.*",
"org.junit.platform.*.NonExistentClass",
"*.NonExistentClass*",
"*NonExistentClass*",
"AVanillaEmpty, BVanillaEmpty"
})
//@formatter:on
@ParameterizedTest
void neverIncludedClassName(String pattern) {
var executionConditions = List.of("org.junit.platform.commons.util.classes.AVanillaEmpty",
"org.junit.platform.commons.util.classes.BVanillaEmpty");
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClassNames(pattern)) //
.isEmpty();
}

//@formatter:off
@ValueSource(strings = {
"org.junit.platform.*",
"*.platform.*",
"*",
"*AVanillaEmpty, *BVanillaEmpty",
"*VanillaEmpty"
})
//@formatter:on
@ParameterizedTest
void alwaysIncludedClassName(String pattern) {
var executionConditions = List.of("org.junit.platform.commons.util.classes.AVanillaEmpty",
"org.junit.platform.commons.util.classes.BVanillaEmpty");
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClassNames(pattern)) //
.hasSize(2);
}

//@formatter:off
@ValueSource(strings = {
"org.junit.platform.*",
"*.platform.*",
"*",
"*AVanillaEmpty, *BVanillaEmpty",
"*VanillaEmpty"
})
//@formatter:on
@ParameterizedTest
void includeAndExcludeSame(String pattern) {
var executionConditions = List.of("org.junit.platform.commons.util.classes.AVanillaEmpty",
"org.junit.platform.commons.util.classes.BVanillaEmpty");
assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClassNames(pattern)) //
.hasSize(2);
}

}

0 comments on commit 3214f05

Please sign in to comment.