From c30a74289ebfd6c0f714cb63bc952a6340b5fca6 Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Thu, 1 Feb 2001 15:56:43 +0000 Subject: [PATCH] Some additional enhancements to junit related classes. Submitted by: Stephane Bailliez git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268557 13f79535-47bb-0310-9956-ffa450edef68 --- .../taskdefs/optional/junit/BatchTest.java | 153 +++++++++----- .../taskdefs/optional/junit/Enumerations.java | 186 +++++++++--------- .../taskdefs/optional/junit/JUnitTask.java | 26 +-- .../taskdefs/optional/junit/JUnitTest.java | 15 +- .../junit/XMLJUnitResultFormatter.java | 33 ++-- 5 files changed, 242 insertions(+), 171 deletions(-) diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java index 1f71c6a90..f25e5ce7f 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java @@ -69,75 +69,140 @@ import java.io.File; * @author Jeff Martin * @author Stefan Bodewig * @author Stephane Bailliez + * + * @see JUnitTest */ public final class BatchTest extends BaseTest { + + /** the reference to the project */ private Project project; + /** the list of filesets containing the testcase filename rules */ private Vector filesets = new Vector(); + /** + * create a new batchtest instance + * @param project the project it depends on. + */ public BatchTest(Project project){ this.project = project; } + /** + * Add a new fileset instance to this batchtest. Whatever the fileset is, + * only filename that are .java or .class will be + * considered as 'candidates'. + * @param fs the new fileset containing the rules to get the testcases. + */ public void addFileSet(FileSet fs) { filesets.addElement(fs); } + /** + * return all JUnitTest instances obtain by applying the fileset rules. + * @return an enumeration of all elements of this batchtest that are + * a JUnitTest instance. + * @see addTestsTo(Vector) + */ public final Enumeration elements(){ - return new FileList(); + JUnitTest[] tests = createAllJUnitTest(); + return Enumerations.fromArray(tests); } - public class FileList implements Enumeration{ - private String files[]=null; - - private int i=0; - - private FileList(){ - Vector v = new Vector(); - for (int j=0; jJUnitTests of this batchtest + * to a Vector. + * @param v the vector to which should be added all individual tests of this + * batch test. + */ + final void addTestsTo(Vector v){ + JUnitTest[] tests = createAllJUnitTest(); + v.ensureCapacity( v.size() + tests.length); + for (int i = 0; i < tests.length; i++) { + v.addElement(tests[i]); } + } - public final boolean hasMoreElements(){ - if(iJUnitTests based on the filesets. Each instance + * is configured to match this instance properties. + * @return the array of all JUnitTests that belongs to this batch. + */ + private JUnitTest[] createAllJUnitTest(){ + String[] filenames = getFilenames(); + JUnitTest[] tests = new JUnitTest[filenames.length]; + for (int i = 0; i < tests.length; i++) { + String classname = javaToClass(filenames[i]); + tests[i] = createJUnitTest(classname); } + return tests; + } - public final Object nextElement() throws NoSuchElementException{ - if(hasMoreElements()){ - JUnitTest test = new JUnitTest(javaToClass(files[i])); - test.setHaltonerror(haltOnError); - test.setHaltonfailure(haltOnFail); - test.setFork(fork); - test.setIf(ifProperty); - test.setUnless(unlessProperty); - test.setTodir(destDir); - Enumeration list = formatters.elements(); - while (list.hasMoreElements()) { - test.addFormatter((FormatterElement)list.nextElement()); + /** + * Iterate over all filesets and return the filename of all files + * that end with .java or .class. This is to avoid + * wrapping a JUnitTest over an xml file for example. A Testcase + * is obviouslly a java file (compiled or not). + * @return an array of filenames without their extension. As they should + * normally be taken from their root, filenames should match their fully + * qualified class name (If it is not the case it will fail when running the test). + * For the class org/apache/Whatever.class it will return org/apache/Whatever. + */ + private String[] getFilenames(){ + Vector v = new Vector(); + final int size = this.filesets.size(); + for (int j=0; jorg/apache/Whatever will + * be converted to org.apache.Whatever + * @param filename the filename to "convert" to a classname. + * @return the classname matching the filename. + */ + public final static String javaToClass(String filename){ + return filename.replace(File.separatorChar, '.'); + } + + /** + * Create a JUnitTest that has the same property as this + * BatchTest instance. + * @param classname the name of the class that should be run as a + * JUnitTest. It must be a fully qualified name. + * @return the JUnitTest over the given classname. + */ + private JUnitTest createJUnitTest(String classname){ + JUnitTest test = new JUnitTest(); + test.setName(classname); + test.setHaltonerror(this.haltOnError); + test.setHaltonfailure(this.haltOnFail); + test.setFork(this.fork); + test.setIf(this.ifProperty); + test.setUnless(this.unlessProperty); + test.setTodir(this.destDir); + Enumeration list = this.formatters.elements(); + while (list.hasMoreElements()) { + test.addFormatter((FormatterElement)list.nextElement()); } + return test; } + } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java index 324982fb8..900d7ae9c 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java @@ -64,29 +64,29 @@ import java.util.NoSuchElementException; * @author Stephane Bailliez */ public final class Enumerations { - - private Enumerations(){ - } + + private Enumerations(){ + } - /** - * creates an enumeration from an array of objects. - * @param array the array of object to enumerate. - * @return the enumeration over the array of objects. - */ - public static Enumeration fromArray(Object[] array){ - return new ArrayEnumeration(array); - } + /** + * creates an enumeration from an array of objects. + * @param array the array of object to enumerate. + * @return the enumeration over the array of objects. + */ + public static Enumeration fromArray(Object[] array){ + return new ArrayEnumeration(array); + } - /** - * creates an enumeration from an array of enumeration. The created enumeration - * will sequentially enumerate over all elements of each enumeration and skip - * null enumeration elements in the array. - * @param enums the array of enumerations. - * @return the enumeration over the array of enumerations. - */ - public static Enumeration fromCompound(Enumeration[] enums){ - return new CompoundEnumeration(enums); - } + /** + * creates an enumeration from an array of enumeration. The created enumeration + * will sequentially enumerate over all elements of each enumeration and skip + * null enumeration elements in the array. + * @param enums the array of enumerations. + * @return the enumeration over the array of enumerations. + */ + public static Enumeration fromCompound(Enumeration[] enums){ + return new CompoundEnumeration(enums); + } } @@ -96,47 +96,47 @@ public final class Enumerations { * @author Stephane Bailliez */ class ArrayEnumeration implements Enumeration { - - /** object array */ - private Object[] array; - - /** current index */ - private int pos; - - /** - * Initialize a new enumeration that wraps an array. - * @param array the array of object to enumerate. - */ - public ArrayEnumeration(Object[] array){ - this.array = array; - this.pos = 0; - } - /** - * Tests if this enumeration contains more elements. - * - * @return true if and only if this enumeration object - * contains at least one more element to provide; - * false otherwise. - */ - public boolean hasMoreElements() { - return (pos < array.length); - } + + /** object array */ + private Object[] array; + + /** current index */ + private int pos; + + /** + * Initialize a new enumeration that wraps an array. + * @param array the array of object to enumerate. + */ + public ArrayEnumeration(Object[] array){ + this.array = array; + this.pos = 0; + } + /** + * Tests if this enumeration contains more elements. + * + * @return true if and only if this enumeration object + * contains at least one more element to provide; + * false otherwise. + */ + public boolean hasMoreElements() { + return (pos < array.length); + } - /** - * Returns the next element of this enumeration if this enumeration - * object has at least one more element to provide. - * - * @return the next element of this enumeration. - * @throws NoSuchElementException if no more elements exist. - */ - public Object nextElement() throws NoSuchElementException { - if (hasMoreElements()) { - Object o = array[pos]; - pos++; - return o; - } - throw new NoSuchElementException(); - } + /** + * Returns the next element of this enumeration if this enumeration + * object has at least one more element to provide. + * + * @return the next element of this enumeration. + * @throws NoSuchElementException if no more elements exist. + */ + public Object nextElement() throws NoSuchElementException { + if (hasMoreElements()) { + Object o = array[pos]; + pos++; + return o; + } + throw new NoSuchElementException(); + } } /** * Convenient enumeration over an array of enumeration. For example: @@ -170,46 +170,46 @@ class ArrayEnumeration implements Enumeration { * @author Stephane Bailliez */ class CompoundEnumeration implements Enumeration { - - /** enumeration array */ - private Enumeration[] enumArray; - - /** index in the enums array */ - private int index = 0; + + /** enumeration array */ + private Enumeration[] enumArray; + + /** index in the enums array */ + private int index = 0; public CompoundEnumeration(Enumeration[] enumarray) { - this.enumArray = enumarray; + this.enumArray = enumarray; } - /** - * Tests if this enumeration contains more elements. - * - * @return true if and only if this enumeration object - * contains at least one more element to provide; - * false otherwise. - */ + /** + * Tests if this enumeration contains more elements. + * + * @return true if and only if this enumeration object + * contains at least one more element to provide; + * false otherwise. + */ public boolean hasMoreElements() { - while (index < enumArray.length) { - if (enumArray[index] != null && enumArray[index].hasMoreElements()) { - return true; - } - index++; - } - return false; + while (index < enumArray.length) { + if (enumArray[index] != null && enumArray[index].hasMoreElements()) { + return true; + } + index++; + } + return false; } - /** - * Returns the next element of this enumeration if this enumeration - * object has at least one more element to provide. - * - * @return the next element of this enumeration. - * @throws NoSuchElementException if no more elements exist. - */ + /** + * Returns the next element of this enumeration if this enumeration + * object has at least one more element to provide. + * + * @return the next element of this enumeration. + * @throws NoSuchElementException if no more elements exist. + */ public Object nextElement() throws NoSuchElementException { - if ( hasMoreElements() ) { - return enumArray[index].nextElement(); - } - throw new NoSuchElementException(); + if ( hasMoreElements() ) { + return enumArray[index].nextElement(); + } + throw new NoSuchElementException(); } } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java index 7f679aec0..ec5085f7d 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java @@ -213,10 +213,7 @@ public class JUnitTask extends Task { public void addSysproperty(Environment.Variable sysp) { commandline.addSysproperty(sysp); } - - /** - * create a classpath to use for forked jvm - */ + public Path createClasspath() { return commandline.createClasspath(project).createPath(); } @@ -260,21 +257,17 @@ public class JUnitTask extends Task { */ public void execute() throws BuildException { Enumeration list = getIndividualTests(); - try { - while (list.hasMoreElements()) { - JUnitTest test = (JUnitTest)list.nextElement(); - if ( test.shouldRun(project)) { - execute(test); - } + while (list.hasMoreElements()) { + JUnitTest test = (JUnitTest)list.nextElement(); + if ( test.shouldRun(project)) { + execute(test); } - } finally { - //@todo here we should run test aggregation (SBa) } } protected void execute(JUnitTest test) throws BuildException { // set the default values if not specified - //@todo should be moved to the test class (?) (SBa) + //@todo should be moved to the test class instead. if (test.getTodir() == null) { test.setTodir(project.resolveFile(".")); } @@ -288,7 +281,7 @@ public class JUnitTask extends Task { boolean wasKilled = false; if (!test.getFork()) { exitValue = executeInVM(test); - } else { + } else { ExecuteWatchdog watchdog = createWatchdog(); exitValue = executeAsForked(test, watchdog); // null watchdog means no timeout, you'd better not check with null @@ -459,10 +452,9 @@ public class JUnitTask extends Task { private FormatterElement[] mergeFormatters(JUnitTest test){ Vector feVector = (Vector)formatters.clone(); - FormatterElement[] fes = test.getFormatters(); - FormatterElement[] feArray = new FormatterElement[feVector.size() + fes.length]; + test.addFormattersTo(feVector); + FormatterElement[] feArray = new FormatterElement[feVector.size()]; feVector.copyInto(feArray); - System.arraycopy(fes, 0, feArray, feVector.size(), fes.length); return feArray; } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java index 6c898cad6..e568f8ec2 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java @@ -73,7 +73,10 @@ public class JUnitTest extends BaseTest { /** the name of the result file */ private String outfile = null; - + + // @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 runTime; @@ -139,4 +142,14 @@ public class JUnitTest extends BaseTest { formatters.copyInto(fes); return fes; } + + /** + * Convenient method to add formatters to a vector + */ + void addFormattersTo(Vector v){ + final int count = formatters.size(); + for (int i = 0; i < count; i++){ + v.addElement( formatters.elementAt(i) ); + } + } } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java index 8e5978ef6..dbdfeff8a 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java @@ -74,7 +74,7 @@ import junit.framework.TestCase; * @author Stefan Bodewig */ -public class XMLJUnitResultFormatter implements JUnitResultFormatter { +public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants { private static DocumentBuilder getDocumentBuilder() { try { @@ -88,7 +88,8 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter { /** * Formatter for timings. */ - private NumberFormat nf = NumberFormat.getInstance(); + private NumberFormat nf = NumberFormat.getInstance(Locale.US); + /** * The XML document. */ @@ -121,19 +122,19 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter { */ public void startTestSuite(JUnitTest suite) { doc = getDocumentBuilder().newDocument(); - rootElement = doc.createElement("testsuite"); - rootElement.setAttribute("name", suite.getName()); + rootElement = doc.createElement(TESTSUITE); + rootElement.setAttribute(ATTR_NAME, suite.getName()); } /** * The whole testsuite ended. */ public void endTestSuite(JUnitTest suite) throws BuildException { - rootElement.setAttribute("tests", ""+suite.runCount()); - rootElement.setAttribute("failures", ""+suite.failureCount()); - rootElement.setAttribute("errors", ""+suite.errorCount()); - rootElement.setAttribute("time", - nf.format(suite.getRunTime()/1000.0)+" sec"); + rootElement.setAttribute(ATTR_TESTS, ""+suite.runCount()); + rootElement.setAttribute(ATTR_FAILURES, ""+suite.failureCount()); + rootElement.setAttribute(ATTR_ERRORS, ""+suite.errorCount()); + rootElement.setAttribute(ATTR_TIME, + nf.format(suite.getRunTime()/1000.0)); if (out != null) { Writer wri = null; try { @@ -162,8 +163,8 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter { */ public void startTest(Test t) { lastTestStart = System.currentTimeMillis(); - currentTest = doc.createElement("testcase"); - currentTest.setAttribute("name", ((TestCase) t).name()); + currentTest = doc.createElement(TESTCASE); + currentTest.setAttribute(ATTR_NAME, ((TestCase) t).name()); rootElement.appendChild(currentTest); } @@ -173,7 +174,7 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter { *

A Test is finished. */ public void endTest(Test test) { - currentTest.setAttribute("time", + currentTest.setAttribute(ATTR_TIME, nf.format((System.currentTimeMillis()-lastTestStart) / 1000.0)); } @@ -184,7 +185,7 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter { *

A Test failed. */ public void addFailure(Test test, Throwable t) { - formatError("failure", test, t); + formatError(FAILURE, test, t); } /** @@ -202,7 +203,7 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter { *

An error occured while running the test. */ public void addError(Test test, Throwable t) { - formatError("error", test, t); + formatError(ERROR, test, t); } private void formatError(String type, Test test, Throwable t) { @@ -219,9 +220,9 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter { String message = t.getMessage(); if (message != null && message.length() > 0) { - nested.setAttribute("message", t.getMessage()); + nested.setAttribute(ATTR_MESSAGE, t.getMessage()); } - nested.setAttribute("type", t.getClass().getName()); + nested.setAttribute(ATTR_TYPE, t.getClass().getName()); StringWriter swr = new StringWriter(); t.printStackTrace(new PrintWriter(swr, true));