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> 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> 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> get() { - return Arrays.asList(fClasses); - } - } - - // Classes -> RunnerBuilder - - @Retention(RetentionPolicy.RUNTIME) - public @interface Classes { - public static interface Value { - public abstract Collection> 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