diff --git a/build.xml b/build.xml
index 5f7d65bb951f..c9635aa28410 100644
--- a/build.xml
+++ b/build.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/doc/ReleaseNotes4.9-SNAPSHOT-20100512-0041.html b/doc/ReleaseNotes4.9-SNAPSHOT-20100512-0041.html
new file mode 100644
index 000000000000..6b99bb39dd9c
--- /dev/null
+++ b/doc/ReleaseNotes4.9-SNAPSHOT-20100512-0041.html
@@ -0,0 +1,4 @@
+
+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.
+Use of uninitialized value in substitution (s///) at build/Markdown.pl line 245.
+Use of uninitialized value in substitution (s///) at build/Markdown.pl line 246.
diff --git a/doc/ReleaseNotes4.9.html b/doc/ReleaseNotes4.9.html
new file mode 100644
index 000000000000..a320c9b85cea
--- /dev/null
+++ b/doc/ReleaseNotes4.9.html
@@ -0,0 +1,28 @@
+
Summary of Changes in version 4.9
+
+SuiteBuilder
+
+A new way of declaring suites to run. SuiteBuilder allows for flexible
+specification of where to find the classes containing tests, and how
+to filter the resulting runners. This suite class lists the
+explicit test classes to consider running, and then filters it down
+to only those tests or classes annotated with @Category(Yes.class)
:
+
+@RunWith(SuiteBuilder.class)
+public static class OnlyYes {
+ @Classes
+ public Listed classes= new Listed(Yes1.class, Yes2.class, No1.class);
+
+ @RunnerFilter
+ public CategoryFilter filter= CategoryFilter.include(Yes.class);
+}
+
+
+We hope to soon include other implementations for the @Classes annotation,
+including a classpath-searching test gatherer.
+
+Bug fixes
+
+
+- github#98: assumeTrue() does not work with expected exceptions
+
diff --git a/doc/ReleaseNotes4.9.txt b/doc/ReleaseNotes4.9.txt
index cbee7e45b8b0..ae4a5027254a 100644
--- a/doc/ReleaseNotes4.9.txt
+++ b/doc/ReleaseNotes4.9.txt
@@ -1,5 +1,25 @@
## Summary of Changes in version 4.9 ##
+### SuiteBuilder ###
+
+A new way of declaring suites to run. SuiteBuilder allows for flexible
+specification of where to find the classes containing tests, and how
+to filter the resulting runners. This suite class lists the
+explicit test classes to consider running, and then filters it down
+to only those tests or classes annotated with `@Category(Yes.class)`:
+
+ @RunWith(SuiteBuilder.class)
+ public static class OnlyYes {
+ @Classes
+ public Listed classes= new Listed(Yes1.class, Yes2.class, No1.class);
+
+ @RunnerFilter
+ public CategoryFilter filter= CategoryFilter.include(Yes.class);
+ }
+
+We hope to soon include other implementations for the @Classes annotation,
+including a classpath-searching test gatherer.
+
### Bug fixes ###
- github#98: assumeTrue() does not work with expected exceptions
\ No newline at end of file
diff --git a/src/main/java/junit/runner/Version.java b/src/main/java/junit/runner/Version.java
index 5f5938640408..9e9366430d0b 100644
--- a/src/main/java/junit/runner/Version.java
+++ b/src/main/java/junit/runner/Version.java
@@ -9,7 +9,7 @@ private Version() {
}
public static String id() {
- return "4.8.2";
+ return "4.9-SNAPSHOT-20100512-0041";
}
public static void main(String[] args) {
diff --git a/src/main/java/org/junit/experimental/categories/CategoryFilter.java b/src/main/java/org/junit/experimental/categories/CategoryFilter.java
index 5f7514de1cf8..8d51ca2bf443 100644
--- a/src/main/java/org/junit/experimental/categories/CategoryFilter.java
+++ b/src/main/java/org/junit/experimental/categories/CategoryFilter.java
@@ -8,10 +8,10 @@
import java.util.Arrays;
import java.util.List;
+import org.junit.experimental.runners.SuiteBuilder;
import org.junit.runner.Runner;
-import org.junit.tests.experimental.categories.SuiteBuilderTest.RunnerFilter;
-public class CategoryFilter implements RunnerFilter.Value {
+public class CategoryFilter implements SuiteBuilder.RunnerFilter.Value {
private final Class> fIncluded;
public CategoryFilter(Class> included) {
diff --git a/src/main/java/org/junit/experimental/runners/Listed.java b/src/main/java/org/junit/experimental/runners/Listed.java
new file mode 100644
index 000000000000..83ec2dc522e5
--- /dev/null
+++ b/src/main/java/org/junit/experimental/runners/Listed.java
@@ -0,0 +1,19 @@
+/**
+ *
+ */
+package org.junit.experimental.runners;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Listed implements SuiteBuilder.Classes.Value {
+ private final Class>[] fClasses;
+
+ public Listed(Class>... classes) {
+ fClasses= classes;
+ }
+
+ public List extends Class>> get() {
+ return Arrays.asList(fClasses);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/junit/experimental/runners/SuiteBuilder.java b/src/main/java/org/junit/experimental/runners/SuiteBuilder.java
new file mode 100644
index 000000000000..b02855960c64
--- /dev/null
+++ b/src/main/java/org/junit/experimental/runners/SuiteBuilder.java
@@ -0,0 +1,99 @@
+/**
+ *
+ */
+package org.junit.experimental.runners;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.TestClass;
+
+public class SuiteBuilder extends Runner {
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface RunnerFilter {
+ public static interface Value {
+ public abstract List matchingRunners(
+ List allPossibleRunners);
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Classes {
+ public static interface Value {
+ public abstract Collection extends Class>> get();
+ }
+ }
+
+ private final TestClass fTestClass;
+ private final Object fInstance;
+ private final List fRunners;
+
+ public SuiteBuilder(Class> testClass) throws InitializationError {
+ fTestClass= new TestClass(testClass);
+ fInstance = createInstance();
+ fRunners= computeRunners();
+ }
+
+ private Object createInstance() throws InitializationError {
+ try {
+ return fTestClass.getOnlyConstructor().newInstance();
+ } catch (Exception e) {
+ throw new InitializationError(e);
+ }
+ }
+
+ @Override
+ public Description getDescription() {
+ Description description= Description.createSuiteDescription(fTestClass.getJavaClass());
+ for (Runner each : fRunners) {
+ description.addChild(each.getDescription());
+ }
+ return description;
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ for (Runner each : fRunners)
+ each.run(notifier);
+ }
+
+ private List computeRunners() throws InitializationError {
+ List> allPossibleClasses= gatherClasses();
+ List allPossibleRunners= runnersForClasses(allPossibleClasses);
+ return filterRunners(allPossibleRunners);
+ }
+
+ private List filterRunners(List allPossibleRunners) {
+ List result= allPossibleRunners;
+ for (SuiteBuilder.RunnerFilter.Value each : getFilters())
+ result= each.matchingRunners(result);
+ return result;
+ }
+
+ private List getFilters() {
+ return fTestClass.getAnnotatedFieldValues(fInstance,
+ SuiteBuilder.RunnerFilter.class, SuiteBuilder.RunnerFilter.Value.class);
+ }
+
+ private List runnersForClasses(List> allPossibleClasses) throws InitializationError {
+ return new AllDefaultPossibilitiesBuilder(true).runners(fTestClass
+ .getJavaClass(), allPossibleClasses);
+ }
+
+ public List> gatherClasses() {
+ ArrayList> result= new ArrayList>();
+ List classeses= fTestClass.getAnnotatedFieldValues(
+ fInstance, SuiteBuilder.Classes.class, SuiteBuilder.Classes.Value.class);
+ for (SuiteBuilder.Classes.Value each : classeses)
+ result.addAll(each.get());
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/junit/runners/model/RunnerBuilder.java b/src/main/java/org/junit/runners/model/RunnerBuilder.java
index 0e4371e1a27d..3a334be7280d 100644
--- a/src/main/java/org/junit/runners/model/RunnerBuilder.java
+++ b/src/main/java/org/junit/runners/model/RunnerBuilder.java
@@ -87,6 +87,11 @@ public List runners(Class> parent, Class>[] children)
}
}
+ public List runners(Class> parent, List> children)
+ throws InitializationError {
+ return runners(parent, children.toArray(new Class>[0]));
+ }
+
private List runners(Class>[] children) {
ArrayList runners= new ArrayList();
for (Class> each : children) {
diff --git a/src/test/java/org/junit/tests/experimental/categories/SuiteBuilderTest.java b/src/test/java/org/junit/tests/experimental/categories/SuiteBuilderTest.java
index df7f957c9681..ed746cdb6387 100644
--- a/src/test/java/org/junit/tests/experimental/categories/SuiteBuilderTest.java
+++ b/src/test/java/org/junit/tests/experimental/categories/SuiteBuilderTest.java
@@ -5,138 +5,32 @@
import static org.junit.experimental.results.PrintableResult.testResult;
import static org.junit.experimental.results.ResultMatchers.isSuccessful;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.experimental.categories.CategoryFilter;
+import org.junit.experimental.runners.Listed;
+import org.junit.experimental.runners.SuiteBuilder;
+import org.junit.experimental.runners.SuiteBuilder.Classes;
+import org.junit.experimental.runners.SuiteBuilder.RunnerFilter;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runner.Runner;
-import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
-import org.junit.runners.model.TestClass;
public class SuiteBuilderTest {
- @Retention(RetentionPolicy.RUNTIME)
- public @interface RunnerFilter {
- public static interface Value {
- public abstract List matchingRunners(
- List allPossibleRunners);
- }
- }
-
- public static class Listed implements Classes.Value {
- private final Class>[] fClasses;
-
- public Listed(Class>... classes) {
- fClasses= classes;
- }
-
- public List extends Class>> get() {
- return Arrays.asList(fClasses);
- }
- }
-
- // Classes -> RunnerBuilder
-
- @Retention(RetentionPolicy.RUNTIME)
- public @interface Classes {
- public static interface Value {
- public abstract Collection extends Class>> get();
- }
- }
-
- public static class SuiteBuilder extends Runner {
- private final TestClass fTestClass;
-
- private final Object fInstance;
-
- private final List fRunners;
-
- public SuiteBuilder(Class> testClass) throws InitializationError {
- fTestClass= new TestClass(testClass);
- // TODO: extract complexity
- try {
- fInstance= fTestClass.getOnlyConstructor().newInstance();
- } catch (Exception e) {
- throw new InitializationError(e);
- }
- fRunners= computeRunners();
- }
-
- @Override
- public Description getDescription() {
- Description description= Description.createSuiteDescription(fTestClass.getJavaClass());
- for (Runner each : fRunners) {
- description.addChild(each.getDescription());
- }
- return description;
- }
-
- // TODO: require an instance?
- @Override
- public void run(RunNotifier notifier) {
- for (Runner each : fRunners)
- each.run(notifier);
- }
-
- private List computeRunners() {
- List> allPossibleClasses= gatherClasses();
- List allPossibleRunners= runnersForClasses(allPossibleClasses);
- return filterRunners(allPossibleRunners);
- }
-
- private List filterRunners(List allPossibleRunners) {
- List result= allPossibleRunners;
- for (RunnerFilter.Value each : getFilters())
- result= each.matchingRunners(result);
- return result;
- }
-
- private List getFilters() {
- return fTestClass.getAnnotatedFieldValues(fInstance,
- RunnerFilter.class, RunnerFilter.Value.class);
- }
-
- private List runnersForClasses(List> allPossibleClasses) {
- // TODO: cheating
- ArrayList result= new ArrayList();
- for (Class> each : allPossibleClasses) {
- try {
- result.add(new BlockJUnit4ClassRunner(each));
- } catch (InitializationError e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return result;
- }
-
- private List> gatherClasses() {
- ArrayList> result= new ArrayList>();
- List classeses= fTestClass.getAnnotatedFieldValues(
- fInstance, Classes.class, Classes.Value.class);
- for (Classes.Value each : classeses)
- result.addAll(each.get());
- return result;
- }
- }
-
static class Yes {
}
static class No {
}
+ // TODO: test multiple filters, multiple class sources
+
@Category(Yes.class)
public static class Yes1 {
@Test
@@ -168,7 +62,7 @@ public static class OnlyYesJustOne {
}
@RunWith(SuiteBuilder.class)
- public static class OnlyYesMaybeTwo {
+ public static class OnlyYes {
@Classes
public Listed classes= new Listed(Yes1.class, Yes2.class, No1.class);
@@ -212,9 +106,9 @@ public void onlyRunOne() {
@Test
public void runTwo() {
- Result result= new JUnitCore().run(OnlyYesMaybeTwo.class);
+ Result result= new JUnitCore().run(OnlyYes.class);
assertEquals(2, result.getRunCount());
- assertThat(testResult(OnlyYesMaybeTwo.class), isSuccessful());
+ assertThat(testResult(OnlyYes.class), isSuccessful());
}
@Test