From a898d14776143b295b706a5e38a2f979e753356d Mon Sep 17 00:00:00 2001 From: "Jesse N. Glick" Date: Tue, 29 Mar 2005 19:19:04 +0000 Subject: [PATCH] #31885: logs more detailed events for individual tests it is running. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@278072 13f79535-47bb-0310-9956-ffa450edef68 --- .../taskdefs/optional/junit/JUnitTask.java | 56 ++++++++++--- .../optional/junit/JUnitTestRunner.java | 72 +++++++++++++++-- .../optional/junit/JUnitTestListenerTest.java | 79 +++++++++++++++++++ 3 files changed, 191 insertions(+), 16 deletions(-) create mode 100644 src/testcases/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestListenerTest.java 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 38f68858f..b2b8b0e49 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 @@ -34,6 +34,9 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Vector; +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestResult; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; @@ -41,7 +44,6 @@ import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Execute; import org.apache.tools.ant.taskdefs.ExecuteWatchdog; import org.apache.tools.ant.taskdefs.LogOutputStream; -import org.apache.tools.ant.taskdefs.LogStreamHandler; import org.apache.tools.ant.types.Assertions; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.CommandlineJava; @@ -52,9 +54,7 @@ import org.apache.tools.ant.types.Permissions; import org.apache.tools.ant.types.PropertySet; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.LoaderUtils; -import junit.framework.AssertionFailedError; -import junit.framework.Test; -import junit.framework.TestResult; +import org.apache.tools.ant.taskdefs.PumpStreamHandler; /** * Runs JUnit tests. @@ -149,6 +149,11 @@ public class JUnitTask extends Task { private ForkMode forkMode = new ForkMode("perTest"); private static final int STRING_BUFFER_SIZE = 128; + /** + * @since Ant 1.7 + */ + public static final String TESTLISTENER_PREFIX = + "junit.framework.TestListener: "; private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); @@ -829,6 +834,7 @@ public class JUnitTask extends Task { cmd.createArgument().setValue("showoutput=" + String.valueOf(showOutput)); + cmd.createArgument().setValue("logtestlistenerevents=true"); // #31885 StringBuffer formatterArg = new StringBuffer(STRING_BUFFER_SIZE); final FormatterElement[] feArray = mergeFormatters(test); @@ -871,9 +877,9 @@ public class JUnitTask extends Task { + "file.", e, getLocation()); } - Execute execute = new Execute(new LogStreamHandler(this, - Project.MSG_INFO, - Project.MSG_WARN), + Execute execute = new Execute(new JUnitLogStreamHandler(this, + Project.MSG_INFO, + Project.MSG_WARN), watchdog); execute.setCommandline(cmd.getCommandline()); execute.setAntRun(getProject()); @@ -941,7 +947,9 @@ public class JUnitTask extends Task { * @since Ant 1.5 */ protected void handleOutput(String output) { - if (runner != null) { + if (output.startsWith(TESTLISTENER_PREFIX)) + log(output, Project.MSG_VERBOSE); + else if (runner != null) { runner.handleOutput(output); if (showOutput) { super.handleOutput(output); @@ -1063,7 +1071,8 @@ public class JUnitTask extends Task { } runner = new JUnitTestRunner(test, test.getHaltonerror(), test.getFiltertrace(), - test.getHaltonfailure(), classLoader); + test.getHaltonfailure(), false, + true, classLoader); if (summary) { log("Running " + test.getName(), Project.MSG_INFO); @@ -1549,4 +1558,33 @@ public class JUnitTask extends Task { public boolean timedOut = false; public boolean crashed = false; } + + /** + * @since Ant 1.7 + */ + protected static class JUnitLogOutputStream extends LogOutputStream { + private Task task; // local copy since LogOutputStream.task is private + + public JUnitLogOutputStream(Task task, int level) { + super(task, level); + this.task = task; + } + + protected void processLine(String line, int level) { + if (line.startsWith(TESTLISTENER_PREFIX)) + task.log(line, Project.MSG_VERBOSE); + else + super.processLine(line, level); + } + } + + /** + * @since Ant 1.7 + */ + protected static class JUnitLogStreamHandler extends PumpStreamHandler { + public JUnitLogStreamHandler(Task task, int outlevel, int errlevel) { + super(new JUnitLogOutputStream(task, outlevel), + new LogOutputStream(task, errlevel)); + } + } } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java index 5262b661e..946487c14 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java @@ -161,6 +161,9 @@ public class JUnitTestRunner implements TestListener { /** ClassLoader passed in in non-forked mode. */ private ClassLoader loader; + + /** Do we print TestListener events? */ + private boolean logTestListenerEvents = false; /** * Constructor for fork=true or when the user hasn't specified a @@ -178,7 +181,19 @@ public class JUnitTestRunner implements TestListener { public JUnitTestRunner(JUnitTest test, boolean haltOnError, boolean filtertrace, boolean haltOnFailure, boolean showOutput) { - this(test, haltOnError, filtertrace, haltOnFailure, showOutput, null); + this(test, haltOnError, filtertrace, haltOnFailure, showOutput, false); + } + + /** + * Constructor for fork=true or when the user hasn't specified a + * classpath. + * @since Ant 1.7 + */ + public JUnitTestRunner(JUnitTest test, boolean haltOnError, + boolean filtertrace, boolean haltOnFailure, + boolean showOutput, boolean logTestListenerEvents) { + this(test, haltOnError, filtertrace, haltOnFailure, showOutput, + logTestListenerEvents, null); } /** @@ -196,14 +211,29 @@ public class JUnitTestRunner implements TestListener { public JUnitTestRunner(JUnitTest test, boolean haltOnError, boolean filtertrace, boolean haltOnFailure, boolean showOutput, ClassLoader loader) { + this(test, haltOnError, filtertrace, haltOnFailure, showOutput, + false, loader); + } + + /** + * Constructor to use when the user has specified a classpath. + * @since Ant 1.7 + */ + public JUnitTestRunner(JUnitTest test, boolean haltOnError, + boolean filtertrace, boolean haltOnFailure, + boolean showOutput, boolean logTestListenerEvents, + ClassLoader loader) { JUnitTestRunner.filtertrace = filtertrace; this.junitTest = test; this.haltOnError = haltOnError; this.haltOnFailure = haltOnFailure; this.showOutput = showOutput; + this.logTestListenerEvents = logTestListenerEvents; this.loader = loader; } + private PrintStream savedOut = null; + public void run() { res = new TestResult(); res.addListener(this); @@ -217,7 +247,6 @@ public class JUnitTestRunner implements TestListener { ByteArrayOutputStream outStrm = new ByteArrayOutputStream(); systemOut = new PrintStream(outStrm); - PrintStream savedOut = null; PrintStream savedErr = null; if (forked) { @@ -295,6 +324,7 @@ public class JUnitTestRunner implements TestListener { junitTest.setRunTime(0); } else { try { + logTestListenerEvent("tests to run: " + suite.countTestCases()); suite.run(res); } finally { junitTest.setCounts(res.runCount(), res.failureCount(), @@ -344,6 +374,8 @@ public class JUnitTestRunner implements TestListener { *

