/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.test.xml;
import java.io.File;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.net.MalformedURLException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Vector;
import org.apache.batik.test.DefaultTestSuite;
import org.apache.batik.test.TestReport;
import org.apache.batik.test.TestSuite;
import org.apache.batik.test.Test;
import org.apache.batik.test.TestException;
import org.apache.batik.test.TestReportProcessor;
import org.apache.batik.dom.util.DocumentFactory;
import org.apache.batik.dom.util.SAXDocumentFactory;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.xml.sax.InputSource;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* This class can be used to build and run a <tt>TestSuite</tt> from
* an XML description following the "XML Test Run" and "XML Test Suite"
* formats, whose constants are defined in the <tt>XTRunConstants</tt>
* and <tt>XTSConstants</tt> interfaces.
*
* This class takes a "Test Run" XML description as an input. That
* description contains: <br />
* + pointers to a number of "Test Suite" XML descriptions,
* which contain the definition of the set of <tt>Tests</tt> to be
* run and their configuration.<br />
* + a description of the set of <tt>TestReportProcessor</tt> and
* their configuration that should be used to process the reports
* generated by the various <tt>TestSuites</tt>.<br />
*
* @author <a href="mailto:vhardy@apache.org">Vincent Hardy</a>
* @version $Id: XMLTestSuiteRunner.java,v 1.7 2001/04/20 06:36:15 vhardy Exp $
*/
public class XMLTestSuiteRunner implements XTRunConstants, XTSConstants{
/**
* An error happened while processing a <tt>TestreportProcessor</tt>
* description.
* {0} : the <testReportProcessor> "className" attribute value
* {1} : exception's class name
* {2} : exception's message
* {3} : exception's stack trace
*/
public static final String CANNOT_CREATE_TEST_REPORT_PROCESSOR
= "xml.XMLTestSuiteRunner.error.cannot.create.test.report.processor";
/**
* An error happened while running the <tt>TestSuite</tt>
* {0} : <tt>TestSuite</tt> name
* {1} : <tt>TestSuite</tt> class name.
* {1} : exception's class name.
* {2} : exception's message
* {3} : exception's stack trace.
*/
public static final String TEST_SUITE_EXCEPTION
= "xml.XMLTestSuiteRunner.test.suite.exception";
/**
* An error happened while processing the <tt>TestReport</tt>
* generated by the <tt>TestSuite</tt>
* {0} : <tt>TestReportProcessor</tt> class name.
* {1} : exception's class name.
* {2} : exception's message
* {3} : exception's stack trace.
*/
public static final String TEST_REPORT_PROCESSING_EXCEPTION
= "xml.XMLTestSuiteRunner.error.test.report.processing.exception";
/**
* Builds an array of <tt>TestReportProcessor</tt> from the input
* element, assuming the input element is a <testSuite> instance,
*/
protected TestReportProcessor[] extractTestReportProcessor(Element element)
throws TestException
{
Vector processors = new Vector();
NodeList children = element.getChildNodes();
if(children != null && children.getLength() > 0){
int n = children.getLength();
for(int i=0; i<n; i++){
Node child = children.item(i);
if(child.getNodeType() == Node.ELEMENT_NODE){
Element childElement = (Element)child;
String tagName = childElement.getTagName().intern();
if(tagName == XTRun_TEST_REPORT_PROCESSOR_TAG){
processors.addElement(buildProcessor(childElement));
}
}
}
}
TestReportProcessor[] p = null;
if(processors.size() > 0){
p = new TestReportProcessor[processors.size()];
processors.copyInto(p);
}
return p;
}
/**
* Builds a <tt>TestResultProcessor</tt> from an element.
*/
protected TestReportProcessor buildProcessor(Element element)
throws TestException {
try{
return (TestReportProcessor)XMLReflect.buildObject(element);
}catch(Exception e){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
throw new TestException(CANNOT_CREATE_TEST_REPORT_PROCESSOR,
new Object[] { element.getAttributeNS(null, XR_CLASS_ATTRIBUTE),
e.getClass().getName(),
e.getMessage(),
sw.toString() },
e);
}
}
/**
* Builds a <tt>TestSuite</tt> from an input element.
* This method assumes that element is a <testRun>
* instance. The element is scanned for children
* <testSuite> elements which is loaded into
* a <tt>Test</tt> and composited into a <tt>TestSuite</tt>
*/
protected DefaultTestSuite buildReferencedTestSuites(Element element)
throws TestException {
DefaultTestSuite testSuite = new DefaultTestSuite();
Element[] testSuites
= getChildrenByTagName(element, XTRun_TEST_SUITE_TAG);
int n = testSuites != null ? testSuites.length : 0;
for(int i=0; i<n; i++){
String suiteHref =
testSuites[i].getAttributeNS(null, XTRun_HREF_ATTRIBUTE);
testSuite.addTest( XMLTestSuiteLoader.loadTestSuite(suiteHref) );
}
return testSuite;
}
/**
* Gets all the children of a given type.
*/
protected Element[] getChildrenByTagName(Element element,
String tagName)
{
tagName = tagName.intern();
Vector childrenWithTagName = new Vector();
NodeList children = element.getChildNodes();
if(children != null && children.getLength() > 0){
int n = children.getLength();
for(int i=0; i<n; i++){
Node child = children.item(i);
if(child.getNodeType() == Node.ELEMENT_NODE){
Element childElement = (Element)child;
String childTagName = childElement.getTagName().intern();
if(childTagName == tagName){
childrenWithTagName.addElement(childElement);
}
}
}
}
Element[] a = null;
if(childrenWithTagName.size() > 0){
a = new Element[childrenWithTagName.size()];
childrenWithTagName.copyInto(a);
}
return a;
}
/**
* Runs the test suite described by the input
* Document object. The root element on a
* 'Test Run' is <testRun> which can
* contain: <br />
* + children <testRun> elements.
* + <testReportProcessor> elements.
* + <testSuite> elements
* <br />
* Each <testRun> element is processed
* by loading
*/
public void run(Document doc)
throws TestException {
Element root = doc.getDocumentElement();
run(root);
}
protected TestReport runTest(Test test)
throws TestException {
try{
return test.run();
}catch(Exception e){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
throw new TestException(TEST_SUITE_EXCEPTION,
new Object[] { test.getName(),
test.getClass().getName(),
e.getClass().getName(),
e.getMessage(),
sw.toString() },
e);
}
}
protected void processReport(TestReport report,
TestReportProcessor[] processors)
throws TestException {
int n = processors.length;
int i=0;
try{
for(; i<n; i++){
processors[i].processReport(report);
}
}catch(Exception e){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
throw new TestException(TEST_REPORT_PROCESSING_EXCEPTION,
new Object[] { processors[i].getClass().getName(),
e.getClass().getName(),
e.getMessage(),
sw.toString() },
e);
}
}
protected void run(Element testRunElement)
throws TestException{
//
// First, extract the TestSuite to run
// the actual tests.
//
DefaultTestSuite testSuite
= buildReferencedTestSuites(testRunElement);
//
// Set the testRun name on the top level testSuite
//
String name = testRunElement.getAttributeNS(null, XTRun_NAME_ATTRIBUTE);
testSuite.setName(name);
//
// Now, get the set of TestReportProcessors
// that can use the data
//
TestReportProcessor[] processors
= extractTestReportProcessor(testRunElement);
if(processors != null){
//
// Run the test
//
TestReport report = runTest(testSuite);
//
// Process the report
//
processReport(report, processors);
}
//
// Run child testRun element
//
run( getChildrenByTagName(testRunElement,
XTRun_TEST_RUN_TAG) );
}
protected void run(Element[] testRunElements)
throws TestException{
if(testRunElements != null
&&
testRunElements.length > 0){
for(int i=0; i<testRunElements.length; i++){
run(testRunElements[i]);
}
}
}
/**
* Displayed when the user passes no arguments to the command line.
*/
public static final String USAGE
= "XMLTestSuiteRunner.messages.error.usage";
/**
* Displayed when the input argument does not represent an existing
* file to notify the user that the argument is going to be
* interpreted as a URI.
*/
public static final String NOT_A_FILE_TRY_URI
= "XMLTestSuiteRunner.messages.error.not.a.file.try.uri";
/**
* Displayed when the input file name cannot be turned into a URL
*/
public static final String COULD_NOT_CONVERT_FILE_NAME_TO_URI
= "XMLTestSuiteRunner.messages.error.could.not.convert.file.name.to.uri";
/**
* Displayed when the input argument does not represent a valid
* URI
*/
public static final String INVALID_URI
= "XMLTestSuiteRunner.messages.error.invalid.uri";
/**
* Displayed when the input document cannot be parsed.
* {0} : uri of the invalid document.
* {1} : exception generated while parsing
* {2} : exception message
*/
public static final String INVALID_DOCUMENT
= "XMLTestSuiteRunner.messages.error.invalid.document";
/**
* Error displayed when an error occurs while running the
* test suite
*/
public static final String ERROR_RUNNING_TEST_SUITE
= "XMLTestSuiteRunner.messages.error.running.test.suite";
/**
* Configuration parameter
*/
public static final String XML_PARSER =
"XMLTestSuiteRunner.config.xml.parser";
public static void main(String[] args) {
if(args.length < 1){
System.err.println(Messages.formatMessage(USAGE, null));
System.exit(0);
}
String uriStr = args[0];
File file = new File(uriStr);
URL url = null;
if(file.exists()){
try {
url = file.toURL();
}catch(MalformedURLException e){
System.err.println(Messages.formatMessage(COULD_NOT_CONVERT_FILE_NAME_TO_URI,
new Object[]{uriStr}));
System.exit(0);
}
}
else {
System.err.println(Messages.formatMessage(NOT_A_FILE_TRY_URI,
new Object[]{uriStr}));
try{
url = new URL(uriStr);
}catch(MalformedURLException e){
System.err.println(Messages.formatMessage(INVALID_URI,
new Object[]{uriStr}));
System.exit(0);
}
}
DocumentFactory df
= new SAXDocumentFactory(SVGDOMImplementation.getDOMImplementation(),
Messages.formatMessage(XML_PARSER, null));
Document doc = null;
try{
System.err.println("Loading document ...");
doc = df.createDocument(null,
XTRun_TEST_RUN_TAG,
url.toString(),
url.openStream());
}catch(Exception e){
e.printStackTrace();
System.err.println(Messages.formatMessage(INVALID_DOCUMENT,
new Object[] { uriStr,
e.getClass().getName(),
e.getMessage() }));
System.exit(0);
}
try{
System.err.println("Running test run...");
XMLTestSuiteRunner r = new XMLTestSuiteRunner();
r.run(doc);
}catch(TestException e){
System.err.println(Messages.formatMessage(ERROR_RUNNING_TEST_SUITE,
new Object[] { e.getMessage() }));
System.exit(0);
}
System.exit(1);
}
}