001package org.apache.maven.doxia.module.fo;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.io.StringReader;
024import java.io.Writer;
025
026import org.apache.maven.doxia.document.DocumentMeta;
027import org.apache.maven.doxia.document.DocumentModel;
028import org.apache.maven.doxia.document.DocumentTOC;
029import org.apache.maven.doxia.document.DocumentTOCItem;
030import org.apache.maven.doxia.parser.XhtmlBaseParser;
031import org.apache.maven.doxia.sink.Sink;
032import org.apache.maven.doxia.sink.impl.AbstractSinkTest;
033import org.apache.maven.doxia.sink.impl.SinkTestDocument;
034
035/**
036 * <code>FO Sink</code> Test case.
037 *
038 * @version $Id$
039 */
040public class FoSinkTest
041    extends AbstractSinkTest
042{
043    private FoConfiguration config;
044
045    // ----------------------------------------------------------------------
046    // Specific test methods
047    // ----------------------------------------------------------------------
048
049    @Override
050    protected String wrapXml( String xmlFragment )
051    {
052        return "<fo:fo xmlns:fo=\"" + FoMarkup.FO_NAMESPACE + "\">" + xmlFragment + "</fo:fo>";
053    }
054
055    /**
056     * Uses fop to generate a pdf from a test document.
057     * @throws Exception If the conversion fails.
058     */
059    public void testConvertFO2PDF()
060        throws Exception
061    {
062        String fileName = "test";
063        // first create fo
064        FoSink fosink = new FoSink( getTestWriter( fileName ) );
065        fosink.beginDocument();
066        SinkTestDocument.generate( fosink );
067        fosink.endDocument();
068        fosink.close();
069
070        // then generate PDF
071        fo2pdf( fileName );
072    }
073
074    /**
075     * Uses fop to generate an aggregated pdf from two test documents.
076     * @throws Exception If the conversion fails.
077     */
078    public void testAggregateMode()
079        throws Exception
080    {
081        FoAggregateSink fosink = new FoAggregateSink( getTestWriter( "aggregate" ) );
082
083        fosink.setDocumentModel( getModel() );
084
085        fosink.beginDocument();
086
087        fosink.coverPage();
088
089        fosink.toc();
090
091        fosink.setDocumentName( "doc1" );
092        fosink.setDocumentTitle( "Document 1" );
093        SinkTestDocument.generate( fosink );
094
095        // re-use the same source
096        fosink.setDocumentName( "doc2" );
097        fosink.setDocumentTitle( "Document 2" );
098        SinkTestDocument.generate( fosink );
099
100        fosink.endDocument();
101
102        // then generate PDF
103        fo2pdf( "aggregate" );
104    }
105
106    private DocumentModel getModel()
107    {
108        DocumentModel model = new DocumentModel();
109        model.setToc( getToc() );
110        model.setMeta( getMeta() );
111        return model;
112    }
113
114    private DocumentMeta getMeta()
115    {
116        DocumentMeta meta = new DocumentMeta();
117        meta.setAuthor( "The Apache Maven Project" );
118        meta.setTitle( "Doxia FO Sink" );
119        return meta;
120    }
121
122    private DocumentTOC getToc()
123    {
124        DocumentTOCItem item1 = new DocumentTOCItem();
125        item1.setName( "First document" );
126        item1.setRef( "doc1.apt" );
127
128        DocumentTOCItem item2 = new DocumentTOCItem();
129        item2.setName( "Second document" );
130        item2.setRef( "doc2.xml" );
131
132        DocumentTOC toc = new DocumentTOC();
133        toc.setName( "What's in here" );
134        toc.addItem( item1 );
135        toc.addItem( item2 );
136
137        return toc;
138    }
139
140    // ----------------------------------------------------------------------
141    // Abstract methods the individual SinkTests must provide
142    // ----------------------------------------------------------------------
143
144    /** {@inheritDoc} */
145    protected String outputExtension()
146    {
147        return "fo";
148    }
149
150    /** {@inheritDoc} */
151    protected Sink createSink( Writer writer )
152    {
153        return new FoSink( writer );
154    }
155
156    /** {@inheritDoc} */
157    protected boolean isXmlSink()
158    {
159        return true;
160    }
161
162    /** {@inheritDoc} */
163    protected String getTitleBlock( String title )
164    {
165        String attribs = getConfig().getAttributeString( "doc.header.title" );
166        return EOL + "<fo:block" + attribs + ">" + title + "</fo:block>" + EOL;
167    }
168
169    /** {@inheritDoc} */
170    protected String getAuthorBlock( String author )
171    {
172        String attribs = getConfig().getAttributeString( "doc.header.author" );
173        return EOL + "<fo:block" + attribs + ">" + author + "</fo:block>" + EOL;
174    }
175
176    /** {@inheritDoc} */
177    protected String getDateBlock( String date )
178    {
179        String attribs = getConfig().getAttributeString( "doc.header.date" );
180        return EOL + "<fo:block" + attribs + ">" + date + "</fo:block>" + EOL;
181    }
182
183    // TODO
184    protected String getHeadBlock()
185    {
186        return "";
187    }
188
189    // TODO: remove
190    public void testHead()
191    {
192        String expected = "";
193        assertEquals( "Wrong head!", expected, getHeadBlock() );
194    }
195
196    /** {@inheritDoc} */
197    protected String getBodyBlock()
198    {
199        return EOL + "</fo:flow>" + EOL + "</fo:page-sequence>" + EOL + "</fo:root>" + EOL;
200    }
201
202    /** {@inheritDoc} */
203    protected String getSectionTitleBlock( String title )
204    {
205        return title;
206    }
207
208    /** {@inheritDoc} */
209    protected String getSection1Block( String title )
210    {
211        String attribs = getConfig().getAttributeString( "body.text" );
212        String attrib2 = getConfig().getAttributeString( "body.h1" );
213        return EOL + EOL + "<fo:block" + attribs + ">" + EOL + EOL + "<fo:block" + attrib2 + ">1   " + title
214            + "</fo:block>" + EOL + "</fo:block>" + EOL;
215    }
216
217    /** {@inheritDoc} */
218    protected String getSection2Block( String title )
219    {
220        String attribs = getConfig().getAttributeString( "body.text" );
221        String attrib2 = getConfig().getAttributeString( "body.h2" );
222        return EOL + EOL + "<fo:block" + attribs + ">" + EOL + EOL + "<fo:block" + attrib2 + ">0.1   " + title
223            + "</fo:block>" + EOL + "</fo:block>" + EOL;
224    }
225
226    /** {@inheritDoc} */
227    protected String getSection3Block( String title )
228    {
229        String attribs = getConfig().getAttributeString( "body.text" );
230        String attrib2 = getConfig().getAttributeString( "body.h3" );
231        return EOL + EOL + "<fo:block" + attribs + ">" + EOL + EOL + "<fo:block" + attrib2 + ">0.0.1   " + title
232            + "</fo:block>" + EOL + "</fo:block>" + EOL;
233    }
234
235    /** {@inheritDoc} */
236    protected String getSection4Block( String title )
237    {
238        String attribs = getConfig().getAttributeString( "body.text" );
239        String attrib2 = getConfig().getAttributeString( "body.h4" );
240        return EOL + EOL + "<fo:block" + attribs + ">" + EOL + EOL + "<fo:block" + attrib2 + ">" + title
241            + "</fo:block>" + EOL + "</fo:block>" + EOL;
242    }
243
244    /** {@inheritDoc} */
245    protected String getSection5Block( String title )
246    {
247        String attribs = getConfig().getAttributeString( "body.text" );
248        String attrib2 = getConfig().getAttributeString( "body.h5" );
249        return EOL + EOL + "<fo:block" + attribs + ">" + EOL + EOL + "<fo:block" + attrib2 + ">" + title
250            + "</fo:block>" + EOL + "</fo:block>" + EOL;
251    }
252
253    /** {@inheritDoc} */
254    protected String getListBlock( String item )
255    {
256        String attribs = getConfig().getAttributeString( "list" );
257        String itemAttribs = getConfig().getAttributeString( "list.item" );
258        return EOL + EOL + "<fo:list-block" + attribs + ">" + EOL + "<fo:list-item" + itemAttribs
259            + "><fo:list-item-label><fo:block>&#8226;</fo:block></fo:list-item-label>" + EOL + EOL
260            + "<fo:list-item-body" + itemAttribs + ">" + EOL + "<fo:block>" + item + "</fo:block>" + EOL
261            + "</fo:list-item-body>" + EOL + "</fo:list-item>" + EOL + "</fo:list-block>" + EOL;
262    }
263
264    /** {@inheritDoc} */
265    protected String getNumberedListBlock( String item )
266    {
267        String attribs = getConfig().getAttributeString( "list" );
268        String itemAttribs = getConfig().getAttributeString( "list.item" );
269        return EOL + EOL + "<fo:list-block" + attribs + ">" + EOL + "<fo:list-item" + itemAttribs + ">" + EOL
270            + "<fo:list-item-label>" + EOL + "<fo:block>i.</fo:block>" + EOL + "</fo:list-item-label>" + EOL + EOL
271            + "<fo:list-item-body" + itemAttribs + ">" + EOL + "<fo:block>" + item + "</fo:block>" + EOL
272            + "</fo:list-item-body>" + EOL + "</fo:list-item>" + EOL + "</fo:list-block>" + EOL;
273    }
274
275    /** {@inheritDoc} */
276    protected String getDefinitionListBlock( String definum, String definition )
277    {
278        String dlAtts = getConfig().getAttributeString( "dl" );
279        String dtAtts = getConfig().getAttributeString( "dt" );
280        String ddAtts = getConfig().getAttributeString( "dd" );
281        return EOL + EOL + "<fo:block" + dlAtts + ">" + EOL + "<fo:block" + dtAtts + ">" + definum + "</fo:block>"
282            + EOL + EOL + EOL + "<fo:block" + ddAtts + ">" + definition + "</fo:block>" + EOL + "</fo:block>"
283            + EOL;
284    }
285
286    /** {@inheritDoc} */
287    protected String getFigureBlock( String source, String caption )
288    {
289        String dlAtts = getConfig().getAttributeString( "figure.display" );
290        String dtAtts = getConfig().getAttributeString( "figure.graphics" );
291        String ddAtts = getConfig().getAttributeString( "figure.caption" );
292
293        String figureBlock = EOL + EOL + "<fo:block" + dlAtts + "><fo:external-graphic" + " src=\"" + source + "\"" + dtAtts
294            + "/>" + EOL;
295        if ( caption != null )
296        {
297            figureBlock += EOL + "<fo:block" + ddAtts + ">" + caption + "</fo:block>" + EOL;
298        }
299        figureBlock +=  "</fo:block>" + EOL;
300        
301        
302        return figureBlock;
303    }
304
305    /** {@inheritDoc} */
306    protected String getTableBlock( String cell, String caption )
307    {
308        String dlAtts = getConfig().getAttributeString( "table.padding" );
309        String dtAtts = getConfig().getAttributeString( "table.layout" );
310        String ddAtts = getConfig().getAttributeString( "table.body.row" );
311        // String deAtts = getConfig().getAttributeString( "table.body.cell" );
312
313        return EOL + EOL + "<fo:block" + dlAtts + ">" + EOL + "<fo:table" + dtAtts + ">" + EOL
314            + "<fo:table-column column-width=\"proportional-column-width(1)\"/>" + EOL + EOL + "<fo:table-body>"
315            + EOL + "<fo:table-row" + ddAtts
316            + "><fo:table-cell column-number=\"1\" padding-after=\"1.5pt\" padding-end=\"5pt\" "
317            + "keep-together.within-column=\"always\" padding-start=\"2.5pt\" "
318            + "background-color=\"#eeeeee\" padding-before=\"4pt\">" + EOL + "<fo:block line-height=\"1.2em\" "
319            + "text-align=\"center\" font-family=\"Helvetica,sans-serif\" font-size=\"9pt\">" + EOL + cell
320            + "</fo:block>" + EOL + "</fo:table-cell>" + EOL + "</fo:table-row>" + EOL + "</fo:table-body>" + EOL
321            + "</fo:table>" + EOL + "</fo:block>" + EOL + EOL
322            + "<fo:block white-space-collapse=\"true\" space-after=\"6pt\" space-before=\"3pt\" "
323            + "font-family=\"Garamond,serif\" line-height=\"12pt\" text-align=\"center\" font-size=\"11pt\">"
324            + "Table_caption</fo:block>" + EOL;
325    }
326
327    /** {@inheritDoc} */
328    protected String getParagraphBlock( String text )
329    {
330        String attribs = getConfig().getAttributeString( "normal.paragraph" );
331        return EOL + "<fo:block" + attribs + ">" + text + "</fo:block>" + EOL;
332    }
333
334    /** {@inheritDoc} */
335    protected String getVerbatimBlock( String text )
336    {
337        String attribs = getConfig().getAttributeString( "body.source" );
338        return EOL + "<fo:block" + attribs + ">" + text + "</fo:block>" + EOL;
339    }
340
341    /** {@inheritDoc} */
342    protected String getHorizontalRuleBlock()
343    {
344        String attribs = getConfig().getAttributeString( "body.rule" );
345        return EOL + EOL + "<fo:block>" + EOL + "<fo:leader" + attribs + " /></fo:block>" + EOL;
346    }
347
348    /** {@inheritDoc} */
349    protected String getPageBreakBlock()
350    {
351        return EOL + "<fo:block break-before=\"page\" />" + EOL;
352    }
353
354    /** {@inheritDoc} */
355    protected String getAnchorBlock( String anchor )
356    {
357        // all anchors get '#' pre-pended
358        return EOL + "<fo:inline id=\"#" + anchor + "\">" + anchor + "</fo:inline>";
359    }
360
361    /** {@inheritDoc} */
362    protected String getLinkBlock( String link, String text )
363    {
364        String attribs = getConfig().getAttributeString( "href.internal" );
365        return EOL + "<fo:basic-link internal-destination=\"" + link + "\">" + EOL + "<fo:inline" + attribs + ">"
366            + text + "</fo:inline></fo:basic-link>";
367    }
368
369    /** {@inheritDoc} */
370    protected String getItalicBlock( String text )
371    {
372        String attribs = getConfig().getAttributeString( "italic" );
373        return EOL + "<fo:inline" + attribs + ">" + text + "</fo:inline>";
374    }
375
376    /** {@inheritDoc} */
377    protected String getBoldBlock( String text )
378    {
379        String attribs = getConfig().getAttributeString( "bold" );
380        return EOL + "<fo:inline" + attribs + ">" + text + "</fo:inline>";
381    }
382
383    /** {@inheritDoc} */
384    protected String getMonospacedBlock( String text )
385    {
386        String attribs = getConfig().getAttributeString( "monospace" );
387        return EOL + "<fo:inline" + attribs + ">" + text + "</fo:inline>";
388    }
389
390    /** {@inheritDoc} */
391    protected String getLineBreakBlock()
392    {
393        return EOL + EOL + "<fo:block />";
394    }
395
396    /** {@inheritDoc} */
397    protected String getNonBreakingSpaceBlock()
398    {
399        return "&#160;";
400    }
401
402    /** {@inheritDoc} */
403    protected String getTextBlock( String text )
404    {
405        return FoSink.escaped( text, false );
406    }
407
408    /** {@inheritDoc} */
409    protected String getRawTextBlock( String text )
410    {
411        return text;
412    }
413
414    // ----------------------------------------------------------------------
415    // Auxiliary methods
416    // ----------------------------------------------------------------------
417
418    private void fo2pdf( String baseName )
419        throws Exception
420    {
421        // File outputDirectory = new File( getBasedirFile(), getOutputDir() );
422        File outputDirectory = new File( getBasedir(), outputBaseDir() + getOutputDir() );
423        File resourceDirectory = new File( getBasedirFile(), "target/test-classes" );
424        File foFile = new File( outputDirectory, baseName + "." + outputExtension() );
425        File pdfFile = new File( outputDirectory, baseName + ".pdf" );
426        FoUtils.convertFO2PDF( foFile, pdfFile, resourceDirectory.getCanonicalPath() );
427    }
428
429    private FoConfiguration getConfig()
430    {
431        if ( config == null )
432        {
433            config = ( (FoSink) getSink() ).getFoConfiguration();
434        }
435
436        return config;
437    }
438
439    /** {@inheritDoc} */
440    protected String getCommentBlock( String text )
441    {
442        return "<!--" + toXmlComment( text ) + "-->";
443    }
444
445    /**
446     * DOXIA-357
447     *
448     * @throws Exception if any
449     */
450    public void testTableCaption()
451        throws Exception
452    {
453        StringBuilder html = new StringBuilder();
454        html.append( "<table>" ).append( EOL );
455        html.append( "<caption>caption table</caption>" ).append( EOL );
456        html.append( "<tr>" ).append( EOL );
457        html.append( "<td>foo</td>" ).append( EOL );
458        html.append( "</tr>" ).append( EOL );
459        html.append( "<tr>" ).append( EOL );
460        html.append( "<td>bar</td>" ).append( EOL );
461        html.append( "</tr>" ).append( EOL );
462        html.append( "</table>" ).append( EOL );
463
464        String fileName = "testTableCaption";
465
466        // first create fo
467        FoSink fosink = new FoSink( getTestWriter( fileName ) );
468        fosink.beginDocument();
469        SinkTestDocument.generateHead( fosink );
470
471        fosink.body();
472        XhtmlBaseParser parser = new XhtmlBaseParser();
473        parser.parse( new StringReader( html.toString() ), fosink );
474        fosink.body_();
475
476        fosink.endDocument();
477        fosink.close();
478
479        // then generate PDF
480        fo2pdf( fileName );
481    }
482
483    /**
484     * @throws Exception if any
485     */
486    public void testNestedTables()
487        throws Exception
488    {
489        StringBuilder html = new StringBuilder();
490        html.append( "<table>" ).append( EOL );
491        html.append( "<caption>first caption</caption>" ).append( EOL );
492        html.append( "<tr>" ).append( EOL );
493        html.append( "<td>foo</td>" ).append( EOL );
494        html.append( "</tr>" ).append( EOL );
495        html.append( "<tr>" ).append( EOL );
496        html.append( "<td>" ).append( EOL );
497
498        html.append( "<table>" ).append( EOL );
499        html.append( "<caption>second caption</caption>" ).append( EOL );
500        html.append( "<tr>" ).append( EOL );
501        html.append( "<td>foo</td>" ).append( EOL );
502        html.append( "<td>bar</td>" ).append( EOL );
503        html.append( "</tr>" ).append( EOL );
504        html.append( "<tr>" ).append( EOL );
505        html.append( "<td>foo1</td>" ).append( EOL );
506        html.append( "<td>" ).append( EOL );
507
508        html.append( "<table>" ).append( EOL );
509        html.append( "<caption>third caption</caption>" ).append( EOL );
510        html.append( "<tr>" ).append( EOL );
511        html.append( "<td>foo1</td>" ).append( EOL );
512        html.append( "<td>bar1</td>" ).append( EOL );
513        html.append( "</tr>" ).append( EOL );
514        html.append( "</table>" ).append( EOL );
515        html.append( "</td>" ).append( EOL );
516
517        html.append( "</tr>" ).append( EOL );
518        html.append( "</table>" ).append( EOL );
519
520        html.append( "</td>" ).append( EOL );
521        html.append( "</tr>" ).append( EOL );
522        html.append( "</table>" ).append( EOL );
523
524        String fileName = "testNestedTables";
525
526        // first create fo
527        FoSink fosink = new FoSink( getTestWriter( fileName ) );
528        fosink.beginDocument();
529        SinkTestDocument.generateHead( fosink );
530
531        fosink.body();
532        XhtmlBaseParser parser = new XhtmlBaseParser();
533        parser.parse( new StringReader( html.toString() ), fosink );
534        fosink.body_();
535
536        fosink.endDocument();
537        fosink.close();
538
539        // then generate PDF
540        fo2pdf( fileName );
541    }
542}