Author: jglick
Date: Tue Feb 28 13:07:15 2006
New Revision: 381780

URL: http://svn.apache.org/viewcvs?rev=381780&view=rev
Log:
#38811: support for JUnit 4.0.

Modified:
    ant/core/trunk/WHATSNEW
    ant/core/trunk/docs/manual/OptionalTasks/junit.html
    
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
    
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java

Modified: ant/core/trunk/WHATSNEW
URL: 
http://svn.apache.org/viewcvs/ant/core/trunk/WHATSNEW?rev=381780&r1=381779&r2=381780&view=diff
==============================================================================
--- ant/core/trunk/WHATSNEW (original)
+++ ant/core/trunk/WHATSNEW Tue Feb 28 13:07:15 2006
@@ -77,6 +77,8 @@
 Fixed bugs:
 -----------
 
+* <junit> now supports JUnit 4. Bugzilla Report 38811.
+
 * <junit> can now work with junit.jar in its <classpath>. Bugzilla Report 
38799.
 
 * Some potential NullPointerExceptions, Bugzilla Reports 37765 and 38056

Modified: ant/core/trunk/docs/manual/OptionalTasks/junit.html
URL: 
http://svn.apache.org/viewcvs/ant/core/trunk/docs/manual/OptionalTasks/junit.html?rev=381780&r1=381779&r2=381780&view=diff
==============================================================================
--- ant/core/trunk/docs/manual/OptionalTasks/junit.html (original)
+++ ant/core/trunk/docs/manual/OptionalTasks/junit.html Tue Feb 28 13:07:15 2006
@@ -12,7 +12,8 @@
 version of the framework can be found at
 <a href="http://www.junit.org";>http://www.junit.org</a>.
 This task has been tested with JUnit 3.0 up to JUnit 3.8.1; it won't
-work with versions prior to JUnit 3.0.</p>
+work with versions prior to JUnit 3.0. It also works with JUnit 4.0, including
+"pure" JUnit 4 tests using only annotations and no 
<code>JUnit4TestAdapter</code>.</p>
 <p><strong>Note:</strong> This task depends on external libraries not included
 in the Ant distribution.  See <a href="../install.html#librarydependencies">
 Library Dependencies</a> for more information.

Modified: 
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
URL: 
http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java?rev=381780&r1=381779&r2=381780&view=diff
==============================================================================
--- 
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
 (original)
+++ 
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
 Tue Feb 28 13:07:15 2006
@@ -35,6 +35,7 @@
 import java.util.Vector;
 import junit.framework.AssertionFailedError;
 import junit.framework.Test;
+import junit.framework.TestFailure;
 import junit.framework.TestListener;
 import junit.framework.TestResult;
 import junit.framework.TestSuite;
@@ -99,7 +100,13 @@
                 "junit.textui.TestRunner",
                 "java.lang.reflect.Method.invoke(",
                 "sun.reflect.",
-                "org.apache.tools.ant."
+                "org.apache.tools.ant.",
+                // JUnit 4 support:
+                "org.junit.",
+                "junit.framework.JUnit4TestAdapter",
+                // See wrapListener for reason:
+                "Caused by: java.lang.AssertionError",
+                " more",
         };
 
 
@@ -141,6 +148,9 @@
     /** Do we print TestListener events? */
     private boolean logTestListenerEvents = false;
 
