diff options
Diffstat (limited to 'src/main/java/org/junit/experimental/categories/Categories.java')
-rw-r--r-- | src/main/java/org/junit/experimental/categories/Categories.java | 108 |
1 files changed, 59 insertions, 49 deletions
diff --git a/src/main/java/org/junit/experimental/categories/Categories.java b/src/main/java/org/junit/experimental/categories/Categories.java index 0c73ed8..290c180 100644 --- a/src/main/java/org/junit/experimental/categories/Categories.java +++ b/src/main/java/org/junit/experimental/categories/Categories.java @@ -2,10 +2,8 @@ package org.junit.experimental.categories; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.Set; import org.junit.runner.Description; @@ -78,7 +76,7 @@ import org.junit.runners.model.RunnerBuilder; * </pre> * * @version 4.12 - * @see <a href="https://github.com/junit-team/junit4/wiki/Categories">Categories at JUnit wiki</a> + * @see <a href="https://github.com/junit-team/junit/wiki/Categories">Categories at JUnit wiki</a> */ public class Categories extends Suite { @@ -88,13 +86,13 @@ public class Categories extends Suite { * Determines the tests to run that are annotated with categories specified in * the value of this annotation or their subtypes unless excluded with {@link ExcludeCategory}. */ - Class<?>[] value() default {}; + public Class<?>[] value() default {}; /** * If <tt>true</tt>, runs tests annotated with <em>any</em> of the categories in * {@link IncludeCategory#value()}. Otherwise, runs tests only if annotated with <em>all</em> of the categories. */ - boolean matchAny() default true; + public boolean matchAny() default true; } @Retention(RetentionPolicy.RUNTIME) @@ -103,13 +101,13 @@ public class Categories extends Suite { * Determines the tests which do not run if they are annotated with categories specified in the * value of this annotation or their subtypes regardless of being included in {@link IncludeCategory#value()}. */ - Class<?>[] value() default {}; + public Class<?>[] value() default {}; /** * If <tt>true</tt>, the tests annotated with <em>any</em> of the categories in {@link ExcludeCategory#value()} * do not run. Otherwise, the tests do not run if and only if annotated with <em>all</em> categories. */ - boolean matchAny() default true; + public boolean matchAny() default true; } public static class CategoryFilter extends Filter { @@ -119,7 +117,10 @@ public class Categories extends Suite { private final boolean excludedAny; public static CategoryFilter include(boolean matchAny, Class<?>... categories) { - return new CategoryFilter(matchAny, categories, true, null); + if (hasNull(categories)) { + throw new NullPointerException("has null category"); + } + return categoryFilter(matchAny, createSet(categories), true, null); } public static CategoryFilter include(Class<?> category) { @@ -131,7 +132,10 @@ public class Categories extends Suite { } public static CategoryFilter exclude(boolean matchAny, Class<?>... categories) { - return new CategoryFilter(true, null, matchAny, categories); + if (hasNull(categories)) { + throw new NullPointerException("has null category"); + } + return categoryFilter(true, null, matchAny, createSet(categories)); } public static CategoryFilter exclude(Class<?> category) { @@ -147,30 +151,14 @@ public class Categories extends Suite { return new CategoryFilter(matchAnyInclusions, inclusions, matchAnyExclusions, exclusions); } - @Deprecated - public CategoryFilter(Class<?> includedCategory, Class<?> excludedCategory) { - includedAny = true; - excludedAny = true; - included = nullableClassToSet(includedCategory); - excluded = nullableClassToSet(excludedCategory); - } - protected CategoryFilter(boolean matchAnyIncludes, Set<Class<?>> includes, - boolean matchAnyExcludes, Set<Class<?>> excludes) { + boolean matchAnyExcludes, Set<Class<?>> excludes) { includedAny = matchAnyIncludes; excludedAny = matchAnyExcludes; included = copyAndRefine(includes); excluded = copyAndRefine(excludes); } - private CategoryFilter(boolean matchAnyIncludes, Class<?>[] inclusions, - boolean matchAnyExcludes, Class<?>[] exclusions) { - includedAny = matchAnyIncludes; - excludedAny = matchAnyExcludes; - included = createSet(inclusions); - excluded = createSet(exclusions); - } - /** * @see #toString() */ @@ -296,13 +284,23 @@ public class Categories extends Suite { } private static Set<Class<?>> copyAndRefine(Set<Class<?>> classes) { - Set<Class<?>> c= new LinkedHashSet<Class<?>>(); + HashSet<Class<?>> c= new HashSet<Class<?>>(); if (classes != null) { c.addAll(classes); } c.remove(null); return c; } + + private static boolean hasNull(Class<?>... classes) { + if (classes == null) return false; + for (Class<?> clazz : classes) { + if (clazz == null) { + return true; + } + } + return false; + } } public Categories(Class<?> klass, RunnerBuilder builder) throws InitializationError { @@ -317,6 +315,7 @@ public class Categories extends Suite { } catch (NoTestsRemainException e) { throw new InitializationError(e); } + assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription()); } private static Set<Class<?>> getIncludedCategory(Class<?> klass) { @@ -339,6 +338,34 @@ public class Categories extends Suite { return annotation == null || annotation.matchAny(); } + private static void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError { + if (!canHaveCategorizedChildren(description)) { + assertNoDescendantsHaveCategoryAnnotations(description); + } + for (Description each : description.getChildren()) { + assertNoCategorizedDescendentsOfUncategorizeableParents(each); + } + } + + private static void assertNoDescendantsHaveCategoryAnnotations(Description description) throws InitializationError { + for (Description each : description.getChildren()) { + if (each.getAnnotation(Category.class) != null) { + throw new InitializationError("Category annotations on Parameterized classes are not supported on individual methods."); + } + assertNoDescendantsHaveCategoryAnnotations(each); + } + } + + // If children have names like [0], our current magical category code can't determine their parentage. + private static boolean canHaveCategorizedChildren(Description description) { + for (Description each : description.getChildren()) { + if (each.getTestClass() == null) { + return false; + } + } + return true; + } + private static boolean hasAssignableTo(Set<Class<?>> assigns, Class<?> to) { for (final Class<?> from : assigns) { if (to.isAssignableFrom(from)) { @@ -348,28 +375,11 @@ public class Categories extends Suite { return false; } - private static Set<Class<?>> createSet(Class<?>[] classes) { - // Not throwing a NPE if t is null is a bad idea, but it's the behavior from JUnit 4.12 - // for include(boolean, Class<?>...) and exclude(boolean, Class<?>...) - if (classes == null || classes.length == 0) { - return Collections.emptySet(); - } - for (Class<?> category : classes) { - if (category == null) { - throw new NullPointerException("has null category"); - } + private static Set<Class<?>> createSet(Class<?>... t) { + final Set<Class<?>> set= new HashSet<Class<?>>(); + if (t != null) { + Collections.addAll(set, t); } - - return classes.length == 1 - ? Collections.<Class<?>>singleton(classes[0]) - : new LinkedHashSet<Class<?>>(Arrays.asList(classes)); - } - - private static Set<Class<?>> nullableClassToSet(Class<?> nullableClass) { - // Not throwing a NPE if t is null is a bad idea, but it's the behavior from JUnit 4.11 - // for CategoryFilter(Class<?> includedCategory, Class<?> excludedCategory) - return nullableClass == null - ? Collections.<Class<?>>emptySet() - : Collections.<Class<?>>singleton(nullableClass); + return set; } } |