aboutsummaryrefslogtreecommitdiffstats
path: root/test/java
diff options
context:
space:
mode:
authorPeter Hancock <phancock@apache.org>2012-02-10 16:51:08 +0000
committerPeter Hancock <phancock@apache.org>2012-02-10 16:51:08 +0000
commita21ecc5e13be09393036efe90f4ab63a7ee09fab (patch)
tree2ed0c7fd447b36aa00c17342f2074300bcb07399 /test/java
parent098ac1879ef71df08ee43eb263f5efac77d4e352 (diff)
parent65e12053cb81114db964534f7e974c338a8a467b (diff)
downloadxmlgraphics-fop-a21ecc5e13be09393036efe90f4ab63a7ee09fab.tar.gz
xmlgraphics-fop-a21ecc5e13be09393036efe90f4ab63a7ee09fab.zip
Merged in Temp_ImproveAccessibility
revs 1187234, 1188205, 1205935, 1236718, 1238313, 1240963 git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1242848 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'test/java')
-rw-r--r--test/java/org/apache/fop/StandardTestSuite.java3
-rw-r--r--test/java/org/apache/fop/accessibility/fo/DOMResultUtil.java54
-rw-r--r--test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java223
-rw-r--r--test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl135
-rw-r--r--test/java/org/apache/fop/accessibility/fo/table-footers.fo195
-rw-r--r--test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl66
-rw-r--r--test/java/org/apache/fop/fo/DelegatingFOEventHandlerTestCase.java531
-rw-r--r--test/java/org/apache/fop/fo/FODocumentParser.java161
-rw-r--r--test/java/org/apache/fop/fo/FONodeMocks.java88
-rw-r--r--test/java/org/apache/fop/fo/LoadingException.java34
-rw-r--r--test/java/org/apache/fop/fo/complete_document.fo176
-rw-r--r--test/java/org/apache/fop/fo/extract-events.xsl62
-rw-r--r--test/java/org/apache/fop/fo/flow/table/AbstractTableTest.java28
-rw-r--r--test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java7
-rw-r--r--test/java/org/apache/fop/fo/flow/table/ErrorCheckTest.java11
-rw-r--r--test/java/org/apache/fop/fo/flow/table/IllegalRowSpanTestCase.java4
-rw-r--r--test/java/org/apache/fop/fo/flow/table/RowGroupBuilderTestCase.java4
-rw-r--r--test/java/org/apache/fop/fo/flow/table/TableColumnColumnNumberTestCase.java7
-rw-r--r--test/java/org/apache/fop/fo/flow/table/TooManyColumnsTestCase.java4
-rw-r--r--test/java/org/apache/fop/fo/flow/table/UnimplementedWarningNeutralizer.java38
-rw-r--r--test/java/org/apache/fop/fo/properties/AltTextHolderTestCase.java77
-rw-r--r--test/java/org/apache/fop/fo/properties/CommonAccessibilityHolderTestCase.java128
-rw-r--r--test/java/org/apache/fop/fo/properties/PropertyListMocks.java94
-rw-r--r--test/java/org/apache/fop/fo/properties/PropertyMocks.java80
-rw-r--r--test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java6
-rw-r--r--test/java/org/apache/fop/fotreetest/FOTreeUnitTester.java96
-rw-r--r--test/java/org/apache/fop/intermediate/IFParserTestCase.java17
-rw-r--r--test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java169
-rw-r--r--test/java/org/apache/fop/render/intermediate/SAXEventRecorderTestCase.java131
-rw-r--r--test/java/org/apache/fop/util/LanguageTagsTestCase.java (renamed from test/java/org/apache/fop/util/XMLUtilTestCase.java)34
30 files changed, 2510 insertions, 153 deletions
diff --git a/test/java/org/apache/fop/StandardTestSuite.java b/test/java/org/apache/fop/StandardTestSuite.java
index bb59c8605..808542306 100644
--- a/test/java/org/apache/fop/StandardTestSuite.java
+++ b/test/java/org/apache/fop/StandardTestSuite.java
@@ -76,7 +76,8 @@ import org.apache.fop.pdf.PDFLibraryTestSuite;
MinOptMaxTestCase.class,
AdobeStandardEncodingTestCase.class,
AFMParserTestCase.class,
- FontEventProcessingTestCase.class
+ FontEventProcessingTestCase.class,
+ org.apache.fop.render.intermediate.IFStructureTreeBuilderTestCase.class
})
public class StandardTestSuite {
}
diff --git a/test/java/org/apache/fop/accessibility/fo/DOMResultUtil.java b/test/java/org/apache/fop/accessibility/fo/DOMResultUtil.java
new file mode 100644
index 000000000..5b4e264f2
--- /dev/null
+++ b/test/java/org/apache/fop/accessibility/fo/DOMResultUtil.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.accessibility.fo;
+
+import java.io.File;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+/**
+ * Utility class to stream an instance of {@link DOMResult} into a file. May be
+ * useful for debugging.
+ */
+final class DOMResultUtil {
+
+ private DOMResultUtil() {
+ }
+
+ /**
+ * Streams the given result into a file of the given name.
+ *
+ * @param result the result of a transformation
+ * @param filename name of the file into which to stream the result
+ * @throws TransformerException if a problem occurs when streaming
+ */
+ public static void streamToFile(DOMResult result, String filename) throws TransformerException {
+ DOMSource source = new DOMSource(result.getNode());
+ TransformerFactory tFactory = TransformerFactory.newInstance();
+ Transformer transformer = tFactory.newTransformer();
+ transformer.transform(source, new StreamResult(new File(filename)));
+ }
+
+}
diff --git a/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java b/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java
new file mode 100644
index 000000000..9c53bdde3
--- /dev/null
+++ b/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.accessibility.fo;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.custommonkey.xmlunit.Diff;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.accessibility.StructureTree2SAXEventAdapter;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fo.FODocumentParser;
+import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory;
+import org.apache.fop.fo.FOEventHandler;
+import org.apache.fop.fo.LoadingException;
+import org.apache.fop.fotreetest.DummyFOEventHandler;
+
+public class FO2StructureTreeConverterTestCase {
+
+ private interface FOLoader {
+
+ InputStream getFoInputStream();
+ }
+
+ private static final String STRUCTURE_TREE_SEQUENCE_NAME = "structure-tree-sequence";
+
+ private FOLoader foLoader;
+
+ @Test
+ public void testCompleteDocument() throws Exception {
+ foLoader = new FOLoader() {
+ public InputStream getFoInputStream() {
+ return getResource("/org/apache/fop/fo/complete_document.fo");
+ }
+ };
+ testConverter();
+ }
+
+ @Test
+ public void testTableFooters() throws Exception {
+ foLoader = new FOLoader() {
+ public InputStream getFoInputStream() {
+ return getResource("table-footers.fo");
+ }
+ };
+ testConverter();
+ }
+
+ @Test
+ public void testCompleteContentWrappedInTableFooter() throws Exception {
+ Source xslt = new StreamSource(getResource("wrapCompleteDocumentInTableFooter.xsl"));
+ Transformer transformer = createTransformer(xslt);
+ InputStream originalFO = getResource("/org/apache/fop/fo/complete_document.fo");
+ ByteArrayOutputStream transformedFoOutput = new ByteArrayOutputStream();
+ transformer.transform(new StreamSource(originalFO), new StreamResult(transformedFoOutput));
+ final byte[] transformedFoOutputBytes = transformedFoOutput.toByteArray();
+ foLoader = new FOLoader() {
+ public InputStream getFoInputStream() {
+ return new ByteArrayInputStream(transformedFoOutputBytes);
+ }
+ };
+ testConverter();
+ }
+
+ private Transformer createTransformer(Source xslt) throws TransformerFactoryConfigurationError,
+ TransformerConfigurationException {
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ return transformerFactory.newTransformer(xslt);
+ }
+
+ private static InputStream getResource(String name) {
+ return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name);
+ }
+
+ private void testConverter() throws Exception {
+ DOMResult expectedStructureTree = loadExpectedStructureTree();
+ DOMResult actualStructureTree = buildActualStructureTree();
+ final Diff diff = createDiff(expectedStructureTree, actualStructureTree);
+ assertTrue(diff.toString(), diff.identical());
+ }
+
+ private DOMResult loadExpectedStructureTree() {
+ DOMResult expectedStructureTree = new DOMResult();
+ InputStream xslt = getResource("fo2StructureTree.xsl");
+ runXSLT(xslt, foLoader.getFoInputStream(), expectedStructureTree);
+ return expectedStructureTree;
+ }
+
+ private static void runXSLT(InputStream xslt, InputStream doc, Result result) {
+ Source fo = new StreamSource(doc);
+ try {
+ Transformer transformer = TransformerFactory.newInstance()
+ .newTransformer(new StreamSource(xslt));
+ transformer.transform(fo, result);
+ } catch (TransformerConfigurationException e) {
+ throw new RuntimeException(e);
+ } catch (TransformerException e) {
+ throw new RuntimeException(e);
+ } finally {
+ closeStream(xslt);
+ closeStream(doc);
+ }
+ }
+
+ private static void closeStream(InputStream stream) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private DOMResult buildActualStructureTree() throws Exception {
+ DOMResult actualStructureTree = new DOMResult();
+ createStructureTreeFromDocument(foLoader.getFoInputStream(), actualStructureTree);
+ return actualStructureTree;
+ }
+
+ private static void createStructureTreeFromDocument(InputStream foInputStream,
+ Result result) throws Exception {
+ TransformerHandler tHandler = createTransformerHandler(result);
+ startStructureTreeSequence(tHandler);
+ StructureTreeEventHandler structureTreeEventHandler
+ = StructureTree2SAXEventAdapter.newInstance(tHandler);
+ FODocumentParser documentParser = createDocumentParser(structureTreeEventHandler);
+ FOUserAgent userAgent = createFOUserAgent(documentParser);
+ parseDocument(foInputStream, documentParser, userAgent);
+ endStructureTreeSequence(tHandler);
+ }
+
+ private static TransformerHandler createTransformerHandler(Result domResult)
+ throws TransformerConfigurationException, TransformerFactoryConfigurationError {
+ SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+ TransformerHandler transformerHandler = factory.newTransformerHandler();
+ transformerHandler.setResult(domResult);
+ return transformerHandler;
+ }
+
+ private static void startStructureTreeSequence(TransformerHandler tHandler) throws SAXException {
+ tHandler.startDocument();
+ tHandler.startElement("", STRUCTURE_TREE_SEQUENCE_NAME, STRUCTURE_TREE_SEQUENCE_NAME,
+ new AttributesImpl());
+ }
+
+ private static FODocumentParser createDocumentParser(
+ final StructureTreeEventHandler structureTreeEventHandler) {
+ return FODocumentParser.newInstance(new FOEventHandlerFactory() {
+ public FOEventHandler newFOEventHandler(FOUserAgent foUserAgent) {
+ return new FO2StructureTreeConverter(structureTreeEventHandler,
+ new DummyFOEventHandler(foUserAgent));
+ }
+ });
+ }
+
+ private static FOUserAgent createFOUserAgent(FODocumentParser documentParser) {
+ FOUserAgent userAgent = documentParser.createFOUserAgent();
+ userAgent.setAccessibility(true);
+ return userAgent;
+ }
+
+ private static void parseDocument(InputStream foInputStream, FODocumentParser documentParser,
+ FOUserAgent userAgent) throws FOPException, LoadingException {
+ try {
+ documentParser.parse(foInputStream, userAgent);
+ } finally {
+ closeStream(foInputStream);
+ }
+ }
+
+ private static void endStructureTreeSequence(TransformerHandler tHandler) throws SAXException {
+ tHandler.endElement("", STRUCTURE_TREE_SEQUENCE_NAME, STRUCTURE_TREE_SEQUENCE_NAME);
+ tHandler.endDocument();
+ }
+
+ private static Diff createDiff(DOMResult expected, DOMResult actual) {
+ Diff diff = new Diff(getDocument(expected), getDocument(actual));
+ return diff;
+ }
+
+ private static Document getDocument(DOMResult result) {
+ return (Document) result.getNode();
+ }
+}
diff --git a/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl b/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl
new file mode 100644
index 000000000..ce326f3b1
--- /dev/null
+++ b/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!-- $Id$ -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
+ xmlns:foi="http://xmlgraphics.apache.org/fop/internal">
+
+ <xsl:output method="xml" indent="no"/>
+
+ <xsl:template name="copy">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+
+ <!-- Ignore fo:root -->
+ <xsl:template match="fo:root">
+ <structure-tree-sequence>
+ <xsl:apply-templates/>
+ </structure-tree-sequence>
+ </xsl:template>
+
+ <!-- fo:page-sequence maps to structure-tree -->
+ <xsl:template match="fo:page-sequence">
+ <structure-tree xmlns="http://xmlgraphics.apache.org/fop/intermediate">
+ <xsl:apply-templates/>
+ </structure-tree>
+ </xsl:template>
+
+
+ <!-- Declarations and Pagination and Layout Formatting Objects -->
+ <xsl:template match="fo:static-content|fo:flow">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Block-level Formatting Objects -->
+ <xsl:template match="fo:block|fo:block-container">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Inline-level Formatting Objects -->
+ <xsl:template match="fo:character|fo:inline|fo:inline-container">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <xsl:template match="fo:external-graphic|fo:instream-foreign-object">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <xsl:template match="fo:page-number|fo:page-number-citation|fo:page-number-citation-last">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Formatting Objects for Tables -->
+ <xsl:template match="fo:table-and-caption|fo:table-caption">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <xsl:template match="fo:table">
+ <xsl:copy>
+ <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="*[name() != 'fo:table-footer']"/>
+ <xsl:apply-templates select="fo:table-footer"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Formatting Objects for Lists -->
+ <xsl:template match="fo:list-block|fo:list-item|fo:list-item-label|fo:list-item-body">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Dynamic Effects: Link and Multi Formatting Objects -->
+ <xsl:template match="fo:basic-link">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Out-of-Line Formatting Objects -->
+ <xsl:template match="fo:float|fo:footnote|fo:footnote-body">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Other Formatting Objects -->
+ <xsl:template match="fo:wrapper|fo:marker">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+
+ <!-- Discard descendants of fo:leader -->
+ <xsl:template match="fo:leader"/>
+
+
+ <!-- Keep fox:alt-text and role attributes, discard everything else -->
+ <xsl:template match="@fox:alt-text|@role">
+ <xsl:copy-of select="."/>
+ </xsl:template>
+
+ <xsl:template match="@*"/>
+
+
+ <!-- Discard text nodes... -->
+ <xsl:template match="text()"/>
+
+ <!-- ...except those that will result into marked content -->
+ <xsl:template match="fo:title/text()
+ |fo:block/text()
+ |fo:bidi-override/text()
+ |fo:inline/text()
+ |fo:basic-link/text()
+ |fo:wrapper/text()
+ |fo:marker/text()">
+ <marked-content xmlns="http://xmlgraphics.apache.org/fop/intermediate"/>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/test/java/org/apache/fop/accessibility/fo/table-footers.fo b/test/java/org/apache/fop/accessibility/fo/table-footers.fo
new file mode 100644
index 000000000..6dcb9b68d
--- /dev/null
+++ b/test/java/org/apache/fop/accessibility/fo/table-footers.fo
@@ -0,0 +1,195 @@
+<?xml version="1.0" standalone="no"?>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="440pt" page-width="420pt" margin="10pt">
+ <fo:region-body display-align="center"/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" line-height="10pt" font-size="8pt">
+ <fo:table width="100% - 6pt" table-layout="fixed"
+ border-collapse="separate" border="2pt solid black" border-separation="2pt" padding="1pt"
+ start-indent="3pt" end-indent="3pt" space-after="2pt">
+ <fo:table-header start-indent="0" end-indent="0">
+ <fo:table-cell background-color="#E0E0E0" padding="2pt">
+ <fo:block>Start Outer Header</fo:block>
+ <fo:table width="100% - 6pt" table-layout="fixed"
+ border="2pt solid red" padding="1pt"
+ start-indent="3pt" end-indent="3pt" space-after="2pt">
+ <fo:table-header start-indent="0" end-indent="0">
+ <fo:table-cell background-color="#FFB0B0" padding="2pt">
+ <fo:block>Inner Header 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="#FFB0B0" padding="2pt">
+ <fo:block>Inner Header 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-header>
+ <fo:table-footer start-indent="0" end-indent="0">
+ <fo:table-cell background-color="#FFB0B0" padding="2pt">
+ <fo:block>Inner Footer 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="#FFB0B0" padding="2pt">
+ <fo:block>Inner Footer 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-footer>
+ <fo:table-body start-indent="0" end-indent="0">
+ <fo:table-row>
+ <fo:table-cell background-color="#FFB0B0" padding="2pt">
+ <fo:block>Inner Body 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="#FFB0B0" padding="2pt">
+ <fo:block>Inner Body 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row>
+ <fo:table-cell background-color="#FFB0B0" padding="2pt">
+ <fo:block>Inner Body 2.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="#FFB0B0" padding="2pt">
+ <fo:block>Inner Body 2.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ <fo:block>End Outer Header</fo:block>
+ </fo:table-cell>
+ </fo:table-header>
+ <fo:table-footer start-indent="0" end-indent="0">
+ <fo:table-cell background-color="#E0E0E0" padding="2pt">
+ <fo:block>Start Outer Footer</fo:block>
+ <fo:table width="100% - 6pt" table-layout="fixed"
+ border="2pt solid green" padding="1pt"
+ start-indent="3pt" end-indent="3pt" space-after="2pt">
+ <fo:table-header start-indent="0" end-indent="0">
+ <fo:table-cell background-color="lightgreen" padding="2pt">
+ <fo:block>Inner Header 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="lightgreen" padding="2pt">
+ <fo:block>Inner Header 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-header>
+ <fo:table-footer start-indent="0" end-indent="0">
+ <fo:table-cell background-color="lightgreen" padding="2pt">
+ <fo:block>Start Inner Footer 1.1</fo:block>
+ <fo:table width="100% - 6pt" table-layout="fixed"
+ border="2pt solid yellow" padding="1pt"
+ start-indent="3pt" end-indent="3pt" space-after="2pt">
+ <fo:table-header start-indent="0" end-indent="0">
+ <fo:table-cell background-color="yellow" padding="2pt">
+ <fo:block>Inner Inner Header 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="yellow" padding="2pt">
+ <fo:block>Inner Inner Header 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-header>
+ <fo:table-footer start-indent="0" end-indent="0">
+ <fo:table-cell background-color="yellow" padding="2pt">
+ <fo:block>Inner Inner Footer 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="yellow" padding="2pt">
+ <fo:block>Inner Inner Footer 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-footer>
+ <fo:table-body start-indent="0" end-indent="0">
+ <fo:table-row>
+ <fo:table-cell background-color="yellow" padding="2pt">
+ <fo:block>Inner Inner Body 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="yellow" padding="2pt">
+ <fo:block>Inner Inner Body 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row>
+ <fo:table-cell background-color="yellow" padding="2pt">
+ <fo:block>Inner Inner Body 2.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="yellow" padding="2pt">
+ <fo:block>Inner Inner Body 2.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ <fo:block>End Inner Footer 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="lightgreen" padding="2pt">
+ <fo:block>Inner Footer 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-footer>
+ <fo:table-body start-indent="0" end-indent="0">
+ <fo:table-row>
+ <fo:table-cell background-color="lightgreen" padding="2pt">
+ <fo:block>Inner Body 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="lightgreen" padding="2pt">
+ <fo:block>Inner Body 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row>
+ <fo:table-cell background-color="lightgreen" padding="2pt">
+ <fo:block>Inner Body 2.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="lightgreen" padding="2pt">
+ <fo:block>Inner Body 2.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ <fo:block>End Outer Footer</fo:block>
+ </fo:table-cell>
+ </fo:table-footer>
+ <fo:table-body start-indent="0" end-indent="0">
+ <fo:table-row>
+ <fo:table-cell background-color="#E0E0E0" padding="2pt">
+ <fo:block>Outer Body Cell 1</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row>
+ <fo:table-cell background-color="#E0E0E0" padding="2pt">
+ <fo:block>Start Outer Body Cell 2</fo:block>
+ <fo:table width="100% - 6pt" table-layout="fixed"
+ border="2pt solid blue" padding="1pt"
+ start-indent="3pt" end-indent="3pt" space-after="2pt">
+ <fo:table-header start-indent="0" end-indent="0">
+ <fo:table-cell background-color="lightblue" padding="2pt">
+ <fo:block>Inner Footer 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="lightblue" padding="2pt">
+ <fo:block>Inner Footer 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-header>
+ <fo:table-footer start-indent="0" end-indent="0">
+ <fo:table-cell background-color="lightblue" padding="2pt">
+ <fo:block>Inner Header 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="lightblue" padding="2pt">
+ <fo:block>Inner Header 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-footer>
+ <fo:table-body start-indent="0" end-indent="0">
+ <fo:table-row>
+ <fo:table-cell background-color="lightblue" padding="2pt">
+ <fo:block>Inner Body 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="lightblue" padding="2pt">
+ <fo:block>Inner Body 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row>
+ <fo:table-cell background-color="lightblue" padding="2pt">
+ <fo:block>Inner Body 2.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="lightblue" padding="2pt">
+ <fo:block>Inner Body 2.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ <fo:block>End Outer Body Cell 2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
diff --git a/test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl b/test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl
new file mode 100644
index 000000000..9608b2fb9
--- /dev/null
+++ b/test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!-- $Id$ -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format">
+
+ <xsl:template match="@*|node()" name="copy">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+
+ <xsl:template match="/">
+ <fo:root>
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="500pt" page-width="300pt" margin="20pt">
+ <fo:region-body margin-top="20pt"/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <xsl:apply-templates select="//fo:page-sequence"/>
+ </fo:root>
+ </xsl:template>
+
+ <xsl:template match="fo:page-sequence">
+ <fo:page-sequence master-reference="page">
+ <xsl:apply-templates select="fo:flow"/>
+ </fo:page-sequence>
+ </xsl:template>
+
+ <xsl:template match="fo:flow">
+ <xsl:copy>
+ <xsl:apply-templates select="@*[not(starts-with(name(), 'space-before'))]"/>
+ <fo:table width="100%" table-layout="fixed">
+ <fo:table-footer>
+ <fo:table-cell background-color="#F0F0F0">
+ <xsl:apply-templates select="@*[starts-with(name(), 'space-before')]"/>
+ <xsl:apply-templates select="*"/>
+ </fo:table-cell>
+ </fo:table-footer>
+ <fo:table-body>
+ <fo:table-cell>
+ <fo:block>The content below is in the table footer.</fo:block>
+ </fo:table-cell>
+ </fo:table-body>
+ </fo:table>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/test/java/org/apache/fop/fo/DelegatingFOEventHandlerTestCase.java b/test/java/org/apache/fop/fo/DelegatingFOEventHandlerTestCase.java
new file mode 100644
index 000000000..313379e02
--- /dev/null
+++ b/test/java/org/apache/fop/fo/DelegatingFOEventHandlerTestCase.java
@@ -0,0 +1,531 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory;
+import org.apache.fop.fo.flow.BasicLink;
+import org.apache.fop.fo.flow.Block;
+import org.apache.fop.fo.flow.BlockContainer;
+import org.apache.fop.fo.flow.Character;
+import org.apache.fop.fo.flow.ExternalGraphic;
+import org.apache.fop.fo.flow.Footnote;
+import org.apache.fop.fo.flow.FootnoteBody;
+import org.apache.fop.fo.flow.Inline;
+import org.apache.fop.fo.flow.InstreamForeignObject;
+import org.apache.fop.fo.flow.Leader;
+import org.apache.fop.fo.flow.ListBlock;
+import org.apache.fop.fo.flow.ListItem;
+import org.apache.fop.fo.flow.ListItemBody;
+import org.apache.fop.fo.flow.ListItemLabel;
+import org.apache.fop.fo.flow.PageNumber;
+import org.apache.fop.fo.flow.PageNumberCitation;
+import org.apache.fop.fo.flow.PageNumberCitationLast;
+import org.apache.fop.fo.flow.Wrapper;
+import org.apache.fop.fo.flow.table.Table;
+import org.apache.fop.fo.flow.table.TableBody;
+import org.apache.fop.fo.flow.table.TableCell;
+import org.apache.fop.fo.flow.table.TableColumn;
+import org.apache.fop.fo.flow.table.TableFooter;
+import org.apache.fop.fo.flow.table.TableHeader;
+import org.apache.fop.fo.flow.table.TableRow;
+import org.apache.fop.fo.pagination.Flow;
+import org.apache.fop.fo.pagination.PageSequence;
+import org.apache.fop.fo.pagination.Root;
+import org.apache.fop.fo.pagination.StaticContent;
+
+/**
+ * Tests that {@link DelegatingFOEventHandler} does forward every event to its delegate
+ * event handler.
+ */
+public class DelegatingFOEventHandlerTestCase {
+
+ private InputStream document;
+
+ private List<String> expectedEvents;
+
+ private List<String> actualEvents;
+
+ private FODocumentParser documentParser;
+
+ private class DelegatingFOEventHandlerTester extends FOEventHandler {
+
+ DelegatingFOEventHandlerTester(FOUserAgent foUserAgent) {
+ super(foUserAgent);
+ }
+
+ private final StringBuilder eventBuilder = new StringBuilder();
+
+ @Override
+ public void startDocument() throws SAXException {
+ actualEvents.add("start document");
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+ actualEvents.add("end document");
+ }
+
+ @Override
+ public void startRoot(Root root) {
+ startElement(root);
+ }
+
+ @Override
+ public void endRoot(Root root) {
+ endElement(root);
+ }
+
+ @Override
+ public void startPageSequence(PageSequence pageSeq) {
+ startElement(pageSeq);
+ }
+
+ @Override
+ public void endPageSequence(PageSequence pageSeq) {
+ endElement(pageSeq);
+ }
+
+ @Override
+ public void startPageNumber(PageNumber pagenum) {
+ startElement(pagenum);
+ }
+
+ @Override
+ public void endPageNumber(PageNumber pagenum) {
+ endElement(pagenum);
+ }
+
+ @Override
+ public void startPageNumberCitation(PageNumberCitation pageCite) {
+ startElement(pageCite);
+ }
+
+ @Override
+ public void endPageNumberCitation(PageNumberCitation pageCite) {
+ endElement(pageCite);
+ }
+
+ @Override
+ public void startPageNumberCitationLast(PageNumberCitationLast pageLast) {
+ startElement(pageLast);
+ }
+
+ @Override
+ public void endPageNumberCitationLast(PageNumberCitationLast pageLast) {
+ endElement(pageLast);
+ }
+
+ @Override
+ public void startFlow(Flow fl) {
+ startElement(fl);
+ }
+
+ @Override
+ public void endFlow(Flow fl) {
+ endElement(fl);
+ }
+
+ @Override
+ public void startBlock(Block bl) {
+ startElement(bl);
+ }
+
+ @Override
+ public void endBlock(Block bl) {
+ endElement(bl);
+ }
+
+ @Override
+ public void startBlockContainer(BlockContainer blc) {
+ startElement(blc);
+ }
+
+ @Override
+ public void endBlockContainer(BlockContainer blc) {
+ endElement(blc);
+ }
+
+ @Override
+ public void startInline(Inline inl) {
+ startElement(inl);
+ }
+
+ @Override
+ public void endInline(Inline inl) {
+ endElement(inl);
+ }
+
+ @Override
+ public void startTable(Table tbl) {
+ startElement(tbl);
+ }
+
+ @Override
+ public void endTable(Table tbl) {
+ endElement(tbl);
+ }
+
+ @Override
+ public void startColumn(TableColumn tc) {
+ startElement(tc);
+ }
+
+ @Override
+ public void endColumn(TableColumn tc) {
+ endElement(tc);
+ }
+
+ @Override
+ public void startHeader(TableHeader header) {
+ startElement(header);
+ }
+
+ @Override
+ public void endHeader(TableHeader header) {
+ endElement(header);
+ }
+
+ @Override
+ public void startFooter(TableFooter footer) {
+ startElement(footer);
+ }
+
+ @Override
+ public void endFooter(TableFooter footer) {
+ endElement(footer);
+ }
+
+ @Override
+ public void startBody(TableBody body) {
+ startElement(body);
+ }
+
+ @Override
+ public void endBody(TableBody body) {
+ endElement(body);
+ }
+
+ @Override
+ public void startRow(TableRow tr) {
+ startElement(tr);
+ }
+
+ @Override
+ public void endRow(TableRow tr) {
+ endElement(tr);
+ }
+
+ @Override
+ public void startCell(TableCell tc) {
+ startElement(tc);
+ }
+
+ @Override
+ public void endCell(TableCell tc) {
+ endElement(tc);
+ }
+
+ @Override
+ public void startList(ListBlock lb) {
+ startElement(lb);
+ }
+
+ @Override
+ public void endList(ListBlock lb) {
+ endElement(lb);
+ }
+
+ @Override
+ public void startListItem(ListItem li) {
+ startElement(li);
+ }
+
+ @Override
+ public void endListItem(ListItem li) {
+ endElement(li);
+ }
+
+ @Override
+ public void startListLabel(ListItemLabel listItemLabel) {
+ startElement(listItemLabel);
+ }
+
+ @Override
+ public void endListLabel(ListItemLabel listItemLabel) {
+ endElement(listItemLabel);
+ }
+
+ @Override
+ public void startListBody(ListItemBody listItemBody) {
+ startElement(listItemBody);
+ }
+
+ @Override
+ public void endListBody(ListItemBody listItemBody) {
+ endElement(listItemBody);
+ }
+
+ @Override
+ public void startStatic(StaticContent staticContent) {
+ startElement(staticContent);
+ }
+
+ @Override
+ public void endStatic(StaticContent statisContent) {
+ endElement(statisContent);
+ }
+
+ @Override
+ public void startLink(BasicLink basicLink) {
+ startElement(basicLink);
+ }
+
+ @Override
+ public void endLink(BasicLink basicLink) {
+ endElement(basicLink);
+ }
+
+ @Override
+ public void image(ExternalGraphic eg) {
+ startElement(eg);
+ endElement(eg);
+ }
+
+ @Override
+ public void startInstreamForeignObject(InstreamForeignObject ifo) {
+ startElement(ifo);
+ }
+
+ @Override
+ public void endInstreamForeignObject(InstreamForeignObject ifo) {
+ endElement(ifo);
+ }
+
+ @Override
+ public void startFootnote(Footnote footnote) {
+ startElement(footnote);
+ }
+
+ @Override
+ public void endFootnote(Footnote footnote) {
+ endElement(footnote);
+ }
+
+ @Override
+ public void startFootnoteBody(FootnoteBody body) {
+ startElement(body);
+ }
+
+ @Override
+ public void endFootnoteBody(FootnoteBody body) {
+ endElement(body);
+ }
+
+ @Override
+ public void startLeader(Leader l) {
+ startElement(l);
+ }
+
+ @Override
+ public void endLeader(Leader l) {
+ endElement(l);
+ }
+
+ @Override
+ public void startWrapper(Wrapper wrapper) {
+ startElement(wrapper);
+ }
+
+ @Override
+ public void endWrapper(Wrapper wrapper) {
+ endElement(wrapper);
+ }
+
+ @Override
+ public void character(Character c) {
+ startElement(c);
+ endElement(c);
+ }
+
+ private void startElement(FObj node) {
+ addEvent("start ", node);
+ }
+
+ private void endElement(FObj node) {
+ addEvent("end ", node);
+ }
+
+ private void addEvent(String event, FObj node) {
+ eventBuilder.append(event);
+ eventBuilder.append(node.getLocalName());
+ addID(node);
+ actualEvents.add(eventBuilder.toString());
+ eventBuilder.setLength(0);
+ }
+
+ private void addID(FObj node) {
+ String id = node.getId();
+ if (id != null && id.length() > 0) {
+ eventBuilder.append(" id=\"");
+ eventBuilder.append(id);
+ eventBuilder.append("\"");
+ }
+ }
+ }
+
+ @Before
+ public void setUp() throws IOException {
+ setUpEvents();
+ loadDocument();
+ createDocumentParser();
+ }
+
+ private void setUpEvents() throws IOException {
+ loadDocument();
+ loadExpectedEvents();
+ actualEvents = new ArrayList<String>(expectedEvents.size());
+ }
+
+ private void loadDocument() {
+ document = getClass().getResourceAsStream("complete_document.fo");
+ }
+
+ private void loadExpectedEvents() throws IOException {
+ expectedEvents = new ArrayList<String>();
+ InputStream xslt = getClass().getResourceAsStream("extract-events.xsl");
+ try {
+ runXSLT(xslt);
+ } finally {
+ closeStream(xslt);
+ closeStream(document);
+ }
+ }
+
+ private void runXSLT(InputStream xslt) {
+ Transformer transformer = createTransformer(xslt);
+ Source fo = new StreamSource(document);
+ Result result = createTransformOutputHandler();
+ try {
+ transformer.transform(fo, result);
+ } catch (TransformerException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Transformer createTransformer(InputStream xslt) {
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ try {
+ return transformerFactory.newTransformer(new StreamSource(xslt));
+ } catch (TransformerConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Result createTransformOutputHandler() {
+ return new SAXResult(new DefaultHandler() {
+
+ private final StringBuilder event = new StringBuilder();
+
+ @Override
+ public void startElement(String uri, String localName, String qName,
+ Attributes attributes) throws SAXException {
+ event.setLength(0);
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ event.append(ch, start, length);
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ expectedEvents.add(event.toString());
+ }
+
+ });
+ }
+
+ private void closeStream(InputStream stream) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void createDocumentParser() {
+ documentParser = FODocumentParser.newInstance(new FOEventHandlerFactory() {
+
+ public FOEventHandler newFOEventHandler(FOUserAgent foUserAgent) {
+ return new DelegatingFOEventHandler(
+ new DelegatingFOEventHandlerTester(foUserAgent)) {
+ };
+ }
+ });
+ }
+
+ @Test
+ public void testFOEventHandler() throws Exception {
+ documentParser.parse(document);
+ assertArrayEquals(expectedEvents.toArray(), actualEvents.toArray());
+ }
+
+ @After
+ public void unloadDocument() throws IOException {
+ document.close();
+ }
+
+ /**
+ * Prints the given list to {@code System.out}, each element on a new line. For
+ * debugging purpose.
+ *
+ * @param list a list
+ */
+ public void printList(List<?> list) {
+ for (Object element : list) {
+ System.out.println(element);
+ }
+ }
+
+}
diff --git a/test/java/org/apache/fop/fo/FODocumentParser.java b/test/java/org/apache/fop/fo/FODocumentParser.java
new file mode 100644
index 000000000..a7574e49d
--- /dev/null
+++ b/test/java/org/apache/fop/fo/FODocumentParser.java
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo;
+
+import java.io.InputStream;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.Fop;
+import org.apache.fop.apps.FopFactory;
+import org.apache.fop.events.EventListener;
+
+/**
+ * Parse an FO document and run the corresponding FO events through a given
+ * {@link FOEventHandler} instance. That instance is created using the helper
+ * {@link FOEventHandlerFactory}.
+ *
+ * <p>An instance of this class may not be used in multiple threads concurrently.<p>
+ *
+ * <p>An instance of this class may be used multiple times if the given
+ * {@link FOEventHandler} implementation can be used multiple times.
+ */
+public final class FODocumentParser {
+
+ private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
+
+ private static final FopFactory FOP_FACTORY = FopFactory.newInstance();
+
+ private final FOEventHandlerFactory foEventHandlerFactory;
+
+ private Fop fop;
+
+ private Transformer transformer;
+
+ private EventListener eventListener;
+
+ /**
+ * A factory to create custom instances of {@link FOEventHandler}.
+ */
+ public static interface FOEventHandlerFactory {
+
+ /**
+ * Creates a new {@code FOEventHandler} instance parameterized with the given FO user agent.
+ *
+ * @param foUserAgent an FO user agent
+ * @return a new {@code FOEventHandler} instance
+ */
+ FOEventHandler newFOEventHandler(FOUserAgent foUserAgent);
+ }
+
+ private FODocumentParser(FOEventHandlerFactory foeEventHandlerFactory) {
+ this.foEventHandlerFactory = foeEventHandlerFactory;
+ }
+
+ /**
+ * Creates and returns a new FO document parser. The given factory will be used to
+ * customize the handler that will receive FO events, using the
+ * {@link FOUserAgent#setFOEventHandlerOverride(FOEventHandler)} method.
+ *
+ * @param foEventHandlerFactory the factory to be used to create {@code
+ * FOEventHandler} instances
+ * @return a new parser
+ */
+ public static FODocumentParser newInstance(FOEventHandlerFactory foEventHandlerFactory) {
+ return new FODocumentParser(foEventHandlerFactory);
+ }
+
+ /**
+ * Sets the event listener to be used if events occurs when parsing the document.
+ *
+ * @param eventListener an event listener
+ */
+ public void setEventListener(EventListener eventListener) {
+ this.eventListener = eventListener;
+ }
+
+ /**
+ * Runs FOP on the given document.
+ *
+ * @param document XSL-FO document to parse
+ * @throws FOPException if an error occurs when initializing FOP
+ * @throws LoadingException if an error occurs when parsing the document
+ */
+ public void parse(InputStream document) throws FOPException, LoadingException {
+ parse(document, createFOUserAgent());
+ }
+
+ /**
+ * Runs FOP on the given document with the supplied {@link FOUserAgent}.
+ *
+ * @param document XSL-FO document to parse
+ * @param foUserAgent The user agent
+ * @throws FOPException if an error occurs when initializing FOP
+ * @throws LoadingException if an error occurs when parsing the document
+ */
+ public void parse(InputStream document, FOUserAgent foUserAgent)
+ throws FOPException, LoadingException {
+ fop = FOP_FACTORY.newFop(foUserAgent);
+ createTransformer();
+ runTransformer(document);
+ }
+
+ /**
+ * Creates a new {@link FOUserAgent}.
+ * @return It
+ */
+ public FOUserAgent createFOUserAgent() {
+ FOUserAgent userAgent = FOP_FACTORY.newFOUserAgent();
+ FOEventHandler foEventHandler = foEventHandlerFactory.newFOEventHandler(userAgent);
+ userAgent.setFOEventHandlerOverride(foEventHandler);
+ if (eventListener != null) {
+ userAgent.getEventBroadcaster().addEventListener(eventListener);
+ }
+ return userAgent;
+ }
+
+ private void createTransformer() {
+ try {
+ transformer = TRANSFORMER_FACTORY.newTransformer();
+ } catch (TransformerConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void runTransformer(InputStream input) throws LoadingException, FOPException {
+ Source source = new StreamSource(input);
+ Result result = new SAXResult(fop.getDefaultHandler());
+ try {
+ transformer.transform(source, result);
+ } catch (TransformerException e) {
+ Throwable cause = e.getCause();
+ throw new LoadingException(cause == null ? e : cause);
+ }
+ }
+}
diff --git a/test/java/org/apache/fop/fo/FONodeMocks.java b/test/java/org/apache/fop/fo/FONodeMocks.java
new file mode 100644
index 000000000..1310d4a78
--- /dev/null
+++ b/test/java/org/apache/fop/fo/FONodeMocks.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.FopFactory;
+
+/**
+ * A helper class for creating mocks of {@link FONode} and its descendants.
+ */
+public final class FONodeMocks {
+
+ private FONodeMocks() { }
+
+ /**
+ * Creates and returns a mock {@link FONode} configured with a mock
+ * {@link FOEventHandler}. The FO event handler returns a mock {@link FOUserAgent},
+ * which in turn returns a mock {@link FopFactory}, which returns a mock
+ * {@link ImageManager}.
+ *
+ * @return a mock FO node
+ */
+ public static FONode mockFONode() {
+ FONode mockFONode = mock(FONode.class);
+ mockGetFOEventHandler(mockFONode);
+ return mockFONode;
+ }
+
+ private static void mockGetFOEventHandler(FONode mockFONode) {
+ FOEventHandler mockFOEventHandler = mock(FOEventHandler.class);
+ mockGetUserAgent(mockFOEventHandler);
+ when(mockFONode.getFOEventHandler()).thenReturn(mockFOEventHandler);
+ }
+
+ private static void mockGetUserAgent(FOEventHandler mockFOEventHandler) {
+ FOUserAgent mockFOUserAgent = mock(FOUserAgent.class);
+ mockGetFactory(mockFOUserAgent);
+ when(mockFOEventHandler.getUserAgent()).thenReturn(mockFOUserAgent);
+ }
+
+ private static void mockGetFactory(FOUserAgent mockFOUserAgent) {
+ FopFactory mockFopFactory = mock(FopFactory.class);
+ mockGetImageManager(mockFopFactory);
+ when(mockFOUserAgent.getFactory()).thenReturn(mockFopFactory);
+ }
+
+ private static void mockGetImageManager(FopFactory mockFopFactory) {
+ try {
+ ImageManager mockImageManager = mock(ImageManager.class);
+ when(mockImageManager.getImageInfo(anyString(), any(ImageSessionContext.class)))
+ .thenReturn(null);
+ when(mockFopFactory.getImageManager()).thenReturn(mockImageManager);
+ } catch (ImageException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/test/java/org/apache/fop/fo/LoadingException.java b/test/java/org/apache/fop/fo/LoadingException.java
new file mode 100644
index 000000000..a5d509209
--- /dev/null
+++ b/test/java/org/apache/fop/fo/LoadingException.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo;
+
+/**
+ * This class specifies an exceptional condition that occurred while an XSL-FO document
+ * was being parsed.
+ */
+public class LoadingException extends Exception {
+
+ private static final long serialVersionUID = 7529029475875542916L;
+
+ LoadingException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/test/java/org/apache/fop/fo/complete_document.fo b/test/java/org/apache/fop/fo/complete_document.fo
new file mode 100644
index 000000000..5a34e9e9a
--- /dev/null
+++ b/test/java/org/apache/fop/fo/complete_document.fo
@@ -0,0 +1,176 @@
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<!-- $Id$ -->
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="400pt" page-width="300pt" margin="20pt" margin-top="10pt">
+ <fo:region-body margin-top="20pt"/>
+ <fo:region-before extent="15pt"/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:static-content flow-name="xsl-region-before">
+ <fo:block id="1" font-size="7pt" text-align-last="justify" padding-bottom="2pt"
+ border-bottom="0.25pt solid black">This is the page header<fo:leader/>Page <fo:page-number
+ id="2"/></fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="xsl-footnote-separator">
+ <fo:block id="3"><fo:leader leader-length="100pt" leader-pattern="rule"/></fo:block>
+ </fo:static-content>
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block id="4">This is a link to the <fo:wrapper id="5" color="blue"><fo:basic-link id="6"
+ internal-destination="second-start">next page-sequence</fo:basic-link></fo:wrapper>
+ (which starts on page <fo:page-number-citation id="7" ref-id="second-start"/> and ends on
+ page <fo:page-number-citation-last id="8" ref-id="second-end"/>).</fo:block>
+ <fo:block id="9" font-family="sans-serif" font-weight="bold" space-before="1em"
+ space-after="0.2em" role="H1"><fo:block id="10">A Title Block</fo:block></fo:block>
+ <fo:block id="11">This block of text contains a footnote<fo:footnote id="12"><fo:inline id="13"
+ baseline-shift="super" font-size="70%">1</fo:inline><fo:footnote-body id="14"><fo:block
+ id="15">A footnote with a link to the <fo:wrapper id="16" color="blue"><fo:basic-link
+ id="17" external-destination="http://xmlgraphics.apache.org/fop/">FOP
+ website</fo:basic-link></fo:wrapper></fo:block></fo:footnote-body></fo:footnote>
+ call.</fo:block>
+ <fo:table id="18" space-before="1em" width="100%" table-layout="fixed">
+ <fo:table-column id="19" column-width="proportional-column-width(1)"/>
+ <fo:table-column id="20" column-width="proportional-column-width(2)"/>
+ <fo:table-header id="21">
+ <fo:table-row id="22">
+ <fo:table-cell id="23" border="2pt solid black" padding="2pt 2pt 0">
+ <fo:block id="24">Header 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell id="25" border="2pt solid black" padding="2pt 2pt 0">
+ <fo:block id="26">Header 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-header>
+ <fo:table-footer id="27">
+ <fo:table-row id="28">
+ <fo:table-cell id="29" border="2pt solid black" padding="2pt 2pt 0">
+ <fo:block id="30">Footer 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell id="31" border="2pt solid black" padding="2pt 2pt 0">
+ <fo:block id="32">Footer 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-footer>
+ <fo:table-body id="33">
+ <fo:table-row id="34">
+ <fo:table-cell id="35" border="1pt solid black" padding="2pt 2pt 0">
+ <fo:block id="36">Cell 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell id="37" border="1pt solid black" padding="2pt 2pt 0">
+ <fo:block id="38">Cell 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row id="39">
+ <fo:table-cell id="40" border="1pt solid black" padding="2pt 2pt 0">
+ <fo:block id="41">Cell 2.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell id="42" border="1pt solid black" padding="2pt 2pt 0">
+ <fo:block id="43">Cell 2.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ <fo:block-container id="44" space-before="1.2em">
+ <fo:block-container id="45" absolute-position="absolute" top="6pt" right="2.5pt"
+ inline-progression-dimension="37%" padding="3pt 1pt 2pt 3pt" border="1.5pt solid
+ darkblue">
+ <fo:block id="46" color="darkblue" font-size="80%">This is an absolutely positioned
+ block-container. Nullam interdum mattis ipsum sit amet molestie.</fo:block>
+ </fo:block-container>
+ <fo:block id="47" end-indent="37% + 15pt">Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer vel lacinia diam. Etiam venenatis magna vel libero imperdiet
+ rhoncus.</fo:block>
+ </fo:block-container>
+ </fo:flow>
+ </fo:page-sequence>
+
+ <fo:page-sequence master-reference="page">
+ <fo:static-content id="48" flow-name="xsl-region-before">
+ <fo:block id="49" font-size="7pt" text-align-last="justify" padding-bottom="2pt"
+ border-bottom="0.25pt solid black">This is the page header<fo:leader id="50"/>Page
+ <fo:page-number id="51"/></fo:block>
+ </fo:static-content>
+ <fo:flow flow-name="xsl-region-body" text-align="justify" space-before.minimum="8pt"
+ space-before.optimum="10pt" space-before.maximum="12pt">
+ <fo:block id="second-start">Starting a new page-sequence.</fo:block>
+ <fo:block id="52" text-align="center">The <fo:external-graphic id="53"
+ src="test/resources/images/fop-logo-color-24bit.png"
+ inline-progression-dimension.maximum="50%" content-width="scale-to-fit"
+ alignment-adjust="-46%" alignment-baseline="middle" fox:alt-text="FOP Logo"/>
+ logo.</fo:block>
+ <fo:list-block id="54" provisional-distance-between-starts="15pt"
+ provisional-label-separation="0" space-before="inherit">
+ <fo:list-item id="55">
+ <fo:list-item-label id="56" end-indent="label-end()">
+ <fo:block id="57">1.</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body id="58" start-indent="body-start()">
+ <fo:block id="59">First item of a list</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ <fo:list-item id="60">
+ <fo:list-item-label id="61" end-indent="label-end()">
+ <fo:block id="62">2.</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body id="63" start-indent="body-start()">
+ <fo:block id="64">Second item of a list</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ <fo:list-item id="65">
+ <fo:list-item-label id="66" end-indent="label-end()">
+ <fo:block id="67">3.</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body id="68" start-indent="body-start()">
+ <fo:block id="69">Third item of a list</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ </fo:list-block>
+ <fo:block id="70" text-align="center"><fo:instream-foreign-object id="71"
+ inline-progression-dimension.maximum="50%" content-width="scale-to-fit"
+ fox:alt-text="An inline SVG">
+ <svg xmlns="http://www.w3.org/2000/svg" width="319" height="286.6">
+ <g style="fill-opacity:0.7; stroke:black; stroke-width:3"
+ transform="translate(0, 286.6) scale(1, -1) translate(100, 100)">
+ <circle cx="50" cy="86.6" r="80" style="fill:red;"/>
+ <circle cx="0" cy="0" r="80" style="fill:green;"/>
+ <circle cx="100" cy="0" r="80" style="fill:blue;"/>
+ </g>
+ </svg>
+ </fo:instream-foreign-object></fo:block>
+ <fo:block id="72" space-before="inherit">A block containing an <fo:inline id="73"
+ border="0.5pt solid black" padding="2pt" padding-bottom="0">inline</fo:inline>
+ element.</fo:block>
+ <fo:block id="74" space-before="inherit">A block containing a fancy <fo:character id="75"
+ border="1pt solid black" padding="0 2pt 1pt 2pt" font-family="Symbol" character="♦"/>
+ character.</fo:block>
+ <fo:block id="76" space-before="inherit" text-align-last="justify">A leader with special
+ content: <fo:leader id="77" leader-pattern="use-content"><fo:inline id="78"><fo:character
+ id="79" character=" "/><fo:inline id="80" border="0.5pt solid black"
+ padding-left="2pt" padding-right="2pt"><fo:character id="81" baseline-shift="-10%"
+ character="•"/></fo:inline></fo:inline></fo:leader>.</fo:block>
+ <fo:block id="second-end" space-before="inherit">Ending the page-sequence.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+</fo:root>
diff --git a/test/java/org/apache/fop/fo/extract-events.xsl b/test/java/org/apache/fop/fo/extract-events.xsl
new file mode 100644
index 000000000..6cf42c984
--- /dev/null
+++ b/test/java/org/apache/fop/fo/extract-events.xsl
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ exclude-result-prefixes="fo">
+
+ <xsl:output indent="yes" omit-xml-declaration="yes"/>
+
+ <xsl:template match="/">
+ <event>
+ <xsl:text>start document</xsl:text>
+ </event>
+ <xsl:apply-templates/>
+ <event>
+ <xsl:text>end document</xsl:text>
+ </event>
+ </xsl:template>
+
+ <xsl:template match="fo:root">
+ <event>start root</event>
+ <xsl:apply-templates select="fo:page-sequence"/>
+ <event>end root</event>
+ </xsl:template>
+
+ <xsl:template match="fo:*">
+ <xsl:call-template name="process.node">
+ <xsl:with-param name="id">
+ <xsl:apply-templates select="@id"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+
+ <!-- Those elements do not retrieve the id property.
+ This will have to be fixed at some point. -->
+ <xsl:template match="fo:footnote|fo:footnote-body">
+ <xsl:call-template name="process.node"/>
+ </xsl:template>
+
+ <xsl:template name="process.node">
+ <xsl:param name="id" select="''"/>
+ <event>
+ <xsl:text>start </xsl:text>
+ <xsl:value-of select="local-name()"/>
+ <xsl:value-of select="$id"/>
+ </event>
+ <xsl:apply-templates/>
+ <event>
+ <xsl:text>end </xsl:text>
+ <xsl:value-of select="local-name()"/>
+ <xsl:value-of select="$id"/>
+ </event>
+ </xsl:template>
+
+ <xsl:template match="@id">
+ <xsl:text> id="</xsl:text>
+ <xsl:value-of select="."/>
+ <xsl:text>"</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="text()"/>
+
+</xsl:stylesheet>
diff --git a/test/java/org/apache/fop/fo/flow/table/AbstractTableTest.java b/test/java/org/apache/fop/fo/flow/table/AbstractTableTest.java
index 69bbc8d8c..fb6ec6a25 100644
--- a/test/java/org/apache/fop/fo/flow/table/AbstractTableTest.java
+++ b/test/java/org/apache/fop/fo/flow/table/AbstractTableTest.java
@@ -19,33 +19,37 @@
package org.apache.fop.fo.flow.table;
+import java.io.FileInputStream;
import java.util.Iterator;
import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fo.FODocumentParser;
import org.apache.fop.fo.FOEventHandler;
-import org.apache.fop.fotreetest.FOTreeUnitTester;
+import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory;
+import org.apache.fop.util.ConsoleEventListenerForTests;
/**
* Superclass for testcases related to tables, factoring the common stuff.
*/
-abstract class AbstractTableTest extends FOTreeUnitTester {
+abstract class AbstractTableTest {
- private FOTreeUnitTester.FOEventHandlerFactory tableHandlerFactory;
+ private FODocumentParser documentParser;
private TableHandler tableHandler;
- public AbstractTableTest() throws Exception {
- super();
- tableHandlerFactory = new FOEventHandlerFactory() {
- public FOEventHandler createFOEventHandler(FOUserAgent foUserAgent) {
+ protected void setUp(String filename) throws Exception {
+ createDocumentParser();
+ documentParser.setEventListener(new ConsoleEventListenerForTests(filename));
+ documentParser.parse(new FileInputStream("test/fotree/unittests/" + filename));
+ }
+
+ private void createDocumentParser() {
+ documentParser = FODocumentParser.newInstance(new FOEventHandlerFactory() {
+ public FOEventHandler newFOEventHandler(FOUserAgent foUserAgent) {
tableHandler = new TableHandler(foUserAgent);
return tableHandler;
}
- };
- }
-
- protected void setUp(String filename) throws Exception {
- setUp(filename, tableHandlerFactory);
+ });
}
protected TableHandler getTableHandler() {
diff --git a/test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java b/test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java
index 0c567b976..7c0301ca7 100644
--- a/test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java
+++ b/test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java
@@ -25,10 +25,11 @@ import java.awt.Color;
import java.util.Iterator;
import java.util.List;
+import org.junit.Test;
+
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FONode.FONodeIterator;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
-import org.junit.Test;
/**
* A testcase for the resolution of collapsed borders in the FO tree, taking
@@ -107,10 +108,6 @@ public class CollapsedConditionalBorderTestCase extends AbstractTableTest {
{{border8pt, Color.black}, {border6pt, Color.blue}, {border8pt, Color.black}, {border6pt, Color.blue}, {border4pt, Color.black}, {border4pt, Color.black}, {border4pt, Color.red}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border4pt, Color.blue}, {border4pt, Color.red}, {border6pt, Color.magenta}, {border6pt, Color.magenta}, {border6pt, Color.magenta}}
};
- public CollapsedConditionalBorderTestCase() throws Exception {
- super();
- }
-
private static GridUnit getGridUnit(TablePart part) {
return (GridUnit) ((List) ((List) part.getRowGroups().get(0)).get(0)).get(0);
}
diff --git a/test/java/org/apache/fop/fo/flow/table/ErrorCheckTest.java b/test/java/org/apache/fop/fo/flow/table/ErrorCheckTest.java
index 724259a75..b30c64c07 100644
--- a/test/java/org/apache/fop/fo/flow/table/ErrorCheckTest.java
+++ b/test/java/org/apache/fop/fo/flow/table/ErrorCheckTest.java
@@ -19,8 +19,10 @@
package org.apache.fop.fo.flow.table;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import org.apache.fop.fo.LoadingException;
import org.apache.fop.fo.ValidationException;
/**
@@ -28,16 +30,13 @@ import org.apache.fop.fo.ValidationException;
*/
abstract class ErrorCheckTest extends AbstractTableTest {
- public ErrorCheckTest() throws Exception {
- super();
- }
-
protected void launchTest(String filename) throws Exception {
try {
setUp(filename);
- fail();
- } catch (ValidationException e) {
+ fail("Expected ValidationException to be thrown");
+ } catch (LoadingException e) {
// TODO check location
+ assertTrue(e.getCause() instanceof ValidationException);
}
}
diff --git a/test/java/org/apache/fop/fo/flow/table/IllegalRowSpanTestCase.java b/test/java/org/apache/fop/fo/flow/table/IllegalRowSpanTestCase.java
index 024e15c2e..b2e7a2c9d 100644
--- a/test/java/org/apache/fop/fo/flow/table/IllegalRowSpanTestCase.java
+++ b/test/java/org/apache/fop/fo/flow/table/IllegalRowSpanTestCase.java
@@ -27,10 +27,6 @@ import org.junit.Test;
*/
public class IllegalRowSpanTestCase extends ErrorCheckTest {
- public IllegalRowSpanTestCase() throws Exception {
- super();
- }
-
@Test
public void testBody1() throws Exception {
launchTest("table/illegal-row-span_body_1.fo");
diff --git a/test/java/org/apache/fop/fo/flow/table/RowGroupBuilderTestCase.java b/test/java/org/apache/fop/fo/flow/table/RowGroupBuilderTestCase.java
index 3df0338ab..361517a66 100644
--- a/test/java/org/apache/fop/fo/flow/table/RowGroupBuilderTestCase.java
+++ b/test/java/org/apache/fop/fo/flow/table/RowGroupBuilderTestCase.java
@@ -35,10 +35,6 @@ import org.junit.Test;
*/
public class RowGroupBuilderTestCase extends AbstractTableTest {
- public RowGroupBuilderTestCase() throws Exception {
- super();
- }
-
/**
* Checks that the given table-body(header,footer) will return row groups as expected.
* More precisely, checks that the number of row groups corresponds to the size of the
diff --git a/test/java/org/apache/fop/fo/flow/table/TableColumnColumnNumberTestCase.java b/test/java/org/apache/fop/fo/flow/table/TableColumnColumnNumberTestCase.java
index 4f7d9e054..a21806559 100644
--- a/test/java/org/apache/fop/fo/flow/table/TableColumnColumnNumberTestCase.java
+++ b/test/java/org/apache/fop/fo/flow/table/TableColumnColumnNumberTestCase.java
@@ -23,9 +23,10 @@ import static org.junit.Assert.assertEquals;
import java.util.Iterator;
+import org.junit.Test;
+
import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.fo.FObj;
-import org.junit.Test;
public class TableColumnColumnNumberTestCase extends AbstractTableTest {
@@ -50,10 +51,6 @@ public class TableColumnColumnNumberTestCase extends AbstractTableTest {
private TablePercentBaseContext percentBaseContext = new TablePercentBaseContext();
- public TableColumnColumnNumberTestCase() throws Exception {
- super();
- }
-
private void checkColumn(Table t, int number, boolean isImplicit, int spans, int repeated, int width) {
TableColumn c = t.getColumn(number - 1);
// TODO a repeated column has a correct number only for its first occurrence
diff --git a/test/java/org/apache/fop/fo/flow/table/TooManyColumnsTestCase.java b/test/java/org/apache/fop/fo/flow/table/TooManyColumnsTestCase.java
index 284fd1d2f..76a5d196d 100644
--- a/test/java/org/apache/fop/fo/flow/table/TooManyColumnsTestCase.java
+++ b/test/java/org/apache/fop/fo/flow/table/TooManyColumnsTestCase.java
@@ -23,10 +23,6 @@ import org.junit.Test;
public class TooManyColumnsTestCase extends ErrorCheckTest {
- public TooManyColumnsTestCase() throws Exception {
- super();
- }
-
@Test
public void testBody1() throws Exception {
launchTest("table/too-many-columns_body_1.fo");
diff --git a/test/java/org/apache/fop/fo/flow/table/UnimplementedWarningNeutralizer.java b/test/java/org/apache/fop/fo/flow/table/UnimplementedWarningNeutralizer.java
new file mode 100644
index 000000000..1a5e38291
--- /dev/null
+++ b/test/java/org/apache/fop/fo/flow/table/UnimplementedWarningNeutralizer.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.flow.table;
+
+/**
+ * This class aims at easing testing, by preventing the event notification system from
+ * getting in the way just to issue an Unimplemented Feature warning.
+ */
+public final class UnimplementedWarningNeutralizer {
+
+ private UnimplementedWarningNeutralizer() { }
+
+ /**
+ * Neutralizes Unimplemented Feature events from the {@link TableAndCaption} and
+ * {@link TableCaption} classes.
+ */
+ public static void neutralizeUnimplementedWarning() {
+ TableAndCaption.notImplementedWarningGiven = true;
+ TableCaption.notImplementedWarningGiven = true;
+ }
+}
diff --git a/test/java/org/apache/fop/fo/properties/AltTextHolderTestCase.java b/test/java/org/apache/fop/fo/properties/AltTextHolderTestCase.java
new file mode 100644
index 000000000..cd5d545ff
--- /dev/null
+++ b/test/java/org/apache/fop/fo/properties/AltTextHolderTestCase.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.FONodeMocks;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.fo.flow.AbstractGraphics;
+import org.apache.fop.fo.flow.ExternalGraphic;
+import org.apache.fop.fo.flow.InstreamForeignObject;
+
+
+/**
+ * Tests that the fox:alt-text property is correctly set on objects that support it.
+ */
+public class AltTextHolderTestCase {
+
+ private final String altText = "alternative text";
+
+ @Test
+ public void externalGraphicHasAltText() throws FOPException {
+ testAltTextGetter(new ExternalGraphic(mockFONode()));
+ }
+
+ @Test
+ public void instreamForeignObjectHasAltText() throws FOPException {
+ testAltTextGetter(new InstreamForeignObject(mockFONode()));
+ }
+
+ private FONode mockFONode() {
+ FONode mockFONode = FONodeMocks.mockFONode();
+ FOUserAgent mockFOUserAgent = mockFONode.getFOEventHandler().getUserAgent();
+ when(mockFOUserAgent.isAccessibilityEnabled()).thenReturn(true);
+ return mockFONode;
+ }
+
+ private void testAltTextGetter(AbstractGraphics g) throws FOPException {
+ g.bind(mockPropertyList());
+ assertEquals(altText, g.getAltText());
+ }
+
+ private PropertyList mockPropertyList() throws PropertyException {
+ PropertyList mockPropertyList = PropertyListMocks.mockPropertyList();
+ Property mockAltText = mock(Property.class);
+ when(mockAltText.getString()).thenReturn(altText);
+ when(mockPropertyList.get(Constants.PR_X_ALT_TEXT)).thenReturn(mockAltText);
+ return mockPropertyList;
+ }
+
+}
diff --git a/test/java/org/apache/fop/fo/properties/CommonAccessibilityHolderTestCase.java b/test/java/org/apache/fop/fo/properties/CommonAccessibilityHolderTestCase.java
new file mode 100644
index 000000000..352a39713
--- /dev/null
+++ b/test/java/org/apache/fop/fo/properties/CommonAccessibilityHolderTestCase.java
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.FONodeMocks;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.fo.flow.table.UnimplementedWarningNeutralizer;
+
+/**
+ * This tests that all the FONodes that implement CommonAccessibilityHolder correctly configure
+ * the CommonAccessibility property.
+ */
+public class CommonAccessibilityHolderTestCase {
+
+ private static final List<Class<? extends CommonAccessibilityHolder>> IMPLEMENTATIONS
+ = new ArrayList<Class<? extends CommonAccessibilityHolder>>();
+
+ private final String role = "role";
+
+ private final String sourceDocument = "source document";
+
+ static {
+ /* This triggers 'unimplemented feature' FO validation events so that the event system is
+ * not triggered when testing, avoiding extra convoluted dependency stubbing. */
+ UnimplementedWarningNeutralizer.neutralizeUnimplementedWarning();
+
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.BasicLink.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.Block.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.pagination.bookmarks.Bookmark.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.pagination.bookmarks.BookmarkTitle.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.ExternalGraphic.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.Footnote.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.FootnoteBody.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.InitialPropertySet.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.Inline.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.InstreamForeignObject.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.Leader.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.ListBlock.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.ListItem.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.ListItemBody.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.ListItemLabel.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.PageNumber.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.PageNumberCitation.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.PageNumberCitationLast.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.pagination.Root.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.table.Table.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.table.TableAndCaption.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.table.TableBody.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.table.TableCaption.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.table.TableCell.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.table.TableFooter.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.table.TableHeader.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.flow.table.TableRow.class);
+ IMPLEMENTATIONS.add(org.apache.fop.fo.pagination.Title.class);
+ }
+
+ /**
+ * Bind should be overridden to correctly configure the CommonAccessibility property
+ * @throws Exception -
+ */
+ @Test
+ public void bindMustSetRoleAndSourceDoc() throws Exception {
+ final PropertyList mockPList = mockPropertyList();
+ final FONode parent = FONodeMocks.mockFONode();
+ for (Class<? extends CommonAccessibilityHolder> clazz : IMPLEMENTATIONS) {
+ Constructor<? extends CommonAccessibilityHolder> constructor
+ = clazz.getConstructor(FONode.class);
+ CommonAccessibilityHolder sut = constructor.newInstance(parent);
+ ((FONode)sut).bind(mockPList);
+ String errorMessage = "Test failed for " + clazz + ": ";
+ assertEquals(errorMessage, role, sut.getCommonAccessibility().getRole());
+ assertEquals(errorMessage, sourceDocument,
+ sut.getCommonAccessibility().getSourceDocument());
+ }
+ }
+
+ private PropertyList mockPropertyList() throws PropertyException {
+ final PropertyList mockPList = PropertyListMocks.mockPropertyList();
+ PropertyListMocks.mockTableProperties(mockPList);
+ PropertyListMocks.mockCommonBorderPaddingBackgroundProps(mockPList);
+ mockRoleProperty(mockPList);
+ mockSourceDocProperty(mockPList);
+ return mockPList;
+ }
+
+ private void mockRoleProperty(PropertyList mockPList) throws PropertyException {
+ final Property mockRoleProperty = mock(Property.class);
+ when(mockRoleProperty.getString()).thenReturn(role);
+ when(mockPList.get(Constants.PR_ROLE)).thenReturn(mockRoleProperty);
+ }
+
+ private void mockSourceDocProperty(PropertyList mockPList) throws PropertyException {
+ final Property mockSourceDocProperty = mock(Property.class);
+ when(mockSourceDocProperty.getString()).thenReturn(sourceDocument);
+ when(mockPList.get(Constants.PR_SOURCE_DOCUMENT)).thenReturn(mockSourceDocProperty);
+ }
+
+}
diff --git a/test/java/org/apache/fop/fo/properties/PropertyListMocks.java b/test/java/org/apache/fop/fo/properties/PropertyListMocks.java
new file mode 100644
index 000000000..380f6e5a8
--- /dev/null
+++ b/test/java/org/apache/fop/fo/properties/PropertyListMocks.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.properties;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.expr.PropertyException;
+
+/**
+ * A helper class for mocking a property list.
+ */
+public final class PropertyListMocks {
+
+ private PropertyListMocks() { }
+
+ /**
+ * Creates and returns a mock property list returning a generic default for the
+ * {@link PropertyList#get(int)} method.
+ *
+ * @return a mock property list
+ */
+ public static PropertyList mockPropertyList() {
+ try {
+ final PropertyList mockPList = mock(PropertyList.class);
+ final Property mockGenericProperty = PropertyMocks.mockGenericProperty();
+ when(mockPList.get(anyInt())).thenReturn(mockGenericProperty);
+ return mockPList;
+ } catch (PropertyException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Overrides with working mock properties the values returned by
+ * {@link PropertyList#get(int)} for {@link Constants#PR_COLUMN_NUMBER},
+ * {@link Constants#PR_NUMBER_COLUMNS_SPANNED},
+ * {@link Constants#PR_NUMBER_ROWS_SPANNED} and {@link Constants#PR_BORDER_COLLAPSE}.
+ *
+ * @param mockPList a mock property list
+ */
+ public static void mockTableProperties(PropertyList mockPList) {
+ try {
+ final Property mockNumberProperty = PropertyMocks.mockNumberProperty();
+ when(mockPList.get(Constants.PR_COLUMN_NUMBER)).thenReturn(mockNumberProperty);
+ when(mockPList.get(Constants.PR_NUMBER_COLUMNS_SPANNED)).thenReturn(mockNumberProperty);
+ when(mockPList.get(Constants.PR_NUMBER_ROWS_SPANNED)).thenReturn(mockNumberProperty);
+
+ final Property borderCollapseProperty = mock(Property.class);
+ when(borderCollapseProperty.getEnum()).thenReturn(Constants.EN_SEPARATE);
+ when(mockPList.get(Constants.PR_BORDER_COLLAPSE)).thenReturn(borderCollapseProperty);
+ } catch (PropertyException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Overrides with a working mock property the value returned by
+ * {@link PropertyList#getBorderPaddingBackgroundProps()}.
+ *
+ * @param mockPList a mock property list
+ */
+ public static void mockCommonBorderPaddingBackgroundProps(PropertyList mockPList) {
+ try {
+ final CommonBorderPaddingBackground mockCommonBorderPaddingBackground
+ = mock(CommonBorderPaddingBackground.class);
+ when(mockPList.getBorderPaddingBackgroundProps())
+ .thenReturn(mockCommonBorderPaddingBackground);
+ } catch (PropertyException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/test/java/org/apache/fop/fo/properties/PropertyMocks.java b/test/java/org/apache/fop/fo/properties/PropertyMocks.java
new file mode 100644
index 000000000..40c923249
--- /dev/null
+++ b/test/java/org/apache/fop/fo/properties/PropertyMocks.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.properties;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.fop.datatypes.Numeric;
+import org.apache.fop.datatypes.PercentBaseContext;
+import org.apache.fop.fo.Constants;
+
+/**
+ * Helper class to create mocks of various kinds of properties.
+ */
+public final class PropertyMocks {
+
+ private PropertyMocks() { }
+
+ /**
+ * Creates and returns a generic mock property returning decent defaults for the
+ * {@link Property#getString()}, {@link Property#getEnum()} and
+ * {@link Property#getLengthRange()} methods.
+ *
+ * @return a mock all-purpose property
+ */
+ public static Property mockGenericProperty() {
+ final Property mockGenericProperty = mock(Property.class);
+ when(mockGenericProperty.getString()).thenReturn("A non-empty string");
+ when(mockGenericProperty.getEnum()).thenReturn(Constants.EN_SPACE);
+ LengthRangeProperty lengthRangeProperty = mockLengthRangeProperty();
+ when(mockGenericProperty.getLengthRange()).thenReturn(lengthRangeProperty);
+ return mockGenericProperty;
+ }
+
+ private static LengthRangeProperty mockLengthRangeProperty() {
+ final LengthRangeProperty mockLengthRangeProperty = mock(LengthRangeProperty.class);
+ final Property optimum = mockOptimumProperty();
+ when(mockLengthRangeProperty.getOptimum(any(PercentBaseContext.class)))
+ .thenReturn(optimum);
+ return mockLengthRangeProperty;
+ }
+
+ /**
+ * Creates and returns a mock property returning a decent default for the
+ * {@link Property#getNumeric()} method.
+ *
+ * @return a mock number property
+ */
+ public static Property mockNumberProperty() {
+ final Property mockNumberProperty = mock(Property.class);
+ final Numeric mockNumeric = mock(Numeric.class);
+ when(mockNumberProperty.getNumeric()).thenReturn(mockNumeric);
+ return mockNumberProperty;
+ }
+
+ private static Property mockOptimumProperty() {
+ final Property optimum = mock(Property.class);
+ when(optimum.isAuto()).thenReturn(true);
+ return optimum;
+ }
+
+}
diff --git a/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java b/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java
index 4a77ca000..b74afefc5 100644
--- a/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java
+++ b/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java
@@ -29,7 +29,9 @@ import org.junit.runners.Suite;
@Suite.SuiteClasses({
org.apache.fop.fo.flow.table.AllTests.class,
org.apache.fop.fo.pagination.AllTests.class,
- FOTreeTestCase.class })
-
+ org.apache.fop.fotreetest.FOTreeTestCase.class,
+ org.apache.fop.fo.properties.CommonAccessibilityHolderTestCase.class,
+ org.apache.fop.fo.DelegatingFOEventHandlerTestCase.class
+})
public final class FOTreeTestSuite {
}
diff --git a/test/java/org/apache/fop/fotreetest/FOTreeUnitTester.java b/test/java/org/apache/fop/fotreetest/FOTreeUnitTester.java
deleted file mode 100644
index 0906c266d..000000000
--- a/test/java/org/apache/fop/fotreetest/FOTreeUnitTester.java
+++ /dev/null
@@ -1,96 +0,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.
- */
-
-/* $Id$ */
-
-package org.apache.fop.fotreetest;
-
-import java.io.File;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.apache.fop.apps.FOUserAgent;
-import org.apache.fop.apps.Fop;
-import org.apache.fop.apps.FopFactory;
-import org.apache.fop.fo.FOEventHandler;
-import org.apache.fop.util.ConsoleEventListenerForTests;
-import org.xml.sax.XMLReader;
-
-
-/**
- * Base class for unit-testing the FO tree building code. It performs the necessary setup
- * to parse an FO file and register a proper {@link FOEventHandler}. That handler will be
- * the entry point to test classes from the FObj hierarchy.
- */
-public abstract class FOTreeUnitTester {
-
- private XMLReader foReader;
-
- private FopFactory fopFactory;
-
- /**
- * Should be implemented by children testcases for properly setting up the custom
- * FOEventHandler needed to test FObj classes.
- */
- public abstract static class FOEventHandlerFactory {
-
- /**
- * This method is called by FOTreeUnitTester when creating a {@link Fop} instance.
- * That lets pass to the custom FOEventHandler the proper user agent that will be
- * used by this instance.
- *
- * @param foUserAgent the user agent needed by the Fop instance that will be used
- * to create the FO tree
- * @return the appropriate FOEventHandler for performing the tests
- */
- public abstract FOEventHandler createFOEventHandler(FOUserAgent foUserAgent);
- }
-
- public FOTreeUnitTester() throws Exception {
- // Stuff that needs to be set up only once and will be re-used for each test
- SAXParserFactory spf = SAXParserFactory.newInstance();
- spf.setNamespaceAware(true);
- spf.setValidating(false);
- SAXParser parser;
- parser = spf.newSAXParser();
- foReader = parser.getXMLReader();
- fopFactory = FopFactory.newInstance();
- }
-
- /**
- * Launches FOP on the given FO file.
- *
- * @param filename path to the test FO file
- * @param factory to create the appropriate FOEventHandler for performing tests
- */
- public void setUp(String filename, FOEventHandlerFactory factory) throws Exception {
- FOUserAgent ua = fopFactory.newFOUserAgent();
- ua.setFOEventHandlerOverride(factory.createFOEventHandler(ua));
- ua.getEventBroadcaster().addEventListener(
- new ConsoleEventListenerForTests(filename));
-
- Fop fop = fopFactory.newFop(ua);
-
- foReader.setContentHandler(fop.getDefaultHandler());
- foReader.setDTDHandler(fop.getDefaultHandler());
- foReader.setErrorHandler(fop.getDefaultHandler());
- foReader.setEntityResolver(fop.getDefaultHandler());
-
- foReader.parse(new File("test/fotree/unittests/" + filename).toURI().toURL().toExternalForm());
- }
-}
diff --git a/test/java/org/apache/fop/intermediate/IFParserTestCase.java b/test/java/org/apache/fop/intermediate/IFParserTestCase.java
index c37897dc1..7d4fb7ad8 100644
--- a/test/java/org/apache/fop/intermediate/IFParserTestCase.java
+++ b/test/java/org/apache/fop/intermediate/IFParserTestCase.java
@@ -48,6 +48,9 @@ import org.apache.fop.render.intermediate.IFSerializer;
@RunWith(Parameterized.class)
public class IFParserTestCase extends AbstractIFTest {
+ /** Set this to true to get the correspondence between test number and test file. */
+ private static final boolean DEBUG = false;
+
/**
* Gets the parameters for this test
*
@@ -56,7 +59,19 @@ public class IFParserTestCase extends AbstractIFTest {
*/
@Parameters
public static Collection<File[]> getParameters() throws IOException {
- return LayoutEngineTestUtils.getLayoutTestFiles();
+ Collection<File[]> testFiles = LayoutEngineTestUtils.getLayoutTestFiles();
+ if (DEBUG) {
+ printFiles(testFiles);
+ }
+ return testFiles;
+ }
+
+ private static void printFiles(Collection<File[]> files) {
+ int index = 0;
+ for (File[] file : files) {
+ assert file.length == 1;
+ System.out.println(String.format("%3d %s", index++, file[0]));
+ }
}
/**
diff --git a/test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java b/test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java
new file mode 100644
index 000000000..65c6b25a6
--- /dev/null
+++ b/test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.intermediate;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.InOrder;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.fo.FOElementMapping;
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.fo.extensions.InternalElementMapping;
+import org.apache.fop.util.XMLUtil;
+
+public class IFStructureTreeBuilderTestCase {
+
+ private IFStructureTreeBuilder sut;
+
+ @Before
+ public void setUp() {
+ sut = new IFStructureTreeBuilder();
+ }
+
+ @Test
+ public void startAndEndPageSequence() throws SAXException {
+ final ContentHandler handler = mock(ContentHandler.class);
+
+ try {
+ sut.replayEventsForPageSequence(handler, 0);
+ fail("No page sequences created");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected
+ }
+
+ sut.startPageSequence(null);
+ sut.endPageSequence();
+
+ sut.replayEventsForPageSequence(handler, 0);
+
+ InOrder inOrder = inOrder(handler);
+
+ inOrder.verify(handler).startPrefixMapping(
+ InternalElementMapping.STANDARD_PREFIX, InternalElementMapping.URI);
+ inOrder.verify(handler).startPrefixMapping(
+ ExtensionElementMapping.STANDARD_PREFIX, ExtensionElementMapping.URI);
+ inOrder.verify(handler).startElement(eq(IFConstants.NAMESPACE),
+ eq(IFConstants.EL_STRUCTURE_TREE),
+ eq(IFConstants.EL_STRUCTURE_TREE),
+ any(Attributes.class));
+ inOrder.verify(handler).endElement(eq(IFConstants.NAMESPACE),
+ eq(IFConstants.EL_STRUCTURE_TREE),
+ eq(IFConstants.EL_STRUCTURE_TREE));
+ inOrder.verify(handler).endPrefixMapping(ExtensionElementMapping.STANDARD_PREFIX);
+ inOrder.verify(handler).endPrefixMapping(InternalElementMapping.STANDARD_PREFIX);
+ }
+
+ @Test
+ public void startNode() throws Exception {
+ final String[] attributes = {"struct-id", "1"};
+ final String nodeName = "block";
+ final ContentHandler handler = mock(ContentHandler.class);
+
+ sut.startPageSequence(null);
+ sut.startNode(nodeName, createSimpleAttributes(attributes));
+ sut.endPageSequence();
+
+ sut.replayEventsForPageSequence(handler, 0);
+
+ verify(handler).startElement(eq(FOElementMapping.URI), eq(nodeName),
+ eq(FOElementMapping.STANDARD_PREFIX + ":" + nodeName),
+ AttributesMatcher.match(createSimpleAttributes(attributes)));
+ }
+
+ @Test
+ public void endNode() throws Exception {
+ final String nodeName = "block";
+ final ContentHandler handler = mock(ContentHandler.class);
+
+ sut.startPageSequence(null);
+ sut.endNode(nodeName);
+ sut.endPageSequence();
+
+ sut.replayEventsForPageSequence(handler, 0);
+
+ verify(handler).endElement(eq(FOElementMapping.URI), eq(nodeName),
+ eq(FOElementMapping.STANDARD_PREFIX + ":" + nodeName));
+ }
+
+ private static Attributes createSimpleAttributes(String... attributes) {
+ assert (attributes.length % 2 == 0);
+ final AttributesImpl atts = new AttributesImpl();
+ for (int i = 0; i < attributes.length; i += 2) {
+ String key = attributes[i];
+ String value = attributes[i + 1];
+ atts.addAttribute("", key, key, XMLUtil.CDATA, value);
+ }
+ return atts;
+ }
+
+ private static final class AttributesMatcher extends ArgumentMatcher<Attributes> {
+
+ private final Attributes expected;
+
+ private AttributesMatcher(Attributes expected) {
+ this.expected = expected;
+ }
+
+ public static Attributes match(Attributes expected) {
+ return argThat(new AttributesMatcher(expected));
+ }
+
+ public boolean matches(Object attributes) {
+ return attributesEqual(expected, (Attributes) attributes);
+ }
+
+ private static boolean attributesEqual(Attributes attributes1, Attributes attributes2) {
+ if (attributes1.getLength() != attributes2.getLength()) {
+ return false;
+ }
+ for (int i = 0; i < attributes1.getLength(); i++) {
+ if (attributes1.getLocalName(i) != attributes2.getLocalName(i)) {
+ return false;
+ }
+ if (attributes1.getQName(i) != attributes2.getQName(i)) {
+ return false;
+ }
+ if (attributes1.getType(i) != attributes2.getType(i)) {
+ return false;
+ }
+ if (attributes1.getURI(i) != attributes2.getURI(i)) {
+ return false;
+ }
+ if (attributes1.getValue(i) != attributes2.getValue(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/test/java/org/apache/fop/render/intermediate/SAXEventRecorderTestCase.java b/test/java/org/apache/fop/render/intermediate/SAXEventRecorderTestCase.java
new file mode 100644
index 000000000..c5aad66d0
--- /dev/null
+++ b/test/java/org/apache/fop/render/intermediate/SAXEventRecorderTestCase.java
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.intermediate;
+
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.render.intermediate.IFStructureTreeBuilder.SAXEventRecorder;
+import org.apache.fop.util.XMLUtil;
+
+/**
+ * Tests {@link SAXEventRecorder}.
+ */
+public class SAXEventRecorderTestCase {
+
+ private static final String URI = "http://www.example.com/";
+
+ private SAXEventRecorder sut;
+
+ @Before
+ public void setUp() {
+ sut = new SAXEventRecorder();
+ }
+
+ @Test
+ public void testStartEvent() throws SAXException {
+ final String localName = "element";
+ final String qName = "prefix:" + localName;
+ final Attributes attributes = new AttributesImpl();
+
+ sut.startElement(URI, localName, qName, attributes);
+ ContentHandler handler = mock(ContentHandler.class);
+ sut.replay(handler);
+ verify(handler).startElement(URI, localName, qName, attributes);
+ }
+
+ @Test
+ public void testEndEvent() throws SAXException {
+ final String localName = "element";
+ final String qName = "prefix:" + localName;
+ sut.endElement(URI, localName, qName);
+ ContentHandler handler = mock(ContentHandler.class);
+ sut.replay(handler);
+ verify(handler).endElement(URI, localName, qName);
+ }
+
+ @Test
+ public void testStartPrefixMapping() throws SAXException {
+ final String prefix = "prefix";
+
+ sut.startPrefixMapping(URI, prefix);
+ ContentHandler handler = mock(ContentHandler.class);
+ sut.replay(handler);
+ verify(handler).startPrefixMapping(URI, prefix);
+ }
+
+ @Test
+ public void testEndPrefixMapping() throws SAXException {
+ final String prefix = "prefix";
+
+ sut.endPrefixMapping(prefix);
+ ContentHandler handler = mock(ContentHandler.class);
+ sut.replay(handler);
+ verify(handler).endPrefixMapping(prefix);
+ }
+
+ @Test
+ public void completeTest() throws SAXException {
+ final String localName1 = "element";
+ final String qName1 = "prefix:" + localName1;
+ final Attributes attributes1 = createAttributes(URI, localName1, qName1, "value-1");
+ final String localName2 = "element2";
+ final String qName2 = "prefix:" + localName2;
+ final Attributes attributes2 = createAttributes(URI, localName2, qName2, "value-2");
+ final ContentHandler handler = mock(ContentHandler.class);
+ final String extensionUrl = "http://www.example.com/extension";
+ final String extensionPrefix = "ext";
+
+ sut.startPrefixMapping(extensionPrefix, extensionUrl);
+ sut.startElement(URI, localName1, qName1, attributes1);
+ sut.startElement(URI, localName2, qName2, attributes2);
+ sut.endElement(URI, localName2, qName2);
+ sut.endElement(URI, localName1, qName1);
+ sut.endPrefixMapping(extensionPrefix);
+
+ sut.replay(handler);
+
+ InOrder inOrder = inOrder(handler);
+ inOrder.verify(handler).startPrefixMapping(extensionPrefix, extensionUrl);
+ inOrder.verify(handler).startElement(URI, localName1, qName1, attributes1);
+ inOrder.verify(handler).startElement(URI, localName2, qName2, attributes2);
+ inOrder.verify(handler).endElement(URI, localName2, qName2);
+ inOrder.verify(handler).endElement(URI, localName1, qName1);
+ inOrder.verify(handler).endPrefixMapping(extensionPrefix);
+ }
+
+ private static Attributes createAttributes(String uri, String localName,
+ String qName, String value) {
+ final AttributesImpl atts = new AttributesImpl();
+ atts.addAttribute(uri, localName, qName, XMLUtil.CDATA, value);
+ return atts;
+ }
+
+}
diff --git a/test/java/org/apache/fop/util/XMLUtilTestCase.java b/test/java/org/apache/fop/util/LanguageTagsTestCase.java
index 4c1b999e1..f7383c720 100644
--- a/test/java/org/apache/fop/util/XMLUtilTestCase.java
+++ b/test/java/org/apache/fop/util/LanguageTagsTestCase.java
@@ -20,31 +20,39 @@
package org.apache.fop.util;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
import java.util.Locale;
import org.junit.Test;
/**
- * Tests {@link XMLUtil}.
+ * Tests {@link LanguageTags}.
*/
-public class XMLUtilTestCase {
+public class LanguageTagsTestCase {
+
+ @Test(expected = NullPointerException.class)
+ public void toLanguageTagRejectsNull() {
+ LanguageTags.toLanguageTag(null);
+ }
@Test
- public void testLocaleToRFC3066() throws Exception {
- assertNull(XMLUtil.toRFC3066(null));
- assertEquals("en", XMLUtil.toRFC3066(new Locale("en")));
- assertEquals("en-US", XMLUtil.toRFC3066(new Locale("en", "US")));
- assertEquals("en-US", XMLUtil.toRFC3066(new Locale("EN", "us")));
+ public void testToLanguageTag() throws Exception {
+ assertEquals("", LanguageTags.toLanguageTag(new Locale("")));
+ assertEquals("en", LanguageTags.toLanguageTag(new Locale("en")));
+ assertEquals("en-US", LanguageTags.toLanguageTag(new Locale("en", "US")));
+ assertEquals("en-US", LanguageTags.toLanguageTag(new Locale("EN", "us")));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void toLocaleRejectsNull() {
+ LanguageTags.toLocale(null);
}
@Test
public void testRFC3066ToLocale() throws Exception {
- assertNull(XMLUtil.convertRFC3066ToLocale(null));
- assertNull(XMLUtil.convertRFC3066ToLocale(""));
- assertEquals(new Locale("en"), XMLUtil.convertRFC3066ToLocale("en"));
- assertEquals(new Locale("en", "US"), XMLUtil.convertRFC3066ToLocale("en-US"));
- assertEquals(new Locale("en", "US"), XMLUtil.convertRFC3066ToLocale("EN-us"));
+ assertEquals(new Locale(""), LanguageTags.toLocale(""));
+ assertEquals(new Locale("en"), LanguageTags.toLocale("en"));
+ assertEquals(new Locale("en", "US"), LanguageTags.toLocale("en-US"));
+ assertEquals(new Locale("en", "US"), LanguageTags.toLocale("EN-us"));
}
}