Skip to content

Commit e77408b

Browse files
committed
Add changes from junit-team/junit4#1663 and suppresss checkstyle violations
1 parent f7e6843 commit e77408b

File tree

3 files changed

+397
-0
lines changed

3 files changed

+397
-0
lines changed

pom.xml

+2
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@
488488
<configLocation>src/main/resources/querydsl_checks_base.xml</configLocation>
489489
<includeTestSourceDirectory>true</includeTestSourceDirectory>
490490
<failOnViolation>true</failOnViolation>
491+
<suppressionsLocation>src/main/resources/checkstyle-suppressions.xml</suppressionsLocation>
492+
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
491493
</configuration>
492494
</execution>
493495
<execution>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,385 @@
1+
// Copied from https://github.com/junit-team/junit4/pull/1663/files until the junit team merges the PR.
2+
package org.junit.experimental.categories;
3+
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.util.Arrays;
7+
import java.util.Collections;
8+
import java.util.HashSet;
9+
import java.util.LinkedHashSet;
10+
import java.util.Set;
11+
12+
import org.junit.runner.Description;
13+
import org.junit.runner.manipulation.Filter;
14+
import org.junit.runner.manipulation.NoTestsRemainException;
15+
import org.junit.runners.Suite;
16+
import org.junit.runners.model.InitializationError;
17+
import org.junit.runners.model.RunnerBuilder;
18+
19+
/**
20+
* From a given set of test classes, runs only the classes and methods that are
21+
* annotated with either the category given with the @IncludeCategory
22+
* annotation, or a subtype of that category.
23+
* <p>
24+
* Note that, for now, annotating suites with {@code @Category} has no effect.
25+
* Categories must be annotated on the direct method or class.
26+
* <p>
27+
* Example:
28+
* <pre>
29+
* public interface FastTests {
30+
* }
31+
*
32+
* public interface SlowTests {
33+
* }
34+
*
35+
* public interface SmokeTests
36+
* }
37+
*
38+
* public static class A {
39+
* &#064;Test
40+
* public void a() {
41+
* fail();
42+
* }
43+
*
44+
* &#064;Category(SlowTests.class)
45+
* &#064;Test
46+
* public void b() {
47+
* }
48+
*
49+
* &#064;Category({FastTests.class, SmokeTests.class})
50+
* &#064;Test
51+
* public void c() {
52+
* }
53+
* }
54+
*
55+
* &#064;Category({SlowTests.class, FastTests.class})
56+
* public static class B {
57+
* &#064;Test
58+
* public void d() {
59+
* }
60+
* }
61+
*
62+
* &#064;RunWith(Categories.class)
63+
* &#064;IncludeCategory(SlowTests.class)
64+
* &#064;SuiteClasses({A.class, B.class})
65+
* // Note that Categories is a kind of Suite
66+
* public static class SlowTestSuite {
67+
* // Will run A.b and B.d, but not A.a and A.c
68+
* }
69+
* </pre>
70+
* <p>
71+
* Example to run multiple categories:
72+
* <pre>
73+
* &#064;RunWith(Categories.class)
74+
* &#064;IncludeCategory({FastTests.class, SmokeTests.class})
75+
* &#064;SuiteClasses({A.class, B.class})
76+
* public static class FastOrSmokeTestSuite {
77+
* // Will run A.c and B.d, but not A.b because it is not any of FastTests or SmokeTests
78+
* }
79+
* </pre>
80+
*
81+
* @version 4.12
82+
* @see <a href="https://github.com/junit-team/junit4/wiki/Categories">Categories at JUnit wiki</a>
83+
*/
84+
public class Categories extends Suite {
85+
86+
@Retention(RetentionPolicy.RUNTIME)
87+
public @interface IncludeCategory {
88+
/**
89+
* Determines the tests to run that are annotated with categories specified in
90+
* the value of this annotation or their subtypes unless excluded with {@link ExcludeCategory}.
91+
*/
92+
Class<?>[] value() default {};
93+
94+
/**
95+
* If <tt>true</tt>, runs tests annotated with <em>any</em> of the categories in
96+
* {@link IncludeCategory#value()}. Otherwise, runs tests only if annotated with <em>all</em> of the categories.
97+
*/
98+
boolean matchAny() default true;
99+
}
100+
101+
@Retention(RetentionPolicy.RUNTIME)
102+
public @interface ExcludeCategory {
103+
/**
104+
* Determines the tests which do not run if they are annotated with categories specified in the
105+
* value of this annotation or their subtypes regardless of being included in {@link IncludeCategory#value()}.
106+
*/
107+
Class<?>[] value() default {};
108+
109+
/**
110+
* If <tt>true</tt>, the tests annotated with <em>any</em> of the categories in {@link ExcludeCategory#value()}
111+
* do not run. Otherwise, the tests do not run if and only if annotated with <em>all</em> categories.
112+
*/
113+
boolean matchAny() default true;
114+
}
115+
116+
public static class CategoryFilter extends Filter {
117+
private final Set<Class<?>> included;
118+
private final Set<Class<?>> excluded;
119+
private final boolean includedAny;
120+
private final boolean excludedAny;
121+
122+
public static CategoryFilter include(boolean matchAny, Class<?>... categories) {
123+
return new CategoryFilter(matchAny, categories, true, null);
124+
}
125+
126+
public static CategoryFilter include(Class<?> category) {
127+
return include(true, category);
128+
}
129+
130+
public static CategoryFilter include(Class<?>... categories) {
131+
return include(true, categories);
132+
}
133+
134+
public static CategoryFilter exclude(boolean matchAny, Class<?>... categories) {
135+
return new CategoryFilter(true, null, matchAny, categories);
136+
}
137+
138+
public static CategoryFilter exclude(Class<?> category) {
139+
return exclude(true, category);
140+
}
141+
142+
public static CategoryFilter exclude(Class<?>... categories) {
143+
return exclude(true, categories);
144+
}
145+
146+
public static CategoryFilter categoryFilter(boolean matchAnyInclusions, Set<Class<?>> inclusions,
147+
boolean matchAnyExclusions, Set<Class<?>> exclusions) {
148+
return new CategoryFilter(matchAnyInclusions, inclusions, matchAnyExclusions, exclusions);
149+
}
150+
151+
@Deprecated
152+
public CategoryFilter(Class<?> includedCategory, Class<?> excludedCategory) {
153+
includedAny = true;
154+
excludedAny = true;
155+
included = nullableClassToSet(includedCategory);
156+
excluded = nullableClassToSet(excludedCategory);
157+
}
158+
159+
protected CategoryFilter(boolean matchAnyIncludes, Set<Class<?>> includes,
160+
boolean matchAnyExcludes, Set<Class<?>> excludes) {
161+
includedAny = matchAnyIncludes;
162+
excludedAny = matchAnyExcludes;
163+
included = copyAndRefine(includes);
164+
excluded = copyAndRefine(excludes);
165+
}
166+
167+
private CategoryFilter(boolean matchAnyIncludes, Class<?>[] inclusions,
168+
boolean matchAnyExcludes, Class<?>[] exclusions) {
169+
includedAny = matchAnyIncludes;
170+
excludedAny = matchAnyExcludes;
171+
included = createSet(inclusions);
172+
excluded = createSet(exclusions);
173+
}
174+
175+
/**
176+
* @see #toString()
177+
*/
178+
@Override
179+
public String describe() {
180+
return toString();
181+
}
182+
183+
/**
184+
* Returns string in the form <tt>&quot;[included categories] - [excluded categories]&quot;</tt>, where both
185+
* sets have comma separated names of categories.
186+
*
187+
* @return string representation for the relative complement of excluded categories set
188+
* in the set of included categories. Examples:
189+
* <ul>
190+
* <li> <tt>&quot;categories [all]&quot;</tt> for all included categories and no excluded ones;
191+
* <li> <tt>&quot;categories [all] - [A, B]&quot;</tt> for all included categories and given excluded ones;
192+
* <li> <tt>&quot;categories [A, B] - [C, D]&quot;</tt> for given included categories and given excluded ones.
193+
* </ul>
194+
* @see Class#toString() name of category
195+
*/
196+
@Override public String toString() {
197+
StringBuilder description= new StringBuilder("categories ")
198+
.append(included.isEmpty() ? "[all]" : included);
199+
if (!excluded.isEmpty()) {
200+
description.append(" - ").append(excluded);
201+
}
202+
return description.toString();
203+
}
204+
205+
@Override
206+
public boolean shouldRun(Description description) {
207+
if (hasCorrectCategoryAnnotation(description)) {
208+
return true;
209+
}
210+
211+
for (Description each : description.getChildren()) {
212+
if (shouldRun(each)) {
213+
return true;
214+
}
215+
}
216+
217+
return false;
218+
}
219+
220+
private boolean hasCorrectCategoryAnnotation(Description description) {
221+
final Set<Class<?>> childCategories= categories(description);
222+
223+
// If a child has no categories, immediately return.
224+
if (childCategories.isEmpty()) {
225+
return included.isEmpty();
226+
}
227+
228+
if (!excluded.isEmpty()) {
229+
if (excludedAny) {
230+
if (matchesAnyParentCategories(childCategories, excluded)) {
231+
return false;
232+
}
233+
} else {
234+
if (matchesAllParentCategories(childCategories, excluded)) {
235+
return false;
236+
}
237+
}
238+
}
239+
240+
if (included.isEmpty()) {
241+
// Couldn't be excluded, and with no suite's included categories treated as should run.
242+
return true;
243+
} else {
244+
if (includedAny) {
245+
return matchesAnyParentCategories(childCategories, included);
246+
} else {
247+
return matchesAllParentCategories(childCategories, included);
248+
}
249+
}
250+
}
251+
252+
/**
253+
* @return <tt>true</tt> if at least one (any) parent category match a child, otherwise <tt>false</tt>.
254+
* If empty <tt>parentCategories</tt>, returns <tt>false</tt>.
255+
*/
256+
private boolean matchesAnyParentCategories(Set<Class<?>> childCategories, Set<Class<?>> parentCategories) {
257+
for (Class<?> parentCategory : parentCategories) {
258+
if (hasAssignableTo(childCategories, parentCategory)) {
259+
return true;
260+
}
261+
}
262+
return false;
263+
}
264+
265+
/**
266+
* @return <tt>false</tt> if at least one parent category does not match children, otherwise <tt>true</tt>.
267+
* If empty <tt>parentCategories</tt>, returns <tt>true</tt>.
268+
*/
269+
private boolean matchesAllParentCategories(Set<Class<?>> childCategories, Set<Class<?>> parentCategories) {
270+
for (Class<?> parentCategory : parentCategories) {
271+
if (!hasAssignableTo(childCategories, parentCategory)) {
272+
return false;
273+
}
274+
}
275+
return true;
276+
}
277+
278+
private static Set<Class<?>> categories(Description description) {
279+
Set<Class<?>> categories= new HashSet<Class<?>>();
280+
Collections.addAll(categories, directCategories(description));
281+
Collections.addAll(categories, directCategories(parentDescription(description)));
282+
Collections.addAll(categories, directCategories(declaringDescription(description)));
283+
return categories;
284+
}
285+
286+
private static Description parentDescription(Description description) {
287+
Class<?> testClass= description.getTestClass();
288+
return testClass == null ? null : Description.createSuiteDescription(testClass);
289+
}
290+
291+
private static Description declaringDescription(Description description) {
292+
Class<?> testClass = description.getTestClass();
293+
if (testClass != null) {
294+
testClass = testClass.getDeclaringClass();
295+
}
296+
return testClass == null ? null : Description.createSuiteDescription(testClass);
297+
}
298+
299+
private static Class<?>[] directCategories(Description description) {
300+
if (description == null) {
301+
return new Class<?>[0];
302+
}
303+
304+
Category annotation= description.getAnnotation(Category.class);
305+
return annotation == null ? new Class<?>[0] : annotation.value();
306+
}
307+
308+
private static Set<Class<?>> copyAndRefine(Set<Class<?>> classes) {
309+
Set<Class<?>> c= new LinkedHashSet<Class<?>>();
310+
if (classes != null) {
311+
c.addAll(classes);
312+
}
313+
c.remove(null);
314+
return c;
315+
}
316+
}
317+
318+
public Categories(Class<?> klass, RunnerBuilder builder) throws InitializationError {
319+
super(klass, builder);
320+
try {
321+
Set<Class<?>> included= getIncludedCategory(klass);
322+
Set<Class<?>> excluded= getExcludedCategory(klass);
323+
boolean isAnyIncluded= isAnyIncluded(klass);
324+
boolean isAnyExcluded= isAnyExcluded(klass);
325+
326+
filter(CategoryFilter.categoryFilter(isAnyIncluded, included, isAnyExcluded, excluded));
327+
} catch (NoTestsRemainException e) {
328+
throw new InitializationError(e);
329+
}
330+
}
331+
332+
private static Set<Class<?>> getIncludedCategory(Class<?> klass) {
333+
IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class);
334+
return createSet(annotation == null ? null : annotation.value());
335+
}
336+
337+
private static boolean isAnyIncluded(Class<?> klass) {
338+
IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class);
339+
return annotation == null || annotation.matchAny();
340+
}
341+
342+
private static Set<Class<?>> getExcludedCategory(Class<?> klass) {
343+
ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class);
344+
return createSet(annotation == null ? null : annotation.value());
345+
}
346+
347+
private static boolean isAnyExcluded(Class<?> klass) {
348+
ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class);
349+
return annotation == null || annotation.matchAny();
350+
}
351+
352+
private static boolean hasAssignableTo(Set<Class<?>> assigns, Class<?> to) {
353+
for (final Class<?> from : assigns) {
354+
if (to.isAssignableFrom(from)) {
355+
return true;
356+
}
357+
}
358+
return false;
359+
}
360+
361+
private static Set<Class<?>> createSet(Class<?>[] classes) {
362+
// Not throwing a NPE if t is null is a bad idea, but it's the behavior from JUnit 4.12
363+
// for include(boolean, Class<?>...) and exclude(boolean, Class<?>...)
364+
if (classes == null || classes.length == 0) {
365+
return Collections.emptySet();
366+
}
367+
for (Class<?> category : classes) {
368+
if (category == null) {
369+
throw new NullPointerException("has null category");
370+
}
371+
}
372+
373+
return classes.length == 1
374+
? Collections.<Class<?>>singleton(classes[0])
375+
: new LinkedHashSet<Class<?>>(Arrays.asList(classes));
376+
}
377+
378+
private static Set<Class<?>> nullableClassToSet(Class<?> nullableClass) {
379+
// Not throwing a NPE if t is null is a bad idea, but it's the behavior from JUnit 4.11
380+
// for CategoryFilter(Class<?> includedCategory, Class<?> excludedCategory)
381+
return nullableClass == null
382+
? Collections.<Class<?>>emptySet()
383+
: Collections.<Class<?>>singleton(nullableClass);
384+
}
385+
}

0 commit comments

Comments
 (0)