@@ -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); | |||||
} | |||||
} | |||||
} |