+    /** Turned on if we are using JUnit 4 for this test suite. see #38811 */
+    private boolean junit4;
+
     /**
      * Constructor for fork=true or when the user hasn't specified a
      * classpath.
@@ -212,9 +222,9 @@
     
     public void run() {
         res = new TestResult();
-        res.addListener(this);
+        res.addListener(wrapListener(this));
         for (int i = 0; i < formatters.size(); i++) {
-            res.addListener((TestListener) formatters.elementAt(i));
+            res.addListener(wrapListener((TestListener) 
formatters.elementAt(i)));
         }
 
         ByteArrayOutputStream errStrm = new ByteArrayOutputStream();
@@ -255,6 +265,19 @@
         try {
 
             try {
+                Class junit4TestAdapterClass = null;
+                // Note that checking for JDK 5 directly won't work; under JDK 
4, this will already have failed.
+                try {
+                    if (loader == null) {
+                        junit4TestAdapterClass = 
Class.forName("junit.framework.JUnit4TestAdapter");
+                    } else {
+                        junit4TestAdapterClass = 
Class.forName("junit.framework.JUnit4TestAdapter", true, loader);
+                    }
+                } catch (ClassNotFoundException e) {
+                    // OK, fall back to JUnit 3.
+                }
+                junit4 = junit4TestAdapterClass != null;
+
                 Class testClass = null;
                 if (loader == null) {
                     testClass = Class.forName(junitTest.getName());
@@ -263,24 +286,33 @@
                                               loader);
                 }
 
-                Method suiteMethod = null;
-                try {
-                    // check if there is a suite method
-                    suiteMethod = testClass.getMethod("suite", new Class[0]);
-                } catch (NoSuchMethodException e) {
-                    // no appropriate suite method found. We don't report any
-                    // error here since it might be perfectly normal.
-                }
-                if (suiteMethod != null) {
-                    // if there is a suite method available, then try
-                    // to extract the suite from it. If there is an error
-                    // here it will be caught below and reported.
-                    suite = (Test) suiteMethod.invoke(null, new Class[0]);
+                if (junit4) {
+                    // Let's use it!
+                    suite = (Test) junit4TestAdapterClass.getConstructor(new 
Class[] {Class.class}).
+                            newInstance(new Object[] {testClass});
                 } else {
-                    // try to extract a test suite automatically this
-                    // will generate warnings if the class is no
-                    // suitable Test
-                    suite = new TestSuite(testClass);
+                    // Use JUnit 3.
+
+                    Method suiteMethod = null;
+                    try {
+                        // check if there is a suite method
+                        suiteMethod = testClass.getMethod("suite", new 
Class[0]);
+                    } catch (NoSuchMethodException e) {
+                        // no appropriate suite method found. We don't report 
any
+                        // error here since it might be perfectly normal.
+                    }
+                    if (suiteMethod != null) {
+                        // if there is a suite method available, then try
+                        // to extract the suite from it. If there is an error
+                        // here it will be caught below and reported.
+                        suite = (Test) suiteMethod.invoke(null, new Class[0]);
+                    } else {
+                        // try to extract a test suite automatically this
+                        // will generate warnings if the class is no
+                        // suitable Test
+                        suite = new TestSuite(testClass);
+                    }
+
                 }
 
             } catch (Throwable e) {
@@ -303,8 +335,13 @@
                     logTestListenerEvent("tests to run: " + 
suite.countTestCases());
                     suite.run(res);
                 } finally {
-                    junitTest.setCounts(res.runCount(), res.failureCount(),
-                                        res.errorCount());
+                    if (junit4) {
+                        int[] cnts = findJUnit4FailureErrorCount(res);
+                        junitTest.setCounts(res.runCount(), cnts[0], cnts[1]);
+                    } else {
+                        junitTest.setCounts(res.runCount(), res.failureCount(),
+                                res.errorCount());
+                    }
                     junitTest.setRunTime(System.currentTimeMillis() - start);
                 }
             }
@@ -692,7 +729,7 @@
 
     private static boolean filterLine(String line) {
         for (int i = 0; i < DEFAULT_TRACE_FILTERS.length; i++) {
-            if (line.indexOf(DEFAULT_TRACE_FILTERS[i]) > 0) {
+            if (line.indexOf(DEFAULT_TRACE_FILTERS[i]) != -1) {
                 return true;
             }
         }
@@ -733,4 +770,83 @@
             }
         }
     }
+
+    /**
+     * Modifies a TestListener when running JUnit 4:
+     * treats AssertionFailedError as a failure not an error.
+     * @since Ant 1.7
+     */
+    private TestListener wrapListener(final TestListener testListener) {
+        return new TestListener() {
+            public void addError(Test test, Throwable t) {
+                if (junit4 && t instanceof AssertionFailedError) {
+                    // JUnit 4 does not distinguish between errors and 
failures even in the JUnit 3 adapter.
+                    // So we need to help it a bit to retain compatibility for 
JUnit 3 tests.
+                    testListener.addFailure(test, (AssertionFailedError) t);
+                } else if (junit4 && 
t.getClass().getName().equals("java.lang.AssertionError")) {
+                    // Not strictly necessary but probably desirable.
+                    // JUnit 4-specific test GUIs will show just "failures".
+                    // But Ant's output shows "failures" vs. "errors".
+                    // We would prefer to show "failure" for things that 
logically are.
+                    try {
+                        String msg = t.getMessage();
+                        AssertionFailedError failure = msg != null ?
+                            new AssertionFailedError(msg) : new 
AssertionFailedError();
+                        // To compile on pre-JDK 4 (even though this should 
always succeed):
+                        Method initCause = 
Throwable.class.getMethod("initCause", new Class[] {Throwable.class});
+                        initCause.invoke(failure, new Object[] {t});
+                        testListener.addFailure(test, failure);
+                    } catch (Exception e) {
+                        // Rats.
+                        e.printStackTrace(); // should not happen
+                        testListener.addError(test, t);
+                    }
+                } else {
+                    testListener.addError(test, t);
+                }
+            }
+            public void addFailure(Test test, AssertionFailedError t) {
+                testListener.addFailure(test, t);
+            }
+            public void addFailure(Test test, Throwable t) { // pre-3.4
+                if (t instanceof AssertionFailedError) {
+                    testListener.addFailure(test, (AssertionFailedError) t);
+                } else {
+                    testListener.addError(test, t);
+                }
+            }
+            public void endTest(Test test) {
+                testListener.endTest(test);
+            }
+            public void startTest(Test test) {
+                testListener.startTest(test);
+            }
+        };
+    }
+
+    /**
+     * Use instead of TestResult.get{Failure,Error}Count on JUnit 4,
+     * since the adapter claims that all failures are errors.
+     * @since Ant 1.7
+     */
+    private int[] findJUnit4FailureErrorCount(TestResult res) {
+        int failures = 0;
+        int errors = 0;
+        Enumeration e = res.failures();
+        while (e.hasMoreElements()) {
+            e.nextElement();
+            failures++;
+        }
+        e = res.errors();
+        while (e.hasMoreElements()) {
+            Throwable t = ((TestFailure) e.nextElement()).thrownException();
+            if (t instanceof AssertionFailedError || 
t.getClass().getName().equals("java.lang.AssertionError")) {
+                failures++;
+            } else {
+                errors++;
+            }
+        }
+        return new int[] {failures, errors};
+    }
+
 } // JUnitTestRunner

