| /***************************************************************************** |
| * 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.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 Suite" format, whose |
| * constants are defined in the<tt>XTSConstants</tt> interface. |
| * |
| * In summary, this class builds a <tt>TestSuite</tt> which is |
| * an aggregation of individual <tt>Test</tt> and <tt>TestSuite</tt> |
| * and requests a set of <tt>TestResultProcessor</tt> to |
| * process the <tt>TestResult</tt> that are produced by the |
| * <tt>Test</tt> and <tt>TestSuite</tt> objects. |
| * |
| * @author <a href="mailto:vhardy@apache.org">Vincent Hardy</a> |
| * @version $Id$ |
| */ |
| public class XMLTestSuiteRunner implements XTSConstants{ |
| /** |
| * An error happened while processing a <tt>Test</tt> |
| * description. |
| * {0} : the <test> "className" attribute value |
| * {1} : exception's class name |
| * {2} : exception's message |
| * {3} : exception's stack trace |
| */ |
| public static final String CANNOT_CREATE_TEST |
| = "xml.XMLTestSuiteRunner.error.cannot.create.test"; |
| |
| /** |
| * 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 == XTS_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 { |
| |
| String className |
| = element.getAttributeNS(null, |
| XTS_CLASS_ATTRIBUTE); |
| |
| try{ |
| return (TestReportProcessor)buildObject(className, 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[] { className, |
| e.getClass().getName(), |
| e.getMessage(), |
| sw.toString() }, |
| e); |
| } |
| } |
| |
| /** |
| * Builds a <tt>TestSuite</tt> from an input element. |
| * This method assumes that element is a <testSuite> |
| * instance, as the input document should have been |
| * validated when loaded. |
| */ |
| protected TestSuite buildTestSuite(Element element) |
| throws TestException { |
| DefaultTestSuite testSuite |
| = new DefaultTestSuite(); |
| |
| String suiteName |
| = element.getAttributeNS(null, |
| XTS_NAME_ATTRIBUTE); |
| |
| testSuite.setName(suiteName + "--" + testSuite.getName()); |
| |
| 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 == XTS_TEST_TAG){ |
| Test t = buildTest(childElement); |
| testSuite.addTest(t); |
| } |
| } |
| } |
| } |
| |
| return testSuite; |
| } |
| |
| protected Test buildTest(Element element) throws TestException { |
| String className |
| = element.getAttributeNS(null, |
| XTS_CLASS_ATTRIBUTE); |
| |
| try{ |
| return (Test)buildObject(className, element); |
| |
| }catch (Exception e) { |
| StringWriter sw = new StringWriter(); |
| PrintWriter pw = new PrintWriter(sw); |
| e.printStackTrace(pw); |
| throw new TestException(CANNOT_CREATE_TEST, |
| new Object[] { className, |
| e.getClass().getName(), |
| e.getMessage(), |
| sw.toString() }, |
| e); |
| } |
| } |
| |
| /** |
| * Implementation helper: builds a generic object |
| */ |
| public Object buildObject(String className, |
| Element element) throws Exception { |
| Class cl = Class.forName(className); |
| Object[] argsArray = null; |
| Class[] argsClasses = null; |
| |
| NodeList children = element.getChildNodes(); |
| if(children != null && children.getLength() > 0){ |
| int n = children.getLength(); |
| Vector args = new Vector(); |
| 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 == XTS_ARG_TAG){ |
| Object arg = buildArgument(childElement); |
| args.addElement(arg); |
| } |
| } |
| } |
| |
| if(args.size() > 0){ |
| argsArray = new Object[args.size()]; |
| args.copyInto(argsArray); |
| |
| argsClasses = new Class[args.size()]; |
| |
| for(int i=0; i<args.size(); i++){ |
| argsClasses[i] = argsArray[i].getClass(); |
| } |
| } |
| } |
| |
| Constructor constructor |
| = getDeclaredConstructor(cl, argsClasses); |
| |
| return constructor.newInstance(argsArray); |
| } |
| |
| /** |
| * Returns a constructor that has can be used for the input class |
| * types. |
| */ |
| protected Constructor getDeclaredConstructor(Class cl, |
| Class[] argClasses){ |
| Constructor[] cs = cl.getDeclaredConstructors(); |
| for(int i=0; i<cs.length; i++){ |
| Class[] reqArgClasses = cs[i].getParameterTypes(); |
| if(reqArgClasses.length == argClasses.length){ |
| int j=0; |
| for(; j<argClasses.length; j++){ |
| if(!reqArgClasses[j].isAssignableFrom(argClasses[j])){ |
| break; |
| } |
| } |
| if(j == argClasses.length){ |
| return cs[i]; |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Limitation: Arguments *must* have a String based |
| * constructor. Or be an object that takes a set of string |
| * based arguments. |
| */ |
| public Object buildArgument(Element element) throws Exception { |
| String classAttr = element.getAttributeNS(null, |
| XTS_CLASS_ATTRIBUTE); |
| |
| if(!element.hasChildNodes()){ |
| String value = element.getAttributeNS(null, |
| XTS_VALUE_ATTRIBUTE); |
| |
| // String based argument |
| Class cl = Class.forName(classAttr); |
| |
| Constructor constructor |
| = cl.getDeclaredConstructor(new Class[] { String.class }); |
| |
| return constructor.newInstance(new Object[] {value}); |
| } |
| else{ |
| return buildObject(classAttr, element); |
| } |
| } |
| |
| /** |
| * Runs the test suite described by the input |
| * Document object. |
| */ |
| public void run(Document doc) |
| throws TestException { |
| |
| // |
| // First, extract the TestSuite to run |
| // the actual tests. |
| // |
| TestSuite testSuite |
| = buildTestSuite(doc.getDocumentElement()); |
| |
| // |
| // Now, get the set of TestReportProcessors |
| // that can use the data |
| // |
| TestReportProcessor[] processors |
| = extractTestReportProcessor(doc.getDocumentElement()); |
| |
| // |
| // Run the test |
| // |
| TestReport report = null; |
| try{ |
| report = testSuite.run(); |
| }catch(Exception e){ |
| StringWriter sw = new StringWriter(); |
| PrintWriter pw = new PrintWriter(sw); |
| e.printStackTrace(pw); |
| throw new TestException(TEST_SUITE_EXCEPTION, |
| new Object[] { testSuite.getName(), |
| testSuite.getClass().getName(), |
| e.getClass().getName(), |
| e.getMessage(), |
| sw.toString() }, |
| e); |
| } |
| |
| // |
| // Process the report |
| // |
| 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); |
| } |
| } |
| |
| /** |
| * 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{ |
| doc = df.createDocument(null, |
| XTS_TEST_SUITE_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{ |
| 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); |
| |
| } |
| } |