/* *******************************************************************
* Copyright (c) 1999-2001 Xerox Corporation,
* 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* Xerox/PARC initial implementation
* ******************************************************************/
import org.apache.tools.ant.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
/**
* Provides utility methods to test ant tasks.
*/
public abstract class AntTaskTester implements BuildListener {
public abstract String getAntFile();
protected PrintStream out = System.out;
protected PrintStream err = System.err;
protected void info(Object msg) {
out.println(" [" + msg + "]");
}
protected Project project;
protected String taskname = "unset";
protected List errors = new Vector();
protected void throwable(Throwable t) {
error(taskname, t);
t.printStackTrace();
}
protected void error(String task, Object msg) {
error("[" + task + "]: " + msg);
}
protected void error(Object msg) {
err.println("Error: " + msg);
errors.add(msg);
}
protected List wants = new Vector();
protected void want(Object object) {
wants.add(object);
}
protected List haves = new Vector();
protected void have(Object object) {
haves.add(object);
}
protected List donts = new Vector();
protected void dont(Object object) {
donts.add(object);
}
protected void clear() {
wants = new Vector();
haves = new Vector();
donts = new Vector();
}
protected final boolean verbose = verbose();
protected boolean verbose() { return false; }
protected void log(String msg) {
if (verbose) out.println("[ " + msg + " ]");
}
public void printSummary() {
Iterator iter = errors.iterator();
out.println();
out.println("----------------------- Test Summary -----------------------");
if (errors.size() == 0) {
out.println("no errors");
} else {
out.println(errors.size() + " error" + (errors.size() > 1 ? "s" : ""));
while (iter.hasNext()) {
out.println(" " + iter.next());
}
}
out.println("------------------------------------------------------------");
}
/**
* Checks the all the assertions we wanted were achieved
* and all those received were desired.
*/
protected void checkAfterTask() {
log("checking after task");
for (Iterator i = wants.iterator(); i.hasNext();) {
Object want = i.next();
check(haves.contains(want),
"didn't see " + want + " in " + haves);
}
for (Iterator i = haves.iterator(); i.hasNext();) {
Object have = i.next();
check(wants.contains(have),
"shouldn't have seen " + have + " in " + wants);
}
for (Iterator i = donts.iterator(); i.hasNext();) {
Object dont = i.next();
check(!haves.contains(dont),
"should't have seen " + dont + " in " + haves);
}
}
/**
* Logs an error in !b
with message msg
.
*
* @param b true
for an error.
* @param msg Failure message.
*/
protected void check(boolean b, String msg) {
if (!b) error(taskname, msg);
}
/**
* Calls {@link #check(boolean,String)} with the result
* of comparing equality of o1
and o2
,
* failing with message msg
.
*
* @param o1 First comparison.
* @param o2 Other comparison.
* @param msg Failure message.
*/
protected void check(Object o1, Object o2, String msg) {
if (o1 != null) {
check(o1.equals(o2), msg);
} else if (o2 != null) {
check(o2.equals(o1), msg);
} else {
check(true, msg);
}
}
/**
* Calls {@link #runProject} with args
and
* the result of {@link #getAntFile}.
*
* @param args Arguments given on the command line.
* @see #runProject(String[], String)
*/
public void runTests(String[] args) {
runProject(args, getAntFile());
}
/**
* Loads the project, collects a list of methods, and
* passes these methods to {@link #runProject(Method[])}.
*
* @param args Command line arguments.
* @param buildFile XML file that we are giving to ANT.
* @see #runProject(Method[])
*/
public void runProject(String[] args, String buildFile) {
loadProject(buildFile);
Method[] methods = null;
if (args == null || args.length == 0 || args[0].equals("${args}")) {
methods = getClass().getMethods();
} else {
methods = new Method[args.length];
for (int i = 0; i < args.length; i++) {
String name = args[i];
if (!Character.isJavaIdentifierStart(name.charAt(0)) || // todo wes: was (i)?
name.charAt(0) == '$') {
continue;
}
try {
methods[i] = getClass().getMethod(name, new Class[]{});
} catch (NoSuchMethodException nsme) {
methods[i] = null;
}
}
}
runProject(methods);
}
/**
* Execute the targets whose name matches those found in methods
.
*
* @param methods List of methods to execute.
*/
protected final void runProject(Method[] methods) {
if (methods == null || methods.length < 1) {
return;
}
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (method == null) {
error("a method is null!");
continue;
}
taskname = method.getName();
if (taskname.startsWith("test")) {
info("test task: " + taskname);
try {
method.invoke(this, new Object[]{});
beforeTasks();
execute(taskname);
afterTasks();
} catch (Throwable t) {
throwable(t);
} finally {
info("done task: " + taskname);
}
} else if (taskname.startsWith("fail")) {
info("fail task: " + taskname);
try {
beforeTasks();
want(taskname + "-error");
execute(taskname);
afterTasks();
} catch (Throwable t) {
if (t instanceof BuildException) {
have(taskname + "-error");
try {
method.invoke(this, new Object[]{t});
} catch (Throwable tt) {
throwable(tt);
}
} else {
throwable(t);
}
} finally {
info("done task: " + taskname);
}
}
}
printSummary();
}
/**
* Called before every task.
*/
private final void beforeTasks() {
clear();
beforeMethod();
beforeEveryTask();
}
/**
* Called after every task.
*/
private final void afterTasks() {
afterMethod();
afterEveryTask();
checkAfterTask();
}
/**
* Invokes the method with prefix prefix
.
*
* @param prefix Prefix of the method to execute.
*/
private final void taskMethod(String prefix) {
String name = prefix + Character.toUpperCase(taskname.charAt(0)) +
taskname.substring(1);
try {
Method method = getClass().getDeclaredMethod(name, new Class[]{});
if (method != null) {
method.invoke(this, new Object[]{});
}
} catch (Throwable t) {
}
}
/**
* Executes the method with prefix after
.
*/
private final void afterMethod() {
taskMethod("after");
}
/**
* Executes the method with prefix before
.
*/
private final void beforeMethod() {
taskMethod("before");
}
/**
* Override this to do some work before every task.
*/
protected void beforeEveryTask() {}
/**
* Override this for initialization -- called at
* the end of {@link #loadProject}.
*/
protected void init() {}
/**
* Override this to do some work after every task.
*/
protected void afterEveryTask() {}
protected void setProperties(Map map, boolean user) {
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = map.get(key);
String keyString = key + "";
String valString = val + "";
if (user) {
project.setUserProperty(keyString, valString);
} else {
project.setProperty(keyString, valString);
}
}
}
protected void setProperties() {
setProperties(getProperties(), false);
}
protected void setUserProperties() {
setProperties(getUserProperties(), true);
}
/**
* Override this to provide user properties -- default to
* an empty HashMap
.
*
* @return Empty HashMap
.
*/
protected Map getUserProperties() {
return new HashMap();
}
/**
* Override this to provide system properties -- default to
* an empty HashMap
.
*
* @return Empty HashMap
.
*/
protected Map getProperties() {
return new HashMap();
}
/**
* Loads the project with file name buildFile
.
*
* @param buildFile Name of the XML file to load.
*/
public void loadProject(String buildFile) {
project = new Project();
project.init();
project.setUserProperty("ant.file", new File(buildFile).getAbsolutePath() );
setProperties();
setUserProperties();
project.addBuildListener(this);
ProjectHelper.configureProject(project, new File(buildFile));
init();
}
public void execute(String targetName) {
try {
project.executeTarget(targetName);
} finally {
}
}
private static class StringBufferOutputStream extends OutputStream {
private StringBuffer buf;
public StringBufferOutputStream(StringBuffer buf) {
this.buf = buf;
}
public void write(int c) {
buf.append((char)c);
}
}
public boolean verbosity(BuildEvent event) {
int[] verbosities = verbosities();
int priority = event.getPriority();
for (int i = 0; i < verbosities.length; i++) {
if (priority == verbosities[i]) return true;
}
return false;
}
public int[] verbosities() {
return new int[] { /*Project.MSG_VERBOSE,*/ Project.MSG_INFO, Project.MSG_WARN, project.MSG_ERR };
}
// BuildListener
public void buildFinished(BuildEvent event) {
}
public void buildStarted(BuildEvent event) {
}
public void messageLogged(BuildEvent event) {
if (verbosity(event)) {
out.println(event.getMessage());
}
}
public void targetFinished(BuildEvent event) {
}
public void targetStarted(BuildEvent event) {
}
public void taskFinished(BuildEvent event) {
}
public void taskStarted(BuildEvent event) {
}
}