blob: 8ec59bf146fe9f5f17c5a0711a41db3d0e1347ef [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
*
* 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.junit3;
import java.io.File;
import java.io.PrintStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.apache.ant.antunit.AntUnitExecutionNotifier;
import org.apache.ant.antunit.AntUnitScriptRunner;
import org.apache.ant.antunit.ProjectFactory;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
/**
* A JUnit 3 TestSuite that group a suite of AntUnit targets coming from an ant
* script.
*/
public class AntUnitSuite extends TestSuite {
private final AntUnitScriptRunner antScriptRunner;
private final MultiProjectDemuxOutputStream stderr;
private final MultiProjectDemuxOutputStream stdout;
private final Test initializationReportingTest;
/**
* Create a JUnit TestSuite that when executed will run the given ant
* script.<br/>
* Note that it is the responsibility of the caller to give the correct
* File reference. Namely, if the File is a relative file, it will
* be resolve relatively to the execution directory (which might be
* different different from the project root directory).
*
* @param scriptFile
* AntUnit script file
* @param rootClass
* The test class that creates this suite. This is used to give
* a name to the suite so that an IDE can reexecute this suite.
*/
public AntUnitSuite(File scriptFile, Class rootClass) {
AntUnitScriptRunner createdScriptRunner = null;
try {
MyProjectFactory prjFactory = new MyProjectFactory(scriptFile);
createdScriptRunner = new AntUnitScriptRunner(prjFactory);
} catch (BuildException e) {
antScriptRunner = null;
stdout = null;
stderr = null;
initializationReportingTest = error(e);
addTest(initializationReportingTest);
return;
}
antScriptRunner = createdScriptRunner;
initializationReportingTest = null;
stdout = new MultiProjectDemuxOutputStream(antScriptRunner, false);
stderr = new MultiProjectDemuxOutputStream(antScriptRunner, true);
setName(antScriptRunner.getName() + "[" + scriptFile + "]");
setName(rootClass.getName());// Allows eclipse to reexecute the test
List testTargets = antScriptRunner.getTestTartgets();
for (Iterator it = testTargets.iterator(); it.hasNext();) {
String target = (String) it.next();
AntUnitTestCase tc = new AntUnitTestCase(this, scriptFile, target);
addTest(tc);
}
}
/**
* Constructor used by AntUnitTestCase when a single test case is created.
* The difference with the public constructor is this version doesn't set
* the name.
* @throws BuildException when the file project can not be create (parsed/read)
*/
AntUnitSuite(AntUnitTestCase singleTc , File scriptFile) throws BuildException {
MyProjectFactory prjFactory = new MyProjectFactory(scriptFile);
antScriptRunner = new AntUnitScriptRunner(prjFactory);
//the exception is throwed, and it is up to the AntUnitTestCase to handle it.
initializationReportingTest = null;
stdout = new MultiProjectDemuxOutputStream(antScriptRunner, false);
stderr = new MultiProjectDemuxOutputStream(antScriptRunner, true);
setName(antScriptRunner.getName() + "[" + scriptFile + "]");
addTest(singleTc);
}
/**
* @Override Run the full AntUnit suite
*/
public void run(TestResult testResult) {
if (initializationReportingTest!=null) {
initializationReportingTest.run(testResult);
} else {
List testTartgets = antScriptRunner.getTestTartgets();
JUnitNotificationAdapter notifier = new JUnitNotificationAdapter(
testResult, tests());
runInContainer(testTartgets, notifier);
}
}
private static Test error(final BuildException ex) {
return new TestCase("warning") {
protected void runTest() throws BuildException {
throw ex;
}
};
}
/**
* @Override Run a single test target of the AntUnit suite. suiteSetUp,
* setUp, tearDown and suiteTearDown are executed around it.
*/
public void runTest(Test test, TestResult result) {
if (initializationReportingTest!=null) {
initializationReportingTest.run(result);
} else {
String targetName = ((AntUnitTestCase) test).getTarget();
List singleTargetList = Collections.singletonList(targetName);
JUnitNotificationAdapter notifier = new JUnitNotificationAdapter(
result, tests());
runInContainer(singleTargetList, notifier);
}
}
/**
* Execute the test suite in a 'container' similar to the ant 'container'.
* When ant executes a project it redirect the input and the output. In this
* context we will only redirect output (unit test are not supposed to be
* interactive).<br/>
*
* @param targetList
* The list of test target to execute
* @param notifier
* The AntUnit notifier that will receive execution notifications
*/
public void runInContainer(List targetList, AntUnitExecutionNotifier notifier) {
PrintStream savedErr = System.err;
PrintStream savedOut = System.out;
try {
System.setOut(new PrintStream(stdout));
System.setErr(new PrintStream(stderr));
antScriptRunner.runSuite(targetList, notifier);
} finally {
System.setOut(savedOut);
System.setErr(savedErr);
}
}
/**
* The antscript project factory that creates projects in a junit context.
*/
private static class MyProjectFactory implements ProjectFactory {
private final File scriptFile;
private final PrintStream realStdErr = System.err;
private final PrintStream realStdOut = System.out;
public MyProjectFactory(File scriptFile) {
this.scriptFile = scriptFile;
}
public Project createProject() {
ProjectHelper prjHelper = ProjectHelper.getProjectHelper();
Project prj = new Project();
DefaultLogger logger = new DefaultLogger();
logger.setMessageOutputLevel(Project.MSG_INFO);
logger.setErrorPrintStream(realStdErr);
logger.setOutputPrintStream(realStdOut);
prj.addBuildListener(logger);
String absolutePath = scriptFile.getAbsolutePath();
prj.setUserProperty(MagicNames.ANT_FILE, absolutePath);
prj.addReference(ProjectHelper.PROJECTHELPER_REFERENCE, prjHelper);
prj.init();
prjHelper.parse(prj, scriptFile);
return prj;
}
}
}