blob: da4ff787589e2c2441bcb0cc9565d1331bb7a670 [file] [log] [blame]
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package common.prettyprint;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/*
* @test
* @bug 6439439 8087303 8174025
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
* @run testng/othervm -DrunSecMngr=true common.prettyprint.PrettyPrintTest
* @run testng/othervm common.prettyprint.PrettyPrintTest
* @summary Test serializing xml and html with indentation.
*/
@Listeners({jaxp.library.FilePolicy.class})
public class PrettyPrintTest {
/*
* test CDATA, elements only, text and element, xml:space property, mixed
* node types.
*/
@DataProvider(name = "xml-data")
public Object[][] xmlData() throws Exception {
return new Object[][] {
{ "xmltest1.xml", "xmltest1.out" },
{ "xmltest2.xml", "xmltest2.out" },
{ "xmltest3.xml", "xmltest3.out" },
{ "xmltest4.xml", "xmltest4.out" },
{ "xmltest6.xml", "xmltest6.out" },
{ "xmltest8.xml", "xmltest8.out" } };
}
/*
* @bug 8087303
* Test the xml document are serialized with pretty-print by
* LSSerializer and transformer correctly
*
*/
@Test(dataProvider = "xml-data")
public void testXMLPrettyPrint(String sourceFile, String expectedFile) throws Exception {
String source = read(sourceFile);
String expected = read(expectedFile);
// test it's no change if no pretty-print
String result = serializerWrite(toXmlDocument(source), false);
assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(result)), "The actual is: " + result);
// test pretty-print
assertEquals(serializerWrite(toXmlDocument(source), true), expected);
// test it's no change if no pretty-print
result = transform(toXmlDocument(source), false);
assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(result)), "The actual is: " + result);
// test pretty-print
assertEquals(transform(toXmlDocument(source), true).replaceAll("\r\n", "\n"), expected);
}
/*
* @bug 8087303
* Test a single text node is serialized with pretty-print by
* LSSerializer and transformer correctly
*
*/
@Test
public void testSingleTextNode() throws Exception {
Node xml = newTextNode(read("nodetest1.txt"));
String expected = read("nodetest1.out");
assertEquals(serializerWrite(xml, true), expected);
assertEquals(transform(xml, true).replaceAll("\r\n", "\n"), expected);
}
/*
* @bug 8087303
* Test the transformer shall keep all whitespace text node in
* sequent text nodes
*
*/
@Test
public void testSequentTextNodesWithTransformer() throws Exception {
Node xml = createDocWithSequentTextNodes();
String expected = read("nodetest2.out");
assertEquals(transform(xml, true).replaceAll("\r\n", "\n"), expected);
}
/*
* @bug 8087303
* Test LSSerializer shall eliminate the whitespace text node
* in sequent text nodes
*
*/
@Test
public void testSequentTextNodesWithLSSerializer() throws Exception {
Node xml = createDocWithSequentTextNodes();
String expected = read("nodetest2ls.out");
assertEquals(serializerWrite(xml, true), expected);
}
/*
* test whitespace and element, nested xml:space property.
*/
@DataProvider(name = "xml-data-whitespace-ls")
public Object[][] whitespaceLS() throws Exception {
return new Object[][] {
{ "xmltest5.xml", "xmltest5ls.out" },
{ "xmltest7.xml", "xmltest7ls.out" } };
}
/*
* @bug 8087303
* Test LSSerializer shall eliminate the whitespace text node
* unless xml:space="preserve"
*
*/
@Test(dataProvider = "xml-data-whitespace-ls")
public void testWhitespaceWithLSSerializer(String sourceFile, String expectedFile) throws Exception {
String source = read(sourceFile);
String expected = read(expectedFile);
// test it's no change if no pretty-print
String result = serializerWrite(toXmlDocument(source), false);
assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(result)), "The actual is: " + result);
// test pretty-print
assertEquals(serializerWrite(toXmlDocument(source), true), expected);
}
/*
* test whitespace and element, nested xml:space property.
*/
@DataProvider(name = "xml-data-whitespace-xslt")
public Object[][] whitespaceXSLT() throws Exception {
return new Object[][] {
{ "xmltest5.xml", "xmltest5xslt.out" },
{ "xmltest7.xml", "xmltest7xslt.out" } };
}
/*
* @bug 8087303
* Test the transformer shall format the output but keep all
* whitespace text node even if xml:space="preserve"
*
*/
@Test(dataProvider = "xml-data-whitespace-xslt")
public void testWhitespaceWithTransformer(String sourceFile, String expectedFile) throws Exception {
String source = read(sourceFile);
String expected = read(expectedFile);
// test it's no change if no pretty-print
String result = transform(toXmlDocument(source), false);
assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(result)), "The actual is: " + result);
// test pretty-print
assertEquals(transform(toXmlDocument(source), true).replaceAll("\r\n", "\n"), expected);
}
/*
* test block element, inline element, text, and mixed elements.
*/
@DataProvider(name = "html-data")
public Object[][] htmlData() throws Exception {
return new Object[][] {
{ "htmltest1.xml", "htmltest1.out" },
{ "htmltest2.xml", "htmltest2.out" },
{ "htmltest3.xml", "htmltest3.out" },
{ "htmltest4.xml", "htmltest4.out" },
{ "htmltest5.xml", "htmltest5.out" },
{ "htmltest6.xml", "htmltest6.out" },
/* @bug 8174025, test whitespace between inline elements */
{ "htmltest7.xml", "htmltest7.out" } };
}
/*
* @bug 8087303
* Transform to HTML, test Pretty Print for HTML.
*
*/
@Test(dataProvider = "html-data")
public void testTransformToHTML(String sourceFile, String expectedFile) throws Exception {
String source = read(sourceFile);
String expected = read(expectedFile);
// test it's no change if no pretty-print
StringWriter writer = new StringWriter();
getTransformer(true, false).transform(new StreamSource(new StringReader(source)), new StreamResult(writer));
assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(writer.toString())), "The actual is: " + writer.toString());
// test pretty-print
writer = new StringWriter();
getTransformer(true, true).transform(new StreamSource(new StringReader(source)), new StreamResult(writer));
assertEquals(writer.toString().replaceAll("\r\n", "\n"), expected);
}
/*
* @bug 8174025
* Test the serializer can handle <xsl:text disable-output-escaping="yes"> correctly.
*
*/
@Test
public void testDisableOutputEscaping() throws Exception {
final String xsl ="generate-catalog.xsl";
final String xml ="simple-entity-resolver-config.xml";
final String expectedOutput ="simple-entity-resolver-config-transformed.xml";
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTemplates(new StreamSource(new StringReader(read(xsl)))).newTransformer();
String key = "schemaBase";
String value = "schemas";
transformer.setParameter(key, value);
StringWriter writer = new StringWriter();
transformer.transform(new StreamSource(new StringReader(read(xml))), new StreamResult(writer));
assertEquals(writer.toString().replaceAll("\r\n", "\n"), read(expectedOutput));
}
@Test
public void testLSSerializerFormatPrettyPrint() {
final String XML_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n"
+ "<hello>before child element<child><children/><children/></child>after child element</hello>";
/**JDK-8035467
* no newline in default output
*/
final String XML_DOCUMENT_DEFAULT_PRINT =
"<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
+ "<hello>"
+ "before child element"
+ "<child><children/><children/></child>"
+ "after child element</hello>";
final String XML_DOCUMENT_PRETTY_PRINT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?><hello>\n" +
" before child element\n" +
" <child>\n" +
" <children/>\n" +
" <children/>\n" +
" </child>\n" +
" after child element\n" +
"</hello>\n";
// it all begins with a Document
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = null;
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException parserConfigurationException) {
parserConfigurationException.printStackTrace();
Assert.fail(parserConfigurationException.toString());
}
Document document = null;
StringReader stringReader = new StringReader(XML_DOCUMENT);
InputSource inputSource = new InputSource(stringReader);
try {
document = documentBuilder.parse(inputSource);
} catch (SAXException saxException) {
saxException.printStackTrace();
Assert.fail(saxException.toString());
} catch (IOException ioException) {
ioException.printStackTrace();
Assert.fail(ioException.toString());
}
// query DOM Interfaces to get to a LSSerializer
DOMImplementation domImplementation = documentBuilder.getDOMImplementation();
DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation;
LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
System.out.println("Serializer is: " + lsSerializer.getClass().getName() + " " + lsSerializer);
// get configuration
DOMConfiguration domConfiguration = lsSerializer.getDomConfig();
// query current configuration
Boolean defaultFormatPrettyPrint = (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT);
Boolean canSetFormatPrettyPrintFalse = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
Boolean canSetFormatPrettyPrintTrue = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
System.out.println(DOM_FORMAT_PRETTY_PRINT + " default/can set false/can set true = " + defaultFormatPrettyPrint + "/"
+ canSetFormatPrettyPrintFalse + "/" + canSetFormatPrettyPrintTrue);
// test values
assertEquals(defaultFormatPrettyPrint, Boolean.FALSE, "Default value of " + DOM_FORMAT_PRETTY_PRINT + " should be " + Boolean.FALSE);
assertEquals(canSetFormatPrettyPrintFalse, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.FALSE + " should be "
+ Boolean.TRUE);
assertEquals(canSetFormatPrettyPrintTrue, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.TRUE + " should be "
+ Boolean.TRUE);
// get default serialization
String prettyPrintDefault = lsSerializer.writeToString(document);
System.out.println("(default) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+ ": \n\"" + prettyPrintDefault + "\"");
assertEquals(prettyPrintDefault, XML_DOCUMENT_DEFAULT_PRINT, "Invalid serialization with default value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+ (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
// configure LSSerializer to not format-pretty-print
domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
String prettyPrintFalse = lsSerializer.writeToString(document);
System.out.println("(FALSE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+ ": \n\"" + prettyPrintFalse + "\"");
assertEquals(prettyPrintFalse, XML_DOCUMENT_DEFAULT_PRINT, "Invalid serialization with FALSE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+ (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
// configure LSSerializer to format-pretty-print
domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
String prettyPrintTrue = lsSerializer.writeToString(document);
System.out.println("(TRUE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+ ": \n\"" + prettyPrintTrue + "\"");
assertEquals(prettyPrintTrue, XML_DOCUMENT_PRETTY_PRINT, "Invalid serialization with TRUE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+ (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
}
private String serializerWrite(Node xml, boolean pretty) throws Exception {
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
DOMImplementationLS domImplementation = (DOMImplementationLS) registry.getDOMImplementation("LS");
StringWriter writer = new StringWriter();
LSOutput formattedOutput = domImplementation.createLSOutput();
formattedOutput.setCharacterStream(writer);
LSSerializer domSerializer = domImplementation.createLSSerializer();
domSerializer.getDomConfig().setParameter(DOM_FORMAT_PRETTY_PRINT, pretty);
domSerializer.getDomConfig().setParameter("xml-declaration", false);
domSerializer.write(xml, formattedOutput);
return writer.toString();
}
private String transform(Node xml, boolean pretty) throws Exception {
Transformer transformer = getTransformer(false, pretty);
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(xml), new StreamResult(writer));
return writer.toString();
}
private Document toXmlDocument(String xmlString) throws Exception {
InputSource xmlInputSource = new InputSource(new StringReader(xmlString));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);
DocumentBuilder xmlDocumentBuilder = dbf.newDocumentBuilder();
Document node = xmlDocumentBuilder.parse(xmlInputSource);
return node;
}
private Text newTextNode(String text) throws Exception {
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
return db.newDocument().createTextNode(text);
}
private Document createDocWithSequentTextNodes() throws Exception {
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.newDocument();
Node root = doc.createElement("root");
doc.appendChild(root);
root.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode("t"));
root.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createTextNode("t"));
root.appendChild(doc.createTextNode(" "));
Node child1 = doc.createElement("child1");
root.appendChild(child1);
child1.appendChild(doc.createTextNode(" "));
child1.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createTextNode("t"));
Node child2 = doc.createElement("child2");
root.appendChild(child2);
child2.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode(" "));
Node child3 = doc.createElement("child3");
root.appendChild(child3);
child3.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode(" "));
Node child4 = doc.createElement("child4");
root.appendChild(child4);
child4.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode(" "));
Node child5 = doc.createElement("child5");
root.appendChild(child5);
child5.appendChild(doc.createTextNode("t"));
Node child51 = doc.createElement("child51");
child5.appendChild(child51);
child51.appendChild(doc.createTextNode(" "));
Node child511 = doc.createElement("child511");
child51.appendChild(child511);
child511.appendChild(doc.createTextNode("t"));
child51.appendChild(doc.createTextNode(" "));
child5.appendChild(doc.createTextNode("t"));
root.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createComment(" test comment "));
root.appendChild(doc.createTextNode(" \n"));
root.appendChild(doc.createComment(" "));
root.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createProcessingInstruction("target1", "test"));
root.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode(" "));
return doc;
}
private Transformer getTransformer(boolean html, boolean pretty) throws Exception {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
if (html)
transformer.setOutputProperty(OutputKeys.METHOD, "html");
transformer.setOutputProperty(OutputKeys.INDENT, pretty ? "yes" : "no");
return transformer;
}
private String read(String filename) throws Exception {
try (InputStream in = PrettyPrintTest.class.getResourceAsStream(filename)) {
return new String(in.readAllBytes());
}
}
private static final String DOM_FORMAT_PRETTY_PRINT = "format-pretty-print";
}