1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id: TestAssistant.java 1884907 2020-12-29 13:33:34Z ssteiner $ */
19 
20 package org.apache.fop.intermediate;
21 
22 import java.io.File;
23 import java.io.IOException;
24 
25 import javax.xml.parsers.DocumentBuilder;
26 import javax.xml.parsers.DocumentBuilderFactory;
27 import javax.xml.transform.Result;
28 import javax.xml.transform.Source;
29 import javax.xml.transform.Templates;
30 import javax.xml.transform.Transformer;
31 import javax.xml.transform.TransformerConfigurationException;
32 import javax.xml.transform.TransformerException;
33 import javax.xml.transform.dom.DOMResult;
34 import javax.xml.transform.dom.DOMSource;
35 import javax.xml.transform.sax.SAXTransformerFactory;
36 import javax.xml.transform.stream.StreamResult;
37 import javax.xml.transform.stream.StreamSource;
38 
39 import org.w3c.dom.Document;
40 import org.w3c.dom.Element;
41 
42 import org.apache.xpath.XPathAPI;
43 import org.apache.xpath.objects.XObject;
44 
45 import org.apache.fop.apps.EnvironmentProfile;
46 import org.apache.fop.apps.EnvironmentalProfileFactory;
47 import org.apache.fop.apps.FopFactory;
48 import org.apache.fop.apps.FopFactoryBuilder;
49 import org.apache.fop.apps.io.ResourceResolverFactory;
50 
51 /**
52  * Helper class for running FOP tests.
53  */
54 public class TestAssistant {
55 
56     // configure fopFactory as desired
57     protected final File testDir = new File("test/layoutengine/standard-testcases");
58 
59     private SAXTransformerFactory tfactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
60 
61     private DocumentBuilderFactory domBuilderFactory;
62 
63     private Templates testcase2fo;
64     private Templates testcase2checks;
65 
66     /**
67      * Main constructor.
68      */
TestAssistant()69     public TestAssistant() {
70         domBuilderFactory = DocumentBuilderFactory.newInstance();
71         domBuilderFactory.setNamespaceAware(true);
72         domBuilderFactory.setValidating(false);
73     }
74 
75     /**
76      * Returns the stylesheet for convert extracting the XSL-FO part from the test case.
77      * @return the stylesheet
78      * @throws TransformerConfigurationException if an error occurs loading the stylesheet
79      */
getTestcase2FOStylesheet()80     public Templates getTestcase2FOStylesheet() throws TransformerConfigurationException {
81         if (testcase2fo == null) {
82             //Load and cache stylesheet
83             Source src = new StreamSource(new File("test/layoutengine/testcase2fo.xsl"));
84             testcase2fo = tfactory.newTemplates(src);
85         }
86         return testcase2fo;
87     }
88 
89     /**
90      * Returns the stylesheet for convert extracting the checks from the test case.
91      * @return the stylesheet
92      * @throws TransformerConfigurationException if an error occurs loading the stylesheet
93      */
getTestcase2ChecksStylesheet()94     private Templates getTestcase2ChecksStylesheet() throws TransformerConfigurationException {
95         if (testcase2checks == null) {
96             //Load and cache stylesheet
97             Source src = new StreamSource(new File("test/layoutengine/testcase2checks.xsl"));
98             testcase2checks = tfactory.newTemplates(src);
99         }
100         return testcase2checks;
101     }
102 
103     /**
104      * Returns the element from the given XML file that encloses the tests.
105      *
106      * @param testFile a test case
107      * @return the parent element of the group(s) of checks
108      * @throws TransformerException if an error occurs while extracting the test element
109      */
getTestRoot(File testFile)110     public Element getTestRoot(File testFile) throws TransformerException {
111         Transformer transformer = getTestcase2ChecksStylesheet().newTransformer();
112         DOMResult res = new DOMResult();
113         transformer.transform(new StreamSource(testFile), res);
114         Document doc = (Document) res.getNode();
115         return doc.getDocumentElement();
116     }
117 
getFopFactory(Document testDoc)118     public FopFactory getFopFactory(Document testDoc) {
119         EnvironmentProfile envProfile = EnvironmentalProfileFactory.createRestrictedIO(
120                 testDir.getParentFile().toURI(),
121                 ResourceResolverFactory.createDefaultResourceResolver());
122         FopFactoryBuilder builder = new FopFactoryBuilder(envProfile);
123         builder.setStrictFOValidation(isStrictValidation(testDoc));
124         builder.getFontManager().setBase14KerningEnabled(isBase14KerningEnabled(testDoc));
125         builder.setTableBorderOverpaint(isTableBorderOverpaint(testDoc));
126         return builder.build();
127     }
128 
isBase14KerningEnabled(Document testDoc)129     private boolean isBase14KerningEnabled(Document testDoc) {
130         try {
131             XObject xo = XPathAPI.eval(testDoc, "/testcase/cfg/base14kerning");
132             String s = xo.str();
133             return ("true".equalsIgnoreCase(s));
134         } catch (TransformerException e) {
135             throw new RuntimeException("Error while evaluating XPath expression", e);
136         }
137     }
138 
isStrictValidation(Document testDoc)139     private boolean isStrictValidation(Document testDoc) {
140         try {
141             XObject xo = XPathAPI.eval(testDoc, "/testcase/cfg/strict-validation");
142             return !("false".equalsIgnoreCase(xo.str()));
143         } catch (TransformerException e) {
144             throw new RuntimeException("Error while evaluating XPath expression", e);
145         }
146     }
147 
isTableBorderOverpaint(Document testDoc)148     private boolean isTableBorderOverpaint(Document testDoc) {
149         try {
150             XObject xo = XPathAPI.eval(testDoc, "/testcase/cfg/table-border-overpaint");
151             String s = xo.str();
152             return "true".equalsIgnoreCase(s);
153         } catch (TransformerException e) {
154             throw new RuntimeException("Error while evaluating XPath expression", e);
155         }
156     }
157 
158     /**
159      * Loads a test case into a DOM document.
160      * @param testFile the test file
161      * @return the loaded test case
162      * @throws IOException if an I/O error occurs loading the test case
163      */
loadTestCase(File testFile)164     public Document loadTestCase(File testFile)
165             throws IOException {
166         try {
167             DocumentBuilder builder = domBuilderFactory.newDocumentBuilder();
168             Document testDoc = builder.parse(testFile);
169             return testDoc;
170         } catch (Exception e) {
171             throw new IOException("Error while loading test case: " + e.getMessage());
172         }
173     }
174 
175     /**
176      * Serialize the DOM for later inspection.
177      * @param doc the DOM document
178      * @param target target file
179      * @throws TransformerException if a problem occurs during serialization
180      */
saveDOM(Document doc, File target)181     public void saveDOM(Document doc, File target) throws TransformerException {
182         Transformer transformer = getTransformerFactory().newTransformer();
183         Source src = new DOMSource(doc);
184         Result res = new StreamResult(target);
185         transformer.transform(src, res);
186     }
187 
188     /**
189      * Returns the SAXTransformerFactory.
190      * @return the SAXTransformerFactory
191      */
getTransformerFactory()192     public SAXTransformerFactory getTransformerFactory() {
193         return tfactory;
194     }
195 }
196