Author: bodewig Date: Fri May 20 04:55:34 2005 New Revision: 171106 URL: http://svn.apache.org/viewcvs?rev=171106&view=rev Log: Add <antunit> task and a very basic test listener
Added: ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit/ ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit.xml (with props) ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit/base.xml (with props) ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java (with props) ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitListener.java (with props) ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/PlainAntUnitListener.java (with props) ant/sandbox/antlibs/antunit/trunk/src/testcases/org/apache/ant/antunit/AntUnitTest.java (with props) Modified: ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/antlib.xml Added: ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit.xml URL: http://svn.apache.org/viewcvs/ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit.xml?rev=171106&view=auto ============================================================================== --- ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit.xml (added) +++ ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit.xml Fri May 20 04:55:34 2005 @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<!-- + Copyright 2005 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. + 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. +--> + +<project name="antunit-test" + default="all" xmlns:au="antlib:org.apache.ant.antunit"> + + <target name="antunit-basetest"> + <au:antunit> + <fileset dir="antunit" includes="base.xml"/> + <au:plainlistener/> + </au:antunit> + </target> +</project> \ No newline at end of file Propchange: ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit.xml ------------------------------------------------------------------------------ svn:eol-style = native Added: ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit/base.xml URL: http://svn.apache.org/viewcvs/ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit/base.xml?rev=171106&view=auto ============================================================================== --- ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit/base.xml (added) +++ ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit/base.xml Fri May 20 04:55:34 2005 @@ -0,0 +1,51 @@ +<?xml version="1.0"?> + +<!-- + Copyright 2005 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. + 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. +--> + +<project name="antunit-base-test" + default="all" xmlns:au="antlib:org.apache.ant.antunit"> + + <target name="setUp"> + <echo>setup</echo> + </target> + + <target name="test1"> + <echo>test1</echo> + </target> + + <target name="test2"> + <echo>test2</echo> + </target> + + <target name="Xtest3"> + <echo>test3</echo> + </target> + + <target name="test4"> + <au:assertTrue message="test4 fails"> + <istrue value="false"/> + </au:assertTrue> + </target> + + <target name="test5"> + <fail message="test5 exits with error"/> + </target> + + <target name="tearDown"> + <echo>tearDown</echo> + </target> +</project> \ No newline at end of file Propchange: ant/sandbox/antlibs/antunit/trunk/src/etc/testcases/antunit/base.xml ------------------------------------------------------------------------------ svn:eol-style = native Added: ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java URL: http://svn.apache.org/viewcvs/ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java?rev=171106&view=auto ============================================================================== --- ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java (added) +++ ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java Fri May 20 04:55:34 2005 @@ -0,0 +1,241 @@ +/* + * Copyright 2005 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. + * 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; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +import org.apache.tools.ant.BuildEvent; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.BuildListener; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.Target; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.taskdefs.LogOutputStream; +import org.apache.tools.ant.types.FileSet; + +/** + * Run all targets in a given build file who's name starts with "test". + * + * <p>Run the "setUp" target before each of them if present, same for + * "tearDown" after each "test" target. If a target throws an + * AssertionFailedException, the test has failed, any other exception + * is counted as an error (although BuildException will be scanned + * recursively for nested AssertionFailedExceptions).</p> + */ +public class AntUnit extends Task { + + private static final String SETUP = "setUp"; + private static final String TEST = "test"; + private static final String TEARDOWN = "tearDown"; + + private ArrayList filesets = new ArrayList(); + private Project newProject; + + private ArrayList listeners = new ArrayList(); + + public void add(FileSet fs) { + filesets.add(fs); + } + + public void add(AntUnitListener al) { + listeners.add(al); + } + + public void execute() { + if (filesets.size() == 0) { + throw new BuildException("You must specify at least one nested" + + " fileset."); + } + Iterator iter = filesets.iterator(); + while (iter.hasNext()) { + doFileSet((FileSet) iter.next()); + } + } + + private void doFileSet(FileSet fs) { + DirectoryScanner ds = fs.getDirectoryScanner(getProject()); + File fromDir = fs.getDir(getProject()); + String[] files = ds.getIncludedFiles(); + for (int i = 0; i < files.length; i++) { + doFile(new File(fromDir, files[i])); + } + } + + private void doFile(File f) { + newProject = new Project(); + newProject.setDefaultInputStream(getProject().getDefaultInputStream()); + newProject.setJavaVersionProperty(); + newProject.setInputHandler(getProject().getInputHandler()); + getProject().initSubProject(newProject); + newProject.setUserProperty("ant.file" , f.getAbsolutePath()); + attachListeners(f, newProject); + ProjectHelper.configureProject(newProject, f); + Map targets = newProject.getTargets(); + Target setUp = (Target) targets.get(SETUP); + Target tearDown = (Target) targets.get(TEARDOWN); + newProject.fireBuildStarted(); + Throwable caught = null; + try { + Iterator iter = targets.keySet().iterator(); + while (iter.hasNext()) { + String name = (String) iter.next(); + if (name.startsWith(TEST)) { + Vector v = new Vector(); + if (setUp != null) { + v.add(SETUP); + } + v.add(name); + try { + newProject.executeTargets(v); + } catch (AssertionFailedException e) { + fireFail(name, e); + } catch (BuildException e) { + BuildException orig = e; + boolean failed = false; + Throwable t = e.getCause(); + while (t != null && t instanceof BuildException) { + if (t instanceof AssertionFailedException) { + failed = true; + fireFail(name, (AssertionFailedException) t); + break; + } + t = ((BuildException) t).getCause(); + } + if (!failed) { + fireError(name, e); + } + } finally { + if (tearDown != null) { + newProject.executeTarget(TEARDOWN); + } + } + } + } + } catch (Throwable e) { + caught = e; + } finally { + newProject.fireBuildFinished(caught); + newProject = null; + } + } + + public void handleOutput(String outputToHandle) { + if (newProject != null) { + newProject.demuxOutput(outputToHandle, false); + } else { + super.handleOutput(outputToHandle); + } + } + + public int handleInput(byte[] buffer, int offset, int length) + throws IOException { + if (newProject != null) { + return newProject.demuxInput(buffer, offset, length); + } + return super.handleInput(buffer, offset, length); + } + + public void handleFlush(String toFlush) { + if (newProject != null) { + newProject.demuxFlush(toFlush, false); + } else { + super.handleFlush(toFlush); + } + } + + public void handleErrorOutput(String errorOutputToHandle) { + if (newProject != null) { + newProject.demuxOutput(errorOutputToHandle, true); + } else { + super.handleErrorOutput(errorOutputToHandle); + } + } + + public void handleErrorFlush(String errorOutputToFlush) { + if (newProject != null) { + newProject.demuxFlush(errorOutputToFlush, true); + } else { + super.handleErrorFlush(errorOutputToFlush); + } + } + + private void attachListeners(File buildFile, Project p) { + Iterator it = listeners.iterator(); + while (it.hasNext()) { + AntUnitListener al = (AntUnitListener) it.next(); + p.addBuildListener(new BuildToAntUnitListener(buildFile + .getAbsolutePath(), + al)); + } + } + + private void fireFail(String targetName, AssertionFailedException ae) { + Iterator it = listeners.iterator(); + while (it.hasNext()) { + AntUnitListener al = (AntUnitListener) it.next(); + al.addFailure(targetName, ae); + } + } + + private void fireError(String targetName, Throwable t) { + Iterator it = listeners.iterator(); + while (it.hasNext()) { + AntUnitListener al = (AntUnitListener) it.next(); + al.addError(targetName, t); + } + } + + private class BuildToAntUnitListener implements BuildListener { + private String buildFile; + private AntUnitListener a; + BuildToAntUnitListener(String buildFile, AntUnitListener a) { + this.buildFile = buildFile; + this.a = a; + a.setOutput(new LogOutputStream(AntUnit.this, Project.MSG_INFO)); + } + public void buildStarted(BuildEvent event) { + a.startTestSuite(buildFile); + } + public void buildFinished(BuildEvent event) { + a.endTestSuite(buildFile); + } + public void targetStarted(BuildEvent event) { + String tName = event.getTarget().getName(); + if (tName.startsWith(TEST)) { + a.startTest(tName); + } + } + public void targetFinished(BuildEvent event) { + String tName = event.getTarget().getName(); + if (tName.startsWith(TEST)) { + a.endTest(tName); + } + } + public void taskStarted(BuildEvent event) {} + public void taskFinished(BuildEvent event) {} + public void messageLogged(BuildEvent event) {} + } + +} Propchange: ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java ------------------------------------------------------------------------------ svn:eol-style = native Added: ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitListener.java URL: http://svn.apache.org/viewcvs/ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitListener.java?rev=171106&view=auto ============================================================================== --- ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitListener.java (added) +++ ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitListener.java Fri May 20 04:55:34 2005 @@ -0,0 +1,34 @@ +/* + * Copyright 2005 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. + * 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; + +import java.io.OutputStream; + +/** + * A test listener for <antunit>. + */ +public interface AntUnitListener { + void setOutput(OutputStream out); + + void startTestSuite(String buildFile); + void endTestSuite(String buildFile); + void startTest(String target); + void endTest(String target); + void addFailure(String target, AssertionFailedException ae); + void addError(String target, Throwable ae); +} \ No newline at end of file Propchange: ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitListener.java ------------------------------------------------------------------------------ svn:eol-style = native Added: ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/PlainAntUnitListener.java URL: http://svn.apache.org/viewcvs/ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/PlainAntUnitListener.java?rev=171106&view=auto ============================================================================== --- ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/PlainAntUnitListener.java (added) +++ ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/PlainAntUnitListener.java Fri May 20 04:55:34 2005 @@ -0,0 +1,149 @@ +/* + * Copyright 2005 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. + * 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; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.NumberFormat; +import java.util.HashMap; + +import org.apache.tools.ant.BuildException; + +/** + * A test listener for <antunit>. + */ +public class PlainAntUnitListener implements AntUnitListener { + /** + * Formatter for timings. + */ + private NumberFormat nf = NumberFormat.getInstance(); + + private OutputStream out = null; + /** + * Helper to store intermediate output. + */ + private StringWriter inner; + /** + * Convenience layer on top of [EMAIL PROTECTED] #inner inner}. + */ + private PrintWriter wri; + + private int runCount, failureCount, errorCount; + private long start, testStart; + + public void setOutput(OutputStream out) { + this.out = out; + } + + public void startTestSuite(String buildFile) { + inner = new StringWriter(); + wri = new PrintWriter(inner); + runCount = failureCount = errorCount; + if (out == null) { + return; // Quick return - no output do nothing. + } + String newLine = System.getProperty("line.separator"); + StringBuffer sb = new StringBuffer("Build File: "); + sb.append(buildFile); + sb.append(newLine); + try { + out.write(sb.toString().getBytes()); + out.flush(); + } catch (IOException ex) { + throw new BuildException("Unable to write output", ex); + } + start = System.currentTimeMillis(); + } + + public void endTestSuite(String buildFile) { + long runTime = System.currentTimeMillis() - start; + String newLine = System.getProperty("line.separator"); + StringBuffer sb = new StringBuffer("Tests run: "); + sb.append(runCount); + sb.append(", Failures: "); + sb.append(failureCount); + sb.append(", Errors: "); + sb.append(errorCount); + sb.append(", Time elapsed: "); + sb.append(nf.format(runTime/ 1000.0)); + sb.append(" sec"); + sb.append(newLine); + +// // append the err and output streams to the log +// if (systemOutput != null && systemOutput.length() > 0) { +// sb.append("------------- Standard Output ---------------") +// .append(newLine) +// .append(systemOutput) +// .append("------------- ---------------- ---------------") +// .append(newLine); +// } +// +// if (systemError != null && systemError.length() > 0) { +// sb.append("------------- Standard Error -----------------") +// .append(newLine) +// .append(systemError) +// .append("------------- ---------------- ---------------") +// .append(newLine); +// } + + if (out != null) { + try { + out.write(sb.toString().getBytes()); + wri.close(); + out.write(inner.toString().getBytes()); + out.flush(); + } catch (IOException ioex) { + throw new BuildException("Unable to write output", ioex); + } finally { + if (out != System.out && out != System.err) { + try { + out.close(); + } catch (IOException e) { + // ignore + } + } + } + } + } + + public void startTest(String target) { + testStart = System.currentTimeMillis(); + runCount++; + } + public void endTest(String target) { + wri.print("Target: " + target); + double seconds = (System.currentTimeMillis() - testStart) / 1000.0; + wri.println(" took " + nf.format(seconds) + " sec"); + } + public void addFailure(String target, AssertionFailedException ae) { + failureCount++; + formatError("\tFAILED", ae); + } + public void addError(String target, Throwable ae) { + errorCount++; + formatError("\tCaused an ERROR", ae); + } + + private void formatError(String type, Throwable t) { + wri.println(type); + wri.println(t.getMessage()); + } + +} \ No newline at end of file Propchange: ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/PlainAntUnitListener.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/antlib.xml URL: http://svn.apache.org/viewcvs/ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/antlib.xml?rev=171106&r1=171105&r2=171106&view=diff ============================================================================== --- ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/antlib.xml (original) +++ ant/sandbox/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/antlib.xml Fri May 20 04:55:34 2005 @@ -15,8 +15,14 @@ limitations under the License. --> <antlib xmlns:au="antlib:org.apache.ant.antunit"> + <taskdef name="antunit" + classname="org.apache.ant.antunit.AntUnit"/> + <taskdef name="assertTrue" classname="org.apache.ant.antunit.AssertTask"/> + + <typedef name="plainlistener" + classname="org.apache.ant.antunit.PlainAntUnitListener"/> <macrodef name="assertFalse"> <attribute name="message" default="Assertion failed"/> Added: ant/sandbox/antlibs/antunit/trunk/src/testcases/org/apache/ant/antunit/AntUnitTest.java URL: http://svn.apache.org/viewcvs/ant/sandbox/antlibs/antunit/trunk/src/testcases/org/apache/ant/antunit/AntUnitTest.java?rev=171106&view=auto ============================================================================== --- ant/sandbox/antlibs/antunit/trunk/src/testcases/org/apache/ant/antunit/AntUnitTest.java (added) +++ ant/sandbox/antlibs/antunit/trunk/src/testcases/org/apache/ant/antunit/AntUnitTest.java Fri May 20 04:55:34 2005 @@ -0,0 +1,57 @@ +/* + * Copyright 2005 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. + * 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; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.BuildFileTest; + +public class AntUnitTest extends BuildFileTest { + + public AntUnitTest(String name) { + super(name); + } + + public void setUp() { + configureProject("src/etc/testcases/antunit.xml"); + } + + public void testBase() { + executeTarget("antunit-basetest"); + String log = getLog(); + int index = log.indexOf("Build File: "); + assertTrue("start recorded", index > -1); + index = log.indexOf("sandbox/antlibs/antunit/trunk/src/etc/testcases/" + + "antunit/base.xml", index); + assertTrue("file name", index > -1); + index = log.indexOf("Tests run: 4, Failures: 1, Errors: 1, Time " + + "elapsed: ", index); + assertTrue("summary", index > -1); + assertTrue("test1", log.indexOf("test1", index) > -1); + assertTrue("test2", log.indexOf("test2", index) > -1); + assertTrue("test3", log.indexOf("test3", index) == -1); + assertTrue("test4", log.indexOf("test4", index) > -1); + assertTrue("test5", log.indexOf("test5", index) > -1); + int index2 = log.indexOf("Caused an ERROR", index); + assertTrue("test5 error", index2 > -1 + && log.indexOf("test5 exits with error", index2) > -1); + assertTrue("Only one error", log.indexOf("ERROR", index2 + 11) == -1); + index2 = log.indexOf("FAILED", index); + assertTrue("test4 failure", index2 > -1 + && log.indexOf("test4 fails", index2) > -1); + assertTrue("Only one failure", log.indexOf("FAILED", index2 + 1) == -1); + } +} Propchange: ant/sandbox/antlibs/antunit/trunk/src/testcases/org/apache/ant/antunit/AntUnitTest.java ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]