diff --git a/docs/failurelistener.html b/docs/failurelistener.html new file mode 100644 index 0000000..c894c24 --- /dev/null +++ b/docs/failurelistener.html @@ -0,0 +1,61 @@ + + + + + + XMLListener AntUnit Listener + + + +

Failure AntUnit Listener

+ +

Description

+ +

Writes reports similar to the "failure" JUnit formatter.

This AntUnitListener creates a new buildfile with a target for each failed test target in the AntUnit run. The generated target calls the failed target (with setUp and tearDown if present in the called project).

This is intended for rerunning just failed tests.

+ + + +

Parameters

+ + + + + + + + + + + +
AttributeDescriptionRequired
fileWhere to write the generated buildfile.
Yes.
+ +

Examples

+ +
 
<au:antunit> + <fileset dir="${tests}" includes="*.xml"/> + <au:failurelistener file="${build.dir}/failed-tests/failed.xml"/> + </au:antunit>
+
+ +

Runs AntUnit on all XML files in the directory + ${tests} and collecting all failed tests. If there was a failure the file ${build.dir}/failed-tests/failed.xml is created and has a textXXX target for each failed test. Additionally it has a default target antunit which runs all these failed tests.

+ + + diff --git a/src/main/org/apache/ant/antunit/antlib.xml b/src/main/org/apache/ant/antunit/antlib.xml index 0ebd1be..30c84a7 100644 --- a/src/main/org/apache/ant/antunit/antlib.xml +++ b/src/main/org/apache/ant/antunit/antlib.xml @@ -33,6 +33,9 @@ under the License. + + diff --git a/src/main/org/apache/ant/antunit/listener/FailureAntUnitListener.java b/src/main/org/apache/ant/antunit/listener/FailureAntUnitListener.java new file mode 100644 index 0000000..4fa7054 --- /dev/null +++ b/src/main/org/apache/ant/antunit/listener/FailureAntUnitListener.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.ant.antunit.listener; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.NumberFormat; +import java.util.Iterator; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.apache.ant.antunit.AssertionFailedException; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.util.FileUtils; + +/** + * This AntUnitListener creates a new buildfile with a target for each + * failed test target in the AntUnit run. The generated target calls + * the failed target (with setUp and tearDown if present in the called + * project). + * This is intended for rerunning just failed tests. + */ +public class FailureAntUnitListener extends BaseAntUnitListener { + + /** LineSeparator just for beautifying the output. */ + private static final String BR = System.getProperty("line.separator"); + + /** A sorted list (without duplicates) of failed tests. */ + private static SortedSet failedTests = new TreeSet(); + + /** Where to write the generated buildfile. */ + private static File failureBuildfile; + + /** The current running test project. Needed for addError()/addFailure(). */ + private Project currentTestProject; + + /** The current running build file. Needed for addError()/addFailure(). */ + private String currentBuildFile; + + + /** No-arg constructor. */ + public FailureAntUnitListener() { + super(new BaseAntUnitListener.SendLogTo(SendLogTo.ANT_LOG), "txt"); + } + + public void startTestSuite(Project testProject, String buildFile) { + super.startTestSuite(testProject, buildFile); + currentTestProject = testProject; + currentBuildFile = buildFile; + } + + public void addError(String target, Throwable ae) { + super.addError(target, ae); + failedTests.add(new TestInfos(currentTestProject, currentBuildFile, target, ae.getMessage())); + } + + public void addFailure(String target, AssertionFailedException ae) { + super.addFailure(target, ae); + failedTests.add(new TestInfos(currentTestProject, currentBuildFile, target, ae.getMessage())); + } + + /** not in use */ + public void endTest(String target) { + } + + public void endTestSuite(Project testProject, String buildFile) { + StringBuffer sb = new StringBuffer(); + // and antunit-target for direct run + sb.append(""); + sb.append(BR); + sb.append(BR); + sb.append(" ").append(BR); + sb.append(" ").append(BR); + sb.append(" ").append(BR); + sb.append(" ").append(BR); + sb.append(" ").append(BR); + sb.append(" ").append(BR); + sb.append(BR); + sb.append(BR); + + // one target for each failed test + int testNumber = 0; + NumberFormat f = NumberFormat.getIntegerInstance(); + for (Iterator it = failedTests.iterator(); it.hasNext();) { + sb.append(" ").append(BR); + TestInfos testInfos = (TestInfos) it.next(); + sb.append(testInfos); + sb.append(" ").append(BR); + sb.append(BR); + } + + // close the + sb.append("").append(BR); + + // write the whole file + try { + FileOutputStream fos = new FileOutputStream(failureBuildfile); + fos.write(sb.toString().getBytes()); + FileUtils.close(fos); + } catch (FileNotFoundException e) { + throw new BuildException(e); + } catch (IOException e) { + throw new BuildException(e); + } + } + + + /** + * Class for collecting needed information about failed tests. + */ + public class TestInfos implements Comparable { + /** Does the project has a setUp target? */ + boolean projectHasSetup = false; + + /** Does the project has a tearDown target? */ + boolean projectHasTearDown = false; + + /** The called target. */ + String target; + + /** The buildfile of the project. */ + String buildfile; + + /** The error message which was shown. */ + String errorMessage; + + public TestInfos(Project project, String buildfile, String target, String errorMessage) { + projectHasSetup = project.getTargets().containsKey("setUp"); + projectHasTearDown = project.getTargets().containsKey("tearDown"); + this.buildfile = buildfile; + this.target = target; + this.errorMessage = errorMessage; + } + + /** + * Creates an call according to the stored information. + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + // make the reader of the buildfile happy + sb.append(" ").append(BR); + // + sb.append(" "); + sb.append(BR); + // + if (projectHasSetup) { + sb.append(" ").append(BR); + } + sb.append(" "); + sb.append(BR); + if (projectHasTearDown) { + sb.append(" ").append(BR); + } + // + sb.append(" ").append(BR); + return sb.toString(); + } + + // Needed, so that a SortedSet could sort this class into the list. + public int compareTo(Object other) { + if (!(other instanceof TestInfos)) { + return -1; + } else { + TestInfos that = (TestInfos)other; + return this.toString().compareTo(that.toString()); + } + } + } + + + + public void setFile(File file) { + this.failureBuildfile = file; + } + +}