junit.extensions.jfcunit.tools.XMLRoot Maven / Gradle / Ivy
package junit.extensions.jfcunit.tools;
import junit.extensions.jfcunit.xml.XMLRecorder;
import junit.extensions.xml.XMLTestSuite;
import junit.extensions.xml.XMLUtil;
import junit.framework.Test;
import junit.textui.TestRunner;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.StringTokenizer;
/**
* Title: JFCUnit
* Description: This class is a tool class which interfaces
* a JUnit test environment to the JFCUnits XML test environment.
* The application can be passed through system properties, the constructor,
* the static call to get the test suite, or through the main methods arguments.
*
* When XMLRoot is instanciated with no arguments then the
* following system properties are queried.
*
* jfcunit.xmlroot.classname required main classname.
* jfcunit.xmlroot.args optional parameters to the main method.
* jfcunit.xmlroot.testsuite XML test suite to be run.
* jfcunit.xmlroot.record If not specified the record tags will be ignored.
* jfcunit.xmlroot.create Create a new xml file if it does not exist.
*
* @author kevin wilson
* @version 1.0
*/
public class XMLRoot extends XMLTestSuite {
/** Document factory to be used as default. */
public static final String DOCUMENT_FACTORY = "javax.xml.parsers.DocumentBuilderFactory";
/** System property for classname. */
public static final String XMLROOT_CLASSNAME = "jfcunit.xmlroot.classname";
/** System property for args. */
public static final String XMLROOT_ARGS = "jfcunit.xmlroot.args";
/** System property for recording. */
public static final String XMLROOT_RECORD = "jfcunit.xmlroot.record";
/** System property for XML file. */
public static final String XMLROOT_TESTSUITE = "jfcunit.xmlroot.testsuite";
/** System property for create the xml root. */
public static final String XMLROOT_CREATE = "jfcunit.xmlroot.create";
/**
* Default constructor. Uses system properties to get the classname and
* testsuite filename.
* @throws Exception may be thrown.
*/
public XMLRoot() throws Exception {
this(
getClassName(),
getArgs(),
getTestSuite());
}
/**
* Default constructor.
* @param classname Class name of the main application class
* @param args Arguments to be passed to the main method.
* @param filename The filename of the XML test suite specification
* @throws Exception may be thrown.
*/
public XMLRoot(final String classname, final String[] args,
final String filename) throws Exception {
super(filename,
getInputStream(
classname.trim(),
args,
filename));
Class applClass = getClass().getClassLoader().loadClass(
classname.trim());
Class[] parameterSpec = {String[].class};
final Method mainMethod = applClass.getMethod("main", parameterSpec);
XMLRecorder.setReplay(!getRecord());
final String[] appArgs;
if (args == null) {
appArgs = new String[0];
} else {
appArgs = args;
}
final Object[] parameters = {appArgs};
// Start the main from another thread so this does not block the test case
// in cases where the main method does not return.
new Thread(
new Runnable() {
public void run() {
try {
mainMethod.invoke(null, parameters);
} catch (IllegalAccessException ex) {
System.err.println(
"Exception occured while invoking application:"
+ classname);
ex.printStackTrace();
} catch (IllegalArgumentException ex) {
System.err.println(
"Exception occured while invoking application:"
+ classname);
ex.printStackTrace();
} catch (InvocationTargetException ex) {
System.err.println(
"Exception occured while invoking application:"
+ classname);
ex.printStackTrace();
}
}
}).start();
}
/**
* Application start method. The application takes two arguments:
* >main class< The Main class of the application to test
* >test suite specification< The XML file containing the test suite
* @param args classname [args...] xmlfile
* @throws Exception may be thrown.
*/
public static void main(final String[] args) throws Exception {
updateDocFactory();
if (args.length < 2) {
TestRunner.run((Test) XMLRoot.suite());
} else if (args.length >= 2) {
System.out.println("Application Class = " + args[0]);
String[] progArgs = new String[args.length - 2];
for (int i = 1; i < (args.length - 1); i++) {
progArgs[i - 1] = args[i];
}
System.out.println("Test Suite = " + args[args.length - 1]);
TestRunner.run((Test) XMLRoot.suite(args[0], progArgs,
args[args.length - 1]));
} else {
System.out.println(
"Usage: junit.extensions.jfcunit.tools.XMLRoot mainclass [class arguments...] [xml file]");
System.exit(1);
}
}
/**
* Creates a new test suite based on the system properties.
* @return Test generated from the System properties.
* @throws Exception may be thrown.
*/
public static Test suite() throws Exception {
updateDocFactory();
return new XMLRoot();
}
/**
* Creates a new test suite based on the main class and filename provided.
* @param classname Class name of the main application class
* @param args Arguments to be passed to the application.
* @param filename Name of XML file containing test suite
* @return Test created with the given arguments.
* @throws Exception may be thrown.
*/
public static Test suite(final String classname, final String[] args,
final String filename) throws Exception {
updateDocFactory();
return new XMLRoot(classname, args, filename);
}
/**
* Get the jfcunit.xmlroot.args system property.
* @return Arguments to be run with the command.
* Assumes space separated list. May not work for
* all cases of program arguments.
*/
protected static final String[] getArgs() {
String args = System.getProperty(XMLROOT_ARGS);
if (args == null) {
return null;
}
StringTokenizer st = new StringTokenizer(args, " ");
String[] tokens = new String[st.countTokens()];
int i = 0;
while (st.hasMoreTokens()) {
tokens[i++] = st.nextToken();
}
return tokens;
}
/**
* Get the jfcunit.xmlroot.classname system property.
* @return class name to be executed.
*/
protected static final String getClassName() {
String classname = System.getProperty(XMLROOT_CLASSNAME);
if (classname == null) {
throw new RuntimeException("Could not find system property:"
+ XMLROOT_CLASSNAME);
}
return classname;
}
/**
* Assembles the classname and args into one string.
* @param classname program name.
* @param args Arguments used.
* @return Program and arguments.
*/
protected static final String getCommand(final String classname,
final String[] args) {
StringBuffer buf = new StringBuffer(1000);
buf.append(classname);
buf.append(" ");
if (args != null) {
for (int i = 0; i < args.length; i++) {
buf.append(args[i]);
buf.append(" ");
}
}
return buf.toString();
}
/**
* Get the XML file name from the jfcunit.xmlroot.create system property.
* @return true if the xml file should be created.
*/
protected static final boolean getCreate() {
if (getRecord()) {
return Boolean.getBoolean(XMLROOT_CREATE);
}
return false;
}
/**
* Get the input stream for the XML file. If a XML file
* cannot be found then a template will be generated
* for recording.
*
* @param classname Classname added to template.
* @param args Arguments to be added to the template.
* @param fileName XML file name to be opened or created.
* @return Input stream of the file opened.
*/
protected static InputStream getInputStream(final String classname,
final String[] args, final String fileName) {
InputStream is = null;
try {
is = XMLUtil.readFileFromClasspath(fileName);
} catch (Exception e) {
; // Ignore exception
}
if (is != null) {
// If record is turned on then save the file to the
// current directory. Then it may be recorded to.
return is;
} else {
// Look in the local directory.
File file = new File(fileName);
if (file.exists()) {
try {
// Found the file so we will open the file.
is = new FileInputStream(file);
} catch (FileNotFoundException ex) {
System.err.println("Error opening local file." + fileName);
is = null;
}
return is;
} else {
if (!getCreate()) {
System.err.println("File not found:" + fileName);
} else {
try {
// File was not found so we will create a new file.
file.createNewFile();
FileOutputStream os = new FileOutputStream(file);
PrintWriter pw = new PrintWriter(os);
pw.println("");
pw.println(
"");
pw.println(
"");
pw.println(
"");
pw.println(
"");
pw.println(
"");
pw.println(
"");
pw.println(
"");
pw.println(
"");
pw.println(
"");
pw.println(
"");
pw.print("");
pw.println(" ");
pw.println(" ");
pw.println(
" ");
pw.print(
" ");
pw.println(" ");
pw.println(" ");
pw.println(" ");
pw.close();
os.close();
return new FileInputStream(file);
} catch (IOException ex1) {
System.err.println("Error creating new XML file."
+ fileName);
ex1.printStackTrace();
}
}
}
}
return null;
}
/**
* Get the state of the jfcunit.xmlroot.record system property.
* @return true if the record element is present and set to true.
*/
protected static final boolean getRecord() {
return Boolean.getBoolean(XMLROOT_RECORD);
}
/**
* Get the XML file name from the jfcunit.xmlroot.testsuite system property.
* @return XML file name.
*/
protected static final String getTestSuite() {
String testsuite = System.getProperty(XMLROOT_TESTSUITE);
if (testsuite == null) {
throw new RuntimeException("Could not find system property: "
+ XMLROOT_TESTSUITE);
}
return testsuite;
}
/**
* Set the document factory if it is not set for java
* versions less than 1.4.
*/
private static void updateDocFactory() {
String version = System.getProperty("java.version");
if (version.startsWith("1.2") || version.startsWith("1.3")) {
if (System.getProperty(DOCUMENT_FACTORY) == null) {
System.setProperty(DOCUMENT_FACTORY,
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
}
}
}
}