blob: c05ae8feebd5bad090f8fd8b28097c7f9e8cae95 [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.
*/
/* $Id$ */
package org.apache.fop.tools;
import java.io.File;
import java.io.OutputStream;
import java.net.URI;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.impl.SimpleLog;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.cli.InputHandler;
import org.apache.fop.tools.anttasks.FileCompare;
/**
* TestConverter is used to process a set of tests specified in
* a testsuite.
* This class retrieves the data in the testsuite and uses FOP
* to convert the xml and xsl file into either an xml representation
* of the area tree or a pdf document.
* The area tree can be used for automatic comparisons between different
* versions of FOP or the pdf can be view for manual checking and
* pdf rendering.
*/
public class TestConverter {
private boolean failOnly;
private String outputFormat = MimeConstants.MIME_FOP_AREA_TREE;
private File destdir;
private File compare;
private String baseDir = "./";
private Map differ = new java.util.HashMap();
/**
* logging instance
*/
protected SimpleLog logger;
/**
* This main method can be used to run the test converter from
* the command line.
* This will take a specified testsuite xml and process all
* tests in it.
* The command line options are:
* -b to set the base directory for where the testsuite and associated files are
* -failOnly to process only the tests which are specified as fail in the test results
* -pdf to output the result as pdf
* @param args command-line arguments
*/
public static void main(String[] args) {
if (args == null || args.length == 0) {
System.out.println("test suite file name required");
return;
}
TestConverter tc = new TestConverter();
String results = "results";
String testFile = null;
for (int count = 0; count < args.length; count++) {
if (args[count].equals("-failOnly")) {
tc.setFailOnly(true);
} else if (args[count].equals("-pdf")) {
tc.setOutputFormat(MimeConstants.MIME_PDF);
} else if (args[count].equals("-rtf")) {
tc.setOutputFormat(MimeConstants.MIME_RTF);
} else if (args[count].equals("-ps")) {
tc.setOutputFormat(MimeConstants.MIME_POSTSCRIPT);
} else if (args[count].equals("-d")) {
tc.setDebug(true);
} else if (args[count].equals("-b")) {
tc.setBaseDir(args[++count]);
} else if (args[count].equals("-results")) {
results = args[++count];
} else {
testFile = args[count];
}
}
if (testFile == null) {
System.out.println("test suite file name required");
}
tc.runTests(testFile, results, null);
}
/**
* Construct a new TestConverter
*/
public TestConverter() {
logger = new SimpleLog("FOP/Test");
logger.setLevel(SimpleLog.LOG_LEVEL_ERROR);
}
/**
* Controls output format to generate
* @param outputFormat the MIME type of the output format
*/
public void setOutputFormat(String outputFormat) {
this.outputFormat = outputFormat;
}
/**
* Controls whether to process only the tests which are specified as fail
* in the test results.
* @param fail True if only fail tests should be processed
*/
public void setFailOnly(boolean fail) {
failOnly = fail;
}
/**
* Sets the base directory.
* @param str base directory
*/
public void setBaseDir(String str) {
baseDir = str;
}
/**
* Controls whether to set logging to debug level
* @param debug If true, debug level, if false, error level
*/
public void setDebug(boolean debug) {
if (debug) {
logger.setLevel(SimpleLog.LOG_LEVEL_DEBUG);
} else {
logger.setLevel(SimpleLog.LOG_LEVEL_ERROR);
}
}
/**
* Run the Tests.
* This runs the tests specified in the xml file fname.
* The document is read as a dom and each testcase is covered.
* @param fname filename of the input file
* @param dest destination directory
* @param compDir comparison directory
* @return Map a Map containing differences
*/
public Map runTests(String fname, String dest, String compDir) {
logger.debug("running tests in file:" + fname);
try {
if (compDir != null) {
compare = new File(baseDir + "/" + compDir);
}
destdir = new File(baseDir + "/" + dest);
destdir.mkdirs();
File f = new File(baseDir + "/" + fname);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
Document doc = db.parse(f);
NodeList suitelist = doc.getChildNodes();
if (suitelist.getLength() == 0) {
return differ;
}
Node testsuite = null;
testsuite = doc.getDocumentElement();
if (testsuite.hasAttributes()) {
String profile
= testsuite.getAttributes().getNamedItem("profile").getNodeValue();
logger.debug("testing test suite:" + profile);
}
NodeList testcases = testsuite.getChildNodes();
for (int count = 0; count < testcases.getLength(); count++) {
Node testcase = testcases.item(count);
if (testcase.getNodeName().equals("testcases")) {
runTestCase(testcase);
}
}
} catch (Exception e) {
logger.error("Error while running tests", e);
}
return differ;
}
/**
* Run a test case.
* This goes through a test case in the document.
* A testcase can contain a test, a result or more test cases.
* A test case is handled recursively otherwise the test is run.
* @param tcase Test case node to run
*/
protected void runTestCase(Node tcase) {
if (tcase.hasAttributes()) {
String profile
= tcase.getAttributes().getNamedItem("profile").getNodeValue();
logger.debug("testing profile:" + profile);
}
NodeList cases = tcase.getChildNodes();
for (int count = 0; count < cases.getLength(); count++) {
Node node = cases.item(count);
String nodename = node.getNodeName();
if (nodename.equals("testcases")) {
runTestCase(node);
} else if (nodename.equals("test")) {
runTest(tcase, node);
} /* else if (nodename.equals("result")) {
//nop
} */
}
}
/**
* Run a particular test.
* This runs a test defined by the xml and xsl documents.
* If the test has a result specified it is checked.
* This creates an XSLTInputHandler to provide the input
* for FOP and writes the data out to an XML are tree.
* @param testcase Test case to run
* @param test Test
*/
protected void runTest(Node testcase, Node test) {
String id = test.getAttributes().getNamedItem("id").getNodeValue();
Node result = locateResult(testcase, id);
boolean pass = false;
if (result != null) {
String agreement
= result.getAttributes().getNamedItem("agreement").getNodeValue();
pass = agreement.equals("full");
}
if (pass && failOnly) {
return;
}
String xml = test.getAttributes().getNamedItem("xml").getNodeValue();
Node xslNode = test.getAttributes().getNamedItem("xsl");
String xsl = null;
if (xslNode != null) {
xsl = xslNode.getNodeValue();
}
logger.debug("converting xml:" + xml + " and xsl:"
+ xsl + " to area tree");
String res = xml;
Node resNode = test.getAttributes().getNamedItem("results");
if (resNode != null) {
res = resNode.getNodeValue();
}
try {
File xmlFile = new File(baseDir + "/" + xml);
URI baseUri = xmlFile.getParentFile().toURI();
InputHandler inputHandler = null;
if (xsl == null) {
inputHandler = new InputHandler(xmlFile);
} else {
inputHandler = new InputHandler(xmlFile, new File(baseDir + "/" + xsl), null);
}
FopFactory fopFactory = FopFactory.newInstance(baseUri);
FOUserAgent userAgent = fopFactory.newFOUserAgent();
userAgent.getRendererOptions().put("fineDetail", false);
userAgent.getRendererOptions().put("consistentOutput", true);
userAgent.setProducer("Testsuite Converter");
String outname = res;
if (outname.endsWith(".xml") || outname.endsWith(".pdf")) {
outname = outname.substring(0, outname.length() - 4);
}
File outputFile = new File(destdir,
outname + makeResultExtension());
outputFile.getParentFile().mkdirs();
OutputStream outStream = null;
try {
outStream = new java.io.BufferedOutputStream(
new java.io.FileOutputStream(outputFile));
logger.debug("ddir:" + destdir + " on:" + outputFile.getName());
inputHandler.renderTo(userAgent, outputFormat, outStream);
} finally {
IOUtils.closeQuietly(outStream);
}
// check difference
if (compare != null) {
File f1 = new File(destdir, outname + ".at.xml");
File f2 = new File(compare, outname + ".at.xml");
if (!compareFiles(f1, f2)) {
differ.put(outname + ".at.xml", pass);
}
}
} catch (Exception e) {
logger.error("Error while running tests", e);
}
}
/**
* Return a suitable file extension for the output format.
*/
private String makeResultExtension() {
if (MimeConstants.MIME_PDF.equals(outputFormat)) {
return ".pdf";
} else if (MimeConstants.MIME_RTF.equals(outputFormat)) {
return ".rtf";
} else if (MimeConstants.MIME_POSTSCRIPT.equals(outputFormat)) {
return ".ps";
} else {
return ".at.xml";
}
}
/**
* Compare files.
* @param f1 first file
* @param f2 second file
* @return true if equal
*/
protected boolean compareFiles(File f1, File f2) {
try {
return FileCompare.compareFiles(f1, f2);
} catch (Exception e) {
logger.error("Error while comparing files", e);
return false;
}
}
private Node locateResult(Node testcase, String id) {
NodeList cases = testcase.getChildNodes();
for (int count = 0; count < cases.getLength(); count++) {
Node node = cases.item(count);
String nodename = node.getNodeName();
if (nodename.equals("result")) {
String resultid
= node.getAttributes().getNamedItem("id").getNodeValue();
if (id.equals(resultid)) {
return node;
}
}
}
return null;
}
}