Browse Source

Some additional enhancements to junit related classes.

Submitted by:	Stephane Bailliez <sbailliez@imediation.com>


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268557 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 24 years ago
parent
commit
c30a74289e
5 changed files with 242 additions and 171 deletions
  1. +109
    -44
      src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java
  2. +93
    -93
      src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java
  3. +9
    -17
      src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
  4. +14
    -1
      src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
  5. +17
    -16
      src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java

+ 109
- 44
src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java View File

@@ -69,75 +69,140 @@ import java.io.File;
* @author <a href="mailto:jeff.martin@synamic.co.uk">Jeff Martin</a> * @author <a href="mailto:jeff.martin@synamic.co.uk">Jeff Martin</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a>
*
* @see JUnitTest
*/ */
public final class BatchTest extends BaseTest { public final class BatchTest extends BaseTest {

/** the reference to the project */
private Project project; private Project project;


/** the list of filesets containing the testcase filename rules */
private Vector filesets = new Vector(); private Vector filesets = new Vector();


/**
* create a new batchtest instance
* @param project the project it depends on.
*/
public BatchTest(Project project){ public BatchTest(Project project){
this.project = project; this.project = project;
} }


/**
* Add a new fileset instance to this batchtest. Whatever the fileset is,
* only filename that are <tt>.java</tt> or <tt>.class</tt> will be
* considered as 'candidates'.
* @param fs the new fileset containing the rules to get the testcases.
*/
public void addFileSet(FileSet fs) { public void addFileSet(FileSet fs) {
filesets.addElement(fs); filesets.addElement(fs);
} }


/**
* return all <tt>JUnitTest</tt> instances obtain by applying the fileset rules.
* @return an enumeration of all elements of this batchtest that are
* a <tt>JUnitTest</tt> instance.
* @see addTestsTo(Vector)
*/
public final Enumeration elements(){ 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; j<filesets.size(); j++) {
FileSet fs = (FileSet) filesets.elementAt(j);
DirectoryScanner ds = fs.getDirectoryScanner(project);
ds.scan();
String[] f = ds.getIncludedFiles();
for (int k=0; k<f.length; k++) {
if (f[k].endsWith(".java")) {
v.addElement(f[k].substring(0, f[k].length()-5));
} else if (f[k].endsWith(".class")) {
v.addElement(f[k].substring(0, f[k].length()-6));
}
}
}

files = new String[v.size()];
v.copyInto(files);
/**
* Convenient method to merge the <tt>JUnitTest</tt>s of this batchtest
* to a <tt>Vector</tt>.
* @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(i<files.length)return true;
return false;
/**
* Create all <tt>JUnitTest</tt>s based on the filesets. Each instance
* is configured to match this instance properties.
* @return the array of all <tt>JUnitTest</tt>s 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 <tt>.java</tt> or <tt>.class</tt>. This is to avoid
* wrapping a <tt>JUnitTest</tt> 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 <tt>org/apache/Whatever.class</tt> it will return <tt>org/apache/Whatever</tt>.
*/
private String[] getFilenames(){
Vector v = new Vector();
final int size = this.filesets.size();
for (int j=0; j<size; j++) {
FileSet fs = (FileSet) filesets.elementAt(j);
DirectoryScanner ds = fs.getDirectoryScanner(project);
ds.scan();
String[] f = ds.getIncludedFiles();
for (int k = 0; k < f.length; k++) {
String pathname = f[k];
if (pathname.endsWith(".java")) {
v.addElement(pathname.substring(0, pathname.length()-".java".length()));
} else if (pathname.endsWith(".class")) {
v.addElement(pathname.substring(0, pathname.length()-".class".length()));
} }
i++;
return test;
} }
throw new NoSuchElementException();
} }


public final String javaToClass(String fileName){
return fileName.replace(java.io.File.separatorChar, '.');
String[] files = new String[v.size()];
v.copyInto(files);
return files;
}

