8345353: Test for JDK-8344800 W3C DTDs and XSDs in the built-in Catalog

Reviewed-by: rriggs, lancea
This commit is contained in:
Joe Wang 2024-12-04 03:48:24 +00:00
parent 43b337eb43
commit 447f8d4996
11 changed files with 415 additions and 0 deletions

View File

@ -0,0 +1,271 @@
/*
* Copyright (c) 2024, 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.jdkcatalog;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.testng.Assert;
import org.testng.Assert.ThrowingRunnable;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/*
* @test
* @bug 8344800 8345353
* @run testng/othervm common.jdkcatalog.JDKCatalogTest
* @summary Verifies the W3C DTDs and XSDs in the JDK built-in catalog.
*/
public class JDKCatalogTest {
static String CLS_DIR = System.getProperty("test.classes");
static String SRC_DIR = System.getProperty("test.src");
public static boolean isWindows = false;
static {
if (System.getProperty("os.name").contains("Windows")) {
isWindows = true;
}
};
public static final String JDKCATALOG_RESOLVE = "jdk.xml.jdkcatalog.resolve";
static final String PUBLIC_ID = "{{publicId}}";
static final String SYSTEM_ID = "{{systemId}}";
static final String XSD_LOCATION = "{{SCHEMA_LOCATION}}";
static final String TARGET_NAMESPACE = "{{targetNamespace}}";
static final String ROOT_ELEMENT = "{{rootElement}}";
/*
* DataProvider: for verifying DTDs in the JDKCatalog
* Data provided: see test testExternalDTD
*/
@DataProvider(name = "externalDTD")
public Object[][] getDTD() throws Exception {
return new Object[][]{
// verifies the test method correctly throws an exception if the specified
// DTD can not be resolved
{"-//ORG//DTD FOO 200102//EN", "http://foo.org/2001/bar.dtd", SAXException.class},
// this test also verifies datatypes.dtd as it's referenced in XMLSchema.dtd
{"-//W3C//DTD XMLSCHEMA 200102//EN", "http://www.w3.org/2001/XMLSchema.dtd", null},
{"-//W3C//DTD XHTML 1.0 Frameset//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd", null},
{"-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", null},
{"-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", null},
{"-//W3C//DTD XHTML 1.1//EN", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd", null},
{"-//W3C//DTD Specification V2.10//EN", "http://www.w3.org/2002/xmlspec/dtd/2.10/xmlspec.dtd", null},
};
}
/*
* DataProvider: for verifying XSDs in the JDKCatalog
* Data provided: see test testXSD
*/
@DataProvider(name = "getXSD")
public Object[][] getXSD() throws Exception {
return new Object[][]{
// verifies the test method correctly throws an exception if the specified
// XSD can not be resolved
{"xsdtest.xml", "http://foo.org/2001/bar.xsd", "http://foo.org/2001/bar", "root", null, SAXException.class},
// application XSD is resolved by a custom catalog, the W3C XSD then by the JDKCatalog
{"testXML.xml", "http://www.w3.org/2001/xml.xsd", "http://www.w3.org/XML/1998/namespace", "testXMLXSD", "TestCatalog.xml", null},
// this test also verifies XMLSchema.dtd and xml.xsd as they are referenced
{"testXMLSchema.xml", "http://www.w3.org/2001/XMLSchema.xsd", "http://www.w3.org/2001/XMLSchema", "xs:schema", null, null},
{"testDatatypes.xml", "http://www.w3.org/2009/XMLSchema/XMLSchema-datatypes.xsd", "http://www.w3.org/2001/XMLSchema-datatypes", "testDatatypes", "TestCatalog.xml", null},
{"xhtml-frameset.xml", "https://www.w3.org/2002/08/xhtml/xhtml1-frameset.xsd", "http://www.w3.org/1999/xhtml", "html", null, null},
{"xhtml.xml", "https://www.w3.org/2002/08/xhtml/xhtml1-strict.xsd", "http://www.w3.org/1999/xhtml", "html", null, null},
{"xhtml.xml", "https://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd", "http://www.w3.org/1999/xhtml", "html", null, null},
{"xhtml.xml", "http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd", "http://www.w3.org/1999/xhtml", "html", null, null},
};
}
/**
* Verifies that references to the W3C DTDs are resolved by the JDK built-in
* catalog.
* @param publicId the PUBLIC identifier
* @param systemId the SYSTEM identifier
* @param expectedThrow the expected throw if the specified DTD can not be
* resolved.
* @throws Exception if the test fails
*/
@Test(dataProvider = "externalDTD")
public void testExternalDTD(String publicId, String systemId, Class<Throwable> expectedThrow)
throws Exception {
final String xmlString = generateXMLWithDTDRef(publicId, systemId);
if (expectedThrow == null) {
assertDoesNotThrow(() -> parseWithResolveStrict(xmlString),
"JDKCatalog shall resolve " + systemId + " but exception is thrown.");
} else {
Assert.assertThrows(expectedThrow,
() -> parseWithResolveStrict(xmlString));
}
}
/**
* Verifies that references to the W3C DTDs are resolved by the JDK built-in
* catalog.
* @param xmlTemplate a template used to generate an XML instance
* @param xsdLocation the XSD to be resolved
* @param targetNS the target namespace
* @param rootElement the root element
* @param catalog the custom catalog to be used to resolve XSDs used by the
* test.
* @param expectedThrow the expected throw if the specified DTD can not be
* resolved.
* @throws Exception if the test fails
*/
@Test(dataProvider = "getXSD")
public void testXSD(String xmlTemplate, String xsdLocation, String targetNS, String rootElement, String catalog,
Class<Throwable> expectedThrow)
throws Exception {
String xmlSrcPath = SRC_DIR + "/" + xmlTemplate;
final String xmlSrcId = getSysId(xmlSrcPath);
final String customCatalog = getSysId((catalog != null) ? SRC_DIR + "/" + catalog : null);
final String xmlString = generateXMLWithXSDRef(xmlSrcPath, xsdLocation,
targetNS, rootElement);
if (expectedThrow == null) {
assertDoesNotThrow(() -> validateWithResolveStrict(xmlString, xmlSrcId, customCatalog),
"JDKCatalog shall resolve " + xsdLocation + " but exception is thrown.");
} else {
Assert.assertThrows(expectedThrow,
() -> validateWithResolveStrict(xmlString, xmlSrcId, customCatalog));
}
}
/**
* Validate the specified XML document with jdk.xml.jdkCatalog.resolve set to strict.
* @param xml the XML document to be validated
* @param xmlSrcPathId the URI to the XML source (template in this case)
* @param customCatalog the custom catalog used to resolve local XSDs
* @throws Exception if validation fails
*/
public void validateWithResolveStrict(String xml, String xmlSrcPathId, String customCatalog)
throws Exception {
SAXSource ss = new SAXSource(new InputSource(new StringReader(xml)));
ss.setSystemId(xmlSrcPathId);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setProperty(JDKCATALOG_RESOLVE, "strict");
if (customCatalog != null) {
schemaFactory.setProperty(CatalogFeatures.Feature.FILES.getPropertyName(), customCatalog);
schemaFactory.setProperty(CatalogFeatures.Feature.RESOLVE.getPropertyName(), "continue");
}
Validator validator = schemaFactory.newSchema().newValidator();
validator.validate(ss);
}
/**
* Parses the XML with jdk.xml.jdkCatalog.resolve set to strict.
* @param xml the XML document to be parsed
* @throws Exception if external access is denied
*/
public void parseWithResolveStrict(String xml)
throws Exception {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setNamespaceAware(true);
XMLReader xmlReader = saxParserFactory.newSAXParser().getXMLReader();
xmlReader.setProperty(JDKCATALOG_RESOLVE, "strict");
xmlReader.setContentHandler(new DefaultHandler());
xmlReader.parse(new InputSource(new StringReader(xml)));
}
/**
* Generates an XML with the specified PUBLIC and SYSTEM identifiers.
* @param publicId the public identifier
* @param systemId the system identifier
* @return an XML
* @throws Exception if error happens
*/
private String generateXMLWithDTDRef(String publicId, String systemId)
throws Exception {
Path path = Paths.get(SRC_DIR + "/dtdtest.xml");
String xmlString = Files.lines(path).map(line -> {
line = line.replace(PUBLIC_ID, publicId);
line = line.replace(SYSTEM_ID, systemId);
return line;
}).collect(Collectors.joining(System.lineSeparator()));
return xmlString;
}
/**
* Generates an XML with the specified XSD location.
* @param xmlSrcPath the path to the XML source
* @param xsd the XSD location
* @return an XML
* @throws Exception if error happens
*/
private String generateXMLWithXSDRef(String xmlSrcPath, String xsd,
String targetNS, String rootElement)
throws Exception {
String xmlString = Files.lines(Paths.get(xmlSrcPath)).map(line -> {
if (line.contains(XSD_LOCATION)) {
line = line.replace(XSD_LOCATION, xsd);
}
if (line.contains(TARGET_NAMESPACE)) {
line = line.replace(TARGET_NAMESPACE, targetNS);
}
if (line.contains(ROOT_ELEMENT)) {
line = line.replace(ROOT_ELEMENT, rootElement);
}
return line;
}).collect(Collectors.joining(System.lineSeparator()));
return xmlString;
}
/**
* Returns the System identifier (URI) of the source.
* @param path the path to the source
* @return the System identifier
*/
private String getSysId(String path) {
if (path == null) return null;
String xmlSysId = "file://" + path;
if (isWindows) {
path = path.replace('\\', '/');
xmlSysId = "file:///" + path;
}
return xmlSysId;
}
/**
* Asserts the run does not cause a Throwable.
* @param runnable the runnable
* @param message the message if the test fails
*/
private void assertDoesNotThrow(ThrowingRunnable runnable, String message) {
try {
runnable.run();
} catch (Throwable t) {
Assert.fail(message + "\n Exception thrown: " + t.getMessage());
}
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<!-- Catalog for testing the JDKCatalog
-->
<systemSuffix systemIdSuffix="testDatatypes.xsd" uri="testDatatypes.xsd"/>
<systemSuffix systemIdSuffix="testXML.xsd" uri="testXML.xsd"/>
</catalog>

View File

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "{{publicId}}"
"{{systemId}}">
<html>
<head>
<title>
XHTML 1.0
</title>
</head>
<body>
<h1>
XHTML 1.0
</h1>
<ul>
<li>
xhtml1-transition.dtd
</li>
</ul>
</body>
</html>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<testDatatypes xmlns="http://xmlschema.datatypes/testSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlschema.datatypes/testSchema testDatatypes.xsd">
<stringType>Hello, World!</stringType>
<integerType>12345</integerType>
<decimalType>67.78</decimalType>
<booleanType>false</booleanType>
<dateType>2024-11-24</dateType>
</testDatatypes>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xmlschema.datatypes/testSchema"
xmlns="http://xmlschema.datatypes/testSchema"
elementFormDefault="qualified">
<!-- Import the XMLSchema-datatypes.xsd -->
<xs:import namespace="http://www.w3.org/2001/XMLSchema-datatypes" schemaLocation="http://www.w3.org/2009/XMLSchema/XMLSchema-datatypes.xsd">
<xs:annotation>
<xs:documentation>
Get access to the type defined in datatypes
</xs:documentation>
</xs:annotation>
</xs:import>
<!-- Define a root element that uses built-in datatypes -->
<xs:element name="testDatatypes">
<xs:complexType>
<xs:sequence>
<xs:element name="stringType" type="xs:string"/>
<xs:element name="integerType" type="xs:integer"/>
<xs:element name="decimalType" type="xs:decimal"/>
<xs:element name="booleanType" type="xs:boolean"/>
<xs:element name="dateType" type="xs:date"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<testXMLXSD xmlns="http://xml.xsd.test/testXMLXSD"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://xml.xsd.test/testXMLXSD testXML.xsd"
xml:lang="en"
xml:base="http://xml.xsd.test/base">
<message>Hello, World!</message>
</testXMLXSD>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
targetNamespace="http://xml.xsd.test/testXMLXSD"
xmlns="http://xml.xsd.test/testXMLXSD"
elementFormDefault="qualified">
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd">
<xs:annotation>
<xs:documentation>
Get access to the xml: attribute groups for xml:lang
as declared on 'schema' and 'documentation' below
</xs:documentation>
</xs:annotation>
</xs:import>
<!-- Define a root element that uses xml:lang and xml:base attributes -->
<xs:element name="testXMLXSD">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element name="message" type="xs:string"/>
</xs:sequence>
<xs:attribute ref="xml:lang"/>
<xs:attribute ref="xml:base"/>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="{{targetNamespace}} {{SCHEMA_LOCATION}}"
xmlns:xs="{{targetNamespace}}">
<xs:element name="example" type="xs:string" />
</xs:schema>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/1999/xhtml {{SCHEMA_LOCATION}}"
>
<head>
<title>Test XHTML</title>
</head>
<frameset cols="1*, 1*, 2*">
<frame src="frame1.html" name="left" />
<frame src="frame2.html" name="middle" />
<frame src="frame3.html" name="right" />
</frameset>
</html>

View File

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/1999/xhtml {{SCHEMA_LOCATION}}"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<head>
<title>Test XHTML</title>
</head>
<body>
<p>Test XHTML</p>
</body>
</html>

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<{{rootElement}} xmlns="{{targetNamespace}}"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="{{targetNamespace}} {{SCHEMA_LOCATION}}"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</{{rootElement}}>