Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java (revision ) @@ -23,20 +23,26 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; -import java.util.Date; -import java.net.InetAddress; -import java.net.UnknownHostException; + import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; + import junit.framework.AssertionFailedError; +import junit.framework.JUnit4TestCaseFacade; import junit.framework.Test; + import org.apache.tools.ant.BuildException; import org.apache.tools.ant.util.DOMElementWriter; import org.apache.tools.ant.util.DateUtils; import org.apache.tools.ant.util.FileUtils; +import org.junit.Ignore; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Text; @@ -48,7 +54,7 @@ * @see FormatterElement */ -public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants { +public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants, IgnoredTestListener { private static final double ONE_SECOND = 1000.0; @@ -73,16 +79,29 @@ private Element rootElement; /** * Element for the current test. + * + * The keying of this map is a bit of a hack: tests are keyed by caseName(className) since + * the Test we get for Test-start isn't the same as the Test we get during test-assumption-fail, + * so we can't easily match Test objects without manually iterating over all keys and checking + * individual fields. */ - private Hashtable testElements = new Hashtable(); + private Hashtable testElements = new Hashtable(); /** * tests that failed. */ private Hashtable failedTests = new Hashtable(); /** + * Tests that were skipped. + */ + private Hashtable skippedTests = new Hashtable(); + /** + * Tests that were ignored. See the note above about the key being a bit of a hack. + */ + private Hashtable ignoredTests = new Hashtable(); + /** * Timing helper. */ - private Hashtable testStarts = new Hashtable(); + private Hashtable testStarts = new Hashtable(); /** * Where to write the log to. */ @@ -161,6 +180,7 @@ rootElement.setAttribute(ATTR_TESTS, "" + suite.runCount()); rootElement.setAttribute(ATTR_FAILURES, "" + suite.failureCount()); rootElement.setAttribute(ATTR_ERRORS, "" + suite.errorCount()); + rootElement.setAttribute(ATTR_SKIPPED, "" + suite.skipCount()); rootElement.setAttribute( ATTR_TIME, "" + (suite.getRunTime() / ONE_SECOND)); if (out != null) { @@ -193,9 +213,13 @@ * @param t the test. */ public void startTest(Test t) { - testStarts.put(t, new Long(System.currentTimeMillis())); + testStarts.put(createDescription(t), System.currentTimeMillis()); } + private static String createDescription(Test test) throws BuildException { + return JUnitVersionHelper.getTestCaseName(test) + "(" + JUnitVersionHelper.getTestCaseClassName(test) + ")"; + } + /** * Interface TestListener. * @@ -203,15 +227,16 @@ * @param test the test. */ public void endTest(Test test) { + String testDescription = createDescription(test); + // Fix for bug #5637 - if a junit.extensions.TestSetup is // used and throws an exception during setUp then startTest // would never have been called - if (!testStarts.containsKey(test)) { + if (!testStarts.containsKey(testDescription)) { startTest(test); } - - Element currentTest = null; - if (!failedTests.containsKey(test)) { + Element currentTest; + if (!failedTests.containsKey(test) && !skippedTests.containsKey(testDescription) && !ignoredTests.containsKey(testDescription)) { currentTest = doc.createElement(TESTCASE); String n = JUnitVersionHelper.getTestCaseName(test); currentTest.setAttribute(ATTR_NAME, @@ -221,15 +246,14 @@ currentTest.setAttribute(ATTR_CLASSNAME, JUnitVersionHelper.getTestCaseClassName(test)); rootElement.appendChild(currentTest); - testElements.put(test, currentTest); + testElements.put(createDescription(test), currentTest); } else { - currentTest = (Element) testElements.get(test); + currentTest = testElements.get(testDescription); } - Long l = (Long) testStarts.get(test); + Long l = testStarts.get(createDescription(test)); currentTest.setAttribute(ATTR_TIME, - "" + ((System.currentTimeMillis() - - l.longValue()) / ONE_SECOND)); + "" + ((System.currentTimeMillis() - l) / ONE_SECOND)); } /** @@ -272,9 +296,9 @@ } Element nested = doc.createElement(type); - Element currentTest = null; + Element currentTest; if (test != null) { - currentTest = (Element) testElements.get(test); + currentTest = testElements.get(createDescription(test)); } else { currentTest = rootElement; } @@ -298,4 +322,63 @@ nested.appendChild(doc.createCDATASection(output)); } + @Override + public void testIgnored(Test test) { + String message = null; + if (test != null && test instanceof JUnit4TestCaseFacade) { + //try and get the message coded as part of the ignore + /* + * org.junit.runner.Description contains a getAnnotation(Class) method... but this + * wasn't in older versions of JUnit4 so we have to try and do this by reflection + */ + try { + Class testClass = Class.forName(JUnitVersionHelper.getTestCaseClassName(test)); + + Method testMethod = testClass.getMethod(JUnitVersionHelper.getTestCaseName(test)); + Ignore annotation = testMethod.getAnnotation(Ignore.class); + if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) { + message = annotation.value(); + } + } catch (NoSuchMethodException e) { + // silently ignore - we'll report a skip with no message + } catch (ClassNotFoundException e) { + // silently ignore - we'll report a skip with no message + } + } + formatSkip(test, message); + if (test != null) { + ignoredTests.put(createDescription(test), test); + } + } + + + public void formatSkip(Test test, String message) { + if (test != null) { + endTest(test); + } + + Element nested = doc.createElement("skipped"); + + if (message != null) { + nested.setAttribute("message", message); + } + + Element currentTest; + if (test != null) { + currentTest = testElements.get(createDescription(test)); + } else { + currentTest = rootElement; + } + + currentTest.appendChild(nested); + + } + + @Override + public void testAssumptionFailure(Test test, Throwable failure) { + String message = failure.getMessage(); + formatSkip(test, message); + skippedTests.put(createDescription(test), test); + + } } // XMLJUnitResultFormatter Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/TestListenerWrapper.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/TestListenerWrapper.java (revision ) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/TestListenerWrapper.java (revision ) @@ -0,0 +1,56 @@ +package org.apache.tools.ant.taskdefs.optional.junit; + +import junit.framework.AssertionFailedError; +import junit.framework.JUnit4TestAdapterCache; +import junit.framework.Test; +import junit.framework.TestListener; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; + +public class TestListenerWrapper implements TestListener, IgnoredTestListener { + + private TestListener wrapped; + + public TestListenerWrapper(TestListener listener) { + super(); + wrapped = listener; + } + + @Override + public void addError(Test test, Throwable throwable) { + wrapped.addError(test, throwable); + } + + @Override + public void addFailure(Test test, AssertionFailedError assertionFailedError) { + wrapped.addFailure(test, assertionFailedError); + } + + @Override + public void endTest(Test test) { + wrapped.endTest(test); + } + + @Override + public void startTest(Test test) { + wrapped.startTest(test); + } + + @Override + public void testIgnored(Test test) { + if (wrapped instanceof IgnoredTestListener) { + ((IgnoredTestListener)wrapped).testIgnored(test); + } + } + + @Override + public void testAssumptionFailure(Test test, Throwable throwable) { + if (wrapped instanceof IgnoredTestListener) { + ((IgnoredTestListener)wrapped).testAssumptionFailure(test, throwable); + } + } + + +} Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestResult.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestResult.java (revision ) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestResult.java (revision ) @@ -0,0 +1,81 @@ +package org.apache.tools.ant.taskdefs.optional.junit; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestListener; +import junit.framework.TestResult; + +/** + * Records ignored and skipped tests reported as part of the execution of + * JUnit 4 tests. + * + * @author Michael Clarke + */ +public class IgnoredTestResult extends TestResult { + + + private List listeners = new ArrayList(); + private List ignored = new ArrayList(); + private List skipped = new ArrayList(); + + public IgnoredTestResult() { + super(); + } + + + public synchronized void addListener(TestListener listener) { + if (listener instanceof IgnoredTestListener) { + listeners.add((IgnoredTestListener)listener); + } + super.addListener(listener); + } + + public synchronized void removeListener(TestListener listener) { + if (listener instanceof IgnoredTestListener) { + listeners.remove(listener); + } + super.removeListener(listener); + } + + /** + * Record a test as having been ignored, normally by the @Ignore annotation. + * @param test the test that was ignored. + * @throws Exception is the listener thrown an exception on handling the notification. + */ + public synchronized void testIgnored(Test test) throws Exception { + ignored.add(new TestIgnored(test)); + for (IgnoredTestListener listener : listeners) { + listener.testIgnored(test); + } + } + + /** + * Report how many tests were ignored. + * @return the number of tests reported as ignored during the current execution. + */ + public long ignoredCount() { + return ignored.size(); + } + + /** + * Records a test as having an assumption failure so JUnit will no longer be executing it. + * Under normal circumstances this would be counted as a skipped test. + * @param failure the details of the test and assumption failure. + */ + public void testAssumptionFailure(Test test, Throwable cause) { + skipped.add(new TestIgnored(test)); + for (IgnoredTestListener listener : listeners) { + listener.testAssumptionFailure(test, cause); + } + } + + /** + * Report how many tests has assumption failures. + * @return the number of tests that reported assumption failures during the current execution. + */ + public long skippedCount() { + return skipped.size(); + } +} Index: src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java (revision 1451903) +++ src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java (revision ) @@ -25,7 +25,15 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildFileTest; import org.apache.tools.ant.util.JavaEnvUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; + public class JUnitTaskTest extends BuildFileTest { /** @@ -262,7 +270,7 @@ line); line = reader.readLine(); assertNotNull(line); - assertTrue(line.startsWith("Tests run: 1, Failures: 0, Errors: 0, Time elapsed:")); + assertTrue(line.startsWith("Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed:")); line = reader.readLine(); assertEquals("------------- Standard Output ---------------", line); @@ -296,4 +304,4 @@ assertEquals(search, line); } -} \ No newline at end of file +} Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java (revision ) @@ -144,6 +144,8 @@ sb.append(suite.failureCount()); sb.append(", Errors: "); sb.append(suite.errorCount()); + sb.append(", Skipped: "); + sb.append(suite.skipCount()); sb.append(", Time elapsed: "); sb.append(nf.format(suite.getRunTime() / ONE_SECOND)); sb.append(" sec"); Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java (revision ) @@ -106,6 +106,8 @@ /** tests attribute for testsuite elements */ String ATTR_TESTS = "tests"; + String ATTR_SKIPPED = "skipped"; + /** type attribute for failure and error elements */ String ATTR_TYPE = "type"; Index: lib/libraries.properties IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>windows-1252 =================================================================== --- lib/libraries.properties (revision 1451903) +++ lib/libraries.properties (revision ) @@ -45,7 +45,7 @@ jasper-runtime.version=${jasper-compiler.version} jdepend.version=2.9.1 jruby.version=0.9.8 -junit.version=4.8.1 +junit.version=4.11 jsch.version=0.1.42 jython.version=2.1 #log4j 1.2.15 requires JMS and a few other Sun jars that are not in the m2 repo Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/TestIgnored.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/TestIgnored.java (revision ) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/TestIgnored.java (revision ) @@ -0,0 +1,17 @@ +package org.apache.tools.ant.taskdefs.optional.junit; + +import junit.framework.Test; + +public class TestIgnored { + + private Test test; + + public TestIgnored(Test test) { + this.test = test; + } + + public Test getTest() { + return test; + } + +} Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/CustomJUnit4TestAdapterCache.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/CustomJUnit4TestAdapterCache.java (revision ) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/CustomJUnit4TestAdapterCache.java (revision ) @@ -0,0 +1,63 @@ +package org.apache.tools.ant.taskdefs.optional.junit; + +import junit.framework.JUnit4TestAdapter; +import junit.framework.JUnit4TestAdapterCache; +import junit.framework.TestResult; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; + +/** + * Provides a custom implementation of the notifier for a Junit4TestAdapter + * so that skipped and ignored tests can be reported to the existing + * TestListeners. + * + * @author Michael Clarke + */ +public class CustomJUnit4TestAdapterCache extends JUnit4TestAdapterCache { + + public CustomJUnit4TestAdapterCache() { + super(); + } + + public RunNotifier getNotifier(final TestResult result, final JUnit4TestAdapter adapter) { + + if (!(result instanceof IgnoredTestResult)) { + //the TestResult doesn't support our ignored method, continue with default functionality + return super.getNotifier(result, adapter); + } + + final IgnoredTestResult resultWrapper = (IgnoredTestResult) result; + + RunNotifier notifier = new RunNotifier(); + notifier.addListener(new RunListener() { + @Override + public void testFailure(Failure failure) throws Exception { + result.addError(asTest(failure.getDescription()), failure.getException()); + } + + @Override + public void testFinished(Description description) throws Exception { + result.endTest(asTest(description)); + } + + @Override + public void testStarted(Description description) throws Exception { + resultWrapper.startTest(asTest(description)); + } + + @Override + public void testIgnored(Description description) throws Exception { + resultWrapper.testIgnored(asTest(description)); + } + + @Override + public void testAssumptionFailure(Failure failure) { + resultWrapper.testAssumptionFailure(asTest(failure.getDescription()), failure.getException()); + } + }); + + return notifier; + } +} Index: src/etc/testcases/taskdefs/optional/junit.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/etc/testcases/taskdefs/optional/junit.xml (revision 1451903) +++ src/etc/testcases/taskdefs/optional/junit.xml (revision ) @@ -276,4 +276,21 @@ + + + + + + + + + + + + + + + + Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java (revision ) @@ -33,7 +33,7 @@ /** * Adapter between JUnit 3.8.x API and JUnit 4.x API for execution of tests - * and listening of events (test start, test finish, test failure). + * and listening of events (test start, test finish, test failure, test skipped). * The constructor is passed a JUnit 4 test class and a list of name of methods * in it that should be executed. Method {@link #run run(TestResult)} executes * the given JUnit-4-style test methods and notifies the given {@code TestResult} @@ -104,7 +104,7 @@ public Class getTestClass() { return testClass; } - + public void run(final TestResult result) { runner.run(cache.getNotifier(result)); } @@ -219,6 +219,12 @@ public void testStarted(Description description) throws Exception { result.startTest(asTest(description)); + } + + public void testIgnored(Description description) throws Exception { + if (result instanceof IgnoredTestResult) { + ((IgnoredTestResult)result).testIgnored(asTest(description)); + } } }); return notifier; Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java (revision ) @@ -25,11 +25,13 @@ import java.text.NumberFormat; import junit.framework.AssertionFailedError; +import junit.framework.JUnit4TestCaseFacade; import junit.framework.Test; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.StringUtils; +import org.junit.Ignore; /** * Prints plain text output of the test to a specified Writer. @@ -38,7 +40,7 @@ * @see FormatterElement * @see PlainJUnitResultFormatter */ -public class BriefJUnitResultFormatter implements JUnitResultFormatter { +public class BriefJUnitResultFormatter implements JUnitResultFormatter, IgnoredTestListener { private static final double ONE_SECOND = 1000.0; @@ -141,6 +143,8 @@ sb.append(suite.failureCount()); sb.append(", Errors: "); sb.append(suite.errorCount()); + sb.append(", Skipped: "); + sb.append(suite.skipCount()); sb.append(", Time elapsed: "); sb.append(numberFormat.format(suite.getRunTime() / ONE_SECOND)); sb.append(" sec"); @@ -266,5 +270,43 @@ } catch (IOException ex) { throw new BuildException(ex); } + } + + + @Override + public void testIgnored(Test test) { + String message = null; + if (test instanceof JUnit4TestCaseFacade) { + JUnit4TestCaseFacade facade = (JUnit4TestCaseFacade) test; + Ignore annotation = facade.getDescription().getAnnotation(Ignore.class); + if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) { + message = annotation.value(); + } + } + formatSkip(test, message); + } + + + public void formatSkip(Test test, String message) { + if (test != null) { + endTest(test); + } + + try { + resultWriter.write(formatTest(test) + "SKIPPED"); + if (message != null) { + resultWriter.write(": "); + resultWriter.write(message); + } + resultWriter.newLine(); + } catch (IOException ex) { + throw new BuildException(ex); + } + + } + + @Override + public void testAssumptionFailure(Test test, Throwable cause) { + formatSkip(test, cause.getMessage()); } } Index: src/tests/junit/org/example/junit/Junit4Skippable.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/tests/junit/org/example/junit/Junit4Skippable.java (revision ) +++ src/tests/junit/org/example/junit/Junit4Skippable.java (revision ) @@ -0,0 +1,56 @@ +package org.example.junit; + +import org.junit.Assume; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class Junit4Skippable { + + @Test + public void passingTest() { + assertTrue("This test passed", true); + } + + @Ignore("Please don't ignore me!") + @Test + public void explicitIgnoreTest() { + fail("This test should be skipped"); + } + + @Test + public void implicitlyIgnoreTest() { + Assume.assumeFalse("This test will be ignored", true); + fail("I told you, this test should have been ignored!"); + } + + @Test + @Ignore + public void explicitlyIgnoreTestNoMessage() { + fail("This test should be skipped"); + } + + @Test + public void implicitlyIgnoreTestNoMessage() { + Assume.assumeFalse(true); + fail("I told you, this test should have been ignored!"); + } + + @Test + public void failingTest() { + fail("I told you this test was going to fail"); + } + + @Test + public void failingTestNoMessage() { + fail(); + } + + @Test + public void errorTest() { + throw new RuntimeException("Whoops, this test went wrong"); + } + +} Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestListener.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestListener.java (revision ) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestListener.java (revision ) @@ -0,0 +1,36 @@ +package org.apache.tools.ant.taskdefs.optional.junit; + +import junit.framework.Test; +import junit.framework.TestListener; +import org.junit.runner.notification.Failure; + +/** + * Provides the functionality for TestListeners to be able to be notified of + * the necessary Junit4 events for test being ignored (@Ignore annotation) + * or skipped (Assume failures). Tests written in Junit4 will report against + * the methods in this interface alongside the methods in the existing TestListener + * @author Michael Clarke + */ +public interface IgnoredTestListener extends TestListener { + + /** + * Reports when a test has been marked with the @Ignore annotation. The parameter + * should normally be typed to Junit's {@link junit.framework.JUnit4TestCaseFacade} + * so implementing classes should be able to get the details of the ignore by casting + * the argument and retrieving the descriptor from the test. + * @param test + */ + void testIgnored(Test test); + + /** + * Receive a report that a test has failed an assumption. Within JUnit4 + * this is normally treated as a test being skipped, although how any + * listener handles this is up to that specific listener.
+ * Note: Tests that throw assumption failures will still report + * the endTest method, which may differ from how the addError and addFailure + * methods work, it's up for any implementing classes to handle this. + * @param test the details of the test and failure that have triggered this report. + * @param exception the AssumptionViolatedException thrown from the current assumption failure. + */ + void testAssumptionFailure(Test test, Throwable exception); +} Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java (revision ) @@ -61,7 +61,7 @@ // @todo this is duplicating TestResult information. Only the time is not // part of the result. So we'd better derive a new class from TestResult // and deal with it. (SB) - private long runs, failures, errors; + private long runs, failures, errors, skips; private long runTime; // Snapshot of the system properties @@ -352,15 +352,17 @@ } /** - * Set the number of runs, failures and errors. + * Set the number of runs, failures, errors, and skipped tests. * @param runs the number of runs. * @param failures the number of failures. * @param errors the number of errors. + * @params skips the number of skipped tests. */ - public void setCounts(long runs, long failures, long errors) { + public void setCounts(long runs, long failures, long errors, long skips) { this.runs = runs; this.failures = failures; this.errors = errors; + this.skips = skips; } /** @@ -393,6 +395,14 @@ */ public long errorCount() { return errors; + } + + /** + * Get the number of skipped tests. + * @return the number of skipped tests. + */ + public long skipCount() { + return skips; } /** Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java (revision ) @@ -1645,7 +1645,7 @@ classLoader.setThreadContextLoader(); } - test.setCounts(1, 0, 1); + test.setCounts(1, 0, 1, 0); test.setProperties(getProject().getProperties()); for (int i = 0; i < feArray.length; i++) { FormatterElement fe = feArray[i]; Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java (revision ) @@ -26,11 +26,14 @@ import java.util.Hashtable; import junit.framework.AssertionFailedError; +import junit.framework.JUnit4TestCaseFacade; import junit.framework.Test; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.StringUtils; +import org.junit.Ignore; +import org.junit.runner.notification.Failure; /** @@ -38,7 +41,7 @@ * */ -public class PlainJUnitResultFormatter implements JUnitResultFormatter { +public class PlainJUnitResultFormatter implements JUnitResultFormatter, IgnoredTestListener { private static final double ONE_SECOND = 1000.0; @@ -123,6 +126,8 @@ sb.append(suite.failureCount()); sb.append(", Errors: "); sb.append(suite.errorCount()); + sb.append(", Skipped: "); + sb.append(suite.skipCount()); sb.append(", Time elapsed: "); sb.append(nf.format(suite.getRunTime() / ONE_SECOND)); sb.append(" sec"); @@ -258,4 +263,40 @@ } } + @Override + public void testIgnored(Test test) { + String message = null; + if (test instanceof JUnit4TestCaseFacade) { + JUnit4TestCaseFacade facade = (JUnit4TestCaseFacade) test; + Ignore annotation = facade.getDescription().getAnnotation(Ignore.class); + if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) { + message = annotation.value(); + } + } + formatSkip(test, message); + } + + + public void formatSkip(Test test, String message) { + if (test != null) { + endTest(test); + } + + try { + wri.write("\tSKIPPED"); + if (message != null) { + wri.write(": "); + wri.write(message); + } + wri.newLine(); + } catch (IOException ex) { + throw new BuildException(ex); + } + + } + + @Override + public void testAssumptionFailure(Test test, Throwable throwable) { + formatSkip(test, throwable.getMessage()); + } } // PlainJUnitResultFormatter Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java (revision 1451903) +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java (revision ) @@ -36,6 +36,7 @@ import java.util.StringTokenizer; import java.util.Vector; import junit.framework.AssertionFailedError; +import junit.framework.JUnit4TestAdapterCache; import junit.framework.Test; import junit.framework.TestFailure; import junit.framework.TestListener; @@ -76,7 +77,7 @@ /** * Collects TestResults. */ - private TestResult res; + private IgnoredTestResult res; /** * Do we filter junit.*.* stack frames out of failure and error exceptions. @@ -289,6 +290,7 @@ boolean filtertrace, boolean haltOnFailure, boolean showOutput, boolean logTestListenerEvents, ClassLoader loader) { + super(); JUnitTestRunner.filtertrace = filtertrace; // XXX clumsy, should use instance field somehow this.junitTest = test; this.haltOnError = haltOnError; @@ -350,7 +352,7 @@ * Run the test. */ public void run() { - res = new TestResult(); + res = new IgnoredTestResult(); res.addListener(wrapListener(this)); final int size = formatters.size(); for (int i = 0; i < size; i++) { @@ -468,8 +470,8 @@ formalParams = new Class[] {Class.class, String[].class}; actualParams = new Object[] {testClass, methods}; } else { - formalParams = new Class[] {Class.class}; - actualParams = new Object[] {testClass}; + formalParams = new Class[] {Class.class, JUnit4TestAdapterCache.class}; + actualParams = new Object[] {testClass, new CustomJUnit4TestAdapterCache()}; } suite = (Test) junit4TestAdapterClass @@ -512,7 +514,7 @@ ((TestListener) formatters.elementAt(i)) .addError(null, exception); } - junitTest.setCounts(1, 0, 1); + junitTest.setCounts(1, 0, 1, 0); junitTest.setRunTime(0); } else { try { @@ -522,10 +524,10 @@ if (junit4 || suite.getClass().getName().equals(JUNIT_4_TEST_ADAPTER)) { int[] cnts = findJUnit4FailureErrorCount(res); - junitTest.setCounts(res.runCount(), cnts[0], cnts[1]); + junitTest.setCounts(res.runCount() + res.ignoredCount(), cnts[0], cnts[1], res.ignoredCount() + res.skippedCount()); } else { - junitTest.setCounts(res.runCount(), res.failureCount(), - res.errorCount()); + junitTest.setCounts(res.runCount() + res.ignoredCount(), res.failureCount(), + res.errorCount(), res.ignoredCount() + res.skippedCount()); } junitTest.setRunTime(System.currentTimeMillis() - start); } @@ -1101,8 +1103,8 @@ * * @since Ant 1.7 */ - private TestListener wrapListener(final TestListener testListener) { - return new TestListener() { + private TestListenerWrapper wrapListener(final TestListener testListener) { + return new TestListenerWrapper(testListener) { public void addError(Test test, Throwable t) { if (junit4 && t instanceof AssertionFailedError) { // JUnit 4 does not distinguish between errors and failures