Index: maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java =================================================================== --- maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java (revision 492552) +++ maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java (working copy) @@ -498,6 +498,10 @@ // different one since its based on the source level, not the JVM. Prune using the filter. addProvider( surefireBooter, "surefire-testng", surefireArtifact.getBaseVersion(), testNgArtifact ); } + else if (junitArtifact != null && junitArtifact.getBaseVersion().startsWith("4")) + { + addProvider( surefireBooter, "surefire-junit4", surefireArtifact.getBaseVersion(), null ); + } else { // add the JUnit provider as default - it doesn't require JUnit to be present, @@ -586,9 +590,19 @@ } else { + String junitDirectoryTestSuite; + if (junitArtifact.getBaseVersion().startsWith("4")) + { + junitDirectoryTestSuite = "org.apache.maven.surefire.junit4.JUnit4DirectoryTestSuite"; + } + else + { + junitDirectoryTestSuite = "org.apache.maven.surefire.junit.JUnitDirectoryTestSuite"; + } + // fall back to JUnit, which also contains POJO support. Also it can run // classes compiled against JUnit since it has a dependency on JUnit itself. - surefireBooter.addTestSuite( "org.apache.maven.surefire.junit.JUnitDirectoryTestSuite", + surefireBooter.addTestSuite( junitDirectoryTestSuite, new Object[]{testClassesDirectory, includes, excludes} ); } } Index: surefire-providers/pom.xml =================================================================== --- surefire-providers/pom.xml (revision 492552) +++ surefire-providers/pom.xml (working copy) @@ -27,6 +27,7 @@ SureFire Providers surefire-junit + surefire-junit4 surefire-testng Property changes on: surefire-providers\surefire-junit ___________________________________________________________________ Name: svn:ignore - target *.iml *.ipr *.iws + target *.iml *.ipr *.iws .settings .classpath .project Property changes on: surefire-providers\surefire-junit4 ___________________________________________________________________ Name: svn:ignore + target .settings .classpath .project Index: surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4StackTraceWriter.java =================================================================== --- surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4StackTraceWriter.java (revision 0) +++ surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4StackTraceWriter.java (revision 0) @@ -0,0 +1,59 @@ +package org.apache.maven.surefire.junit4; + +import org.apache.maven.surefire.report.StackTraceWriter; +import org.junit.runner.notification.Failure; + +/** + * Writes out a specific {@link org.junit.runner.notification.Failure} for + * surefire as a stacktrace. + * + * @author Karl M. Davis + */ +public class JUnit4StackTraceWriter implements StackTraceWriter +{ + // Member Variables + private Failure junitFailure; + + /** + * Constructor. + * + * @param junitFailure + * the {@link Failure} that this will be operating on + */ + public JUnit4StackTraceWriter(Failure junitFailure) + { + this.junitFailure = junitFailure; + } + + /* + * (non-Javadoc) + * + * @see org.apache.maven.surefire.report.StackTraceWriter#writeTraceToString() + */ + public String writeTraceToString() + { + return junitFailure.getTrace(); + } + + /** + * At the moment, returns the same as {@link #writeTraceToString()}. + * + * @see org.apache.maven.surefire.report.StackTraceWriter#writeTrimmedTraceToString() + */ + public String writeTrimmedTraceToString() + { + return junitFailure.getTrace(); + } + + /** + * Returns the exception associated with this failure. + * + * @see org.apache.maven.surefire.report.StackTraceWriter#getThrowable() + */ + public Throwable getThrowable() + { + return junitFailure.getException(); + } + +} + Index: surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSet.java =================================================================== --- surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSet.java (revision 0) +++ surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSet.java (revision 0) @@ -0,0 +1,60 @@ +package org.apache.maven.surefire.junit4; + +import org.apache.maven.surefire.report.ReporterManager; +import org.apache.maven.surefire.testset.AbstractTestSet; +import org.apache.maven.surefire.testset.TestSetFailedException; +import org.junit.runner.Request; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; + +public class JUnit4TestSet extends AbstractTestSet +{ + // Member Variables + private Runner junitTestRunner; + + /** + * Constructor. + * + * @param testClass the class to be run as a test + */ + protected JUnit4TestSet(Class testClass) + { + super(testClass); + + junitTestRunner = Request.aClass(testClass).getRunner(); + } + + /** + * Actually runs the test and adds the tests results to the reportManager. + * + * @see org.apache.maven.surefire.testset.SurefireTestSet#execute(org.apache.maven.surefire.report.ReporterManager, java.lang.ClassLoader) + */ + public void execute(ReporterManager reportManager, ClassLoader loader) + throws TestSetFailedException + { + RunNotifier fNotifier = new RunNotifier(); + RunListener listener = new JUnit4TestSetReporter(this, reportManager); + fNotifier.addListener(listener); + + try + { + junitTestRunner.run(fNotifier); + } + finally + { + fNotifier.removeListener(listener); + } + } + + /** + * Returns the number of tests to be run in this class. + * + * @see org.apache.maven.surefire.testset.SurefireTestSet#getTestCount() + */ + public int getTestCount() throws TestSetFailedException + { + return junitTestRunner.testCount(); + } +} + Index: surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4DirectoryTestSuite.java =================================================================== --- surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4DirectoryTestSuite.java (revision 0) +++ surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4DirectoryTestSuite.java (revision 0) @@ -0,0 +1,41 @@ +package org.apache.maven.surefire.junit4; + +import java.io.File; +import java.util.ArrayList; + +import org.apache.maven.surefire.suite.AbstractDirectoryTestSuite; +import org.apache.maven.surefire.testset.SurefireTestSet; +import org.apache.maven.surefire.testset.TestSetFailedException; + +/** + * Test suite for JUnit4 based on a directory of Java test classes. This is + * capable of running both JUnit3 and JUnit4 test classes (I think). + * + * @author Karl M. Davis + */ +public class JUnit4DirectoryTestSuite extends AbstractDirectoryTestSuite +{ + /** + * Constructor. + */ + public JUnit4DirectoryTestSuite(File basedir, ArrayList includes, + ArrayList excludes) + { + super(basedir, includes, excludes); + } + + /** + * This method will be called for each class to be run as a test. It returns + * a surefire test set that will later be executed. + * + * @see org.apache.maven.surefire.suite.AbstractDirectoryTestSuite#createTestSet(java.lang.Class, + * java.lang.ClassLoader) + */ + protected SurefireTestSet createTestSet(Class testClass, + ClassLoader classLoader) throws TestSetFailedException + { + return new JUnit4TestSet(testClass); + } + +} + Index: surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSetReporter.java =================================================================== --- surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSetReporter.java (revision 0) +++ surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSetReporter.java (revision 0) @@ -0,0 +1,130 @@ +package org.apache.maven.surefire.junit4; + +import java.util.ResourceBundle; + +import org.apache.maven.surefire.Surefire; +import org.apache.maven.surefire.report.ReportEntry; +import org.apache.maven.surefire.report.ReporterManager; +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +public class JUnit4TestSetReporter extends RunListener +{ + // Constants + private static ResourceBundle bundle = ResourceBundle.getBundle( Surefire.SUREFIRE_BUNDLE_NAME ); + + // Member Variables + private JUnit4TestSet testSet; + private ReporterManager reportMgr; + /** + * This flag is set after a failure has occurred so that a testSucceeded event is not fired. This is necessary because JUnit4 always fires a testRunFinished event-- even if there was a failure. + */ + private boolean failureFlag; + + /** + * Constructor. + * + * @param testSet + * the specific test set that this will report on as it is + * executed + * @param reportManager + * the report manager to log testing events to + */ + JUnit4TestSetReporter(JUnit4TestSet testSet, ReporterManager reportManager) + { + this.testSet = testSet; + this.reportMgr = reportManager; + } + + /** + * Called right before any tests from a specific class are run. + * + * @see org.junit.runner.notification.RunListener#testRunStarted(org.junit.runner.Description) + */ + public void testRunStarted(Description description) throws Exception + { + String rawString = bundle.getString( "testSetStarting" ); + ReportEntry report = new ReportEntry(testSet, testSet.getName(), rawString); + + this.reportMgr.testSetStarting(report); + } + + /** + * Called right after all tests from a specific class are run. + * + * @see org.junit.runner.notification.RunListener#testRunFinished(org.junit.runner.Result) + */ + public void testRunFinished(Result result) throws Exception + { + String rawString = bundle.getString( "testSetCompletedNormally" ); + ReportEntry report = new ReportEntry(testSet, testSet.getName(), rawString); + + this.reportMgr.testSetCompleted(report); + this.reportMgr.reset(); + } + + /** + * Called when a specific test has been skipped (for whatever reason). + * + * @see org.junit.runner.notification.RunListener#testIgnored(org.junit.runner.Description) + */ + public void testIgnored(Description description) throws Exception + { + String rawString = bundle.getString( "testSkipped" ); + ReportEntry report = new ReportEntry(testSet, description.getDisplayName(), rawString); + + this.reportMgr.testSkipped(report); + } + + /** + * Called when a specific test has started. + * + * @see org.junit.runner.notification.RunListener#testStarted(org.junit.runner.Description) + */ + public void testStarted(Description description) throws Exception + { + String rawString = bundle.getString( "testStarting" ); + ReportEntry report = new ReportEntry(testSet, description.getDisplayName(), rawString); + + this.reportMgr.testStarting(report); + + this.failureFlag = false; + } + + /** + * Called when a specific test has failed. + * + * @see org.junit.runner.notification.RunListener#testFailure(org.junit.runner.notification.Failure) + */ + public void testFailure(Failure failure) throws Exception + { + String rawString = bundle.getString( "executeException" ); + ReportEntry report = new ReportEntry(testSet, failure.getTestHeader(), rawString, new JUnit4StackTraceWriter(failure)); + + if(failure.getException() instanceof AssertionError) + this.reportMgr.testFailed(report); + else + this.reportMgr.testError(report); + + failureFlag = true; + } + + /** + * Called after a specific test has finished. + * + * @see org.junit.runner.notification.RunListener#testFinished(org.junit.runner.Description) + */ + public void testFinished(Description description) throws Exception + { + if(failureFlag == false) + { + String rawString = bundle.getString( "testSuccessful" ); + ReportEntry report = new ReportEntry(testSet, description.getDisplayName(), rawString); + + this.reportMgr.testSucceeded(report); + } + } +} + Index: surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4DirectoryTestSuite.java =================================================================== --- surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4DirectoryTestSuite.java (revision 0) +++ surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4DirectoryTestSuite.java (revision 0) @@ -0,0 +1,41 @@ +package org.apache.maven.surefire.junit4; + +import java.io.File; +import java.util.ArrayList; + +import org.apache.maven.surefire.suite.AbstractDirectoryTestSuite; +import org.apache.maven.surefire.testset.SurefireTestSet; +import org.apache.maven.surefire.testset.TestSetFailedException; + +/** + * Test suite for JUnit4 based on a directory of Java test classes. This is + * capable of running both JUnit3 and JUnit4 test classes (I think). + * + * @author Karl M. Davis + */ +public class JUnit4DirectoryTestSuite extends AbstractDirectoryTestSuite +{ + /** + * Constructor. + */ + public JUnit4DirectoryTestSuite(File basedir, ArrayList includes, + ArrayList excludes) + { + super(basedir, includes, excludes); + } + + /** + * This method will be called for each class to be run as a test. It returns + * a surefire test set that will later be executed. + * + * @see org.apache.maven.surefire.suite.AbstractDirectoryTestSuite#createTestSet(java.lang.Class, + * java.lang.ClassLoader) + */ + protected SurefireTestSet createTestSet(Class testClass, + ClassLoader classLoader) throws TestSetFailedException + { + return new JUnit4TestSet(testClass); + } + +} + Index: surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4StackTraceWriter.java =================================================================== --- surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4StackTraceWriter.java (revision 0) +++ surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4StackTraceWriter.java (revision 0) @@ -0,0 +1,59 @@ +package org.apache.maven.surefire.junit4; + +import org.apache.maven.surefire.report.StackTraceWriter; +import org.junit.runner.notification.Failure; + +/** + * Writes out a specific {@link org.junit.runner.notification.Failure} for + * surefire as a stacktrace. + * + * @author Karl M. Davis + */ +public class JUnit4StackTraceWriter implements StackTraceWriter +{ + // Member Variables + private Failure junitFailure; + + /** + * Constructor. + * + * @param junitFailure + * the {@link Failure} that this will be operating on + */ + public JUnit4StackTraceWriter(Failure junitFailure) + { + this.junitFailure = junitFailure; + } + + /* + * (non-Javadoc) + * + * @see org.apache.maven.surefire.report.StackTraceWriter#writeTraceToString() + */ + public String writeTraceToString() + { + return junitFailure.getTrace(); + } + + /** + * At the moment, returns the same as {@link #writeTraceToString()}. + * + * @see org.apache.maven.surefire.report.StackTraceWriter#writeTrimmedTraceToString() + */ + public String writeTrimmedTraceToString() + { + return junitFailure.getTrace(); + } + + /** + * Returns the exception associated with this failure. + * + * @see org.apache.maven.surefire.report.StackTraceWriter#getThrowable() + */ + public Throwable getThrowable() + { + return junitFailure.getException(); + } + +} + Index: surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSet.java =================================================================== --- surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSet.java (revision 0) +++ surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSet.java (revision 0) @@ -0,0 +1,60 @@ +package org.apache.maven.surefire.junit4; + +import org.apache.maven.surefire.report.ReporterManager; +import org.apache.maven.surefire.testset.AbstractTestSet; +import org.apache.maven.surefire.testset.TestSetFailedException; +import org.junit.runner.Request; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; + +public class JUnit4TestSet extends AbstractTestSet +{ + // Member Variables + private Runner junitTestRunner; + + /** + * Constructor. + * + * @param testClass the class to be run as a test + */ + protected JUnit4TestSet(Class testClass) + { + super(testClass); + + junitTestRunner = Request.aClass(testClass).getRunner(); + } + + /** + * Actually runs the test and adds the tests results to the reportManager. + * + * @see org.apache.maven.surefire.testset.SurefireTestSet#execute(org.apache.maven.surefire.report.ReporterManager, java.lang.ClassLoader) + */ + public void execute(ReporterManager reportManager, ClassLoader loader) + throws TestSetFailedException + { + RunNotifier fNotifier = new RunNotifier(); + RunListener listener = new JUnit4TestSetReporter(this, reportManager); + fNotifier.addListener(listener); + + try + { + junitTestRunner.run(fNotifier); + } + finally + { + fNotifier.removeListener(listener); + } + } + + /** + * Returns the number of tests to be run in this class. + * + * @see org.apache.maven.surefire.testset.SurefireTestSet#getTestCount() + */ + public int getTestCount() throws TestSetFailedException + { + return junitTestRunner.testCount(); + } +} + Index: surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSetReporter.java =================================================================== --- surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSetReporter.java (revision 0) +++ surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4TestSetReporter.java (revision 0) @@ -0,0 +1,130 @@ +package org.apache.maven.surefire.junit4; + +import java.util.ResourceBundle; + +import org.apache.maven.surefire.Surefire; +import org.apache.maven.surefire.report.ReportEntry; +import org.apache.maven.surefire.report.ReporterManager; +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +public class JUnit4TestSetReporter extends RunListener +{ + // Constants + private static ResourceBundle bundle = ResourceBundle.getBundle( Surefire.SUREFIRE_BUNDLE_NAME ); + + // Member Variables + private JUnit4TestSet testSet; + private ReporterManager reportMgr; + /** + * This flag is set after a failure has occurred so that a testSucceeded event is not fired. This is necessary because JUnit4 always fires a testRunFinished event-- even if there was a failure. + */ + private boolean failureFlag; + + /** + * Constructor. + * + * @param testSet + * the specific test set that this will report on as it is + * executed + * @param reportManager + * the report manager to log testing events to + */ + JUnit4TestSetReporter(JUnit4TestSet testSet, ReporterManager reportManager) + { + this.testSet = testSet; + this.reportMgr = reportManager; + } + + /** + * Called right before any tests from a specific class are run. + * + * @see org.junit.runner.notification.RunListener#testRunStarted(org.junit.runner.Description) + */ + public void testRunStarted(Description description) throws Exception + { + String rawString = bundle.getString( "testSetStarting" ); + ReportEntry report = new ReportEntry(testSet, testSet.getName(), rawString); + + this.reportMgr.testSetStarting(report); + } + + /** + * Called right after all tests from a specific class are run. + * + * @see org.junit.runner.notification.RunListener#testRunFinished(org.junit.runner.Result) + */ + public void testRunFinished(Result result) throws Exception + { + String rawString = bundle.getString( "testSetCompletedNormally" ); + ReportEntry report = new ReportEntry(testSet, testSet.getName(), rawString); + + this.reportMgr.testSetCompleted(report); + this.reportMgr.reset(); + } + + /** + * Called when a specific test has been skipped (for whatever reason). + * + * @see org.junit.runner.notification.RunListener#testIgnored(org.junit.runner.Description) + */ + public void testIgnored(Description description) throws Exception + { + String rawString = bundle.getString( "testSkipped" ); + ReportEntry report = new ReportEntry(testSet, description.getDisplayName(), rawString); + + this.reportMgr.testSkipped(report); + } + + /** + * Called when a specific test has started. + * + * @see org.junit.runner.notification.RunListener#testStarted(org.junit.runner.Description) + */ + public void testStarted(Description description) throws Exception + { + String rawString = bundle.getString( "testStarting" ); + ReportEntry report = new ReportEntry(testSet, description.getDisplayName(), rawString); + + this.reportMgr.testStarting(report); + + this.failureFlag = false; + } + + /** + * Called when a specific test has failed. + * + * @see org.junit.runner.notification.RunListener#testFailure(org.junit.runner.notification.Failure) + */ + public void testFailure(Failure failure) throws Exception + { + String rawString = bundle.getString( "executeException" ); + ReportEntry report = new ReportEntry(testSet, failure.getTestHeader(), rawString, new JUnit4StackTraceWriter(failure)); + + if(failure.getException() instanceof AssertionError) + this.reportMgr.testFailed(report); + else + this.reportMgr.testError(report); + + failureFlag = true; + } + + /** + * Called after a specific test has finished. + * + * @see org.junit.runner.notification.RunListener#testFinished(org.junit.runner.Description) + */ + public void testFinished(Description description) throws Exception + { + if(failureFlag == false) + { + String rawString = bundle.getString( "testSuccessful" ); + ReportEntry report = new ReportEntry(testSet, description.getDisplayName(), rawString); + + this.reportMgr.testSucceeded(report); + } + } +} +