1 package org.apache.maven.doxia.module.confluence;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.FilterWriter;
23 import java.io.IOException;
24 import java.io.Reader;
25 import java.io.StringReader;
26 import java.io.StringWriter;
27 import java.io.Writer;
28 import java.util.Iterator;
29
30 import org.apache.maven.doxia.parser.AbstractParserTest;
31 import org.apache.maven.doxia.parser.ParseException;
32 import org.apache.maven.doxia.parser.Parser;
33 import org.apache.maven.doxia.sink.Sink;
34 import org.apache.maven.doxia.sink.SinkEventAttributeSet;
35 import org.apache.maven.doxia.sink.SinkEventElement;
36 import org.apache.maven.doxia.sink.SinkEventTestingSink;
37 import org.apache.maven.doxia.sink.TextSink;
38
39 import org.codehaus.plexus.util.IOUtil;
40 import org.codehaus.plexus.util.StringUtils;
41
42
43
44
45 public class ConfluenceParserTest
46 extends AbstractParserTest
47 {
48 private ConfluenceParser parser;
49
50 private StringWriter output;
51
52 private Reader reader;
53
54 private Writer writer;
55
56
57 protected void setUp()
58 throws Exception
59 {
60 super.setUp();
61
62 parser = (ConfluenceParser) lookup( Parser.ROLE, "confluence" );
63
64 output = null;
65 reader = null;
66 writer = null;
67 }
68
69
70 protected void tearDown()
71 throws Exception
72 {
73 IOUtil.close( output );
74 IOUtil.close( reader );
75 IOUtil.close( writer );
76
77 super.tearDown();
78 }
79
80
81 protected Parser createParser()
82 {
83 return parser;
84 }
85
86
87 protected String outputExtension()
88 {
89 return "confluence";
90 }
91
92
93 public void testMarkupTestPage()
94 throws Exception
95 {
96 String result = locateAndParseTestSourceFile( "test" );
97 assertContainsLines( result, "end:body" );
98 }
99
100
101 public void testParagraphWithSimpleFormatting()
102 throws Exception
103 {
104 String result = locateAndParseTestSourceFile( "simple-paragraph" );
105
106 assertContainsLines( result, "begin:bold\ntext: bold\n" );
107 assertContainsLines( result, "begin:italic\ntext: italic\n" );
108 assertContainsLines( result, "begin:monospaced\ntext: monospaced\n" );
109 assertContainsLines( result, "begin:link, name: http://jira.codehaus.org\ntext: http://jira.codehaus.org" );
110 assertContainsLines( result, "begin:link, name: http://jira.codehaus.org\ntext: JIRA\n" );
111
112 assertEquals( 5, result.split( "end:paragraph" ).length );
113 }
114
115
116 public void testLineBreak()
117 throws Exception
118 {
119 String lineBreak = getLineBreakString();
120
121 String result = locateAndParseTestSourceFile( "linebreak" );
122
123 assertContainsLines( result, "Line\n" + lineBreak );
124 assertContainsLines( result, "with 2\n" + lineBreak );
125 assertContainsLines( result, "inline\n" + lineBreak );
126 }
127
128
129 public void testEscapes()
130 throws Exception
131 {
132 String result = locateAndParseTestSourceFile( "escapes" );
133
134 assertContainsLines( result, "asterisk *" );
135 assertContainsLines( result, "underline _" );
136 assertContainsLines( result, "asterisk *not bold*" );
137 assertContainsLines( result, "underline _not italic_" );
138 assertContainsLines( result, "normal character" );
139 assertContainsLines( result, "trailing slash\\\n" );
140 }
141
142
143 public void testSectionTitles()
144 throws Exception
145 {
146 String result = locateAndParseTestSourceFile( "section" );
147
148 for ( int i = 1; i <= 5; i++ )
149 {
150 assertContainsLines( "Could not locate section " + i + " title", result,
151 "sectionTitle" + i + "\ntext: Section" + i );
152 }
153
154 assertContainsLines( "Section title has leading space", result, "sectionTitle1\ntext: TitleWithLeadingSpace" );
155 }
156
157
158 public void testNestedBulletList()
159 throws Exception
160 {
161 String result = locateAndParseTestSourceFile( "nested-list" );
162
163 assertContainsLines( "Nested list not found", result,
164 "begin:listItem\ntext: A top level list item\nbegin:list" );
165
166 assertEquals( 3, result.split( "end:list\n" ).length );
167
168 assertEquals( 5, result.split( "end:listItem\n" ).length );
169 }
170
171
172 public void testNestedHeterogenousList()
173 throws Exception
174 {
175 String result = locateAndParseTestSourceFile( "nested-list-heterogenous" );
176
177
178 assertContainsLines( "Nested list not found", result, "begin:listItem\ntext: A top level list item\nbegin:numberedList" );
179
180
181 assertEquals( 2, result.split( "begin:list\n" ).length );
182 assertEquals( 2, result.split( "begin:numberedList" ).length );
183
184
185 assertEquals( 5, result.split( "end:listItem\n" ).length );
186 }
187
188
189 public void testListWithSimpleFormatting()
190 throws Exception
191 {
192 String result = locateAndParseTestSourceFile( "simple-list" );
193
194 assertContainsLines( result, "begin:bold\ntext: bold\n" );
195 assertContainsLines( result, "begin:italic\ntext: italic\n" );
196 assertContainsLines( result, "begin:monospaced\ntext: monospaced\n" );
197 assertContainsLines( result, "begin:monospaced\ntext: some escaped monospaced \\\\unc\\path\n" );
198 assertContainsLines( result, "begin:link, name: http://jira.codehaus.org\ntext: http://jira.codehaus.org\n" );
199 assertContainsLines( result, "begin:link, name: http://jira.codehaus.org\ntext: JIRA\n" );
200 assertContainsLines( result, "begin:listItem\ntext: Item with no formatting\nend:listItem\n" );
201 assertContainsLines( result, "begin:listItem\ntext: One bullet\nend:listItem\n" );
202 assertContainsLines( result, "begin:listItem\ntext: A list item with more than one line\nend:listItem\n" );
203
204 assertEquals( 4, result.split( "end:list\n" ).length );
205
206 assertEquals( 9, result.split( "end:listItem\n" ).length );
207 }
208
209
210 public void testAnchor()
211 throws Exception
212 {
213 String result = locateAndParseTestSourceFile( "anchor" );
214
215 assertContainsLines( result, "begin:paragraph\nbegin:anchor, name: start\nend:anchor" );
216 assertContainsLines( result, "begin:anchor, name: middle\nend:anchor" );
217 assertContainsLines( result, "begin:paragraph\ntext: Simple paragraph\nbegin:anchor, name: end\nend:anchor" );
218
219 assertEquals( 4, result.split( "end:anchor\n" ).length );
220 }
221
222
223 public void testUnknownMacro()
224 throws Exception
225 {
226 String result = locateAndParseTestSourceFile( "unknown-macro" );
227
228 assertContainsLines( result, "begin:paragraph\ntext: {unknown:start}" );
229 }
230
231
232 public void testCodeMacro()
233 throws Exception
234 {
235 String result = locateAndParseTestSourceFile( "code" );
236
237 assertContainsLines( result, "begin:verbatim, boxed: true\ntext: public class Cat {" );
238
239 assertEquals( 5, result.split( "end:paragraph\n" ).length );
240
241 assertEquals( 3, result.split( "end:verbatim\n" ).length );
242 }
243
244
245 public void testFigure()
246 throws Exception
247 {
248 Reader result = getTestReader( "figure" );
249
250 SinkEventTestingSink sink = new SinkEventTestingSink();
251
252 parser.parse( result, sink );
253
254 Iterator<SinkEventElement> it = sink.getEventList().iterator();
255
256 assertEquals( it, "head", "head_", "body", "paragraph" );
257 assertEquals( it.next(), "text", "Simple paragraph." );
258 assertEquals( it, "paragraph_", "figure" );
259 assertEquals( it.next(), "figureGraphics", "images/photo.jpg" );
260 assertEquals( it, "figure_", "paragraph" );
261 assertEquals( it.next(), "text", "Simple paragraph with attempted inline !image.jpg! (should fail)." );
262 assertEquals( it, "paragraph_", "figure" );
263 assertEquals( it.next(), "figureGraphics", "images/photo.jpg" );
264 assertEquals( it.next().getName(), "figureCaption" );
265 assertEquals( it.next(), "text", "With caption on same line" );
266 assertEquals( it, "figureCaption_", "figure_", "figure" );
267 assertEquals( it.next(), "figureGraphics", "images/linebreak.jpg" );
268 assertEquals( it.next().getName(), "figureCaption" );
269 assertEquals( it.next(), "text", "With caption underneath and linebreak" );
270 assertEquals( it, "figureCaption_", "figure_", "figure" );
271 assertEquals( it.next(), "figureGraphics", "images/nolinebreak.jpg" );
272 assertEquals( it.next().getName(), "figureCaption" );
273 assertEquals( it.next(), "text", "With caption underneath and no linebreak" );
274 assertEquals( it, "figureCaption_", "figure_", "figure" );
275 assertEquals( it.next(), "figureGraphics", "images/bold.jpg" );
276 assertEquals( it.next().getName(), "figureCaption" );
277 assertEquals( it.next(), "text", "With *bold* caption underneath" );
278 assertEquals( it, "figureCaption_", "figure_", "figure" );
279 assertEquals( it.next(), "figureGraphics", "image.gif" );
280 assertEquals( it, "figure_", "body_" );
281 assertFalse( it.hasNext() );
282 }
283
284
285 public void testLink()
286 throws Exception
287 {
288 String result = locateAndParseTestSourceFile( "link" );
289
290 assertContainsLines( result, "begin:link, name: middle.html\ntext: middle\nend:link" );
291 assertContainsLines( result, "begin:link, name: end.html\ntext: end\nend:link" );
292 assertContainsLines( result, "begin:link, name: link.html\ntext: alias\nend:link" );
293 assertContainsLines( result, "begin:link, name: link.html#anchor\ntext: link#anchor\nend:link" );
294 assertContainsLines( result, "begin:link, name: #simple\ntext: simple\nend:link" );
295 assertContainsLines( result, "begin:link, name: resource.pdf\ntext: resource.pdf\nend:link" );
296 assertContainsLines( result, "begin:link, name: resource.pdf\ntext: alias pdf\nend:link" );
297 assertContainsLines( result, "begin:link, name: http://link.to/page_with_underscore-and-dash\ntext: underscore_-dash\nend:link" );
298
299 assertEquals( 6, result.split( "end:paragraph\n" ).length );
300
301 assertEquals( 9, result.split( "end:link\n" ).length );
302 }
303
304
305 public void testTableWithLinks()
306 throws Exception
307 {
308 String result = locateAndParseTestSourceFile( "table-link" );
309
310 assertContainsLines( result, "begin:tableCell\nbegin:link, name: http://example.com/release.0.1.3/ex-win32-win32.x86.zip\ntext: Download\nend:link\n\n\nend:tableCell\n" );
311 assertContainsLines( result, "begin:tableCell\nbegin:link, name: http://example.com/release.0.1.2/ex-win32-win32.x86.zip\ntext: http://example.com/release.0.1.2/ex-win32-win32.x86.zip\nend:link\n\n\nend:tableCell\n" );
312
313
314 assertEquals( 4, result.split( "end:link\n" ).length );
315 }
316
317
318 public void testTableWithImages()
319 throws Exception
320 {
321
322 StringReader reader =
323 new StringReader( "Table containing image in cell:\n" + "\n" + "||Header 1||\n"
324 + "|!images/test/Image.png!|" );
325
326 SinkEventTestingSink sink = new SinkEventTestingSink();
327
328 parser.parse( reader, sink );
329
330 Iterator<SinkEventElement> it = sink.getEventList().iterator();
331
332 assertEquals( it, "head", "head_", "body", "paragraph" );
333 assertEquals( it.next(), "text", "Table containing image in cell:" );
334 assertEquals( it, "paragraph_", "table", "tableRows", "tableRow", "tableHeaderCell", "bold" );
335 assertEquals( it.next(), "text", "Header 1" );
336 assertEquals( it, "bold_", "tableHeaderCell_", "tableRow_", "tableRow", "tableCell", "figure" );
337 assertEquals( it.next(), "figureGraphics", "images/test/Image.png" );
338 assertEquals( it, "figure_", "tableCell_", "tableRow_", "tableRows_", "table_", "body_" );
339 assertFalse( it.hasNext() );
340 }
341
342
343 public void testParagraphWithList()
344 throws Exception
345 {
346 String result = locateAndParseTestSourceFile( "paragraph-list" );
347
348 assertContainsLines( result, "begin:paragraph\ntext: A paragraph\nend:paragraph\n" );
349 assertContainsLines( result, "begin:listItem\ntext: A nested list item\nend:listItem\n" );
350 assertContainsLines( result, "begin:listItem\ntext: Another nested list item with two lines\nend:listItem\n" );
351
352 assertEquals( 3, result.split( "end:paragraph\n" ).length );
353
354 assertEquals( 2, result.split( "end:list\n" ).length );
355 }
356
357
358 public void testParagraphWithFigure()
359 throws Exception
360 {
361 String result = locateAndParseTestSourceFile( "paragraph-figure" );
362
363 assertContainsLines( result, "begin:paragraph\ntext: A paragraph\nend:paragraph\n" );
364 assertContainsLines( result, "begin:figure\nfigureGraphics, name: images/logo.png\nbegin:figureCaption\ntext: with a figure\nend:figureCaption" );
365
366 assertEquals( 3, result.split( "end:paragraph\n" ).length );
367
368 assertEquals( 2, result.split( "end:figure\n" ).length );
369 }
370
371
372 public void testParagraphWithHeader()
373 throws Exception
374 {
375 String result = locateAndParseTestSourceFile( "paragraph-header" );
376
377 assertContainsLines( result, "begin:paragraph\ntext: A paragraph\nend:paragraph\n" );
378 assertContainsLines( result, "begin:section2\nbegin:sectionTitle2\ntext: A header\nend:sectionTitle2" );
379
380 assertEquals( 4, result.split( "end:paragraph\n" ).length );
381
382 assertEquals( 2, result.split( "end:sectionTitle2\n" ).length );
383 }
384
385
386 public void testNestedFormats()
387 throws Exception
388 {
389 String result = locateAndParseTestSourceFile( "nested-format" );
390
391 assertContainsLines( result, "begin:bold\nbegin:italic\ntext: bold italic\nend:italic" );
392 assertContainsLines( result, "begin:italic\nbegin:bold\ntext: italic bold\nend:bold" );
393 assertContainsLines( result, "begin:bold\nbegin:monospaced\ntext: bold monospaced\nend:monospaced" );
394 assertContainsLines( result, "text: A paragraph with \nbegin:bold\ntext: bold \nbegin:italic\ntext: italic\nend:italic" );
395 assertContainsLines( result, "begin:italic\ntext: italic \nbegin:bold\ntext: bold\nend:bold" );
396 assertContainsLines( result, "begin:bold\ntext: bold \nbegin:monospaced\ntext: monospaced\nend:monospaced" );
397
398 assertEquals( 3, result.split( "end:paragraph\n" ).length );
399
400 assertEquals( 7, result.split( "end:bold\n" ).length );
401
402 assertEquals( 5, result.split( "end:italic\n" ).length );
403
404 assertEquals( 3, result.split( "end:monospaced\n" ).length );
405 }
406
407
408 public void testNoteInfoTipQuote()
409 throws Exception
410 {
411 String result = locateAndParseTestSourceFile( "note-tip-info" );
412
413 assertContainsLines( result, "begin:definedTerm\ntext: Be Careful\nend:definedTerm\n" );
414 assertContainsLines( result, "begin:definition\ntext: The body of the note here..\nend:definition" );
415 assertContainsLines( result, "begin:definedTerm\ntext: Guess What?\nend:definedTerm\n" );
416 assertContainsLines( result, "begin:definition\ntext: The body of the tip here..\nend:definition" );
417 assertContainsLines( result, "begin:definedTerm\ntext: Some Info\nend:definedTerm\n" );
418 assertContainsLines( result, "begin:definition\ntext: The body of the info here..\nend:definition" );
419 assertContainsLines( result, "begin:definedTerm\ntext: Simon Says\nend:definedTerm\n" );
420 assertContainsLines( result, "begin:definition\ntext: The body of the \nbegin:bold\ntext: quote\nend:bold" );
421
422
423 assertEquals( 6, result.split( "end:paragraph\n" ).length );
424
425 assertEquals( 5, result.split( "end:definitionList\n" ).length );
426 }
427
428
429
430
431
432
433 public void testEndBracket()
434 throws ParseException
435 {
436 String document = "Test"
437 + "\n\n* list1"
438 + "\n\n* list2"
439 + "\n\n* list2"
440 + "\n{pre}123{/pre}";
441
442 output = new StringWriter();
443 Sink sink = new TextSink( output );
444
445
446 createParser().parse( new StringReader( document + " " ), sink );
447 assertTrue( "generated document should have a size > 0", output.toString().length() > 0 );
448
449
450 try
451 {
452 createParser().parse( new StringReader( document ), sink );
453 }
454 catch ( Exception e )
455 {
456 e.printStackTrace();
457 fail( "parsing with document ending in } should not fail" );
458 }
459
460 assertTrue( "generated document should have a size > 0", output.toString().length() > 0 );
461 }
462
463
464
465
466
467
468 public void testEndBracketInList()
469 throws ParseException
470 {
471 String document1 = "Test"
472 + "\n\n* list1"
473 + "\n\n* list2"
474 + "\n\n* list2{pre}123{/pre} "
475 + "\n123";
476
477 String document2 = "Test"
478 + "\n\n* list1"
479 + "\n\n* list2"
480 + "\n\n* list2{pre}123{/pre}"
481 + "\n123";
482
483 output = new StringWriter();
484 Sink sink = new TextSink( output );
485
486
487 createParser().parse( new StringReader( document1 ), sink );
488 assertTrue( "generated document should have a size > 0", output.toString().length() > 0 );
489
490
491 try
492 {
493 createParser().parse( new StringReader( document2 ), sink );
494 }
495 catch ( Exception e )
496 {
497 e.printStackTrace();
498 fail( "parsing with end of list item ending in } should not fail" );
499 }
500
501 assertTrue( "generated document should have a size > 0", output.toString().length() > 0 );
502 }
503
504 public void testDoxia382SinkCannotBeReused()
505 throws ParseException
506 {
507 String document1 = "Test A"
508 + "\n\n* list1"
509 + "\n\n* list2"
510 + "\n\n* list2{pre}123{/pre} "
511 + "\n123";
512
513 String document2 = "Test B"
514 + "\n\n* list1"
515 + "\n\n* list2"
516 + "\n\n* list2{pre}123{/pre}"
517 + "\n123";
518
519 output = new StringWriter();
520 Sink sink = new TextSink( new FilterWriter( output )
521 {
522 public void close() throws IOException
523 {
524 super.close();
525 this.out = null;
526 }
527
528 public void write( String str, int off, int len )
529 throws IOException
530 {
531 if ( out == null )
532 {
533 throw new IOException( "Writing to an already closed Writer" );
534 }
535 }
536 });
537
538 createParser().parse( new StringReader( document1 ), sink );
539 createParser().parse( new StringReader( document2 ), sink );
540 }
541
542
543
544
545
546
547
548 public void testSeparatorInParagraph()
549 throws ParseException
550 {
551 String document = "Up\n---\nDown\n";
552
553 output = new StringWriter();
554 Sink sink = new TextSink( output );
555
556
557 createParser().parse( new StringReader( document ), sink );
558 assertTrue( "generated document should have a size > 0", output.toString().length() > 0 );
559
560 }
561
562 public void testListFollowedByMacro() throws Exception
563 {
564
565
566 String document = "- This is a little test. \r\n" +
567 "\r\n" +
568 "{code}\r\n" +
569 " @Autowired\r\n" +
570 " private DataSource dataSource;\r\n" +
571 "{code}\r\n";
572 output = new StringWriter();
573 SinkEventTestingSink sink = new SinkEventTestingSink();
574 createParser().parse( new StringReader( document ), sink );
575
576 Iterator<SinkEventElement> it = sink.getEventList().iterator();
577 assertEquals("head", it.next().getName() );
578 assertEquals("head_", it.next().getName() );
579 assertEquals("body", it.next().getName() );
580 assertEquals("list", it.next().getName() );
581 assertEquals("listItem", it.next().getName() );
582 assertEquals( it.next(), "text", "This is a little test." );
583 assertEquals("listItem_", it.next().getName() );
584 assertEquals("list_", it.next().getName() );
585 assertEquals("verbatim", it.next().getName() );
586 assertEquals( it.next(), "text", " @Autowired\n private DataSource dataSource;\n" );
587 assertEquals("verbatim_", it.next().getName() );
588 assertEquals("body_", it.next().getName() );
589 }
590
591 public void testLinethrough() throws Exception {
592 String document = "-Linethrough-";
593 output = new StringWriter();
594 SinkEventTestingSink sink = new SinkEventTestingSink();
595 createParser().parse(new StringReader(document), sink);
596
597 Iterator<SinkEventElement> it = sink.getEventList().iterator();
598 assertEquals(it, "head", "head_", "body", "paragraph");
599 assertEquals(it.next(), "text", "Linethrough",
600 new SinkEventAttributeSet("decoration", "line-through"));
601 assertEquals(it, "paragraph_", "body_");
602 assertFalse(it.hasNext());
603 }
604
605 public void testUnderline() throws Exception {
606 String document = "+Underline+";
607 output = new StringWriter();
608 SinkEventTestingSink sink = new SinkEventTestingSink();
609 createParser().parse(new StringReader(document), sink);
610
611 Iterator<SinkEventElement> it = sink.getEventList().iterator();
612 assertEquals(it, "head", "head_", "body", "paragraph");
613 assertEquals(it.next(), "text", "Underline", new SinkEventAttributeSet(
614 "decoration", "underline"));
615 assertEquals(it, "paragraph_", "body_");
616 assertFalse(it.hasNext());
617 }
618
619 public void testSub() throws Exception {
620 String document = "~Sub~";
621 output = new StringWriter();
622 SinkEventTestingSink sink = new SinkEventTestingSink();
623 createParser().parse(new StringReader(document), sink);
624
625 Iterator<SinkEventElement> it = sink.getEventList().iterator();
626 assertEquals(it, "head", "head_", "body", "paragraph");
627 assertEquals(it.next(), "text", "Sub", new SinkEventAttributeSet(
628 "valign", "sub"));
629 assertEquals(it, "paragraph_", "body_");
630 assertFalse(it.hasNext());
631 }
632
633 public void testSup() throws Exception {
634 String document = "^Sup^";
635 output = new StringWriter();
636 SinkEventTestingSink sink = new SinkEventTestingSink();
637 createParser().parse(new StringReader(document), sink);
638
639 Iterator<SinkEventElement> it = sink.getEventList().iterator();
640 assertEquals(it, "head", "head_", "body", "paragraph");
641 assertEquals(it.next(), "text", "Sup", new SinkEventAttributeSet(
642 "valign", "sup"));
643 assertEquals(it, "paragraph_", "body_");
644 assertFalse(it.hasNext());
645 }
646
647 private void assertContainsLines( String message, String result, String lines )
648 {
649 lines = StringUtils.replace( lines, "\n", EOL );
650 if ( message != null )
651 {
652 assertTrue( message, result.indexOf( lines ) != -1 );
653 }
654 else
655 {
656 assertTrue( result.indexOf( lines ) != -1 );
657 }
658 }
659
660 private void assertContainsLines( String result, String lines )
661 {
662 this.assertContainsLines( null, result, lines );
663 }
664
665 private String getLineBreakString()
666 {
667 StringWriter sw = new StringWriter();
668 Sink sink = new TextSink( sw );
669 sink.lineBreak();
670
671 return sw.toString();
672 }
673
674 private String locateAndParseTestSourceFile( String stem )
675 throws IOException, ParseException
676 {
677 output = new StringWriter();
678 reader = getTestReader( stem, outputExtension() );
679 writer = getTestWriter( stem, "txt" );
680
681 Sink sink = new TextSink( output );
682 createParser().parse( reader, sink );
683
684
685 String expected = output.toString();
686 writer.write( expected );
687 writer.flush();
688 return expected;
689 }
690
691 }