A new Test is started. */ public void startTest(Test t) { + String testName = JUnitVersionHelper.getTestCaseName(t); + logTestListenerEvent("startTest(" + testName + ")"); } /** @@ -352,6 +384,17 @@ public class JUnitTestRunner implements TestListener { *

A Test is finished. */ public void endTest(Test test) { + String testName = JUnitVersionHelper.getTestCaseName(test); + logTestListenerEvent("endTest(" + testName + ")"); + } + + private void logTestListenerEvent(String msg) { + PrintStream out = forked ? savedOut : System.out; + if (logTestListenerEvents) { + out.flush(); + out.println(JUnitTask.TESTLISTENER_PREFIX + msg); + out.flush(); + } } /** @@ -360,6 +403,8 @@ public class JUnitTestRunner implements TestListener { *

A Test failed. */ public void addFailure(Test test, Throwable t) { + String testName = JUnitVersionHelper.getTestCaseName(test); + logTestListenerEvent("addFailure(" + testName + ", " + t.getMessage() + ")"); if (haltOnFailure) { res.stop(); } @@ -380,6 +425,8 @@ public class JUnitTestRunner implements TestListener { *

An error occurred while running the test. */ public void addError(Test test, Throwable t) { + String testName = JUnitVersionHelper.getTestCaseName(test); + logTestListenerEvent("addError(" + testName + ", " + t.getMessage() + ")"); if (haltOnError) { res.stop(); } @@ -395,7 +442,9 @@ public class JUnitTestRunner implements TestListener { } protected void handleOutput(String output) { - if (systemOut != null) { + if (!logTestListenerEvents && output.startsWith(JUnitTask.TESTLISTENER_PREFIX)) + ; // ignore + else if (systemOut != null) { systemOut.print(output); } } @@ -478,6 +527,9 @@ public class JUnitTestRunner implements TestListener { * showoutputsend output to System.err/.out as * well as to the formatters?false * + * logtestlistenereventslog TestListener events to + * System.out.false + * * */ public static void main(String[] args) throws IOException { @@ -486,6 +538,7 @@ public class JUnitTestRunner implements TestListener { boolean stackfilter = true; Properties props = new Properties(); boolean showOut = false; + boolean logTestListenerEvents = false; String noCrashFile = null; if (args.length == 0) { @@ -521,6 +574,8 @@ public class JUnitTestRunner implements TestListener { in.close(); } else if (args[i].startsWith("showoutput=")) { showOut = Project.toBoolean(args[i].substring(11)); + } else if (args[i].startsWith("logtestlistenerevents=")) { + logTestListenerEvents = Project.toBoolean(args[i].substring(22)); } } @@ -548,7 +603,7 @@ public class JUnitTestRunner implements TestListener { t.setTodir(new File(st.nextToken())); t.setOutfile(st.nextToken()); code = launch(t, haltError, stackfilter, haltFail, - showOut, props); + showOut, logTestListenerEvents, props); errorOccured = (code == ERRORS); failureOccured = (code != SUCCESS); if (errorOccured || failureOccured) { @@ -570,7 +625,8 @@ public class JUnitTestRunner implements TestListener { } } else { returnCode = launch(new JUnitTest(args[0]), haltError, - stackfilter, haltFail, showOut, props); + stackfilter, haltFail, showOut, + logTestListenerEvents, props); } registerNonCrash(noCrashFile); @@ -668,10 +724,12 @@ public class JUnitTestRunner implements TestListener { */ private static int launch(JUnitTest t, boolean haltError, boolean stackfilter, boolean haltFail, - boolean showOut, Properties props) { + boolean showOut, boolean logTestListenerEvents, + Properties props) { t.setProperties(props); JUnitTestRunner runner = - new JUnitTestRunner(t, haltError, stackfilter, haltFail, showOut); + new JUnitTestRunner(t, haltError, stackfilter, haltFail, showOut, + logTestListenerEvents); runner.forked = true; transferFormatters(runner, t); diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestListenerTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestListenerTest.java new file mode 100644 index 000000000..9d456b523 --- /dev/null +++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestListenerTest.java @@ -0,0 +1,79 @@ +/* + * 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.tools.ant.taskdefs.optional.junit; + +import org.apache.tools.ant.BuildFileTest; + +public class JUnitTestListenerTest extends BuildFileTest { + + // The captureToSummary test writes to stdout and stderr, good for + // verifying that the TestListener support doesn't break anything. + private static final String PASS_TEST_TARGET = "captureToSummary"; + + // testNoCrash is the test invoked by the captureToSummary's junit task + private static final String PASS_TEST = "testNoCrash"; + + public JUnitTestListenerTest(String name) { + super(name); + } + + public void setUp() { + configureProject("src/etc/testcases/taskdefs/optional/junit.xml"); + } + + public void testFullLogOutput() { + executeTarget(PASS_TEST_TARGET); + assertTrue("expecting full log to have BuildListener events", + hasBuildListenerEvents(getFullLog())); + } + + public void testNoLogOutput() { + executeTarget(PASS_TEST_TARGET); + assertFalse("expecting log to not have BuildListener events", + hasBuildListenerEvents(getLog())); + } + + public void testTestCountFired() { + executeTarget(PASS_TEST_TARGET); + assertTrue("expecting test count message", + hasEventMessage(JUnitTask.TESTLISTENER_PREFIX + + "tests to run: ")); + } + + public void testStartTestFired() { + executeTarget(PASS_TEST_TARGET); + assertTrue("expecting test started message", + hasEventMessage(JUnitTask.TESTLISTENER_PREFIX + + "startTest(" + PASS_TEST + ")")); + } + + public void testEndTestFired() { + executeTarget(PASS_TEST_TARGET); + assertTrue("expecting test ended message", + hasEventMessage(JUnitTask.TESTLISTENER_PREFIX + + "endTest(" + PASS_TEST + ")")); + } + + private boolean hasBuildListenerEvents(String log) { + return log.indexOf(JUnitTask.TESTLISTENER_PREFIX) >= 0; + } + + private boolean hasEventMessage(String eventPrefix) { + return getFullLog().indexOf(eventPrefix) >= 0; + } +}