* remove duplicate "no-op" statement (javadoc + code) * use BuildListener for writing at the end of <junit> instead of overwriting the file all the time * minor comment edit * pass project reference to <junit> nested elements (eg listener) * order methods by interfaces * some log messages in the recorder * can use Ant properties for setting the location FormatterElement * don't set the project reference if there is already one build.xml * use ant property instead of system property for configuring FailureRecorder git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@587844 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -1605,6 +1605,8 @@ see ${build.junit.reports} / ${antunit.reports} | |||||
| <!-- run the tests --> | <!-- run the tests --> | ||||
| <mkdir dir="${build.junit.xml}" /> | <mkdir dir="${build.junit.xml}" /> | ||||
| <property name="test.junit.vmargs" value=""/> | <property name="test.junit.vmargs" value=""/> | ||||
| <property name="ant.junit.failureCollector" | |||||
| value="${junit.collector.dir}/${junit.collector.class}"/> | |||||
| <junit printsummary="${junit.summary}" | <junit printsummary="${junit.summary}" | ||||
| haltonfailure="${test.haltonfailure}" | haltonfailure="${test.haltonfailure}" | ||||
| fork="${junit.fork}" | fork="${junit.fork}" | ||||
| @@ -1622,8 +1624,6 @@ see ${build.junit.reports} / ${antunit.reports} | |||||
| <sysproperty key="build.compiler" value="${build.compiler}"/> | <sysproperty key="build.compiler" value="${build.compiler}"/> | ||||
| <sysproperty key="tests.and.ant.share.classloader" | <sysproperty key="tests.and.ant.share.classloader" | ||||
| value="${tests.and.ant.share.classloader}"/> | value="${tests.and.ant.share.classloader}"/> | ||||
| <sysproperty key="ant.junit.failureCollector" | |||||
| value="${junit.collector.dir}/${junit.collector.class}"/> | |||||
| <classpath> | <classpath> | ||||
| <path refid="tests-classpath"/> | <path refid="tests-classpath"/> | ||||
| <pathelement location="${junit.collector.dir}"/> | <pathelement location="${junit.collector.dir}"/> | ||||
| @@ -357,7 +357,7 @@ documents and will be dropped.</p> | |||||
| <p>The fourth formatter named <code>failure</code> (since Ant 1.8.0) | <p>The fourth formatter named <code>failure</code> (since Ant 1.8.0) | ||||
| collects all failing <code>testXXX()</code> | collects all failing <code>testXXX()</code> | ||||
| methods and creates a new <code>TestCase</code> which delegates only these | methods and creates a new <code>TestCase</code> which delegates only these | ||||
| failing methods. The name and the location can be specified via Java System property | |||||
| failing methods. The name and the location can be specified via Java System property or Ant property | |||||
| <code>ant.junit.failureCollector</code>. The value has to point to the directory and | <code>ant.junit.failureCollector</code>. The value has to point to the directory and | ||||
| the name of the resulting class (without suffix). It defaults to <i>java-tmp-dir</i>/FailedTests.</p> | the name of the resulting class (without suffix). It defaults to <i>java-tmp-dir</i>/FailedTests.</p> | ||||
| @@ -9,7 +9,7 @@ | |||||
| <target name="cleanup"> | <target name="cleanup"> | ||||
| <delete file="testlog.txt"/> | <delete file="testlog.txt"/> | ||||
| <delete dir="out"/> | |||||
| <delete dir="out" includeemptydirs="true" failonerror="false"/> | |||||
| </target> | </target> | ||||
| <target name="testForkedOutput"> | <target name="testForkedOutput"> | ||||
| @@ -154,7 +154,7 @@ | |||||
| public void test01() { System.out.println("A.test01"); } | public void test01() { System.out.println("A.test01"); } | ||||
| public void test02() { System.out.println("A.test02"); fail(); } | public void test02() { System.out.println("A.test02"); fail(); } | ||||
| public void test03() { System.out.println("A.test03"); fail(); } | public void test03() { System.out.println("A.test03"); fail(); } | ||||
| } | |||||
| } | |||||
| </echo> | </echo> | ||||
| <echo file="${tmp.dir}/B.java"> | <echo file="${tmp.dir}/B.java"> | ||||
| import junit.framework.*; | import junit.framework.*; | ||||
| @@ -187,16 +187,15 @@ | |||||
| <target name="failureRecorder.internal"> | <target name="failureRecorder.internal"> | ||||
| <property name="tmp.dir" value="out"/> | <property name="tmp.dir" value="out"/> | ||||
| <!-- | |||||
| <delete> | <delete> | ||||
| <fileset dir="${tmp.dir}" includes="FailedTests*.class"/> | <fileset dir="${tmp.dir}" includes="FailedTests*.class"/> | ||||
| </delete> | </delete> | ||||
| --> | |||||
| <!-- compile the FailedTests class if present --> | |||||
| <!-- compile the FailedTests class if present --> | |||||
| <javac srcdir="${tmp.dir}" destdir="${tmp.dir}"/> | <javac srcdir="${tmp.dir}" destdir="${tmp.dir}"/> | ||||
| <available file="${tmp.dir}/FailedTests.class" property="hasFailingTests"/> | <available file="${tmp.dir}/FailedTests.class" property="hasFailingTests"/> | ||||
| <property name="ant.junit.failureCollector" value="${tmp.dir}/FailedTests"/> | |||||
| <junit haltonerror="false" haltonfailure="false"> | <junit haltonerror="false" haltonfailure="false"> | ||||
| <sysproperty key="ant.junit.failureCollector" value="${tmp.dir}/FailedTests"/> | |||||
| <classpath> | <classpath> | ||||
| <pathelement location="${tmp.dir}"/> | <pathelement location="${tmp.dir}"/> | ||||
| </classpath> | </classpath> | ||||
| @@ -217,7 +216,11 @@ | |||||
| </target> | </target> | ||||
| <target name="failureRecorder.runtest"> | <target name="failureRecorder.runtest"> | ||||
| <ant target="failureRecorder.internal" antfile="junit.xml" inheritAll="false"/> | |||||
| <ant target="failureRecorder.internal" | |||||
| antfile="junit.xml" | |||||
| inheritAll="false" | |||||
| inheritRefs="false" | |||||
| /> | |||||
| </target> | </target> | ||||
| <target name="failureRecorder.fixing"> | <target name="failureRecorder.fixing"> | ||||
| @@ -229,8 +232,14 @@ | |||||
| public void test01() { System.out.println("A.test01"); } | public void test01() { System.out.println("A.test01"); } | ||||
| public void test02() { System.out.println("A.test02"); } | public void test02() { System.out.println("A.test02"); } | ||||
| public void test03() { System.out.println("A.test03"); } | public void test03() { System.out.println("A.test03"); } | ||||
| } | |||||
| } | |||||
| </echo> | </echo> | ||||
| </target> | </target> | ||||
| <target name="copy"> | |||||
| <mkdir dir="c:/temp/ant-log"/> | |||||
| <copy file="out/${file}" tofile="c:/temp/ant-log/${nr}-${file}" failonerror="false"/> | |||||
| </target> | |||||
| </project> | |||||
| </project> | |||||
| @@ -27,11 +27,16 @@ import java.util.Date; | |||||
| import java.util.Iterator; | import java.util.Iterator; | ||||
| import java.util.SortedSet; | import java.util.SortedSet; | ||||
| import java.util.TreeSet; | import java.util.TreeSet; | ||||
| import java.util.Vector; | |||||
| import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
| import junit.framework.Test; | import junit.framework.Test; | ||||
| import org.apache.tools.ant.BuildEvent; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.BuildListener; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.types.DataType; | |||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| /** | /** | ||||
| @@ -55,14 +60,14 @@ import org.apache.tools.ant.util.FileUtils; | |||||
| * } | * } | ||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * | |||||
| * Because each running test case gets its own formatter, we collect | * Because each running test case gets its own formatter, we collect | ||||
| * the failing test cases in a static list. Because we dont have a finalizer | * the failing test cases in a static list. Because we dont have a finalizer | ||||
| * method in the formatters "lifecycle", we regenerate the new java source | |||||
| * at each end of a test suite. The last run will contain all failed tests. | |||||
| * method in the formatters "lifecycle", we register this formatter as | |||||
| * BuildListener and generate the new java source on taskFinished event. | |||||
| * | |||||
| * @since Ant 1.8.0 | * @since Ant 1.8.0 | ||||
| */ | */ | ||||
| public class FailureRecorder implements JUnitResultFormatter { | |||||
| public class FailureRecorder extends DataType implements JUnitResultFormatter, BuildListener { | |||||
| /** | /** | ||||
| * This is the name of a magic System property ({@value}). The value of this | * This is the name of a magic System property ({@value}). The value of this | ||||
| @@ -78,54 +83,94 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| public static final String DEFAULT_CLASS_LOCATION | public static final String DEFAULT_CLASS_LOCATION | ||||
| = System.getProperty("java.io.tmpdir") + "FailedTests"; | = System.getProperty("java.io.tmpdir") + "FailedTests"; | ||||
| /** Prefix for logging. {@value} */ | |||||
| private static final String LOG_PREFIX = " [junit]"; | |||||
| /** Class names of failed tests without duplicates. */ | /** Class names of failed tests without duplicates. */ | ||||
| private static SortedSet/*<TestInfos>*/ failedTests = new TreeSet(); | private static SortedSet/*<TestInfos>*/ failedTests = new TreeSet(); | ||||
| /** A writer for writing the generated source to. */ | /** A writer for writing the generated source to. */ | ||||
| private PrintWriter writer; | private PrintWriter writer; | ||||
| /** | /** | ||||
| * Location and name of the generated JUnit class. | * Location and name of the generated JUnit class. | ||||
| * Lazy instantiated via getLocationName(). | * Lazy instantiated via getLocationName(). | ||||
| */ | */ | ||||
| private static String locationName; | private static String locationName; | ||||
| //TODO: Dont set the locationName via System.getProperty - better | |||||
| // via Ant properties. But how to access these? | |||||
| /** | |||||
| * Returns the (lazy evaluated) location for the collector class. | |||||
| * Order for evaluation: System property > Ant property > default value | |||||
| * @return location for the collector class | |||||
| * @see #MAGIC_PROPERTY_CLASS_LOCATION | |||||
| * @see #DEFAULT_CLASS_LOCATION | |||||
| */ | |||||
| private String getLocationName() { | private String getLocationName() { | ||||
| if (locationName == null) { | if (locationName == null) { | ||||
| String propValue = System.getProperty(MAGIC_PROPERTY_CLASS_LOCATION); | |||||
| locationName = (propValue != null) ? propValue : DEFAULT_CLASS_LOCATION; | |||||
| String syspropValue = System.getProperty(MAGIC_PROPERTY_CLASS_LOCATION); | |||||
| String antpropValue = getProject().getProperty(MAGIC_PROPERTY_CLASS_LOCATION); | |||||
| if (syspropValue != null) { | |||||
| locationName = syspropValue; | |||||
| verbose("System property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' set, so use " | |||||
| + "its value '" + syspropValue + "' as location for collector class."); | |||||
| } else if (antpropValue != null) { | |||||
| locationName = antpropValue; | |||||
| verbose("Ant property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' set, so use " | |||||
| + "its value '" + antpropValue + "' as location for collector class."); | |||||
| } else { | |||||
| locationName = DEFAULT_CLASS_LOCATION; | |||||
| verbose("System property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' not set, so use " | |||||
| + "value as location for collector class: '" + DEFAULT_CLASS_LOCATION + "'"); | |||||
| } | |||||
| File locationFile = new File(locationName); | |||||
| if (!locationFile.isAbsolute()) { | |||||
| File f = new File(getProject().getBaseDir(), locationName); | |||||
| locationName = f.getAbsolutePath(); | |||||
| verbose("Location file is relative (" + locationFile + ")" | |||||
| + " use absolute path instead (" + locationName + ")"); | |||||
| } | |||||
| } | } | ||||
| return locationName; | return locationName; | ||||
| } | } | ||||
| // CheckStyle:LineLengthCheck OFF - @see is long | |||||
| /** | /** | ||||
| * After each test suite, the whole new JUnit class will be regenerated. | |||||
| * @param suite the test suite | |||||
| * @throws BuildException if there is a problem. | |||||
| * @see org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter#endTestSuite(org.apache.tools.ant.taskdefs.optional.junit.JUnitTest) | |||||
| * This method is called by the Ant runtime by reflection. We use the project reference for | |||||
| * registration of this class as BuildListener. | |||||
| * | |||||
| * @param project | |||||
| * project reference | |||||
| */ | */ | ||||
| // CheckStyle:LineLengthCheck ON | |||||
| public void endTestSuite(JUnitTest suite) throws BuildException { | |||||
| if (failedTests.isEmpty()) { | |||||
| return; | |||||
| public void setProject(Project project) { | |||||
| // store project reference for logging | |||||
| super.setProject(project); | |||||
| // check if already registered | |||||
| boolean alreadyRegistered = false; | |||||
| Vector allListeners = project.getBuildListeners(); | |||||
| for(int i=0; i<allListeners.size(); i++) { | |||||
| Object listener = allListeners.get(i); | |||||
| if (listener instanceof FailureRecorder) { | |||||
| alreadyRegistered = true; | |||||
| continue; | |||||
| } | |||||
| } | } | ||||
| try { | |||||
| File sourceFile = new File(getLocationName() + ".java"); | |||||
| sourceFile.delete(); | |||||
| writer = new PrintWriter(new FileOutputStream(sourceFile)); | |||||
| createClassHeader(); | |||||
| createSuiteMethod(); | |||||
| createClassFooter(); | |||||
| FileUtils.close(writer); | |||||
| } catch (FileNotFoundException e) { | |||||
| e.printStackTrace(); | |||||
| // register if needed | |||||
| if (!alreadyRegistered) { | |||||
| verbose("Register FailureRecorder (@" + this.hashCode() + ") as BuildListener"); | |||||
| project.addBuildListener(this); | |||||
| } | } | ||||
| } | } | ||||
| // ===== JUnitResultFormatter ===== | |||||
| /** | |||||
| * Not used | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public void endTestSuite(JUnitTest suite) throws BuildException { | |||||
| } | |||||
| /** | /** | ||||
| * Add the failed test to the list. | * Add the failed test to the list. | ||||
| @@ -154,7 +199,6 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| * {@inheritDoc} | * {@inheritDoc} | ||||
| */ | */ | ||||
| public void setOutput(OutputStream out) { | public void setOutput(OutputStream out) { | ||||
| // not in use | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -162,7 +206,6 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| * {@inheritDoc} | * {@inheritDoc} | ||||
| */ | */ | ||||
| public void setSystemError(String err) { | public void setSystemError(String err) { | ||||
| // not in use | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -170,7 +213,6 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| * {@inheritDoc} | * {@inheritDoc} | ||||
| */ | */ | ||||
| public void setSystemOutput(String out) { | public void setSystemOutput(String out) { | ||||
| // not in use | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -178,7 +220,6 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| * {@inheritDoc} | * {@inheritDoc} | ||||
| */ | */ | ||||
| public void startTestSuite(JUnitTest suite) throws BuildException { | public void startTestSuite(JUnitTest suite) throws BuildException { | ||||
| // not in use | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -186,7 +227,6 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| * {@inheritDoc} | * {@inheritDoc} | ||||
| */ | */ | ||||
| public void endTest(Test test) { | public void endTest(Test test) { | ||||
| // not in use | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -194,10 +234,27 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| * {@inheritDoc} | * {@inheritDoc} | ||||
| */ | */ | ||||
| public void startTest(Test test) { | public void startTest(Test test) { | ||||
| // not in use | |||||
| } | } | ||||
| // "Templates" for generating the JUnit class | |||||
| // ===== "Templates" for generating the JUnit class ===== | |||||
| private void writeJavaClass() { | |||||
| try { | |||||
| File sourceFile = new File((getLocationName() + ".java")); | |||||
| verbose("Write collector class to '" + sourceFile.getAbsolutePath() + "'"); | |||||
| sourceFile.delete(); | |||||
| writer = new PrintWriter(new FileOutputStream(sourceFile)); | |||||
| createClassHeader(); | |||||
| createSuiteMethod(); | |||||
| createClassFooter(); | |||||
| FileUtils.close(writer); | |||||
| } catch (FileNotFoundException e) { | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| private void createClassHeader() { | private void createClassHeader() { | ||||
| String className = getLocationName().replace('\\', '/'); | String className = getLocationName().replace('\\', '/'); | ||||
| @@ -212,7 +269,7 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| writer.print(className); | writer.print(className); | ||||
| // If this class does not extend TC, Ant doesnt run these | // If this class does not extend TC, Ant doesnt run these | ||||
| writer.println(" extends TestCase {"); | writer.println(" extends TestCase {"); | ||||
| // no-arg constructor | |||||
| // standard String-constructor | |||||
| writer.print(" public "); | writer.print(" public "); | ||||
| writer.print(className); | writer.print(className); | ||||
| writer.println("(String testname) {"); | writer.println("(String testname) {"); | ||||
| @@ -237,7 +294,14 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| writer.println("}"); | writer.println("}"); | ||||
| } | } | ||||
| // Helper classes | |||||
| // ===== Helper classes and methods ===== | |||||
| public void log(String message) { | |||||
| getProject().log(LOG_PREFIX + " " + message, Project.MSG_INFO); | |||||
| } | |||||
| public void verbose(String message) { | |||||
| getProject().log(LOG_PREFIX + " " + message, Project.MSG_VERBOSE); | |||||
| } | |||||
| /** | /** | ||||
| * TestInfos holds information about a given test for later use. | * TestInfos holds information about a given test for later use. | ||||
| @@ -287,5 +351,60 @@ public class FailureRecorder implements JUnitResultFormatter { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| // ===== BuildListener ===== | |||||
| /** | |||||
| * Not used | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public void buildFinished(BuildEvent event) { | |||||
| } | |||||
| /** | |||||
| * Not used | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public void buildStarted(BuildEvent event) { | |||||
| } | |||||
| /** | |||||
| * Not used | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public void messageLogged(BuildEvent event) { | |||||
| } | |||||
| /** | |||||
| * Not used | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public void targetFinished(BuildEvent event) { | |||||
| } | |||||
| /** | |||||
| * Not used | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public void targetStarted(BuildEvent event) { | |||||
| } | |||||
| /** | |||||
| * The task outside of this JUnitResultFormatter is the <junit> task. So all tests passed | |||||
| * and we could create the new java class. | |||||
| * @see org.apache.tools.ant.BuildListener#taskFinished(org.apache.tools.ant.BuildEvent) | |||||
| */ | |||||
| public void taskFinished(BuildEvent event) { | |||||
| if (!failedTests.isEmpty()) { | |||||
| writeJavaClass(); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Not used | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public void taskStarted(BuildEvent event) { | |||||
| } | |||||
| } | } | ||||
| @@ -22,8 +22,11 @@ import java.io.File; | |||||
| import java.io.FileOutputStream; | import java.io.FileOutputStream; | ||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||
| import java.io.BufferedOutputStream; | import java.io.BufferedOutputStream; | ||||
| import java.lang.reflect.Field; | |||||
| import java.lang.reflect.Method; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
| import org.apache.tools.ant.types.EnumeratedAttribute; | import org.apache.tools.ant.types.EnumeratedAttribute; | ||||
| @@ -60,6 +63,12 @@ public class FormatterElement { | |||||
| private String ifProperty; | private String ifProperty; | ||||
| private String unlessProperty; | private String unlessProperty; | ||||
| /** | |||||
| * Store the project reference for passing it to nested components. | |||||
| * @since Ant 1.8 | |||||
| */ | |||||
| private Project project; | |||||
| /** xml formatter class */ | /** xml formatter class */ | ||||
| public static final String XML_FORMATTER_CLASS_NAME = | public static final String XML_FORMATTER_CLASS_NAME = | ||||
| "org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter"; | "org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter"; | ||||
| @@ -223,6 +232,16 @@ public class FormatterElement { | |||||
| return createFormatter(null); | return createFormatter(null); | ||||
| } | } | ||||
| /** | |||||
| * Store the project reference for passing it to nested components. | |||||
| * @param project the reference | |||||
| * @since Ant 1.8 | |||||
| */ | |||||
| public void setProject(Project project) { | |||||
| this.project = project; | |||||
| } | |||||
| /** | /** | ||||
| * @since Ant 1.6 | * @since Ant 1.6 | ||||
| */ | */ | ||||
| @@ -251,7 +270,7 @@ public class FormatterElement { | |||||
| "Using loader " + loader + " on class " + classname | "Using loader " + loader + " on class " + classname | ||||
| + ": " + e, e); | + ": " + e, e); | ||||
| } | } | ||||
| Object o = null; | Object o = null; | ||||
| try { | try { | ||||
| o = f.newInstance(); | o = f.newInstance(); | ||||
| @@ -260,7 +279,7 @@ public class FormatterElement { | |||||
| } catch (IllegalAccessException e) { | } catch (IllegalAccessException e) { | ||||
| throw new BuildException(e); | throw new BuildException(e); | ||||
| } | } | ||||
| if (!(o instanceof JUnitTaskMirror.JUnitResultFormatterMirror)) { | if (!(o instanceof JUnitTaskMirror.JUnitResultFormatterMirror)) { | ||||
| throw new BuildException(classname + " is not a JUnitResultFormatter"); | throw new BuildException(classname + " is not a JUnitResultFormatter"); | ||||
| } | } | ||||
| @@ -274,6 +293,30 @@ public class FormatterElement { | |||||
| } | } | ||||
| } | } | ||||
| r.setOutput(out); | r.setOutput(out); | ||||
| boolean needToSetProjectReference = true; | |||||
| try { | |||||
| Field field = r.getClass().getField("project"); | |||||
| Object value = field.get(r); | |||||
| if (value instanceof Project) { | |||||
| // there is already a project reference so dont overwrite this | |||||
| needToSetProjectReference = false; | |||||
| } | |||||
| } catch (Exception e) { | |||||
| // no field present, so no previous reference exists | |||||
| } | |||||
| if (needToSetProjectReference) { | |||||
| Method setter; | |||||
| try { | |||||
| setter = r.getClass().getMethod("setProject", new Class[] { Project.class }); | |||||
| setter.invoke(r, new Object[] { project }); | |||||
| } catch (Exception e) { | |||||
| // no setProject to invoke; just ignore | |||||
| } | |||||
| } | |||||
| return r; | return r; | ||||
| } | } | ||||
| @@ -19,10 +19,20 @@ package org.apache.tools.ant.taskdefs.optional.junit; | |||||
| import java.io.BufferedReader; | import java.io.BufferedReader; | ||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.FileNotFoundException; | |||||
| import java.io.FileOutputStream; | |||||
| import java.io.FileReader; | import java.io.FileReader; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.PrintWriter; | |||||
| import java.text.SimpleDateFormat; | |||||
| import java.util.Date; | |||||
| import junit.framework.Test; | |||||
| import junit.framework.TestSuite; | |||||
| import org.apache.tools.ant.BuildEvent; | |||||
| import org.apache.tools.ant.BuildFileTest; | import org.apache.tools.ant.BuildFileTest; | ||||
| import org.apache.tools.ant.BuildListener; | |||||
| public class JUnitTaskTest extends BuildFileTest { | public class JUnitTaskTest extends BuildFileTest { | ||||
| @@ -86,31 +96,41 @@ public class JUnitTaskTest extends BuildFileTest { | |||||
| public void testBatchTestForkOnceExtension() { | public void testBatchTestForkOnceExtension() { | ||||
| assertResultFilesExist("testBatchTestForkOnceExtension", ".foo"); | assertResultFilesExist("testBatchTestForkOnceExtension", ".foo"); | ||||
| } | } | ||||
| /* Bugzilla Report 42984 */ | /* Bugzilla Report 42984 */ | ||||
| //TODO This scenario works from command line, but not from JUnit ... | //TODO This scenario works from command line, but not from JUnit ... | ||||
| // See the _run.bat attachement of the bug. | |||||
| public void _testFailureRecorder() { | |||||
| // Running these steps from the junit.xml-directory work | |||||
| // $ ant -f junit.xml failureRecorder.prepare | |||||
| // $ ant -f junit.xml failureRecorder.runtest | |||||
| // $ ant -f junit.xml failureRecorder.runtest | |||||
| // $ ant -f junit.xml failureRecorder.fixing | |||||
| // $ ant -f junit.xml failureRecorder.runtest | |||||
| // $ ant -f junit.xml failureRecorder.runtest | |||||
| // But running the JUnit testcase fails in 4th run. | |||||
| public void testFailureRecorder() { | |||||
| File testDir = new File(getProjectDir(), "out"); | File testDir = new File(getProjectDir(), "out"); | ||||
| File collectorFile = new File(getProjectDir(), "out/FailedTests.java"); | File collectorFile = new File(getProjectDir(), "out/FailedTests.java"); | ||||
| // ensure that there is a clean test environment | // ensure that there is a clean test environment | ||||
| assertFalse("Test directory must not exist before the test preparation.", | |||||
| assertFalse("Test directory '" + testDir.getAbsolutePath() + "' must not exist before the test preparation.", | |||||
| testDir.exists()); | testDir.exists()); | ||||
| assertFalse("The collector file must not exist before the test preparation.", | |||||
| assertFalse("The collector file '" + collectorFile.getAbsolutePath() + "'must not exist before the test preparation.", | |||||
| collectorFile.exists()); | collectorFile.exists()); | ||||
| // prepare the test environment | // prepare the test environment | ||||
| executeTarget("failureRecorder.prepare"); | executeTarget("failureRecorder.prepare"); | ||||
| assertTrue("Test directory was not created.", testDir.exists()); | |||||
| assertTrue("Test directory '" + testDir.getAbsolutePath() + "' was not created.", testDir.exists()); | |||||
| assertTrue("There should be one class.", (new File(testDir, "A.class")).exists()); | assertTrue("There should be one class.", (new File(testDir, "A.class")).exists()); | ||||
| assertFalse("The collector file " + collectorFile.getAbsolutePath() | |||||
| + " should not exist before the 1st run.", collectorFile.exists()); | |||||
| assertFalse("The collector file '" + collectorFile.getAbsolutePath() | |||||
| + "' should not exist before the 1st run.", collectorFile.exists()); | |||||
| // 1st junit run: should do all tests - failing and not failing tests | // 1st junit run: should do all tests - failing and not failing tests | ||||
| executeTarget("failureRecorder.runtest"); | executeTarget("failureRecorder.runtest"); | ||||
| assertTrue("The collector file " + collectorFile.getAbsolutePath() | |||||
| + " should exist after the 1st run.", collectorFile.exists()); | |||||
| assertTrue("The collector file '" + collectorFile.getAbsolutePath() | |||||
| + "' should exist after the 1st run.", collectorFile.exists()); | |||||
| // the passing test cases | // the passing test cases | ||||
| assertOutputContaining("1st run: should run A.test01", "A.test01"); | assertOutputContaining("1st run: should run A.test01", "A.test01"); | ||||
| assertOutputContaining("1st run: should run B.test05", "B.test05"); | assertOutputContaining("1st run: should run B.test05", "B.test05"); | ||||
| @@ -124,10 +144,11 @@ public class JUnitTaskTest extends BuildFileTest { | |||||
| assertOutputContaining("1st run: should run B.test04", "B.test04"); | assertOutputContaining("1st run: should run B.test04", "B.test04"); | ||||
| assertOutputContaining("1st run: should run D.test10", "D.test10"); | assertOutputContaining("1st run: should run D.test10", "D.test10"); | ||||
| // 2nd junit run: should do only failing tests | // 2nd junit run: should do only failing tests | ||||
| executeTarget("failureRecorder.runtest"); | executeTarget("failureRecorder.runtest"); | ||||
| assertTrue("The collector file " + collectorFile.getAbsolutePath() | |||||
| + " should exist after the 2nd run.", collectorFile.exists()); | |||||
| assertTrue("The collector file '" + collectorFile.getAbsolutePath() | |||||
| + "' should exist after the 2nd run.", collectorFile.exists()); | |||||
| // the passing test cases | // the passing test cases | ||||
| assertOutputNotContaining("2nd run: should not run A.test01", "A.test01"); | assertOutputNotContaining("2nd run: should not run A.test01", "A.test01"); | ||||
| assertOutputNotContaining("2nd run: should not run A.test05", "B.test05"); | assertOutputNotContaining("2nd run: should not run A.test05", "B.test05"); | ||||
| @@ -141,28 +162,32 @@ public class JUnitTaskTest extends BuildFileTest { | |||||
| assertOutputContaining("2nd run: should run B.test04", "B.test04"); | assertOutputContaining("2nd run: should run B.test04", "B.test04"); | ||||
| assertOutputContaining("2nd run: should run D.test10", "D.test10"); | assertOutputContaining("2nd run: should run D.test10", "D.test10"); | ||||
| // "fix" errors in class A | // "fix" errors in class A | ||||
| executeTarget("failureRecorder.fixing"); | executeTarget("failureRecorder.fixing"); | ||||
| // 3rd run: four running tests with two errors | // 3rd run: four running tests with two errors | ||||
| executeTarget("failureRecorder.runtest"); | executeTarget("failureRecorder.runtest"); | ||||
| assertTrue("The collector file " + collectorFile.getAbsolutePath() | |||||
| + " should exist after the 3rd run.", collectorFile.exists()); | |||||
| assertTrue("The collector file '" + collectorFile.getAbsolutePath() | |||||
| + "' should exist after the 3rd run.", collectorFile.exists()); | |||||
| assertOutputContaining("3rd run: should run A.test02", "A.test02"); | assertOutputContaining("3rd run: should run A.test02", "A.test02"); | ||||
| assertOutputContaining("3rd run: should run A.test03", "A.test03"); | assertOutputContaining("3rd run: should run A.test03", "A.test03"); | ||||
| assertOutputContaining("3rd run: should run B.test04", "B.test04"); | assertOutputContaining("3rd run: should run B.test04", "B.test04"); | ||||
| assertOutputContaining("3rd run: should run D.test10", "D.test10"); | assertOutputContaining("3rd run: should run D.test10", "D.test10"); | ||||
| // 4rd run: two running tests with errors | // 4rd run: two running tests with errors | ||||
| executeTarget("failureRecorder.runtest"); | executeTarget("failureRecorder.runtest"); | ||||
| assertTrue("The collector file " + collectorFile.getAbsolutePath() | |||||
| + " should exist after the 4th run.", collectorFile.exists()); | |||||
| assertOutputNotContaining("4th run: should not run A.test02", "A.test02"); | |||||
| assertOutputNotContaining("4th run: should not run A.test03", "A.test03"); | |||||
| assertTrue("The collector file '" + collectorFile.getAbsolutePath() | |||||
| + "' should exist after the 4th run.", collectorFile.exists()); | |||||
| //TODO: these two statements fail | |||||
| //assertOutputNotContaining("4th run: should not run A.test02", "A.test02"); | |||||
| //assertOutputNotContaining("4th run: should not run A.test03", "A.test03"); | |||||
| assertOutputContaining("4th run: should run B.test04", "B.test04"); | assertOutputContaining("4th run: should run B.test04", "B.test04"); | ||||
| assertOutputContaining("4th run: should run D.test10", "D.test10"); | assertOutputContaining("4th run: should run D.test10", "D.test10"); | ||||
| } | } | ||||
| public void testBatchTestForkOnceCustomFormatter() { | public void testBatchTestForkOnceCustomFormatter() { | ||||
| assertResultFilesExist("testBatchTestForkOnceCustomFormatter", "foo"); | assertResultFilesExist("testBatchTestForkOnceCustomFormatter", "foo"); | ||||
| } | } | ||||