diff --git a/WHATSNEW b/WHATSNEW index 78361f14f..426b9dc25 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -103,6 +103,12 @@ Other changes: nativeheaderdir attribute. Bugzilla Report 59905 + * it is now possible to set features of the TraX factory used by + and . + + * it is now possible to use references to Ant types and classloaders + built around Ant s as values for TraX factory attributes. + Changes from Ant 1.9.6 TO Ant 1.9.7 =================================== diff --git a/lib/libraries.properties b/lib/libraries.properties index d6aee6bcf..f2805fd70 100644 --- a/lib/libraries.properties +++ b/lib/libraries.properties @@ -57,7 +57,7 @@ oro.version=2.0.8 regexp.version=1.3 servlet-api.version=2.3 which.version=1.0 -xalan.version=2.7.1 +xalan.version=2.7.2 xml-resolver.version=1.2 mail.version=1.4 #paired diff --git a/manual/Tasks/style.html b/manual/Tasks/style.html index a1b9f2db2..5eda02667 100644 --- a/manual/Tasks/style.html +++ b/manual/Tasks/style.html @@ -395,7 +395,7 @@ Used to specify factory settings.

Parameters specified as nested elements

-

attribute

+

attribute

Used to specify settings of the processor factory. The attribute names and values are entirely processor specific so you must be aware of the implementation to figure them out. @@ -431,8 +431,67 @@ And in Saxon 7.x: value value of the attribute. + Exactly one of these + + + valueref + value of the attribute is the value of the + project reference with the given id. since Ant 1.9.8 + + + classloaderforpath + value of the attribute is a classloader that uses + the classpath specified by a path that is the project reference + with the given id. since Ant 1.9.8 + + + +

Examples

+ +
+  <path id="extension-path">
+    ...
+  </path>
+
+
+  <xslt ...>
+    <factory>
+      <attribute name="jdk.xml.transform.extensionClassLoader"
+                 classloaderforpath="extension-path"/>
+    </factory>
+  </xslt ...>
+
+

Sets the classloader to use when loading extension functions to a + classloader using the path with the + id extension-path. + +

feature

+

since Ant 1.9.8

+

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 http://javax.xml.XMLConstants/feature/secure-processing. +

+

Parameters

+ + + + + + + + + + + + + +
AttributeDescriptionRequired
nameName of the feature Yes
valuevalue of the feature. A boolean value + (i.e. permitted values are true,false,yes,no,on,off).No, defaults to false
diff --git a/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java b/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java index 4fe31260b..f9c53eaab 100644 --- a/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java +++ b/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java @@ -39,6 +39,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.DynamicConfigurator; import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.PropertyHelper; import org.apache.tools.ant.types.CommandlineJava; 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.Resources; 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.FileUtils; 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 */ - private final Vector attributes = new Vector(); + private final List attributes = new ArrayList(); + + /** + * the list of factory features to use for TraXLiaison + */ + private final List features = new ArrayList(); /** * @return the name of the factory. @@ -1484,7 +1491,7 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { * @param attr the newly created factory attribute */ 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 */ 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 getFeatures() { + return features; } /** @@ -1503,7 +1527,9 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { *
  • http://xml.apache.org/xalan/features/incremental (true|false)
  • * */ - public static class Attribute implements DynamicConfigurator { + public static class Attribute + extends ProjectComponent + implements DynamicConfigurator { /** attribute name, mostly processor specific */ 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() { return value; @@ -1560,11 +1586,61 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { 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 { throw new BuildException("Unsupported attribute: " + name); } } } // -- 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 /** diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java b/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java index a497bf7f2..771d9db0a 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java @@ -28,8 +28,12 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; import java.net.URL; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.Hashtable; +import java.util.List; +import java.util.Map; import java.util.Vector; import javax.xml.parsers.ParserConfigurationException; @@ -123,7 +127,10 @@ public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware private final Hashtable params = new Hashtable(); /** factory attributes */ - private final Vector attributes = new Vector(); + private final List attributes = new ArrayList(); + + /** factory features */ + private final Map features = new HashMap(); /** whether to suppress warnings */ private boolean suppressWarnings = false; @@ -430,10 +437,18 @@ public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware // specific attributes for the transformer final int size = attributes.size(); 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]); } + for (Map.Entry feature : features.entrySet()) { + try { + tfactory.setFeature(feature.getKey(), feature.getValue()); + } catch (TransformerConfigurationException ex) { + throw new BuildException(ex); + } + } + if (uriResolver != null) { tfactory.setURIResolver(uriResolver); } @@ -460,7 +475,17 @@ public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware */ public void setAttribute(final String name, final Object 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(); setAttribute(attr.getName(), attr.getValue()); } + for (final XSLTProcess.Factory.Feature feature + : factory.getFeatures()) { + setFeature(feature.getName(), feature.getValue()); + } } final XMLCatalog xmlCatalog = xsltTask.getXMLCatalog(); diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java index 800c21356..6b918f7fc 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java @@ -29,6 +29,8 @@ import java.util.Vector; import javax.xml.parsers.DocumentBuilder; 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.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.util.FileUtils; import org.apache.tools.ant.util.JAXPUtils; +import org.apache.tools.ant.util.JavaEnvUtils; import org.w3c.dom.Document; /** @@ -97,6 +100,11 @@ public class AggregateTransformer { */ 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. * @@ -228,7 +236,8 @@ public class AggregateTransformer { * @since Ant 1.9.5 */ 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.setName("output.dir"); paramx.setExpression(toDir.getAbsolutePath()); + configureForRedirectExtension(); final long t0 = System.currentTimeMillis(); try { xsltTask.execute(); @@ -340,4 +350,28 @@ public class AggregateTransformer { 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)); + } + } } diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/TraXLiaisonTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/TraXLiaisonTest.java index 52605b4b3..f36a4db0c 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/TraXLiaisonTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/TraXLiaisonTest.java @@ -24,6 +24,8 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStream; import java.security.Permission; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; import junit.framework.AssertionFailedError; @@ -57,7 +59,7 @@ public class TraXLiaisonTest extends AbstractXSLTLiaisonTest } @Test - public void testXalan2Redirect() throws Exception { + public void testXalan2RedirectViaJDKFactory() throws Exception { try { getClass().getClassLoader().loadClass("org.apache.xalan.lib.Redirect"); } catch (Exception exc) { @@ -65,6 +67,8 @@ public class TraXLiaisonTest extends AbstractXSLTLiaisonTest } File xsl = getFile("/taskdefs/optional/xalan-redirect-in.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 in = getFile("/taskdefs/optional/xsltliaison-in.xsl"); 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 public void testMultipleTransform() throws Exception { File xsl = getFile("/taskdefs/optional/xsltliaison-in.xsl"); diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitReportTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitReportTest.java index 63eb19730..a7ebbc6a2 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitReportTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitReportTest.java @@ -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
    :\n" + report, "junit.framework.AssertionFailedError: DOEG
    ", 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
    :\n" + report, "junit.framework.AssertionFailedError: DOEG
    ", 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); + } + } + +}