Skip to content

Commit f09cff7

Browse files
committed
alpha-ready implementation of SuiteBuilder
1 parent 3b7ab4a commit f09cff7

File tree

10 files changed

+188
-119
lines changed

10 files changed

+188
-119
lines changed

build.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<property name="src" value="src/main/java" />
66
<property name="target" location="target" />
77
<property name="bin" location="${target}/main" />
8-
<property name="version-base" value="4.8.2" />
8+
<property name="version-base" value="4.9-SNAPSHOT-20100512-0041" />
99
<property name="version-status" value="" />
1010
<property name="version" value="${version-base}${version-status}" />
1111
<property name="dist" value="junit${version}" />
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
Can't open /Users/saff/Documents/git-repos/junit/doc/ReleaseNotes4.9-SNAPSHOT-20100512-0041.txt: No such file or directory at build/Markdown.pl line 218.
3+
Use of uninitialized value in substitution (s///) at build/Markdown.pl line 245.
4+
Use of uninitialized value in substitution (s///) at build/Markdown.pl line 246.

doc/ReleaseNotes4.9.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<h2>Summary of Changes in version 4.9</h2>
2+
3+
<h3>SuiteBuilder</h3>
4+
5+
<p>A new way of declaring suites to run. SuiteBuilder allows for flexible
6+
specification of where to find the classes containing tests, and how
7+
to filter the resulting runners. This suite class lists the
8+
explicit test classes to consider running, and then filters it down
9+
to only those tests or classes annotated with <code>@Category(Yes.class)</code>:</p>
10+
11+
<pre><code>@RunWith(SuiteBuilder.class)
12+
public static class OnlyYes {
13+
@Classes
14+
public Listed classes= new Listed(Yes1.class, Yes2.class, No1.class);
15+
16+
@RunnerFilter
17+
public CategoryFilter filter= CategoryFilter.include(Yes.class);
18+
}
19+
</code></pre>
20+
21+
<p>We hope to soon include other implementations for the @Classes annotation,
22+
including a classpath-searching test gatherer.</p>
23+
24+
<h3>Bug fixes</h3>
25+
26+
<ul>
27+
<li>github#98: assumeTrue() does not work with expected exceptions</li>
28+
</ul>

doc/ReleaseNotes4.9.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
## Summary of Changes in version 4.9 ##
22

3+
### SuiteBuilder ###
4+
5+
A new way of declaring suites to run. SuiteBuilder allows for flexible
6+
specification of where to find the classes containing tests, and how
7+
to filter the resulting runners. This suite class lists the
8+
explicit test classes to consider running, and then filters it down
9+
to only those tests or classes annotated with `@Category(Yes.class)`:
10+
11+
@RunWith(SuiteBuilder.class)
12+
public static class OnlyYes {
13+
@Classes
14+
public Listed classes= new Listed(Yes1.class, Yes2.class, No1.class);
15+
16+
@RunnerFilter
17+
public CategoryFilter filter= CategoryFilter.include(Yes.class);
18+
}
19+
20+
We hope to soon include other implementations for the @Classes annotation,
21+
including a classpath-searching test gatherer.
22+
323
### Bug fixes ###
424

525
- github#98: assumeTrue() does not work with expected exceptions

src/main/java/junit/runner/Version.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ private Version() {
99
}
1010

1111
public static String id() {
12-
return "4.8.2";
12+
return "4.9-SNAPSHOT-20100512-0041";
1313
}
1414

1515
public static void main(String[] args) {

src/main/java/org/junit/experimental/categories/CategoryFilter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
import java.util.Arrays;
99
import java.util.List;
1010

11+
import org.junit.experimental.runners.SuiteBuilder;
1112
import org.junit.runner.Runner;
12-
import org.junit.tests.experimental.categories.SuiteBuilderTest.RunnerFilter;
1313

14-
public class CategoryFilter implements RunnerFilter.Value {
14+
public class CategoryFilter implements SuiteBuilder.RunnerFilter.Value {
1515
private final Class<?> fIncluded;
1616

1717
public CategoryFilter(Class<?> included) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
*
3+
*/
4+
package org.junit.experimental.runners;
5+
6+
import java.util.Arrays;
7+
import java.util.List;
8+
9+
public class Listed implements SuiteBuilder.Classes.Value {
10+
private final Class<?>[] fClasses;
11+
12+
public Listed(Class<?>... classes) {
13+
fClasses= classes;
14+
}
15+
16+
public List<? extends Class<?>> get() {
17+
return Arrays.asList(fClasses);
18+
}
19+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
*
3+
*/
4+
package org.junit.experimental.runners;
5+
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.util.ArrayList;
9+
import java.util.Collection;
10+
import java.util.List;
11+
12+
import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
13+
import org.junit.runner.Description;
14+
import org.junit.runner.Runner;
15+
import org.junit.runner.notification.RunNotifier;
16+
import org.junit.runners.model.InitializationError;
17+
import org.junit.runners.model.TestClass;
18+
19+
public class SuiteBuilder extends Runner {
20+
@Retention(RetentionPolicy.RUNTIME)
21+
public @interface RunnerFilter {
22+
public static interface Value {
23+
public abstract List<Runner> matchingRunners(
24+
List<Runner> allPossibleRunners);
25+
}
26+
}
27+
28+
@Retention(RetentionPolicy.RUNTIME)
29+
public @interface Classes {
30+
public static interface Value {
31+
public abstract Collection<? extends Class<?>> get();
32+
}
33+
}
34+
35+
private final TestClass fTestClass;
36+
private final Object fInstance;
37+
private final List<Runner> fRunners;
38+
39+
public SuiteBuilder(Class<?> testClass) throws InitializationError {
40+
fTestClass= new TestClass(testClass);
41+
fInstance = createInstance();
42+
fRunners= computeRunners();
43+
}
44+
45+
private Object createInstance() throws InitializationError {
46+
try {
47+
return fTestClass.getOnlyConstructor().newInstance();
48+
} catch (Exception e) {
49+
throw new InitializationError(e);
50+
}
51+
}
52+
53+
@Override
54+
public Description getDescription() {
55+
Description description= Description.createSuiteDescription(fTestClass.getJavaClass());
56+
for (Runner each : fRunners) {
57+
description.addChild(each.getDescription());
58+
}
59+
return description;
60+
}
61+
62+
@Override
63+
public void run(RunNotifier notifier) {
64+
for (Runner each : fRunners)
65+
each.run(notifier);
66+
}
67+
68+
private List<Runner> computeRunners() throws InitializationError {
69+
List<Class<?>> allPossibleClasses= gatherClasses();
70+
List<Runner> allPossibleRunners= runnersForClasses(allPossibleClasses);
71+
return filterRunners(allPossibleRunners);
72+
}
73+
74+
private List<Runner> filterRunners(List<Runner> allPossibleRunners) {
75+
List<Runner> result= allPossibleRunners;
76+
for (SuiteBuilder.RunnerFilter.Value each : getFilters())
77+
result= each.matchingRunners(result);
78+
return result;
79+
}
80+
81+
private List<SuiteBuilder.RunnerFilter.Value> getFilters() {
82+
return fTestClass.getAnnotatedFieldValues(fInstance,
83+
SuiteBuilder.RunnerFilter.class, SuiteBuilder.RunnerFilter.Value.class);
84+
}
85+
86+
private List<Runner> runnersForClasses(List<Class<?>> allPossibleClasses) throws InitializationError {
87+
return new AllDefaultPossibilitiesBuilder(true).runners(fTestClass
88+
.getJavaClass(), allPossibleClasses);
89+
}
90+
91+
public List<Class<?>> gatherClasses() {
92+
ArrayList<Class<?>> result= new ArrayList<Class<?>>();
93+
List<SuiteBuilder.Classes.Value> classeses= fTestClass.getAnnotatedFieldValues(
94+
fInstance, SuiteBuilder.Classes.class, SuiteBuilder.Classes.Value.class);
95+
for (SuiteBuilder.Classes.Value each : classeses)
96+
result.addAll(each.get());
97+
return result;
98+
}
99+
}

src/main/java/org/junit/runners/model/RunnerBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ public List<Runner> runners(Class<?> parent, Class<?>[] children)
8787
}
8888
}
8989

90+
public List<Runner> runners(Class<?> parent, List<Class<?>> children)
91+
throws InitializationError {
92+
return runners(parent, children.toArray(new Class<?>[0]));
93+
}
94+
9095
private List<Runner> runners(Class<?>[] children) {
9196
ArrayList<Runner> runners= new ArrayList<Runner>();
9297
for (Class<?> each : children) {

src/test/java/org/junit/tests/experimental/categories/SuiteBuilderTest.java

Lines changed: 9 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -5,138 +5,32 @@
55
import static org.junit.experimental.results.PrintableResult.testResult;
66
import static org.junit.experimental.results.ResultMatchers.isSuccessful;
77

8-
import java.lang.annotation.Retention;
9-
import java.lang.annotation.RetentionPolicy;
10-
import java.util.ArrayList;
118
import java.util.Arrays;
12-
import java.util.Collection;
13-
import java.util.List;
149

1510
import org.junit.Test;
1611
import org.junit.experimental.categories.Category;
1712
import org.junit.experimental.categories.CategoryFilter;
13+
import org.junit.experimental.runners.Listed;
14+
import org.junit.experimental.runners.SuiteBuilder;
15+
import org.junit.experimental.runners.SuiteBuilder.Classes;
16+
import org.junit.experimental.runners.SuiteBuilder.RunnerFilter;
1817
import org.junit.runner.Description;
1918
import org.junit.runner.JUnitCore;
2019
import org.junit.runner.Result;
2120
import org.junit.runner.RunWith;
2221
import org.junit.runner.Runner;
23-
import org.junit.runner.notification.RunNotifier;
2422
import org.junit.runners.BlockJUnit4ClassRunner;
2523
import org.junit.runners.model.InitializationError;
26-
import org.junit.runners.model.TestClass;
2724

2825
public class SuiteBuilderTest {
29-
@Retention(RetentionPolicy.RUNTIME)
30-
public @interface RunnerFilter {
31-
public static interface Value {
32-
public abstract List<Runner> matchingRunners(
33-
List<Runner> allPossibleRunners);
34-
}
35-
}
36-
37-
public static class Listed implements Classes.Value {
38-
private final Class<?>[] fClasses;
39-
40-
public Listed(Class<?>... classes) {
41-
fClasses= classes;
42-
}
43-
44-
public List<? extends Class<?>> get() {
45-
return Arrays.asList(fClasses);
46-
}
47-
}
48-
49-
// Classes -> RunnerBuilder
50-
51-
@Retention(RetentionPolicy.RUNTIME)
52-
public @interface Classes {
53-
public static interface Value {
54-
public abstract Collection<? extends Class<?>> get();
55-
}
56-
}
57-
58-
public static class SuiteBuilder extends Runner {
59-
private final TestClass fTestClass;
60-
61-
private final Object fInstance;
62-
63-
private final List<Runner> fRunners;
64-
65-
public SuiteBuilder(Class<?> testClass) throws InitializationError {
66-
fTestClass= new TestClass(testClass);
67-
// TODO: extract complexity
68-
try {
69-
fInstance= fTestClass.getOnlyConstructor().newInstance();
70-
} catch (Exception e) {
71-
throw new InitializationError(e);
72-
}
73-
fRunners= computeRunners();
74-
}
75-
76-
@Override
77-
public Description getDescription() {
78-
Description description= Description.createSuiteDescription(fTestClass.getJavaClass());
79-
for (Runner each : fRunners) {
80-
description.addChild(each.getDescription());
81-
}
82-
return description;
83-
}
84-
85-
// TODO: require an instance?
86-
@Override
87-
public void run(RunNotifier notifier) {
88-
for (Runner each : fRunners)
89-
each.run(notifier);
90-
}
91-
92-
private List<Runner> computeRunners() {
93-
List<Class<?>> allPossibleClasses= gatherClasses();
94-
List<Runner> allPossibleRunners= runnersForClasses(allPossibleClasses);
95-
return filterRunners(allPossibleRunners);
96-
}
97-
98-
private List<Runner> filterRunners(List<Runner> allPossibleRunners) {
99-
List<Runner> result= allPossibleRunners;
100-
for (RunnerFilter.Value each : getFilters())
101-
result= each.matchingRunners(result);
102-
return result;
103-
}
104-
105-
private List<RunnerFilter.Value> getFilters() {
106-
return fTestClass.getAnnotatedFieldValues(fInstance,
107-
RunnerFilter.class, RunnerFilter.Value.class);
108-
}
109-
110-
private List<Runner> runnersForClasses(List<Class<?>> allPossibleClasses) {
111-
// TODO: cheating
112-
ArrayList<Runner> result= new ArrayList<Runner>();
113-
for (Class<?> each : allPossibleClasses) {
114-
try {
115-
result.add(new BlockJUnit4ClassRunner(each));
116-
} catch (InitializationError e) {
117-
// TODO Auto-generated catch block
118-
e.printStackTrace();
119-
}
120-
}
121-
return result;
122-
}
123-
124-
private List<Class<?>> gatherClasses() {
125-
ArrayList<Class<?>> result= new ArrayList<Class<?>>();
126-
List<Classes.Value> classeses= fTestClass.getAnnotatedFieldValues(
127-
fInstance, Classes.class, Classes.Value.class);
128-
for (Classes.Value each : classeses)
129-
result.addAll(each.get());
130-
return result;
131-
}
132-
}
133-
13426
static class Yes {
13527
}
13628

13729
static class No {
13830
}
13931

32+
// TODO: test multiple filters, multiple class sources
33+
14034
@Category(Yes.class)
14135
public static class Yes1 {
14236
@Test
@@ -168,7 +62,7 @@ public static class OnlyYesJustOne {
16862
}
16963

17064
@RunWith(SuiteBuilder.class)
171-
public static class OnlyYesMaybeTwo {
65+
public static class OnlyYes {
17266
@Classes
17367
public Listed classes= new Listed(Yes1.class, Yes2.class, No1.class);
17468

@@ -212,9 +106,9 @@ public void onlyRunOne() {
212106

213107
@Test
214108
public void runTwo() {
215-
Result result= new JUnitCore().run(OnlyYesMaybeTwo.class);
109+
Result result= new JUnitCore().run(OnlyYes.class);
216110
assertEquals(2, result.getRunCount());
217-
assertThat(testResult(OnlyYesMaybeTwo.class), isSuccessful());
111+
assertThat(testResult(OnlyYes.class), isSuccessful());
218112
}
219113

220114
@Test

0 commit comments

Comments
 (0)