/**
* convenient method to convert a pathname without extension to a
* fully qualified classname. For example <tt>org/apache/Whatever</tt> will
* be converted to <tt>org.apache.Whatever</tt>
* @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 <tt>JUnitTest</tt> that has the same property as this
* <tt>BatchTest</tt> instance.
* @param classname the name of the class that should be run as a
* <tt>JUnitTest</tt>. It must be a fully qualified name.
* @return the <tt>JUnitTest</tt> 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;
} }

} }

+ 93
- 93
src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java View File

@@ -64,29 +64,29 @@ import java.util.NoSuchElementException;
* @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a>
*/ */
public final class Enumerations { 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
* <tt>null</tt> 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
* <tt>null</tt> 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 <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a>
*/ */
class ArrayEnumeration implements Enumeration { 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 <code>true</code> if and only if this enumeration object
* contains at least one more element to provide;
* <code>false</code> 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 <code>true</code> if and only if this enumeration object
* contains at least one more element to provide;
* <code>false</code> 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: * Convenient enumeration over an array of enumeration. For example:
@@ -170,46 +170,46 @@ class ArrayEnumeration implements Enumeration {
* @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a>
*/ */
class CompoundEnumeration implements Enumeration { 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) { public CompoundEnumeration(Enumeration[] enumarray) {
this.enumArray = enumarray;
this.enumArray = enumarray;
} }


/**
* Tests if this enumeration contains more elements.
*
* @return <code>true</code> if and only if this enumeration object
* contains at least one more element to provide;
* <code>false</code> otherwise.
*/
/**
* Tests if this enumeration contains more elements.
*
* @return <code>true</code> if and only if this enumeration object
* contains at least one more element to provide;
* <code>false</code> otherwise.
*/
public boolean hasMoreElements() { 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 { public Object nextElement() throws NoSuchElementException {
if ( hasMoreElements() ) {
return enumArray[index].nextElement();
}
throw new NoSuchElementException();
if ( hasMoreElements() ) {
return enumArray[index].nextElement();
}
throw new NoSuchElementException();
} }
} }




+ 9
- 17
src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java View File

@@ -213,10 +213,7 @@ public class JUnitTask extends Task {
public void addSysproperty(Environment.Variable sysp) { public void addSysproperty(Environment.Variable sysp) {
commandline.addSysproperty(sysp); commandline.addSysproperty(sysp);
} }

/**
* create a classpath to use for forked jvm
*/
public Path createClasspath() { public Path createClasspath() {
return commandline.createClasspath(project).createPath(); return commandline.createClasspath(project).createPath();
} }
@@ -260,21 +257,17 @@ public class JUnitTask extends Task {
*/ */
public void execute() throws BuildException { public void execute() throws BuildException {
Enumeration list = getIndividualTests(); 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 { protected void execute(JUnitTest test) throws BuildException {
// set the default values if not specified // 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) { if (test.getTodir() == null) {
test.setTodir(project.resolveFile(".")); test.setTodir(project.resolveFile("."));
} }
@@ -288,7 +281,7 @@ public class JUnitTask extends Task {
boolean wasKilled = false; boolean wasKilled = false;
if (!test.getFork()) { if (!test.getFork()) {
exitValue = executeInVM(test); exitValue = executeInVM(test);
} else {
} else {
ExecuteWatchdog watchdog = createWatchdog(); ExecuteWatchdog watchdog = createWatchdog();
exitValue = executeAsForked(test, watchdog); exitValue = executeAsForked(test, watchdog);
// null watchdog means no timeout, you'd better not check with null // 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){ private FormatterElement[] mergeFormatters(JUnitTest test){
Vector feVector = (Vector)formatters.clone(); 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); feVector.copyInto(feArray);
System.arraycopy(fes, 0, feArray, feVector.size(), fes.length);
return feArray; return feArray;
} }




+ 14
- 1
src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java View File

@@ -73,7 +73,10 @@ public class JUnitTest extends BaseTest {
/** the name of the result file */ /** the name of the result file */
private String outfile = null; 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 runs, failures, errors;
private long runTime; private long runTime;


@@ -139,4 +142,14 @@ public class JUnitTest extends BaseTest {
formatters.copyInto(fes); formatters.copyInto(fes);
return 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) );
}
}
} }

+ 17
- 16
src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java View File

@@ -74,7 +74,7 @@ import junit.framework.TestCase;
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
*/ */


public class XMLJUnitResultFormatter implements JUnitResultFormatter {
public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants {


private static DocumentBuilder getDocumentBuilder() { private static DocumentBuilder getDocumentBuilder() {
try { try {
@@ -88,7 +88,8 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter {
/** /**
* Formatter for timings. * Formatter for timings.
*/ */
private NumberFormat nf = NumberFormat.getInstance();
private NumberFormat nf = NumberFormat.getInstance(Locale.US);

/** /**
* The XML document. * The XML document.
*/ */
@@ -121,19 +122,19 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter {
*/ */
public void startTestSuite(JUnitTest suite) { public void startTestSuite(JUnitTest suite) {
doc = getDocumentBuilder().newDocument(); 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. * The whole testsuite ended.
*/ */
public void endTestSuite(JUnitTest suite) throws BuildException { 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) { if (out != null) {
Writer wri = null; Writer wri = null;
try { try {
@@ -162,8 +163,8 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter {
*/ */
public void startTest(Test t) { public void startTest(Test t) {
lastTestStart = System.currentTimeMillis(); 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); rootElement.appendChild(currentTest);
} }


@@ -173,7 +174,7 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter {
* <p>A Test is finished. * <p>A Test is finished.
*/ */
public void endTest(Test test) { public void endTest(Test test) {
currentTest.setAttribute("time",
currentTest.setAttribute(ATTR_TIME,
nf.format((System.currentTimeMillis()-lastTestStart) nf.format((System.currentTimeMillis()-lastTestStart)
/ 1000.0)); / 1000.0));
} }
@@ -184,7 +185,7 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter {
* <p>A Test failed. * <p>A Test failed.
*/ */
public void addFailure(Test test, Throwable t) { public void addFailure(Test test, Throwable t) {
formatError("failure", test, t);
formatError(FAILURE, test, t);
} }


/** /**
@@ -202,7 +203,7 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter {
* <p>An error occured while running the test. * <p>An error occured while running the test.
*/ */
public void addError(Test test, Throwable t) { public void addError(Test test, Throwable t) {
formatError("error", test, t);
formatError(ERROR, test, t);
} }


private void formatError(String type, Test test, Throwable t) { private void formatError(String type, Test test, Throwable t) {
@@ -219,9 +220,9 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter {


String message = t.getMessage(); String message = t.getMessage();
if (message != null && message.length() > 0) { 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(); StringWriter swr = new StringWriter();
t.printStackTrace(new PrintWriter(swr, true)); t.printStackTrace(new PrintWriter(swr, true));


Loading…
Cancel
Save