001package org.apache.maven.doxia.module.apt;
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.IOException;
023import java.io.Reader;
024import java.io.StringWriter;
025import java.io.Writer;
026import java.util.Iterator;
027
028import org.apache.maven.doxia.parser.AbstractParserTest;
029import org.apache.maven.doxia.parser.Parser;
030import org.apache.maven.doxia.parser.ParseException;
031
032import org.apache.maven.doxia.sink.Sink;
033import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
034import org.apache.maven.doxia.sink.impl.SinkEventElement;
035import org.apache.maven.doxia.sink.impl.SinkEventTestingSink;
036import org.codehaus.plexus.util.IOUtil;
037
038/**
039 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
040 * @version $Id$
041 */
042public class AptParserTest
043    extends AbstractParserTest
044{
045
046    private AptParser parser;
047
048    @Override
049    protected void setUp()
050        throws Exception
051    {
052        super.setUp();
053
054        parser = (AptParser) lookup( Parser.ROLE, "apt" );
055    }
056
057    /** {@inheritDoc} */
058    protected Parser createParser()
059    {
060        return parser;
061    }
062
063    protected String parseFileToAptSink( String file )
064        throws ParseException
065    {
066        StringWriter output = null;
067        Reader reader = null;
068        try
069        {
070            output = new StringWriter();
071            reader = getTestReader( file );
072
073            Sink sink = new AptSink( output );
074            createParser().parse( reader, sink );
075        }
076        finally
077        {
078            IOUtil.close( output );
079            IOUtil.close( reader );
080        }
081
082        return output.toString();
083    }
084
085    /** @throws Exception  */
086    public void testLineBreak()
087        throws Exception
088    {
089        String linebreak = parseFileToAptSink( "test/linebreak" );
090
091        assertTrue( linebreak.indexOf( "Line\\" + EOL + "break." ) != -1 );
092    }
093
094    /** @throws Exception  */
095    public void testSnippetMacro()
096        throws Exception
097    {
098        String macro = parseFileToAptSink( "test/macro" );
099
100        assertTrue( macro.indexOf( "<modelVersion\\>4.0.0\\</modelVersion\\>" ) != -1 );
101    }
102
103    /** @throws Exception  */
104    public void testCommentsBeforeTitle()
105        throws Exception
106    {
107        String comments = parseFileToAptSink( "test/comments" );
108
109        assertEquals( 0, comments.indexOf( "~~ comments before title" + EOL + "~~ like a license header, for example"
110            + EOL + " -----" + EOL + " Test DOXIA-379" ) );
111    }
112
113    /** @throws Exception  */
114    public void testSnippet()
115        throws Exception
116    {
117        // DOXIA-259
118
119        Reader reader = null;
120        SinkEventTestingSink sink = new SinkEventTestingSink();
121
122        try
123        {
124            reader = getTestReader( "test/snippet" );
125
126            createParser().parse( reader, sink );
127        }
128        finally
129        {
130            IOUtil.close( reader );
131        }
132
133        Iterator<SinkEventElement> it = sink.getEventList().iterator();
134
135        assertEquals( it, "head", "head_", "body", "list", "listItem", "text", "verbatim", "text", "verbatim_",
136                      "paragraph", "text", "paragraph_", "listItem_", "listItem", "text", "verbatim", "text",
137                      "verbatim_", "paragraph", "text", "paragraph_", "listItem_", "list_", "body_" );
138    }
139
140
141    /** @throws Exception  */
142    public void testSnippetTrailingSpace()
143        throws Exception
144    {
145        // DOXIA-425
146        String text = "%{snippet|id=myid|file=pom.xml}  " + EOL;
147
148        SinkEventTestingSink sink = new SinkEventTestingSink();
149
150        parser.parse( text, sink );
151
152        Iterator<SinkEventElement> it = sink.getEventList().iterator();
153
154        assertEquals( it, "head", "head_", "body", "verbatim", "text", "verbatim_", "body_" );
155    }
156
157    /** @throws Exception  */
158    public void testTocMacro()
159        throws Exception
160    {
161        String toc = parseFileToAptSink( "test/toc" );
162
163        // No section, only subsection 1 and 2
164        assertTrue( toc.indexOf( "* {{{SubSection_1.1}SubSection 1.1}}" ) != -1 );
165        assertTrue( toc.indexOf( "* {{{SubSection_1.1.2.1.1}SubSection 1.1.2.1.1}}" ) == -1 );
166    }
167
168    /**
169     * Parses the test document test.apt and re-emits
170     * it into parser/test.apt.
171     *
172     * @throws java.io.IOException if the test file cannot be read.
173     * @throws org.apache.maven.doxia.parser.ParseException if the test file cannot be parsed.
174     */
175    public void testTestDocument()
176        throws IOException, ParseException
177    {
178        Writer writer = null;
179        Reader reader = null;
180        try
181        {
182            writer = getTestWriter( "test" );
183            reader = getTestReader( "test" );
184
185            Sink sink = new AptSink( writer );
186
187            createParser().parse( reader, sink );
188        }
189        finally
190        {
191            IOUtil.close( writer );
192            IOUtil.close( reader );
193        }
194    }
195
196    /** @throws Exception  */
197    public void testBoxedVerbatim()
198        throws Exception
199    {
200        String text = "+--" + EOL + "boxed verbatim" + EOL + "+--" + EOL
201                + "---" + EOL + "un-boxed verbatim" + EOL + "---" + EOL;
202
203        SinkEventTestingSink sink = new SinkEventTestingSink();
204
205        parser.parse( text, sink );
206
207        Iterator<SinkEventElement> it = sink.getEventList().iterator();
208
209        assertStartsWith( it, "head", "head_", "body" );
210        assertEquals( it.next(), "verbatim", SinkEventAttributeSet.BOXED );
211        assertStartsWith( it, "text", "verbatim_" );
212
213        assertEquals( it.next(), "verbatim", new Object[] { null } );
214        assertEquals( it, "text", "verbatim_", "body_" );
215    }
216
217    /** @throws Exception  */
218    public void testMultiLinesInTableCells()
219        throws Exception
220    {
221        String text = "*----------*--------------+----------------:" + EOL +
222                " cell 1, | cell 1,2       | cell 1,3" + EOL +
223                " 1       |                | " + EOL +
224                "*----------*--------------+----------------:" + EOL +
225                " cell 2,1 | cell 2,       | cell 2,3" + EOL +
226                "          | 2             |" + EOL +
227                "*----------*--------------+----------------:" + EOL +
228                " cell 3,1 | cell 3,2      | cell 3," + EOL +
229                "          |               | 3" + EOL +
230                "*----------*--------------+----------------:" + EOL;
231
232        SinkEventTestingSink sink = new SinkEventTestingSink();
233
234        parser.parse( text, sink );
235
236        Iterator<SinkEventElement> it = sink.getEventList().iterator();
237
238        assertStartsWith( it, "head", "head_", "body", "table", "tableRows", "tableRow", "tableCell" );
239        assertEquals( it.next(), "text", "cell 1, 1" );
240
241        assertStartsWith( it, "tableCell_", "tableCell" );
242        assertEquals( it.next(), "text", "cell 1,2" );
243
244        assertStartsWith( it, "tableCell_", "tableCell" );
245        assertEquals( it.next(), "text", "cell 1,3" );
246
247        assertStartsWith( it, "tableCell_", "tableRow_", "tableRow", "tableCell" );
248        assertEquals( it.next(), "text", "cell 2,1" );
249
250        assertStartsWith( it, "tableCell_", "tableCell" );
251        assertEquals( it.next(), "text", "cell 2, 2" );
252
253        assertStartsWith( it, "tableCell_", "tableCell" );
254        assertEquals( it.next(), "text", "cell 2,3" );
255        
256        assertStartsWith( it, "tableCell_", "tableRow_", "tableRow", "tableCell" );
257        assertEquals( it.next(), "text", "cell 3,1" );
258
259        assertStartsWith( it, "tableCell_", "tableCell" );
260        assertEquals( it.next(), "text", "cell 3,2" );
261
262        assertStartsWith( it, "tableCell_", "tableCell" );
263        assertEquals( it.next(), "text", "cell 3, 3" );
264
265        assertEquals( it, "tableCell_", "tableRow_", "tableRows_", "table_", "body_" );
266    }
267
268    /** @throws Exception  */
269    public void testLineBreakInTableCells()
270        throws Exception
271    {
272        String text = "*----------*--------------+----------------:" + EOL +
273                " cell 1,\\ | cell 1,2       | cell 1,3" + EOL +
274                " 1       |                | " + EOL +
275                "*----------*--------------+----------------:" + EOL +
276                " cell 2,1 | cell 2,\\     | cell 2,3" + EOL +
277                "          | 2             |" + EOL +
278                "*----------*--------------+----------------:" + EOL +
279                " cell 3,1 | cell 3,2      | cell 3,\\" + EOL +
280                "          |               | 3" + EOL +
281                "*----------*--------------+----------------:" + EOL;
282
283        SinkEventTestingSink sink = new SinkEventTestingSink();
284
285        parser.parse( text, sink );
286
287        Iterator<SinkEventElement> it = sink.getEventList().iterator();
288
289        assertStartsWith( it, "head", "head_", "body", "table", "tableRows", "tableRow", "tableCell" );
290        assertEquals( it.next(), "text", "cell 1,\u00A0" );
291
292        assertEquals( it.next().getName(), "lineBreak" );
293        assertEquals( it.next(), "text", "1" );
294
295        assertStartsWith( it, "tableCell_", "tableCell" );
296        assertEquals( it.next(), "text", "cell 1,2" );
297
298        assertStartsWith( it, "tableCell_", "tableCell" );
299        assertEquals( it.next(), "text", "cell 1,3" );
300
301        assertStartsWith( it, "tableCell_", "tableRow_", "tableRow", "tableCell" );
302        assertEquals( it.next(), "text", "cell 2,1" );
303
304        assertStartsWith( it, "tableCell_", "tableCell" );
305        assertEquals( it.next(), "text", "cell 2,\u00A0" );
306
307        assertEquals( it.next().getName(), "lineBreak" );
308        assertEquals( it.next(), "text", "2" );
309
310        assertStartsWith( it, "tableCell_", "tableCell" );
311        assertEquals( it.next(), "text", "cell 2,3" );
312
313        assertStartsWith( it, "tableCell_", "tableRow_", "tableRow", "tableCell" );
314        assertEquals( it.next(), "text", "cell 3,1" );
315
316        assertStartsWith( it, "tableCell_", "tableCell" );
317        assertEquals( it.next(), "text", "cell 3,2" );
318
319        assertStartsWith( it, "tableCell_", "tableCell" );
320        assertEquals( it.next(), "text", "cell 3,\u00A0" );
321
322        assertEquals( it.next().getName(), "lineBreak" );
323        assertEquals( it.next(), "text", "3" );
324
325        assertEquals( it, "tableCell_", "tableRow_", "tableRows_", "table_", "body_" );
326    }
327
328    /** @throws Exception  */
329    public void testDOXIA38()
330        throws Exception
331    {
332        String text =
333                "*----------*--------------*---------------*" + EOL +
334                "| Centered |   Centered   |   Centered    |" + EOL +
335                "*----------*--------------+---------------:" + EOL +
336                "| Centered | Left-aligned | Right-aligned |" + EOL +
337                "*----------*--------------+---------------:";
338
339        SinkEventTestingSink sink = new SinkEventTestingSink();
340
341        parser.parse( text, sink );
342
343        Iterator<SinkEventElement> it = sink.getEventList().iterator();
344
345        assertStartsWith( it, "head", "head_", "body", "table", "tableRows", "tableRow" );
346        assertAttributeEquals( it.next(), "tableCell", SinkEventAttributeSet.ALIGN, "center" );
347        assertEquals( it.next(), "text", "Centered" );
348        assertEquals( it.next().getName(), "tableCell_" );
349        
350        assertAttributeEquals( it.next(), "tableCell", SinkEventAttributeSet.ALIGN, "center" );
351        assertEquals( it.next(), "text", "Centered" );
352        assertEquals( it.next().getName(), "tableCell_" );
353        
354        assertAttributeEquals( it.next(), "tableCell", SinkEventAttributeSet.ALIGN, "center" );
355        assertEquals( it.next(), "text", "Centered" );
356        assertStartsWith( it, "tableCell_", "tableRow_", "tableRow" );
357        
358        assertAttributeEquals( it.next(), "tableCell", SinkEventAttributeSet.ALIGN, "center" );
359        assertEquals( it.next(), "text", "Centered" );
360        assertEquals( it.next().getName(), "tableCell_" );
361        
362        assertAttributeEquals( it.next(), "tableCell", SinkEventAttributeSet.ALIGN, "left" );
363        assertEquals( it.next(), "text", "Left-aligned" );
364        assertEquals( it.next().getName(), "tableCell_" );
365        
366        assertAttributeEquals( it.next(), "tableCell", SinkEventAttributeSet.ALIGN, "right" );
367        assertEquals( it.next(), "text", "Right-aligned" );
368        assertEquals( it, "tableCell_", "tableRow_", "tableRows_", "table_", "body_" );
369    }
370
371    /** @throws Exception  */
372    public void testSpecialCharactersInTables()
373        throws Exception
374    {
375        // DOXIA-323, DOXIA-433
376        String text =
377                "  \\~ \\= \\- \\+ \\* \\[ \\] \\< \\> \\{ \\} \\\\ \\u2713" + EOL
378                + EOL
379                + "*--------------------------------------------------+---------------+" + EOL
380                + "| \\~ \\= \\- \\+ \\* \\[ \\] \\< \\> \\{ \\} \\\\ \\u2713 | special chars |" + EOL
381                + "*--------------------------------------------------+---------------+";
382
383        SinkEventTestingSink sink = new SinkEventTestingSink();
384        parser.parse( text, sink );
385
386        Iterator<SinkEventElement> it = sink.getEventList().iterator();
387
388        assertStartsWith( it, "head", "head_", "body", "paragraph" );
389        assertEquals( it.next(), "text", "~ = - + * [ ] < > { } \\ \u2713" );
390
391        assertStartsWith( it, "paragraph_", "table", "tableRows", "tableRow", "tableCell" );
392        assertEquals( it.next(), "text", "~ = - + * [ ] < > { } \\ \u2713" );
393
394        assertEquals( it, "tableCell_", "tableCell", "text", "tableCell_", "tableRow_", "tableRows_", "table_", "body_" );
395    }
396
397    /** @throws Exception  */
398    public void testSpacesAndBracketsInAnchors()
399        throws Exception
400    {
401        final String text = "  {Anchor with spaces (and brackets)}" + EOL
402            + "  Link to {{Anchor with spaces (and brackets)}}" + EOL
403            + "  {{{http://fake.api#method(with, args)}method(with, args)}}" + EOL;
404
405        final SinkEventTestingSink sink = new SinkEventTestingSink();
406
407        parser.parse( text, sink );
408
409        Iterator<SinkEventElement> it = sink.getEventList().iterator();
410
411        assertStartsWith( it, "head", "head_", "body", "paragraph" );
412        assertEquals( it.next(), "anchor", "Anchor_with_spaces_and_brackets" );
413
414        assertEquals( it.next(), "text", "Anchor with spaces (and brackets)" );
415
416        assertStartsWith( it, "anchor_", "text" );
417        assertEquals( it.next(), "link", "#Anchor_with_spaces_and_brackets" );
418
419        assertEquals( it.next(), "text", "Anchor with spaces (and brackets)" );
420
421        assertStartsWith( it, "link_", "text" );
422        assertEquals( it.next(), "link", "http://fake.api#method(with, args)" );
423
424        assertEquals( it.next(), "text", "method(with, args)" );
425
426        assertEquals( it, "link_", "paragraph_", "body_" );
427    }
428
429    /** @throws Exception  */
430    public void testSectionTitleAnchors()
431        throws Exception
432    {
433        // DOXIA-420
434        String text = "Enhancements to the APT format" + EOL + EOL
435            + "{Title with anchor}" + EOL;
436
437        SinkEventTestingSink sink = new SinkEventTestingSink();
438
439        parser.parse( text, sink );
440
441        Iterator<SinkEventElement> it = sink.getEventList().iterator();
442
443        assertEquals( it, "head", "head_", "body", "section1", "sectionTitle1", "text", "sectionTitle1_", "section1_",
444                      "section1", "sectionTitle1", "anchor", "text", "anchor_", "sectionTitle1_", "section1_", "body_" );
445    }
446    
447    /**
448     * @throws Exception
449     */
450    public void testTableHeaders() throws Exception
451    {
452        // DOXIA-404
453        String text = "*-----------+-----------+" + EOL + 
454                        "|| Header 1 || Header 2 |" + EOL +
455                        "*-----------+-----------+" + EOL +
456                        "  Cell 1    | Cell 2    |" + EOL +
457                        "*-----------+-----------+" + EOL +
458                        "  Cell 3    | Cell 4    |" + EOL +
459                        "*-----------+-----------+" + EOL;
460        
461        SinkEventTestingSink sink = new SinkEventTestingSink();
462
463        parser.parse( text, sink );
464
465        Iterator<SinkEventElement> it = sink.getEventList().iterator();
466
467        assertStartsWith( it, "head", "head_", "body", "table", "tableRows" );
468        assertStartsWith( it, "tableRow", "tableHeaderCell", "text", "tableHeaderCell_", "tableHeaderCell", "text",
469                          "tableHeaderCell_", "tableRow_" );
470        assertStartsWith( it, "tableRow", "tableCell", "text", "tableCell_", "tableCell", "text", "tableCell_",
471                          "tableRow_" );
472        assertStartsWith( it, "tableRow", "tableCell", "text", "tableCell_", "tableCell", "text", "tableCell_",
473                          "tableRow_" );
474        assertEquals( it, "tableRows_", "table_", "body_" );
475    }
476    
477    public void testEscapedPipeInTableCell() throws Exception
478    {
479        // DOXIA-479
480        String text="*---+---+" + EOL + 
481                        "| cell \\| pipe | next cell " + EOL + 
482                        "*---+---+" + EOL;
483        
484        SinkEventTestingSink sink = new SinkEventTestingSink();
485
486        parser.parse( text, sink );
487
488        Iterator<SinkEventElement> it = sink.getEventList().iterator();
489        assertStartsWith( it, "head", "head_", "body", "table", "tableRows", "tableRow", "tableCell" );
490        assertEquals( it.next(), "text", "cell | pipe" );
491        assertStartsWith( it, "tableCell_", "tableCell" );
492        assertEquals( it.next(), "text", "next cell" );
493        assertEquals( it, "tableCell_", "tableRow_", "tableRows_", "table_", "body_" );
494    }
495
496    public void testLiteralAnchor()
497        throws Exception
498    {
499        // DOXIA-397
500        String text =
501            "{{{../apidocs/groovyx/net/http/ParserRegistry.html##parseText(org.apache.http.HttpResponse)}ParserRegistry}}";
502
503        SinkEventTestingSink sink = new SinkEventTestingSink();
504
505        parser.parse( text, sink );
506
507        Iterator<SinkEventElement> it = sink.getEventList().iterator();
508        assertStartsWith( it, "head", "head_", "body", "section1", "sectionTitle1" );
509        assertEquals( it.next(), "link",
510                      "../apidocs/groovyx/net/http/ParserRegistry.html#parseText(org.apache.http.HttpResponse)" );
511        assertEquals( it.next(), "text", "ParserRegistry" );
512        assertEquals( it, "link_", "sectionTitle1_", "section1_", "body_" );
513    }
514
515    /** {@inheritDoc} */
516    protected String outputExtension()
517    {
518        return "apt";
519    }
520}