/**
* Copyright 2010 the original author or authors.
*
* 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 datameer.awstasks.ant.junit;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestListener;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitVersionHelper;
import org.apache.tools.ant.util.StringUtils;
/**
* Enhanced version of the
* {@link org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter}. Inspired by
* http://shaman-sir.wikidot.com/one-liner-output-formatter.
*/
public class EnhancedJunitFormatter implements JUnitResultFormatter, TestListener {
// TODO combine with BuildListener ?
private PrintWriter _console;
private String _systemOutput = null;
private String _systemError = null;
private Map<Test, Throwable> failedTests = new LinkedHashMap<Test, Throwable>();
private final boolean _showOutput;
private final boolean _showCurrentTest;
public EnhancedJunitFormatter() {
_showOutput = System.getProperty("showOutput", "false").equals("true");
_showCurrentTest = System.getProperty("showCurrentTest", "true").equals("true");
}
@Override
public void setOutput(OutputStream out) {
_console = new PrintWriter(out);
}
@Override
public void setSystemOutput(String out) {
_systemOutput = out;
}
@Override
public void setSystemError(String err) {
_systemError = err;
}
@Override
public void startTestSuite(JUnitTest suite) {
_console.write(fillWithWhiteSpace(String.format("Running %s...", suite.getName()), 80));
if (_showCurrentTest) {
_console.write('\n');
_console.flush();
}
}
@Override
public void endTestSuite(JUnitTest suite) {
if (_showCurrentTest) {
_console.write("\t");
}
if (suite.failureCount() > 0 || suite.errorCount() > 0) {
_console.write("FAILED!");
} else if (suite.runCount() == 0) {
_console.write("IGNORED");
} else {
_console.write("SUCCEED");
}
StringBuilder sb = new StringBuilder(" in " + formatTimeDuration(suite.getRunTime()));
if (suite.runCount() > 0) {
sb.append("\t- Tests/Failures/Errors: ");
sb.append(suite.runCount());
sb.append("/");
sb.append(suite.failureCount());
sb.append("/");
sb.append(suite.errorCount());
}
sb.append(StringUtils.LINE_SEP);
// append the err and output streams to the log
if (_showOutput) {
if (_systemOutput != null && _systemOutput.length() > 0) {
sb.append("------------- Standard Output ---------------").append(StringUtils.LINE_SEP).append(_systemOutput).append("------------- ---------------- ---------------").append(
StringUtils.LINE_SEP);
}
if (_systemError != null && _systemError.length() > 0) {
sb.append("------------- Standard Error -----------------").append(StringUtils.LINE_SEP).append(_systemError).append("------------- ---------------- ---------------").append(
StringUtils.LINE_SEP);
}
}
_console.write(sb.toString());
if (!failedTests.isEmpty()) {
for (Entry<Test, Throwable> entry : failedTests.entrySet()) {
if (_showCurrentTest) {
_console.write('\t');
}
_console.write("\t" + getTestName(entry.getKey()) + "() \t| " + entry.getValue().getClass().getSimpleName() + ": " + entry.getValue().getMessage() + "\n");
}
failedTests.clear();
}
_console.flush();
}
@Override
public void startTest(Test test) {
}
@Override
public void endTest(Test test) {
}
/**
* Interface TestListener for JUnit <= 3.4.
*
* <p>
* A Test failed.
*
* @param test
* a test
* @param t
* the exception thrown by the test
*/
public void addFailure(Test test, Throwable t) {
formatError("\tFAILED", test, t);
}
/**
* Interface TestListener for JUnit > 3.4.
*
* <p>
* A Test failed.
*
* @param test
* a test
* @param t
* the assertion failed by the test
*/
@Override
public void addFailure(Test test, AssertionFailedError t) {
addFailure(test, (Throwable) t);
}
/**
* A test caused an error.
*
* @param test
* a test
* @param error
* the error thrown by the test
*/
@Override
public void addError(Test test, Throwable error) {
formatError("\tCaused an ERROR", test, error);
}
/**
* Get test name
*
* @param test
* a test
* @return test name
*/
protected String getTestName(Test test) {
if (test == null) {
return "null";
} else {
return /* JUnitVersionHelper.getTestCaseClassName(test) + ": " + */
JUnitVersionHelper.getTestCaseName(test);
}
}
/**
* Get test case full class name
*
* @param test
* a test
* @return test full class name
*/
protected String getTestCaseClassName(Test test) {
if (test == null) {
return "null";
} else {
return JUnitVersionHelper.getTestCaseClassName(test);
}
}
/**
* Format the test for printing..
*
* @param test
* a test
* @return the formatted testname
*/
protected String formatTest(Test test) {
if (test == null) {
return "Null Test: ";
} else {
return "Testcase: " + test.toString() + ":";
}
}
/**
* Format an error and print it.
*
* @param type
* the type of error
* @param test
* the test that failed
* @param error
* the exception that the test threw
*/
protected synchronized void formatError(String type, Test test, Throwable error) {
failedTests.put(test, error);
}
private static String formatTimeDuration(long timeDuration) {
StringBuilder builder = new StringBuilder();
long hours = timeDuration / (60 * 60 * 1000);
long rem = (timeDuration % (60 * 60 * 1000));
long minutes = rem / (60 * 1000);
rem = rem % (60 * 1000);
long seconds = rem / 1000;
if (hours != 0) {
builder.append(hours);
builder.append(" hrs, ");
}
if (minutes != 0) {
builder.append(minutes);
builder.append(" mins, ");
}
// return "0sec if no difference
builder.append(seconds);
builder.append(" sec");
return builder.toString();
}
/**
*
* @param string
* @param length
* @return the given path + as many whitespace that the given string reaches the given length
*/
private static String fillWithWhiteSpace(String string, int length) {
int neededWhiteSpace = length - string.length();
if (neededWhiteSpace > 0) {
StringBuilder builder = new StringBuilder(string);
for (int i = 0; i < neededWhiteSpace; i++) {
builder.append(" ");
}
return builder.toString();
}
return string;
}
@Override
protected void finalize() throws Throwable {
_console.write("bye bye");
super.finalize();
}
}