From 49cc1576d6d53b85ac0c156c0aa6baeeb2dfa1ba Mon Sep 17 00:00:00 2001 From: Adam Retter Date: Mon, 30 Oct 2023 15:01:55 +0100 Subject: [PATCH] [test] Add tests for relative XSLT imports from fn:transform and transform:transform --- exist-core/pom.xml | 6 + .../AbstractTransformIncludeTest.java | 349 ++++++++++++++++++ .../fn/transform/FunTransformIncludeTest.java | 67 ++++ .../transform/TransformIncludeTest.java | 59 +++ 4 files changed, 481 insertions(+) create mode 100644 exist-core/src/test/java/org/exist/xquery/functions/fn/transform/AbstractTransformIncludeTest.java create mode 100644 exist-core/src/test/java/org/exist/xquery/functions/fn/transform/FunTransformIncludeTest.java create mode 100644 exist-core/src/test/java/org/exist/xquery/functions/transform/TransformIncludeTest.java diff --git a/exist-core/pom.xml b/exist-core/pom.xml index 90163e4ad44..fc25c23baa5 100644 --- a/exist-core/pom.xml +++ b/exist-core/pom.xml @@ -753,7 +753,10 @@ src/test/java/org/exist/xquery/ImportModuleTest.java src/test/java/org/exist/xquery/XQueryContextAttributesTest.java src/main/java/org/exist/xquery/functions/map/MapType.java + src/test/java/org/exist/xquery/functions/fn/transform/AbstractTransformIncludeTest.java + src/test/java/org/exist/xquery/functions/fn/transform/FunTransformIncludeTest.java src/test/java/org/exist/xquery/functions/session/AbstractSessionTest.java + src/test/java/org/exist/xquery/functions/transform/TransformIncludeTest.java src/test/java/org/exist/xquery/functions/xmldb/AbstractXMLDBTest.java src/test/java/org/exist/xquery/functions/session/AttributeTest.java src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java @@ -914,7 +917,10 @@ The original license statement is also included below.]]> src/test/java/org/exist/xquery/ImportModuleTest.java src/test/java/org/exist/xquery/XQueryContextAttributesTest.java src/main/java/org/exist/xquery/functions/map/MapType.java + src/test/java/org/exist/xquery/functions/fn/transform/AbstractTransformIncludeTest.java + src/test/java/org/exist/xquery/functions/fn/transform/FunTransformIncludeTest.java src/test/java/org/exist/xquery/functions/session/AbstractSessionTest.java + src/test/java/org/exist/xquery/functions/transform/TransformIncludeTest.java src/test/java/org/exist/xquery/functions/xmldb/AbstractXMLDBTest.java src/test/java/org/exist/xquery/functions/session/AttributeTest.java src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java diff --git a/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/AbstractTransformIncludeTest.java b/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/AbstractTransformIncludeTest.java new file mode 100644 index 00000000000..d54d99ec6be --- /dev/null +++ b/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/AbstractTransformIncludeTest.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to eXist-db by + * Evolved Binary, for the benefit of the eXist-db Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to eXist-db, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in eXist-db. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * --------------------------------------------------------------------- + * + * Copyright (C) 2014, Evolved Binary Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.xquery.functions.fn.transform; + +import com.evolvedbinary.j8fu.function.Function2E; +import com.evolvedbinary.j8fu.tuple.Tuple2; +import org.exist.EXistException; +import org.exist.collections.Collection; +import org.exist.security.PermissionDeniedException; +import org.exist.source.Source; +import org.exist.source.StringSource; +import org.exist.storage.BrokerPool; +import org.exist.storage.DBBroker; +import org.exist.storage.XQueryPool; +import org.exist.storage.lock.Lock; +import org.exist.storage.txn.Txn; +import org.exist.test.ExistEmbeddedServer; +import org.exist.util.LockException; +import org.exist.util.MimeType; +import org.exist.util.StringInputSource; +import org.exist.xmldb.XmldbURI; +import org.exist.xquery.CompiledXQuery; +import org.exist.xquery.XPathException; +import org.exist.xquery.XQuery; +import org.exist.xquery.XQueryContext; +import org.exist.xquery.value.Sequence; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; +import org.xmlunit.builder.DiffBuilder; +import org.xmlunit.builder.Input; +import org.xmlunit.diff.Diff; + +import java.io.IOException; +import java.util.Optional; +import java.util.Properties; + +import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertFalse; + +/** + * @author Adam Retter + */ +public abstract class AbstractTransformIncludeTest { + + @ClassRule + public static final ExistEmbeddedServer existEmbeddedServer = new ExistEmbeddedServer(true, true); + + private static XmldbURI TEST_COLLECTION_URI = XmldbURI.create("/db/transform-include-test"); + private static XmldbURI INCLUDING_XSLT_URI = TEST_COLLECTION_URI.append("including.xslt"); + private static XmldbURI IMPORTING_XSLT_URI = TEST_COLLECTION_URI.append("importing.xslt"); + private static XmldbURI TRANSFORMING_XSLT_URI = TEST_COLLECTION_URI.append("transforming.xslt"); + private static XmldbURI INCLUDED_XSLT_URI = TEST_COLLECTION_URI.append("included.xslt"); + + private static String INCLUDING_XSLT = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + private static String IMPORTING_XSLT = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + private static String TRANSFORMING_XSLT = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + private static String INCLUDED_XSLT = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + @BeforeClass + public static void setup() throws PermissionDeniedException, IOException, SAXException, EXistException, LockException { + final BrokerPool brokerPool = existEmbeddedServer.getBrokerPool(); + try (final Txn transaction = brokerPool.getTransactionManager().beginTransaction(); + final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()))) { + + try (final Collection testCollection = broker.getOrCreateCollection(transaction, TEST_COLLECTION_URI)) { + storeXslt(broker, transaction, TEST_COLLECTION_URI, + Tuple(INCLUDING_XSLT_URI, INCLUDING_XSLT), + Tuple(IMPORTING_XSLT_URI, IMPORTING_XSLT), + Tuple(TRANSFORMING_XSLT_URI, TRANSFORMING_XSLT), + Tuple(INCLUDED_XSLT_URI, INCLUDED_XSLT) + ); + } + + transaction.commit(); + } + } + + /** + * Generate the XQuery for transforming a source node from a stylesheet location. + * + * @param stylesheetLocation the location of the stylesheet. + * @param sourceNode the source node (as a string). + * + * @return the xquery. + */ + protected abstract String xqueryTransformFromLocation(final String stylesheetLocation, final String sourceNode); + + /** + * Generate the XQuery for transforming a source node from a stylesheet node in-memory. + * + * @param stylesheetNode the stylesheet node (as a string). + * @param sourceNode the source node (as a string). + * + * @return the xquery. + */ + protected abstract String xqueryTransformFromInMemoryNode(final String stylesheetNode, final String sourceNode); + + /** + * Generate the XQuery for transforming a source node from a stylesheet node stored in the database. + * + * @param stylesheetDbLocation the stylesheet location in the database. + * @param sourceNode the source node (as a string). + * + * @return the xquery. + */ + protected abstract String xqueryTransformFromStoredNode(final XmldbURI stylesheetDbLocation, final String sourceNode); + + @Test + public void relativeXsltIncludeFromDbUri() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xsltLocation = INCLUDING_XSLT_URI.getCollectionPath(); + final String xquery = xqueryTransformFromLocation(xsltLocation, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltIncludeFromXmldbUri() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xsltLocation = XmldbURI.create(XmldbURI.EMBEDDED_SHORT_URI_PREFIX).append(INCLUDING_XSLT_URI).toString(); + final String xquery = xqueryTransformFromLocation(xsltLocation, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltIncludeFromInMemoryNode() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xquery = xqueryTransformFromInMemoryNode(INCLUDING_XSLT, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltIncludeFromStoredNode() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xquery = xqueryTransformFromStoredNode(INCLUDING_XSLT_URI, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltImportFromDbUri() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xsltLocation = IMPORTING_XSLT_URI.getCollectionPath(); + final String xquery = xqueryTransformFromLocation(xsltLocation, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltImportFromXmldbUri() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xsltLocation = XmldbURI.create(XmldbURI.EMBEDDED_SHORT_URI_PREFIX).append(IMPORTING_XSLT_URI).toString(); + final String xquery = xqueryTransformFromLocation(xsltLocation, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltImportFromInMemoryNode() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xquery = xqueryTransformFromInMemoryNode(IMPORTING_XSLT, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltImportFromStoredNode() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xquery = xqueryTransformFromStoredNode(IMPORTING_XSLT_URI, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltTransformingFromDbUri() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xsltLocation = TRANSFORMING_XSLT_URI.getCollectionPath(); + final String xquery = xqueryTransformFromLocation(xsltLocation, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltTransformingFromXmldbUri() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xsltLocation = XmldbURI.create(XmldbURI.EMBEDDED_SHORT_URI_PREFIX).append(TRANSFORMING_XSLT_URI).toString(); + final String xquery = xqueryTransformFromLocation(xsltLocation, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltTransformingFromInMemoryNode() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xquery = xqueryTransformFromInMemoryNode(TRANSFORMING_XSLT, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + @Test + public void relativeXsltTransformingFromStoredNode() throws XPathException, PermissionDeniedException, EXistException, IOException { + final String xquery = xqueryTransformFromStoredNode(TRANSFORMING_XSLT_URI, "AABB"); + javax.xml.transform.Source expected = Input.fromString("AABB").build(); + assertXQuery(xquery, expected); + } + + private void assertXQuery(final String xquery, final javax.xml.transform.Source expected) throws EXistException, XPathException, PermissionDeniedException, IOException { + final BrokerPool brokerPool = existEmbeddedServer.getBrokerPool(); + try (final Txn transaction = brokerPool.getTransactionManager().beginTransaction(); + final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()))) { + + final Diff diff = withCompiledQuery(broker, new StringSource(xquery), compiledXQuery -> { + final Sequence result = executeQuery(broker, compiledXQuery); + + javax.xml.transform.Source actual = Input.fromNode(result.itemAt(0).toJavaObject(Node.class)).build(); + return DiffBuilder.compare(expected) + .withTest(actual) + .checkForSimilar() + .build(); + }); + + transaction.commit(); + + assertFalse(diff.toString(), diff.hasDifferences()); + } + } + + private Sequence executeQuery(final DBBroker broker, final CompiledXQuery compiledXQuery) throws PermissionDeniedException, XPathException { + final BrokerPool pool = broker.getBrokerPool(); + final XQuery xqueryService = pool.getXQueryService(); + return xqueryService.execute(broker, compiledXQuery, null, new Properties()); + } + + private T withCompiledQuery(final DBBroker broker, final Source source, final Function2E op) throws XPathException, PermissionDeniedException, IOException { + final BrokerPool pool = broker.getBrokerPool(); + final XQuery xqueryService = pool.getXQueryService(); + final XQueryPool xqueryPool = pool.getXQueryPool(); + final CompiledXQuery compiledQuery = compileQuery(broker, xqueryService, xqueryPool, source); + try { + return op.apply(compiledQuery); + } finally { + if (compiledQuery != null) { + xqueryPool.returnCompiledXQuery(source, compiledQuery); + } + } + } + + private CompiledXQuery compileQuery(final DBBroker broker, final XQuery xqueryService, final XQueryPool xqueryPool, final Source query) throws PermissionDeniedException, XPathException, IOException { + CompiledXQuery compiled = xqueryPool.borrowCompiledXQuery(broker, query); + XQueryContext context; + if (compiled == null) { + context = new XQueryContext(broker.getBrokerPool()); + } else { + context = compiled.getContext(); + context.prepareForReuse(); + } + + if (compiled == null) { + compiled = xqueryService.compile(context, query); + } else { + compiled.getContext().updateContext(context); + context.getWatchDog().reset(); + } + + return compiled; + } + + private static void storeXslt(final DBBroker broker, final Txn transaction, final XmldbURI collectionUri, final Tuple2... xslts) throws PermissionDeniedException, IOException, SAXException, LockException, EXistException { + // store modules + try (final Collection collection = broker.openCollection(collectionUri, Lock.LockMode.WRITE_LOCK)) { + + for (final Tuple2 xslt : xslts) { + broker.storeDocument(transaction, xslt._1.lastSegment(), new StringInputSource(xslt._2.getBytes(UTF_8)), MimeType.XSLT_TYPE, collection); + } + } + } +} diff --git a/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/FunTransformIncludeTest.java b/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/FunTransformIncludeTest.java new file mode 100644 index 00000000000..265454526e1 --- /dev/null +++ b/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/FunTransformIncludeTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to eXist-db by + * Evolved Binary, for the benefit of the eXist-db Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to eXist-db, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in eXist-db. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * --------------------------------------------------------------------- + * + * Copyright (C) 2014, Evolved Binary Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.xquery.functions.fn.transform; + +import org.exist.xmldb.XmldbURI; + +/** + * @author Adam Retter + */ +public class FunTransformIncludeTest extends AbstractTransformIncludeTest { + @Override + protected String xqueryTransformFromLocation(final String stylesheetLocation, final String sourceNode) { + return + "fn:transform(map{\n" + + " 'source-node': " + sourceNode + ",\n" + + " 'stylesheet-location': '" + stylesheetLocation + "'\n" + + "})?output"; + } + + @Override + protected String xqueryTransformFromInMemoryNode(final String stylesheetNode, final String sourceNode) { + return + "fn:transform(map{\n" + + " 'source-node': " + sourceNode + ",\n" + + " 'stylesheet-node': " + stylesheetNode + "\n" + + "})?output"; + } + + @Override + protected String xqueryTransformFromStoredNode(final XmldbURI stylesheetDbLocation, final String sourceNode) { + return + "fn:transform(map{\n" + + " 'source-node': " + sourceNode + ",\n" + + " 'stylesheet-node': fn:doc('" + stylesheetDbLocation + "')\n" + + "})?output"; + } +} diff --git a/exist-core/src/test/java/org/exist/xquery/functions/transform/TransformIncludeTest.java b/exist-core/src/test/java/org/exist/xquery/functions/transform/TransformIncludeTest.java new file mode 100644 index 00000000000..09c617dcbcf --- /dev/null +++ b/exist-core/src/test/java/org/exist/xquery/functions/transform/TransformIncludeTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to eXist-db by + * Evolved Binary, for the benefit of the eXist-db Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to eXist-db, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in eXist-db. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * --------------------------------------------------------------------- + * + * Copyright (C) 2014, Evolved Binary Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.xquery.functions.transform; + +import org.exist.xmldb.XmldbURI; +import org.exist.xquery.functions.fn.transform.AbstractTransformIncludeTest; + +/** + * @author Adam Retter + */ +public class TransformIncludeTest extends AbstractTransformIncludeTest { + @Override + protected String xqueryTransformFromLocation(final String stylesheetLocation, final String sourceNode) { + return + "transform:transform(" + sourceNode + ", '" + stylesheetLocation + "', ())"; + } + + @Override + protected String xqueryTransformFromInMemoryNode(final String stylesheetNode, final String sourceNode) { + return + "transform:transform(" + sourceNode + ", " + stylesheetNode + ", ())"; + } + + @Override + protected String xqueryTransformFromStoredNode(final XmldbURI stylesheetDbLocation, final String sourceNode) { + return + "transform:transform(" + sourceNode + ", fn:doc('" + stylesheetDbLocation + "'), ())"; + } +}