Modified: 
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java
URL: 
http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java?rev=381780&r1=381779&r2=381780&view=diff
==============================================================================
--- 
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java
 (original)
+++ 
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java
 Tue Feb 28 13:07:15 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright  2001-2002,2004-2005 The Apache Software Foundation
+ * Copyright  2001-2002,2004-2006 The Apache Software Foundation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -51,8 +51,21 @@
      * <p>since Ant 1.5.1 this method will invoke &quot;<code>public
      * String getName()</code>&quot; on any implementation of Test if
      * it exists.</p>
+     *
+     * <p>Since Ant 1.7 also checks for JUnit4TestCaseFacade explicitly.
+     * This is used by junit.framework.JUnit4TestAdapter.</p>
      */
     public static String getTestCaseName(Test t) {
+        if (t != null && 
t.getClass().getName().equals("junit.framework.JUnit4TestCaseFacade")) {
+            // Self-describing as of JUnit 4 (#38811). But trim "(ClassName)".
+            String name = t.toString();
+            if (name.endsWith(")")) {
+                int paren = name.lastIndexOf('(');
+                return name.substring(0, paren);
+            } else {
+                return name;
+            }
+        }
         if (t instanceof TestCase && testCaseName != null) {
             try {
                 return (String) testCaseName.invoke(t, new Object[0]);



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to