| @@ -103,6 +103,12 @@ Other changes: | |||||
| nativeheaderdir attribute. | nativeheaderdir attribute. | ||||
| Bugzilla Report 59905 | Bugzilla Report 59905 | ||||
| * it is now possible to set features of the TraX factory used by <xslt> | |||||
| and <junitreport>. | |||||
| * it is now possible to use references to Ant types and classloaders | |||||
| built around Ant <path>s as values for TraX factory attributes. | |||||
| Changes from Ant 1.9.6 TO Ant 1.9.7 | Changes from Ant 1.9.6 TO Ant 1.9.7 | ||||
| =================================== | =================================== | ||||
| @@ -57,7 +57,7 @@ oro.version=2.0.8 | |||||
| regexp.version=1.3 | regexp.version=1.3 | ||||
| servlet-api.version=2.3 | servlet-api.version=2.3 | ||||
| which.version=1.0 | which.version=1.0 | ||||
| xalan.version=2.7.1 | |||||
| xalan.version=2.7.2 | |||||
| xml-resolver.version=1.2 | xml-resolver.version=1.2 | ||||
| mail.version=1.4 | mail.version=1.4 | ||||
| #paired | #paired | ||||
| @@ -395,7 +395,7 @@ Used to specify factory settings. | |||||
| </tr> | </tr> | ||||
| </table> | </table> | ||||
| <h3>Parameters specified as nested elements</h3> | <h3>Parameters specified as nested elements</h3> | ||||
| <h4>attribute </h4> | |||||
| <h4>attribute</h4> | |||||
| <p>Used to specify settings of the processor factory. | <p>Used to specify settings of the processor factory. | ||||
| The attribute names and values are entirely processor specific | The attribute names and values are entirely processor specific | ||||
| so you must be aware of the implementation to figure them out. | so you must be aware of the implementation to figure them out. | ||||
| @@ -431,8 +431,67 @@ And in Saxon 7.x: | |||||
| <tr> | <tr> | ||||
| <td valign="top">value</td> | <td valign="top">value</td> | ||||
| <td valign="top">value of the attribute.</td> | <td valign="top">value of the attribute.</td> | ||||
| <td align="center" valign="middle" rowspan="3">Exactly one of these</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">valueref</td> | |||||
| <td valign="top">value of the attribute is the value of the | |||||
| project reference with the given id. <em>since Ant 1.9.8</em></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">classloaderforpath</td> | |||||
| <td valign="top">value of the attribute is a classloader that uses | |||||
| the classpath specified by a path that is the project reference | |||||
| with the given id. <em>since Ant 1.9.8</em></td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4>Examples</h4> | |||||
| <pre> | |||||
| <path id="extension-path"> | |||||
| ... | |||||
| </path> | |||||
| <xslt ...> | |||||
| <factory> | |||||
| <attribute name="jdk.xml.transform.extensionClassLoader" | |||||
| classloaderforpath="extension-path"/> | |||||
| </factory> | |||||
| </xslt ...> | |||||
| </pre> | |||||
| <p>Sets the classloader to use when loading extension functions to a | |||||
| classloader using the <code>path</code> with the | |||||
| id <code>extension-path</code>. | |||||
| </blockquote> | |||||
| <h4>feature</h4> | |||||
| <p><em>since Ant 1.9.8</em></p> | |||||
| <p>Used to specify settings of the processor factory. The feature | |||||
| names are mostly processor specific so you must be aware of the | |||||
| implementation to figure them out. Read the documentation of your | |||||
| processor. The only feature all implementations are required to | |||||
| support | |||||
| is <code>http://javax.xml.XMLConstants/feature/secure-processing</code>. | |||||
| <blockquote> | |||||
| <h4>Parameters</h4> | |||||
| <table width="60%" border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td valign="top"><b>Attribute</b></td> | |||||
| <td valign="top"><b>Description</b></td> | |||||
| <td align="center" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">name</td> | |||||
| <td valign="top">Name of the feature</td> | |||||
| <td align="center" valign="top">Yes</td> | <td align="center" valign="top">Yes</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">value</td> | |||||
| <td valign="top">value of the feature. A boolean value | |||||
| (i.e. permitted values are true,false,yes,no,on,off).</td> | |||||
| <td align="center" valign="top">No, defaults to false</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| </blockquote> | </blockquote> | ||||
| </blockquote> | </blockquote> | ||||
| @@ -39,6 +39,7 @@ import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.DirectoryScanner; | import org.apache.tools.ant.DirectoryScanner; | ||||
| import org.apache.tools.ant.DynamicConfigurator; | import org.apache.tools.ant.DynamicConfigurator; | ||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| import org.apache.tools.ant.ProjectComponent; | |||||
| import org.apache.tools.ant.PropertyHelper; | import org.apache.tools.ant.PropertyHelper; | ||||
| import org.apache.tools.ant.types.CommandlineJava; | import org.apache.tools.ant.types.CommandlineJava; | ||||
| import org.apache.tools.ant.types.Environment; | import org.apache.tools.ant.types.Environment; | ||||
| @@ -53,6 +54,7 @@ import org.apache.tools.ant.types.resources.FileProvider; | |||||
| import org.apache.tools.ant.types.resources.FileResource; | import org.apache.tools.ant.types.resources.FileResource; | ||||
| import org.apache.tools.ant.types.resources.Resources; | import org.apache.tools.ant.types.resources.Resources; | ||||
| import org.apache.tools.ant.types.resources.Union; | import org.apache.tools.ant.types.resources.Union; | ||||
| import org.apache.tools.ant.util.ClasspathUtils; | |||||
| import org.apache.tools.ant.util.FileNameMapper; | import org.apache.tools.ant.util.FileNameMapper; | ||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| import org.apache.tools.ant.util.ResourceUtils; | import org.apache.tools.ant.util.ResourceUtils; | ||||
| @@ -1462,7 +1464,12 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||||
| /** | /** | ||||
| * the list of factory attributes to use for TraXLiaison | * the list of factory attributes to use for TraXLiaison | ||||
| */ | */ | ||||
| private final Vector attributes = new Vector(); | |||||
| private final List<Attribute> attributes = new ArrayList<Attribute>(); | |||||
| /** | |||||
| * the list of factory features to use for TraXLiaison | |||||
| */ | |||||
| private final List<Feature> features = new ArrayList<Feature>(); | |||||
| /** | /** | ||||
| * @return the name of the factory. | * @return the name of the factory. | ||||
| @@ -1484,7 +1491,7 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||||
| * @param attr the newly created factory attribute | * @param attr the newly created factory attribute | ||||
| */ | */ | ||||
| public void addAttribute(final Attribute attr) { | public void addAttribute(final Attribute attr) { | ||||
| attributes.addElement(attr); | |||||
| attributes.add(attr); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -1492,7 +1499,24 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||||
| * @return the enumeration of attributes | * @return the enumeration of attributes | ||||
| */ | */ | ||||
| public Enumeration getAttributes() { | public Enumeration getAttributes() { | ||||
| return attributes.elements(); | |||||
| return Collections.enumeration(attributes); | |||||
| } | |||||
| /** | |||||
| * Create an instance of a factory feature. | |||||
| * @param feature the newly created feature | |||||
| * @since Ant 1.9.8 | |||||
| */ | |||||
| public void addFeature(final Feature feature) { | |||||
| features.add(feature); | |||||
| } | |||||
| /** | |||||
| * The configured features. | |||||
| * @since Ant 1.9.8 | |||||
| */ | |||||
| public Iterable<Feature> getFeatures() { | |||||
| return features; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -1503,7 +1527,9 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||||
| * <li>http://xml.apache.org/xalan/features/incremental (true|false) </li> | * <li>http://xml.apache.org/xalan/features/incremental (true|false) </li> | ||||
| * </ul> | * </ul> | ||||
| */ | */ | ||||
| public static class Attribute implements DynamicConfigurator { | |||||
| public static class Attribute | |||||
| extends ProjectComponent | |||||
| implements DynamicConfigurator { | |||||
| /** attribute name, mostly processor specific */ | /** attribute name, mostly processor specific */ | ||||
| private String name; | private String name; | ||||
| @@ -1519,7 +1545,7 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||||
| } | } | ||||
| /** | /** | ||||
| * @return the output property value. | |||||
| * @return the attribute value. | |||||
| */ | */ | ||||
| public Object getValue() { | public Object getValue() { | ||||
| return value; | return value; | ||||
| @@ -1560,11 +1586,61 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||||
| this.value = value; | this.value = value; | ||||
| } | } | ||||
| } | } | ||||
| } else if ("valueref".equalsIgnoreCase(name)) { | |||||
| this.value = getProject().getReference(value); | |||||
| } else if ("classloaderforpath".equalsIgnoreCase(name)) { | |||||
| this.value = | |||||
| ClasspathUtils.getClassLoaderForPath(getProject(), | |||||
| new Reference(getProject(), | |||||
| value)); | |||||
| } else { | } else { | ||||
| throw new BuildException("Unsupported attribute: " + name); | throw new BuildException("Unsupported attribute: " + name); | ||||
| } | } | ||||
| } | } | ||||
| } // -- class Attribute | } // -- class Attribute | ||||
| /** | |||||
| * A feature for the TraX factory. | |||||
| * @since Ant 1.9.8 | |||||
| */ | |||||
| public static class Feature { | |||||
| private String name; | |||||
| private boolean value; | |||||
| public Feature() { } | |||||
| public Feature(String name, boolean value) { | |||||
| this.name = name; | |||||
| this.value = value; | |||||
| } | |||||
| /** | |||||
| * @param name the feature name. | |||||
| */ | |||||
| public void setName(String name) { | |||||
| this.name = name; | |||||
| } | |||||
| /** | |||||
| * @param value the feature value. | |||||
| */ | |||||
| public void setValue(boolean value) { | |||||
| this.value = value; | |||||
| } | |||||
| /** | |||||
| * @return the feature name. | |||||
| */ | |||||
| public String getName() { | |||||
| return name; | |||||
| } | |||||
| /** | |||||
| * @return the feature value. | |||||
| */ | |||||
| public boolean getValue() { | |||||
| return value; | |||||
| } | |||||
| } | |||||
| } // -- class Factory | } // -- class Factory | ||||
| /** | /** | ||||
| @@ -28,8 +28,12 @@ import java.io.InputStream; | |||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||
| import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||
| import java.net.URL; | import java.net.URL; | ||||
| import java.util.ArrayList; | |||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||
| import java.util.HashMap; | |||||
| import java.util.Hashtable; | import java.util.Hashtable; | ||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import java.util.Vector; | import java.util.Vector; | ||||
| import javax.xml.parsers.ParserConfigurationException; | import javax.xml.parsers.ParserConfigurationException; | ||||
| @@ -123,7 +127,10 @@ public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware | |||||
| private final Hashtable<String, Object> params = new Hashtable<String, Object>(); | private final Hashtable<String, Object> params = new Hashtable<String, Object>(); | ||||
| /** factory attributes */ | /** factory attributes */ | ||||
| private final Vector attributes = new Vector(); | |||||
| private final List<Object[]> attributes = new ArrayList<Object[]>(); | |||||
| /** factory features */ | |||||
| private final Map<String, Boolean> features = new HashMap<String, Boolean>(); | |||||
| /** whether to suppress warnings */ | /** whether to suppress warnings */ | ||||
| private boolean suppressWarnings = false; | private boolean suppressWarnings = false; | ||||
| @@ -430,10 +437,18 @@ public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware | |||||
| // specific attributes for the transformer | // specific attributes for the transformer | ||||
| final int size = attributes.size(); | final int size = attributes.size(); | ||||
| for (int i = 0; i < size; i++) { | for (int i = 0; i < size; i++) { | ||||
| final Object[] pair = (Object[]) attributes.elementAt(i); | |||||
| final Object[] pair = attributes.get(i); | |||||
| tfactory.setAttribute((String) pair[0], pair[1]); | tfactory.setAttribute((String) pair[0], pair[1]); | ||||
| } | } | ||||
| for (Map.Entry<String, Boolean> feature : features.entrySet()) { | |||||
| try { | |||||
| tfactory.setFeature(feature.getKey(), feature.getValue()); | |||||
| } catch (TransformerConfigurationException ex) { | |||||
| throw new BuildException(ex); | |||||
| } | |||||
| } | |||||
| if (uriResolver != null) { | if (uriResolver != null) { | ||||
| tfactory.setURIResolver(uriResolver); | tfactory.setURIResolver(uriResolver); | ||||
| } | } | ||||
| @@ -460,7 +475,17 @@ public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware | |||||
| */ | */ | ||||
| public void setAttribute(final String name, final Object value) { | public void setAttribute(final String name, final Object value) { | ||||
| final Object[] pair = new Object[]{name, value}; | final Object[] pair = new Object[]{name, value}; | ||||
| attributes.addElement(pair); | |||||
| attributes.add(pair); | |||||
| } | |||||
| /** | |||||
| * Set a custom feature for the JAXP factory implementation. | |||||
| * @param name the feature name. | |||||
| * @param value the value of the feature | |||||
| * @since Ant 1.9.8 | |||||
| */ | |||||
| public void setFeature(final String name, final boolean value) { | |||||
| features.put(name, value); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -619,6 +644,10 @@ public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware | |||||
| (XSLTProcess.Factory.Attribute) attrs.nextElement(); | (XSLTProcess.Factory.Attribute) attrs.nextElement(); | ||||
| setAttribute(attr.getName(), attr.getValue()); | setAttribute(attr.getName(), attr.getValue()); | ||||
| } | } | ||||
| for (final XSLTProcess.Factory.Feature feature | |||||
| : factory.getFeatures()) { | |||||
| setFeature(feature.getName(), feature.getValue()); | |||||
| } | |||||
| } | } | ||||
| final XMLCatalog xmlCatalog = xsltTask.getXMLCatalog(); | final XMLCatalog xmlCatalog = xsltTask.getXMLCatalog(); | ||||
| @@ -29,6 +29,8 @@ import java.util.Vector; | |||||
| import javax.xml.parsers.DocumentBuilder; | import javax.xml.parsers.DocumentBuilder; | ||||
| import javax.xml.parsers.DocumentBuilderFactory; | import javax.xml.parsers.DocumentBuilderFactory; | ||||
| import javax.xml.transform.TransformerFactory; | |||||
| import javax.xml.transform.TransformerFactoryConfigurationError; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| @@ -43,6 +45,7 @@ import org.apache.tools.ant.types.resources.FileResource; | |||||
| import org.apache.tools.ant.types.resources.URLResource; | import org.apache.tools.ant.types.resources.URLResource; | ||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| import org.apache.tools.ant.util.JAXPUtils; | import org.apache.tools.ant.util.JAXPUtils; | ||||
| import org.apache.tools.ant.util.JavaEnvUtils; | |||||
| import org.w3c.dom.Document; | import org.w3c.dom.Document; | ||||
| /** | /** | ||||
| @@ -97,6 +100,11 @@ public class AggregateTransformer { | |||||
| */ | */ | ||||
| private XSLTProcess xsltTask; | private XSLTProcess xsltTask; | ||||
| /** | |||||
| * The JAXP factory used for the internal XSLT task. | |||||
| */ | |||||
| private XSLTProcess.Factory xsltFactory; | |||||
| /** | /** | ||||
| * Instance of a utility class to use for file operations. | * Instance of a utility class to use for file operations. | ||||
| * | * | ||||
| @@ -228,7 +236,8 @@ public class AggregateTransformer { | |||||
| * @since Ant 1.9.5 | * @since Ant 1.9.5 | ||||
| */ | */ | ||||
| public XSLTProcess.Factory createFactory() { | public XSLTProcess.Factory createFactory() { | ||||
| return xsltTask.createFactory(); | |||||
| return xsltFactory != null ? xsltFactory | |||||
| : (xsltFactory = xsltTask.createFactory()); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -263,6 +272,7 @@ public class AggregateTransformer { | |||||
| paramx.setProject(task.getProject()); | paramx.setProject(task.getProject()); | ||||
| paramx.setName("output.dir"); | paramx.setName("output.dir"); | ||||
| paramx.setExpression(toDir.getAbsolutePath()); | paramx.setExpression(toDir.getAbsolutePath()); | ||||
| configureForRedirectExtension(); | |||||
| final long t0 = System.currentTimeMillis(); | final long t0 = System.currentTimeMillis(); | ||||
| try { | try { | ||||
| xsltTask.execute(); | xsltTask.execute(); | ||||
| @@ -340,4 +350,28 @@ public class AggregateTransformer { | |||||
| return JAXPUtils.getSystemId(file); | return JAXPUtils.getSystemId(file); | ||||
| } | } | ||||
| private static final String JDK_INTERNAL_FACTORY = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"; | |||||
| /** | |||||
| * If we end up using the JDK's own TraX factory on Java 9+, then | |||||
| * set the features and attributes necessary to allow redirect | |||||
| * extensions to be used. | |||||
| * @since Ant 1.9.8 | |||||
| */ | |||||
| protected void configureForRedirectExtension() { | |||||
| XSLTProcess.Factory factory = createFactory(); | |||||
| String factoryName = factory.getName(); | |||||
| if (factoryName == null) { | |||||
| try { | |||||
| factoryName = TransformerFactory.newInstance().getClass().getName(); | |||||
| } catch (TransformerFactoryConfigurationError exc) { | |||||
| throw new BuildException(exc); | |||||
| } | |||||
| } | |||||
| if (JDK_INTERNAL_FACTORY.equals(factoryName) | |||||
| && JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_9)) { | |||||
| factory.addFeature(new XSLTProcess.Factory.Feature("http://www.oracle.com/xml/jaxp/properties/enableExtensionFunctions", | |||||
| true)); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -24,6 +24,8 @@ import java.io.ByteArrayInputStream; | |||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.InputStream; | import java.io.InputStream; | ||||
| import java.security.Permission; | import java.security.Permission; | ||||
| import javax.xml.transform.TransformerFactory; | |||||
| import javax.xml.transform.TransformerFactoryConfigurationError; | |||||
| import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
| @@ -57,7 +59,7 @@ public class TraXLiaisonTest extends AbstractXSLTLiaisonTest | |||||
| } | } | ||||
| @Test | @Test | ||||
| public void testXalan2Redirect() throws Exception { | |||||
| public void testXalan2RedirectViaJDKFactory() throws Exception { | |||||
| try { | try { | ||||
| getClass().getClassLoader().loadClass("org.apache.xalan.lib.Redirect"); | getClass().getClassLoader().loadClass("org.apache.xalan.lib.Redirect"); | ||||
| } catch (Exception exc) { | } catch (Exception exc) { | ||||
| @@ -65,6 +67,8 @@ public class TraXLiaisonTest extends AbstractXSLTLiaisonTest | |||||
| } | } | ||||
| File xsl = getFile("/taskdefs/optional/xalan-redirect-in.xsl"); | File xsl = getFile("/taskdefs/optional/xalan-redirect-in.xsl"); | ||||
| liaison.setStylesheet(xsl); | liaison.setStylesheet(xsl); | ||||
| ((TraXLiaison) liaison) | |||||
| .setFeature("http://www.oracle.com/xml/jaxp/properties/enableExtensionFunctions", true); | |||||
| File out = new File("xalan2-redirect-out-dummy.tmp"); | File out = new File("xalan2-redirect-out-dummy.tmp"); | ||||
| File in = getFile("/taskdefs/optional/xsltliaison-in.xsl"); | File in = getFile("/taskdefs/optional/xsltliaison-in.xsl"); | ||||
| ClassLoader orig = Thread.currentThread().getContextClassLoader(); | ClassLoader orig = Thread.currentThread().getContextClassLoader(); | ||||
| @@ -90,6 +94,35 @@ public class TraXLiaisonTest extends AbstractXSLTLiaisonTest | |||||
| } | } | ||||
| } | } | ||||
| @Test | |||||
| public void testXalan2RedirectViaXalan() throws Exception { | |||||
| try { | |||||
| getClass().getClassLoader().loadClass("org.apache.xalan.lib.Redirect"); | |||||
| } catch (Exception exc) { | |||||
| Assume.assumeNoException("xalan redirect is not on the classpath", exc); | |||||
| } | |||||
| try { | |||||
| String factoryName = TransformerFactory.newInstance().getClass().getName(); | |||||
| Assume.assumeTrue("TraxFactory is " + factoryName + " and not Xalan", | |||||
| "org.apache.xalan.processor.TransformerFactoryImpl" | |||||
| .equals(factoryName)); | |||||
| } catch (TransformerFactoryConfigurationError exc) { | |||||
| throw new RuntimeException(exc); | |||||
| } | |||||
| File xsl = getFile("/taskdefs/optional/xalan-redirect-in.xsl"); | |||||
| liaison.setStylesheet(xsl); | |||||
| File out = new File("xalan2-redirect-out-dummy.tmp"); | |||||
| File in = getFile("/taskdefs/optional/xsltliaison-in.xsl"); | |||||
| try { | |||||
| liaison.addParam("xalan-version", "2"); | |||||
| System.setSecurityManager(new SecurityManager() {public void checkPermission(Permission perm) {}}); | |||||
| liaison.transform(in, out); | |||||
| } finally { | |||||
| out.delete(); | |||||
| System.setSecurityManager(null); | |||||
| } | |||||
| } | |||||
| @Test | @Test | ||||
| public void testMultipleTransform() throws Exception { | public void testMultipleTransform() throws Exception { | ||||
| File xsl = getFile("/taskdefs/optional/xsltliaison-in.xsl"); | File xsl = getFile("/taskdefs/optional/xsltliaison-in.xsl"); | ||||
| @@ -1,211 +1,227 @@ | |||||
| /* | |||||
| * 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. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.junit; | |||||
| import static org.junit.Assert.assertFalse; | |||||
| import static org.junit.Assert.assertTrue; | |||||
| import static org.apache.tools.ant.AntAssert.assertContains; | |||||
| import static org.junit.Assert.fail; | |||||
| import java.io.File; | |||||
| import java.io.FileReader; | |||||
| import java.io.InputStream; | |||||
| import java.net.URL; | |||||
| import org.apache.tools.ant.BuildFileRule; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| import org.junit.Before; | |||||
| import org.junit.Rule; | |||||
| import org.junit.Test; | |||||
| /** | |||||
| * Small testcase for the junitreporttask. | |||||
| * First test added to reproduce an fault, still a lot to improve | |||||
| * | |||||
| */ | |||||
| public class JUnitReportTest { | |||||
| @Rule | |||||
| public BuildFileRule buildRule = new BuildFileRule(); | |||||
| @Before | |||||
| public void setUp() { | |||||
| buildRule.configureProject("src/etc/testcases/taskdefs/optional/junitreport.xml"); | |||||
| } | |||||
| /** | |||||
| * Verifies that no empty junit-noframes.html is generated when frames | |||||
| * output is selected via the default. | |||||
| * Needs reports1 task from junitreport.xml. | |||||
| */ | |||||
| @Test | |||||
| public void testNoFileJUnitNoFrames() { | |||||
| buildRule.executeTarget("reports1"); | |||||
| assertFalse("No file junit-noframes.html expected", (new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/junit-noframes.html").exists())); | |||||
| } | |||||
| public void assertIndexCreated() { | |||||
| if (!new File(buildRule.getProject().getProperty("output"), "html/index.html").exists()) { | |||||
| fail("No file index file found"); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testEmptyFile() throws Exception { | |||||
| buildRule.executeTarget("testEmptyFile"); | |||||
| assertIndexCreated(); | |||||
| assertContains("Required text not found in log", XMLResultAggregator.WARNING_EMPTY_FILE, buildRule.getLog()); | |||||
| } | |||||
| @Test | |||||
| public void testIncompleteFile() throws Exception { | |||||
| buildRule.executeTarget("testIncompleteFile"); | |||||
| assertIndexCreated(); | |||||
| assertContains("Required text not found in log", XMLResultAggregator.WARNING_IS_POSSIBLY_CORRUPTED, buildRule.getLog()); | |||||
| } | |||||
| @Test | |||||
| public void testWrongElement() throws Exception { | |||||
| buildRule.executeTarget("testWrongElement"); | |||||
| assertIndexCreated(); | |||||
| assertContains("Required text not found in log", XMLResultAggregator.WARNING_INVALID_ROOT_ELEMENT, buildRule.getLog()); | |||||
| } | |||||
| // Bugzilla Report 34963 | |||||
| @Test | |||||
| public void testStackTraceLineBreaks() throws Exception { | |||||
| buildRule.executeTarget("testStackTraceLineBreaks"); | |||||
| assertIndexCreated(); | |||||
| FileReader r = null; | |||||
| try { | |||||
| r = new FileReader(new File(buildRule.getOutputDir(), "html/sampleproject/coins/0_CoinTest.html")); | |||||
| String report = FileUtils.readFully(r); | |||||
| assertContains("output must contain <br>:\n" + report, "junit.framework.AssertionFailedError: DOEG<br>", report); | |||||
| assertContains("#51049: output must translate line breaks:\n" + report, "cur['line.separator'] = '\\r\\n';", report); | |||||
| } finally { | |||||
| FileUtils.close(r); | |||||
| } | |||||
| } | |||||
| // Bugzilla Report 38477 | |||||
| @Test | |||||
| public void testSpecialSignsInSrcPath() throws Exception { | |||||
| buildRule.executeTarget("testSpecialSignsInSrcPath"); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html/index.html"); | |||||
| // tests one the file object | |||||
| assertTrue("No index.html present. Not generated?", reportFile.exists() ); | |||||
| assertTrue("Cant read the report file.", reportFile.canRead() ); | |||||
| assertTrue("File shouldn't be empty.", reportFile.length() > 0 ); | |||||
| // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report | |||||
| URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) ); | |||||
| InputStream reportStream = reportUrl.openStream(); | |||||
| assertTrue("This shouldn't be an empty stream.", reportStream.available() > 0); | |||||
| } | |||||
| @Test | |||||
| public void testSpecialSignsInHtmlPath() throws Exception { | |||||
| buildRule.executeTarget("testSpecialSignsInHtmlPath"); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html# $%\u00A7&-!report/index.html"); | |||||
| // tests one the file object | |||||
| assertTrue("No index.html present. Not generated?", reportFile.exists() ); | |||||
| assertTrue("Cant read the report file.", reportFile.canRead() ); | |||||
| assertTrue("File shouldn't be empty.", reportFile.length() > 0 ); | |||||
| // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report | |||||
| URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) ); | |||||
| InputStream reportStream = reportUrl.openStream(); | |||||
| assertTrue("This shouldn't be an empty stream.", reportStream.available() > 0); | |||||
| } | |||||
| //Bugzilla Report 39708 | |||||
| @Test | |||||
| public void testWithStyleFromDir() throws Exception { | |||||
| buildRule.executeTarget("testWithStyleFromDir"); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html/index.html"); | |||||
| // tests one the file object | |||||
| assertTrue("No index.html present. Not generated?", reportFile.exists() ); | |||||
| assertTrue("Cant read the report file.", reportFile.canRead() ); | |||||
| assertTrue("File shouldn't be empty.", reportFile.length() > 0 ); | |||||
| // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report | |||||
| URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) ); | |||||
| InputStream reportStream = reportUrl.openStream(); | |||||
| assertTrue("This shouldn't be an empty stream.", reportStream.available() > 0); | |||||
| } | |||||
| //Bugzilla Report 40021 | |||||
| @Test | |||||
| public void testNoFrames() throws Exception { | |||||
| buildRule.executeTarget("testNoFrames"); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html/junit-noframes.html"); | |||||
| // tests one the file object | |||||
| assertTrue("No junit-noframes.html present. Not generated?", reportFile.exists() ); | |||||
| assertTrue("Cant read the report file.", reportFile.canRead() ); | |||||
| assertTrue("File shouldn't be empty.", reportFile.length() > 0 ); | |||||
| // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report | |||||
| URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) ); | |||||
| InputStream reportStream = reportUrl.openStream(); | |||||
| assertTrue("This shouldn't be an empty stream.", reportStream.available() > 0); | |||||
| } | |||||
| //Bugzilla Report 39708 | |||||
| @Test | |||||
| public void testWithStyleFromDirAndXslImport() throws Exception { | |||||
| buildRule.executeTarget("testWithStyleFromDirAndXslImport"); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html/index.html"); | |||||
| // tests one the file object | |||||
| assertTrue("No index.html present. Not generated?", reportFile.exists() ); | |||||
| assertTrue("Cant read the report file.", reportFile.canRead() ); | |||||
| assertTrue("File shouldn't be empty.", reportFile.length() > 0 ); | |||||
| // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report | |||||
| URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) ); | |||||
| InputStream reportStream = reportUrl.openStream(); | |||||
| assertTrue("This shouldn't be an empty stream.", reportStream.available() > 0); | |||||
| } | |||||
| @Test | |||||
| public void testWithStyleFromClasspath() throws Exception { | |||||
| buildRule.executeTarget("testWithStyleFromClasspath"); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html/index.html"); | |||||
| // tests one the file object | |||||
| assertTrue("No index.html present. Not generated?", reportFile.exists() ); | |||||
| assertTrue("Cant read the report file.", reportFile.canRead() ); | |||||
| assertTrue("File shouldn't be empty.", reportFile.length() > 0 ); | |||||
| // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report | |||||
| URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) ); | |||||
| InputStream reportStream = reportUrl.openStream(); | |||||
| assertTrue("This shouldn't be an empty stream.", reportStream.available() > 0); | |||||
| } | |||||
| @Test | |||||
| public void testWithParams() throws Exception { | |||||
| buildRule.executeTarget("testWithParams"); | |||||
| assertContains("key1=value1,key2=value2", buildRule.getLog()); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html/index.html"); | |||||
| // tests one the file object | |||||
| assertTrue("No index.html present. Not generated?", reportFile.exists() ); | |||||
| assertTrue("Cant read the report file.", reportFile.canRead() ); | |||||
| assertTrue("File shouldn't be empty.", reportFile.length() > 0 ); | |||||
| // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report | |||||
| URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) ); | |||||
| InputStream reportStream = reportUrl.openStream(); | |||||
| assertTrue("This shouldn't be an empty stream.", reportStream.available() > 0); | |||||
| } | |||||
| } | |||||
| /* | |||||
| * 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. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.junit; | |||||
| import static org.junit.Assert.assertFalse; | |||||
| import static org.junit.Assert.assertTrue; | |||||
| import static org.apache.tools.ant.AntAssert.assertContains; | |||||
| import static org.junit.Assert.fail; | |||||
| import java.io.ByteArrayInputStream; | |||||
| import java.io.File; | |||||
| import java.io.FileReader; | |||||
| import java.io.InputStream; | |||||
| import java.io.IOException; | |||||
| import java.net.URL; | |||||
| import java.security.Permission; | |||||
| import javax.xml.transform.TransformerFactory; | |||||
| import javax.xml.transform.TransformerFactoryConfigurationError; | |||||
| import org.apache.tools.ant.BuildFileRule; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| import org.junit.Assume; | |||||
| import org.junit.Before; | |||||
| import org.junit.Rule; | |||||
| import org.junit.Test; | |||||
| /** | |||||
| * Small testcase for the junitreporttask. | |||||
| * First test added to reproduce an fault, still a lot to improve | |||||
| * | |||||
| */ | |||||
| public class JUnitReportTest { | |||||
| @Rule | |||||
| public BuildFileRule buildRule = new BuildFileRule(); | |||||
| @Before | |||||
| public void setUp() { | |||||
| buildRule.configureProject("src/etc/testcases/taskdefs/optional/junitreport.xml"); | |||||
| } | |||||
| /** | |||||
| * Verifies that no empty junit-noframes.html is generated when frames | |||||
| * output is selected via the default. | |||||
| * Needs reports1 task from junitreport.xml. | |||||
| */ | |||||
| @Test | |||||
| public void testNoFileJUnitNoFrames() { | |||||
| buildRule.executeTarget("reports1"); | |||||
| assertFalse("No file junit-noframes.html expected", (new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/junit-noframes.html").exists())); | |||||
| } | |||||
| public void assertIndexCreated() { | |||||
| try { | |||||
| commonIndexFileAssertions(); | |||||
| } catch (IOException ex) { | |||||
| throw new RuntimeException(ex); | |||||
| } | |||||
| } | |||||
| private File commonIndexFileAssertions() throws IOException { | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html/index.html"); | |||||
| commonIndexFileAssertions(reportFile); | |||||
| return reportFile; | |||||
| } | |||||
| private void commonIndexFileAssertions(File reportFile) throws IOException { | |||||
| // tests one the file object | |||||
| assertTrue("No index.html present. Not generated?", reportFile.exists() ); | |||||
| assertTrue("Cant read the report file.", reportFile.canRead() ); | |||||
| assertTrue("File shouldn't be empty.", reportFile.length() > 0 ); | |||||
| // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report | |||||
| URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) ); | |||||
| InputStream reportStream = reportUrl.openStream(); | |||||
| try { | |||||
| assertTrue("This shouldn't be an empty stream.", reportStream.available() > 0); | |||||
| } finally { | |||||
| FileUtils.getFileUtils().close(reportStream); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testEmptyFile() throws Exception { | |||||
| buildRule.executeTarget("testEmptyFile"); | |||||
| assertIndexCreated(); | |||||
| assertContains("Required text not found in log", XMLResultAggregator.WARNING_EMPTY_FILE, buildRule.getLog()); | |||||
| } | |||||
| @Test | |||||
| public void testIncompleteFile() throws Exception { | |||||
| buildRule.executeTarget("testIncompleteFile"); | |||||
| assertIndexCreated(); | |||||
| assertContains("Required text not found in log", XMLResultAggregator.WARNING_IS_POSSIBLY_CORRUPTED, buildRule.getLog()); | |||||
| } | |||||
| @Test | |||||
| public void testWrongElement() throws Exception { | |||||
| buildRule.executeTarget("testWrongElement"); | |||||
| assertIndexCreated(); | |||||
| assertContains("Required text not found in log", XMLResultAggregator.WARNING_INVALID_ROOT_ELEMENT, buildRule.getLog()); | |||||
| } | |||||
| // Bugzilla Report 34963 | |||||
| @Test | |||||
| public void testStackTraceLineBreaks() throws Exception { | |||||
| buildRule.executeTarget("testStackTraceLineBreaks"); | |||||
| assertIndexCreated(); | |||||
| FileReader r = null; | |||||
| try { | |||||
| r = new FileReader(new File(buildRule.getOutputDir(), "html/sampleproject/coins/0_CoinTest.html")); | |||||
| String report = FileUtils.readFully(r); | |||||
| assertContains("output must contain <br>:\n" + report, "junit.framework.AssertionFailedError: DOEG<br>", report); | |||||
| assertContains("#51049: output must translate line breaks:\n" + report, "cur['line.separator'] = '\\r\\n';", report); | |||||
| } finally { | |||||
| FileUtils.close(r); | |||||
| } | |||||
| } | |||||
| // Bugzilla Report 38477 | |||||
| @Test | |||||
| public void testSpecialSignsInSrcPath() throws Exception { | |||||
| buildRule.executeTarget("testSpecialSignsInSrcPath"); | |||||
| commonIndexFileAssertions(); | |||||
| } | |||||
| @Test | |||||
| public void testSpecialSignsInHtmlPath() throws Exception { | |||||
| buildRule.executeTarget("testSpecialSignsInHtmlPath"); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html# $%\u00A7&-!report/index.html"); | |||||
| commonIndexFileAssertions(reportFile); | |||||
| } | |||||
| //Bugzilla Report 39708 | |||||
| @Test | |||||
| public void testWithStyleFromDir() throws Exception { | |||||
| buildRule.executeTarget("testWithStyleFromDir"); | |||||
| commonIndexFileAssertions(); | |||||
| } | |||||
| //Bugzilla Report 40021 | |||||
| @Test | |||||
| public void testNoFrames() throws Exception { | |||||
| buildRule.executeTarget("testNoFrames"); | |||||
| File reportFile = new File(buildRule.getOutputDir(), "html/junit-noframes.html"); | |||||
| commonIndexFileAssertions(reportFile); | |||||
| } | |||||
| //Bugzilla Report 39708 | |||||
| @Test | |||||
| public void testWithStyleFromDirAndXslImport() throws Exception { | |||||
| buildRule.executeTarget("testWithStyleFromDirAndXslImport"); | |||||
| commonIndexFileAssertions(); | |||||
| } | |||||
| @Test | |||||
| public void testWithStyleFromClasspath() throws Exception { | |||||
| buildRule.executeTarget("testWithStyleFromClasspath"); | |||||
| commonIndexFileAssertions(); | |||||
| } | |||||
| @Test | |||||
| public void testWithParams() throws Exception { | |||||
| buildRule.executeTarget("testWithParams"); | |||||
| assertContains("key1=value1,key2=value2", buildRule.getLog()); | |||||
| commonIndexFileAssertions(); | |||||
| } | |||||
| @Test | |||||
| public void testWithSecurityManagerAndXalanFactory() throws Exception { | |||||
| try { | |||||
| String factoryName = TransformerFactory.newInstance().getClass().getName(); | |||||
| Assume.assumeTrue("TraxFactory is " + factoryName + " and not Xalan", | |||||
| "org.apache.xalan.processor.TransformerFactoryImpl" | |||||
| .equals(factoryName)); | |||||
| } catch (TransformerFactoryConfigurationError exc) { | |||||
| throw new RuntimeException(exc); | |||||
| } | |||||
| try { | |||||
| System.setSecurityManager(new SecurityManager() {public void checkPermission(Permission perm) {}}); | |||||
| buildRule.executeTarget("testWithStyleFromClasspath"); | |||||
| commonIndexFileAssertions(); | |||||
| } finally { | |||||
| System.setSecurityManager(null); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testWithSecurityManagerAndJDKFactory() throws Exception { | |||||
| ClassLoader orig = Thread.currentThread().getContextClassLoader(); | |||||
| try { | |||||
| Thread.currentThread().setContextClassLoader(new ClassLoader(ClassLoader.getSystemClassLoader().getParent()) { | |||||
| public InputStream getResourceAsStream(String name) { | |||||
| if (name.startsWith("META-INF/services/")) { | |||||
| // work around JAXP #6723276 in JDK 6 | |||||
| return new ByteArrayInputStream(new byte[0]); | |||||
| } | |||||
| return super.getResourceAsStream(name); | |||||
| } | |||||
| }); | |||||
| System.setSecurityManager(new SecurityManager() {public void checkPermission(Permission perm) {}}); | |||||
| buildRule.executeTarget("testWithStyleFromClasspath"); | |||||
| commonIndexFileAssertions(); | |||||
| } finally { | |||||
| System.setSecurityManager(null); | |||||
| Thread.currentThread().setContextClassLoader(orig); | |||||
| } | |||||
| } | |||||
| } | |||||