View Javadoc
1   package org.apache.maven.doxia.module.markdown;
2   
3   import java.io.Reader;
4   import java.util.Iterator;
5   
6   /*
7    * Licensed to the Apache Software Foundation (ASF) under one
8    * or more contributor license agreements.  See the NOTICE file
9    * distributed with this work for additional information
10   * regarding copyright ownership.  The ASF licenses this file
11   * to you under the Apache License, Version 2.0 (the
12   * "License"); you may not use this file except in compliance
13   * with the License.  You may obtain a copy of the License at
14   *
15   *   http://www.apache.org/licenses/LICENSE-2.0
16   *
17   * Unless required by applicable law or agreed to in writing,
18   * software distributed under the License is distributed on an
19   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20   * KIND, either express or implied.  See the License for the
21   * specific language governing permissions and limitations
22   * under the License.
23   */
24  
25  import org.apache.maven.doxia.parser.AbstractParserTest;
26  import org.apache.maven.doxia.parser.ParseException;
27  import org.apache.maven.doxia.parser.Parser;
28  import org.apache.maven.doxia.sink.Sink;
29  import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
30  import org.apache.maven.doxia.sink.impl.SinkEventElement;
31  import org.apache.maven.doxia.sink.impl.SinkEventTestingSink;
32  import org.codehaus.plexus.util.IOUtil;
33  
34  /**
35   * Tests for {@link MarkdownParser}.
36   *
37   * @author Julien Nicoulaud <julien.nicoulaud@gmail.com>
38   * @since 1.3
39   */
40  public class MarkdownParserTest
41      extends AbstractParserTest
42  {
43  
44      /**
45       * The {@link MarkdownParser} used for the tests.
46       */
47      protected MarkdownParser parser;
48  
49      /**
50       * {@inheritDoc}
51       */
52      @Override
53      protected void setUp()
54          throws Exception
55      {
56          super.setUp();
57          parser = (MarkdownParser) lookup( Parser.ROLE, MarkdownParser.ROLE_HINT );
58      }
59  
60      /**
61       * {@inheritDoc}
62       */
63      @Override
64      protected Parser createParser()
65      {
66          return parser;
67      }
68  
69      /**
70       * {@inheritDoc}
71       */
72      @Override
73      protected String outputExtension()
74      {
75          return MarkdownParserModule.FILE_EXTENSION;
76      }
77  
78      /**
79       * Assert the paragraph sink event is fired when parsing "paragraph.md".
80       *
81       * @throws Exception if the event list is not correct when parsing the document.
82       */
83      public void testParagraphSinkEvent()
84          throws Exception
85      {
86          Iterator<SinkEventElement> it = parseFileToEventTestingSink( "paragraph" ).getEventList().iterator();
87  
88          assertEquals( it, "head", "head_", "body", "paragraph", "text", "paragraph_", "body_" );
89  
90          assertFalse( it.hasNext() );
91      }
92  
93      /**
94       * Assert the bold sink event is fired when parsing "bold.md".
95       *
96       * @throws Exception if the event list is not correct when parsing the document.
97       */
98      public void testBoldSinkEvent()
99          throws Exception
100     {
101         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "bold" ).getEventList().iterator();
102 
103         assertEquals( it, "head", "head_", "body", "paragraph", "bold", "text", "bold_", "paragraph_", "body_" );
104 
105         assertFalse( it.hasNext() );
106     }
107 
108     /**
109      * Assert the italic sink event is fired when parsing "italic.md".
110      *
111      * @throws Exception if the event list is not correct when parsing the document.
112      */
113     public void testItalicSinkEvent()
114         throws Exception
115     {
116         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "italic" ).getEventList().iterator();
117 
118         assertEquals( it, "head", "head_", "body", "paragraph", "italic", "text", "italic_", "paragraph_", "body_" );
119 
120         assertFalse( it.hasNext() );
121     }
122 
123     /**
124      * Assert the code sink event is fired when parsing "code.md".
125      *
126      * @throws Exception if the event list is not correct when parsing the document.
127      */
128     public void testCodeSinkEvent()
129         throws Exception
130     {
131         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "code" ).getEventList().iterator();
132 
133         assertEquals( it, "head", "head_", "body", "paragraph", "text", "paragraph_", "text", "unknown", "verbatim", "text", "verbatim_", "unknown", "body_" );
134 
135         assertFalse( it.hasNext() );
136     }
137 
138     /**
139      * Assert the image sink event is fired when parsing "image.md".
140      *
141      * @throws Exception if the event list is not correct when parsing the document.
142      */
143     public void testImageSinkEvent()
144         throws Exception
145     {
146         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "image" ).getEventList().iterator();
147 
148         assertEquals( it, "head", "head_", "body", "paragraph", "text", "figureGraphics", "text", "paragraph_", "body_" );
149 
150         assertFalse( it.hasNext() );
151     }
152 
153     /**
154      * Assert the link sink event is fired when parsing "link.md".
155      *
156      * @throws Exception if the event list is not correct when parsing the document.
157      */
158     public void testLinkSinkEvent()
159         throws Exception
160     {
161         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "link" ).getEventList().iterator();
162 
163         assertEquals( it, "head", "head_", "body", "paragraph", "text", "link", "text", "link_", "text", "paragraph_", "body_" );
164 
165         assertFalse( it.hasNext() );
166     }
167     
168     public void testLinkWithAnchorAndQuery() throws Exception
169     {
170         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "link_anchor_query" ).getEventList().iterator();
171         
172         assertEquals( it, "head", "head_", "body", "paragraph", "link", "text", "link_", "paragraph_", "body_" );
173 
174         assertFalse( it.hasNext() );
175     }
176 
177     /**
178      * Assert the list sink event is fired when parsing "list.md".
179      *
180      * @throws Exception if the event list is not correct when parsing the document.
181      */
182     public void testListSinkEvent()
183         throws Exception
184     {
185         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "list" ).getEventList().iterator();
186 
187         assertEquals( it, "head", "head_", "body", "list", "text", "listItem", "text", "listItem_", "listItem", "text",
188                       "listItem_", "text", "list_", "body_" );
189 
190         assertFalse( it.hasNext() );
191     }
192 
193     /**
194      * Assert the numbered list sink event is fired when parsing "numbered-list.md".
195      *
196      * @throws Exception if the event list is not correct when parsing the document.
197      */
198     public void testNumberedListSinkEvent()
199         throws Exception
200     {
201         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "numbered-list" ).getEventList().iterator();
202 
203         assertEquals( it, "head", "head_", "body", "numberedList", "text", "numberedListItem", "text", "numberedListItem_",
204                       "numberedListItem", "text", "numberedListItem_", "text", "numberedList_", "body_" );
205 
206         assertFalse( it.hasNext() );
207     }
208 
209     /**
210      * Assert the metadata is passed through when parsing "metadata.md".
211      *
212      * @throws Exception if the event list is not correct when parsing the document.
213      */
214     public void testMetadataSinkEvent()
215         throws Exception
216     {
217         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "metadata" ).getEventList().iterator();
218 
219         assertEquals( it, "head", "title", "text", "title_", "author", "text", "author_", "date", "text", "date_",
220                       "head_", "body", "unknown", "text", "unknown", "paragraph", "text", "paragraph_", "section1",
221                       "sectionTitle1", "text", "sectionTitle1_", "paragraph", "text", "paragraph_", "section1_",
222                       "body_" );
223 
224         assertFalse( it.hasNext() );
225     }
226 
227     /**
228      * Assert the first header is passed as title event when parsing "first-heading.md".
229      *
230      * @throws Exception if the event list is not correct when parsing the document.
231      */
232     public void testFirstHeadingSinkEvent()
233         throws Exception
234     {
235         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "first-heading" ).getEventList().iterator();
236 
237         // NOTE: H1 is rendered as "unknown" and H2 is "section1" (see DOXIA-203)
238         assertEquals( it, "head", "title", "text", "title_", "head_", "body", "section1", "sectionTitle1", "text",
239                       "sectionTitle1_", "paragraph", "text", "paragraph_", "section1_", "body_" );
240 
241         assertFalse( it.hasNext() );
242     }
243 
244     /**
245      * Assert the first header is passed as title event when parsing "comment-before-heading.md".
246      *
247      * @throws Exception if the event list is not correct when parsing the document.
248      */
249     public void testCommentBeforeHeadingSinkEvent()
250         throws Exception
251     {
252         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "comment-before-heading" ).getEventList().iterator();
253 
254         // NOTE: H1 is rendered as "unknown" and H2 is "section1" (see DOXIA-203)
255         assertEquals( it, "head", "title", "text", "title_", "head_", "body", "comment", "text", "unknown", "text",
256                       "unknown", "paragraph", "text", "link", "text", "link_", "text", "paragraph_", "body_" );
257 
258         assertFalse( it.hasNext() );
259     }
260 
261     /**
262      * Assert the first header is passed as title event when parsing "comment-before-heading.md".
263      *
264      * @throws Exception if the event list is not correct when parsing the document.
265      */
266     public void testHtmlContent()
267         throws Exception
268     {
269         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "html-content" ).getEventList().iterator();
270 
271         // NOTE: H1 and DIV are rendered as "unknown" and H2 is "section1" (see DOXIA-203)
272         assertEquals( it, "head", "head_", "body", "unknown", "text", "paragraph", "bold", "text",
273                       "bold_", "text", "bold", "text", "bold_", "text", "paragraph_", "text", "unknown", "text", "horizontalRule", "unknown",
274                 "text", "unknown", "paragraph", "text", "paragraph_", "text", "table", "tableRows", "text", "tableRow",
275                 "tableHeaderCell", "text", "tableHeaderCell_", "tableRow_", "text", "tableRow",
276                                 "tableCell", "text", "tableCell_", "tableRow_", "text", "tableRows_", "table_",
277                 "body_" );
278 
279         assertFalse( it.hasNext() );
280     }
281 
282     /**
283      * Parse the file and return a {@link SinkEventTestingSink}.
284      *
285      * @param file the file to parse with {@link #parser}.
286      * @return a sink to test parsing events.
287      * @throws ParseException if the document parsing failed.
288      */
289     protected SinkEventTestingSink parseFileToEventTestingSink( String file )
290         throws ParseException
291     {
292         Reader reader = null;
293         SinkEventTestingSink sink = null;
294         try
295         {
296             reader = getTestReader( file );
297             sink = new SinkEventTestingSink();
298             parser.parse( reader, sink );
299         }
300         finally
301         {
302             IOUtil.close( reader );
303         }
304 
305         return sink;
306     }
307 
308     /** @throws Exception  */
309     public void testTocMacro()
310         throws Exception
311     {
312         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "macro-toc" ).getEventList().iterator();
313 
314         assertEquals( it, "head", "title", "text", "title_", "head_",
315                       "body",
316                       "list", // TOC start
317                       "listItem", "link", "text", "link_", // emtpy section 2 TOC entry
318                       "list", // sections 3 list start
319                       "listItem", "link", "text", "link_", "listItem_", // first section 3 TOC entry
320                       "listItem", "link", "text", "link_", "listItem_", // second section 3 TOC entry
321                       "list_", // sections 3 list end
322                       "listItem_", // emtpy section 2 TOC entry end
323                       "list_", // TOC end
324                       "text",
325                       "section1",
326                       "section2", "sectionTitle2", "text", "sectionTitle2_", "section2_",
327                       "section2", "sectionTitle2", "text", "sectionTitle2_", "section2_",
328                       "section1_",
329                       "body_" );
330     }
331 
332     /**
333      * TOC macro fails with EmptyStackException when title 2 followed by title 4 then title 2
334      * 
335      * @throws Exception
336      */
337     public void testTocMacroDoxia559()
338         throws Exception
339     {
340         Iterator<SinkEventElement> it = parseFileToEventTestingSink( "macro-toc-DOXIA-559" ).getEventList().iterator();
341 
342         assertEquals( it, "head", "title", "text", "title_", "head_",
343                       "body",
344                       "list", // TOC start
345                       "listItem", "link", "text", "link_", // first section 2 TOC entry
346                       "list", // sections 3 list start
347                       "listItem", "link", "text", "link_", "listItem_", // empty section 3 TOC entry
348                       "list_", // sections 3 list end
349                       "listItem_", // first section 2 TOC entry end
350                       "listItem", "link", "text", "link_", "listItem_", // second section 2 TOC entry
351                       "list_", // TOC end
352                       "text",
353                       "section1", "sectionTitle1", "text", "sectionTitle1_",
354                       "section2",
355                       "section3", "sectionTitle3", "text", "sectionTitle3_",
356                       "section3_",
357                       "section2_",
358                       "section1_",
359                       "section1", "sectionTitle1", "text", "sectionTitle1_",
360                       "section1_",
361                       "body_" );
362     }
363 }