blob: 199f6195c9112d077f7309c10b141a0a0bb10f07 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* https://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.listener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.NumberFormat;
import org.apache.ant.antunit.AntUnitListener;
import org.apache.ant.antunit.AssertionFailedException;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.Location;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.LogOutputStream;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.KeepAliveOutputStream;
import org.apache.tools.ant.util.TeeOutputStream;
/**
* A test listener for <antunit> modeled aftern the Plain JUnit
* test listener that is part of Ant.
*/
public abstract class BaseAntUnitListener implements AntUnitListener {
/**
* Formatter for timings.
*/
protected static final NumberFormat nf = NumberFormat.getInstance();
/**
* Create a new {@link BaseAntUnitListener} instance.
* @param defaultReportTarget
* @param extension
*/
protected BaseAntUnitListener(SendLogTo defaultReportTarget, String extension) {
logTo = defaultReportTarget;
this.extension = extension;
logLevel = BaseAntUnitListener.AntUnitLogLevel.NONE;
}
/**
* Directory to write reports to.
*/
private File toDir;
/**
* Extension for report files.
*/
private String extension;
/**
* Directory to write reports to.
* @return directory to write reports to
*/
protected final File getToDir() {
return toDir;
}
/**
* Sets the directory to write test reports to.
* @param f directory to write reports to
*/
public void setToDir(File f) {
toDir = f;
}
/**
* Where to send log.
*/
private SendLogTo logTo;
/**
* Where to send the test report.
* @param logTo where to send the test report
*/
protected void setSendLogTo(SendLogTo logTo) {
this.logTo = logTo;
}
private Task parentTask;
public void setParentTask(Task t) {
parentTask = t;
}
/**
* keeps track of the numer of executed targets, the failures an errors.
*/
protected int runCount, failureCount, errorCount;
/**
* time for the starts of the current test-suite and test-target.
*/
protected long start, testStart;
public void startTestSuite(Project testProject, String buildFile) {
start = System.currentTimeMillis();
runCount = failureCount = errorCount = 0;
}
protected final void close(OutputStream out) {
FileUtils.close(out);
}
public void startTest(String target) {
testStart = System.currentTimeMillis();
runCount++;
}
public void addFailure(String target, AssertionFailedException ae) {
failureCount++;
}
public void addError(String target, Throwable ae) {
errorCount++;
}
protected final OutputStream getOut(String buildFile) {
final String dest = logTo.getValue();
if (logTo.getIndex() < 0) {
throw new BuildException(String.format("Invalid @sendlogto value '%s'", dest));
}
OutputStream l;
if (SendLogTo.ANT_LOG.equals(dest) || SendLogTo.BOTH.equals(dest)) {
if (parentTask != null) {
l = new LogOutputStream(parentTask, Project.MSG_INFO);
} else {
l = new KeepAliveOutputStream(System.out);
}
if (SendLogTo.ANT_LOG.equals(dest)) {
return l;
}
} else {
l = null;
}
OutputStream f;
String fileName = "TEST-" + normalize(buildFile) + "." + extension;
File file;
if (toDir != null) {
file = new File(toDir, fileName);
} else if (parentTask == null) {
file = new File(fileName);
} else {
file = parentTask.getProject().resolveFile(fileName);
}
try {
f = new FileOutputStream(file);
} catch (IOException e) {
throw new BuildException(e);
}
if (SendLogTo.FILE.equals(dest)) {
return f;
}
return new TeeOutputStream(l, f);
}
/**
* Turns the build file name into something that vaguely looks
* like a Java classname. Close enough to be suitable for
* junitreport.
* @param buildFile the test file name
* @return the normalized name
*/
protected final String normalize(String buildFile) {
File base = parentTask != null ? parentTask.getProject().getBaseDir()
: new File(System.getProperty("user.dir"));
buildFile = FileUtils.getFileUtils().removeLeadingPath(base, new File(buildFile));
if (buildFile.length() > 0 && buildFile.charAt(0) == File.separatorChar) {
buildFile = buildFile.substring(1);
}
return buildFile.replace('.', '_').replace(':', '_').replace(File.separatorChar, '.');
}
protected final Location getLocation(Throwable t) {
Location l = Location.UNKNOWN_LOCATION;
if (t instanceof BuildException) {
Location l2 = ((BuildException) t).getLocation();
if (l2 != null) {
l = l2;
}
}
return l;
}
private Project currentTest;
public void setCurrentTestProject(Project p) {
currentTest = p;
p.addBuildListener(new LogGrabber());
}
protected Project getCurrentTestProject() {
return currentTest;
}
/**
* The minimum level a log message must be logged at to be
* included in the output.
*/
private AntUnitLogLevel logLevel;
/**
* Sets the minimum level a log message must be logged at to be
* included in the output.
* @param l minimum level
*/
public void setLogLevel(AntUnitLogLevel l) {
logLevel = l;
}
/**
* Gets messages from the project running the test target if their
* level is at least of the level specified with {@link
* #setLogLevel setLogLevel}.
*
* <p>This implementation is empty.</p>
* @param event the logged message
*/
protected void messageLogged(BuildEvent event) {}
public static class SendLogTo extends EnumeratedAttribute {
public static final String ANT_LOG = "ant";
public static final String FILE = "file";
public static final String BOTH = "both";
public SendLogTo() {}
public SendLogTo(String s) {
setValue(s);
}
public String[] getValues() {
return new String[] {ANT_LOG, FILE, BOTH};
}
}
public static class AntUnitLogLevel extends EnumeratedAttribute {
public static final AntUnitLogLevel NONE = new AntUnitLogLevel("none");
public AntUnitLogLevel() {
super();
}
private AntUnitLogLevel(String value) {
super();
setValue(value);
}
public String[] getValues() {
return new String[] {
"none",
"error",
"warn",
"warning",
"info",
"verbose",
"debug"};
}
private static int[] levels = {
Project.MSG_ERR - 1,
Project.MSG_ERR,
Project.MSG_WARN,
Project.MSG_WARN,
Project.MSG_INFO,
Project.MSG_VERBOSE,
Project.MSG_DEBUG
};
public int getLevel() {
return levels[getIndex()];
}
}
public class LogGrabber implements BuildListener {
public void buildStarted(BuildEvent event) {}
public void buildFinished(BuildEvent event) {}
public void targetStarted(BuildEvent event) {}
public void targetFinished(BuildEvent event) {}
public void taskStarted(BuildEvent event) {}
public void taskFinished(BuildEvent event) {}
public void messageLogged(BuildEvent event) {
int priority = event.getPriority();
// Filter out messages based on priority
if (priority <= logLevel.getLevel()) {
BaseAntUnitListener.this.messageLogged(event);
}
}
}
}