View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.doxia.sink.impl;
20  
21  import java.io.CharArrayWriter;
22  import java.io.IOException;
23  import java.io.Writer;
24  import java.util.stream.IntStream;
25  
26  import org.apache.maven.doxia.AbstractModuleTest;
27  import org.apache.maven.doxia.sink.Sink;
28  import org.apache.maven.doxia.sink.SinkEventAttributes;
29  import org.junit.jupiter.api.BeforeEach;
30  import org.junit.jupiter.api.Test;
31  
32  import static org.hamcrest.MatcherAssert.assertThat;
33  import static org.junit.jupiter.api.Assertions.assertEquals;
34  import static org.xmlunit.matchers.CompareMatcher.isIdenticalTo;
35  
36  /**
37   * Abstract base class to test sinks.
38   */
39  public abstract class AbstractSinkTest extends AbstractModuleTest {
40      private final CharArrayWriter testWriter = new CharArrayWriter();
41      private Sink sink;
42  
43      /**
44       * Resets the writer and creates a new sink with it.
45       */
46      @BeforeEach
47      protected void setUp() {
48          testWriter.reset();
49          sink = createSink(testWriter);
50      }
51  
52      /**
53       * Ability to wrap the xmlFragment with a roottag and namespaces, when required
54       *
55       * @param xmlFragment XML fragment to wrap
56       * @return valid XML
57       */
58      protected String wrapXml(String xmlFragment) {
59          return xmlFragment;
60      }
61  
62      /**
63       * Transforms a given string to be compatible to XML comments.
64       *
65       * @param comment The string to transform.
66       *
67       * @return The given string transformed to be compatible to XML comments.
68       *
69       * @see <a href="http://www.w3.org/TR/2000/REC-xml-20001006#sec-comments">
70       *   http://www.w3.org/TR/2000/REC-xml-20001006#sec-comments</a>
71       * @since 1.7
72       */
73      protected static String toXmlComment(final String comment) {
74          String processed = comment;
75  
76          if (processed != null) {
77              while (processed.contains("--")) {
78                  processed = processed.replace("--", "- -");
79              }
80  
81              if (processed.endsWith("-")) {
82                  processed += " ";
83              }
84          }
85  
86          return processed;
87      }
88  
89      // ---------------------------------------------------------------------
90      // Common test cases
91      // ----------------------------------------------------------------------
92  
93      /**
94       * Tests that the current sink is able to render the common test document. If the sink is an Xml sink defined
95       * by {@link #isXmlSink()}, it uses an Xml Writer defined by {@link #getXmlTestWriter(String)}. If not, it uses
96       * the Writer defined by {@link #getTestWriter(String)}.
97       *
98       * @see SinkTestDocument
99       * @throws IOException If the target test document could not be generated.
100      * @see #isXmlSink()
101      * @see #getTestWriter(String)
102      * @see #getXmlTestWriter(String)
103      */
104     @Test
105     public final void testTestDocument() throws IOException {
106         Writer writer = (isXmlSink() ? getXmlTestWriter("testDocument") : getTestWriter("testDocument"));
107         Sink testSink = createSink(writer);
108 
109         try {
110             SinkTestDocument.generate(testSink);
111         } finally {
112             testSink.close();
113         }
114     }
115 
116     /**
117      * Checks that the sequence <code>[title(), text(title), title_()]</code>,
118      * invoked on the current sink, produces the same result as
119      * {@link #getTitleBlock getTitleBlock}(title).
120      */
121     @Test
122     public void testTitle() {
123         String title = "Grodek";
124         sink.title();
125         sink.text(title);
126         sink.title_();
127         sink.flush();
128         sink.close();
129 
130         String actual = testWriter.toString();
131         String expected = getTitleBlock(title);
132 
133         assertEquals(expected, actual, "Wrong title!");
134     }
135 
136     /**
137      * Checks that the sequence <code>[author(), text(author), author_()]
138      * </code>, invoked on the current sink, produces the same result as
139      * {@link #getAuthorBlock getAuthorBlock}(author).
140      */
141     @Test
142     public void testAuthor() {
143         String author = "Georg_Trakl";
144         sink.author();
145         sink.text(author);
146         sink.author_();
147         sink.flush();
148         sink.close();
149 
150         String actual = testWriter.toString();
151         String expected = getAuthorBlock(author);
152 
153         assertEquals(expected, actual, "Wrong author!");
154     }
155 
156     /**
157      * Checks that the sequence <code>[date(), text(date), date_()]</code>,
158      * invoked on the current sink, produces the same result as
159      * {@link #getDateBlock getDateBlock}(date).
160      */
161     @Test
162     public void testDate() {
163         String date = "1914";
164         sink.date();
165         sink.text(date);
166         sink.date_();
167         sink.flush();
168         sink.close();
169 
170         String actual = testWriter.toString();
171         String expected = getDateBlock(date);
172 
173         assertEquals(expected, actual, "Wrong date!");
174     }
175 
176     /**
177      * Checks that the sequence <code>[head(), head_()]</code>,
178      * invoked on the current sink, produces the same result as
179      * {@link #getHeadBlock getHeadBlock()}.
180      */
181     @Test
182     public void testHead() {
183         sink.head();
184         sink.head_();
185         sink.flush();
186         sink.close();
187 
188         String actual = normalizeLineEnds(testWriter.toString());
189         String expected = normalizeLineEnds(getHeadBlock());
190 
191         assertEquals(expected, actual, "Wrong head!");
192     }
193 
194     /**
195      * Checks that the sequence <code>[body(), body_()]</code>,
196      * invoked on the current sink, produces the same result as
197      * {@link #getBodyBlock getBodyBlock()}.
198      */
199     @Test
200     public void testBody() {
201         sink.body();
202         sink.body_();
203         sink.flush();
204         sink.close();
205 
206         String actual = testWriter.toString();
207         String expected = getBodyBlock();
208 
209         assertEquals(expected, actual, "Wrong body!");
210     }
211 
212     /**
213      * Checks that the sequence <code>[article(), article_()]</code>,
214      * invoked on the current sink, produces the same result as
215      * {@link #getArticleBlock getArticleBlock()}.
216      */
217     @Test
218     public void testArticle() {
219         sink.article();
220         sink.article_();
221         sink.flush();
222         sink.close();
223 
224         String actual = testWriter.toString();
225         String expected = getArticleBlock();
226 
227         assertEquals(expected, actual, "Wrong article!");
228     }
229 
230     /**
231      * Checks that the sequence <code>[navigation(), navigation_()]</code>,
232      * invoked on the current sink, produces the same result as
233      * {@link #getNavigationBlock getNavigationBlock()}.
234      */
235     @Test
236     public void testNavigation() {
237         sink.navigation();
238         sink.navigation_();
239         sink.flush();
240         sink.close();
241 
242         String actual = testWriter.toString();
243         String expected = getNavigationBlock();
244 
245         assertEquals(expected, actual, "Wrong navigation!");
246     }
247 
248     /**
249      * Checks that the sequence <code>[sidebar(), sidebar_()]</code>,
250      * invoked on the current sink, produces the same result as
251      * {@link #getSidebarBlock getSidebarBlock()}.
252      */
253     @Test
254     public void testSidebar() {
255         sink.sidebar();
256         sink.sidebar_();
257         sink.flush();
258         sink.close();
259 
260         String actual = testWriter.toString();
261         String expected = getSidebarBlock();
262 
263         assertEquals(expected, actual, "Wrong sidebar!");
264     }
265 
266     /**
267      * Checks that the sequence <code>[sectionTitle(), text(title),
268      * sectionTitle_()]</code>, invoked on the current sink, produces
269      * the same result as
270      * {@link #getSectionTitleBlock getSectionTitleBlock}(title).
271      */
272     @Test
273     public void testSectionTitle() {
274         String title = "Title";
275         sink.sectionTitle();
276         sink.text(title);
277         sink.sectionTitle_();
278         sink.flush();
279         sink.close();
280 
281         String actual = testWriter.toString();
282         String expected = getSectionTitleBlock(title);
283 
284         assertEquals(expected, actual, "Wrong sectionTitle!");
285     }
286 
287     /**
288      * Checks that the sequence <code>[section1(), sectionTitle1(),
289      * text(title), sectionTitle1_(), section1_()]</code>,
290      * invoked on the current sink, produces the same result as
291      * {@link #getSection1Block getSection1Block}(title).
292      */
293     @Test
294     public void testSection1() {
295         String title = "Title1";
296         sink.section1();
297         sink.header();
298         sink.sectionTitle1();
299         sink.text(title);
300         sink.sectionTitle1_();
301         sink.header_();
302         sink.section1_();
303         sink.flush();
304         sink.close();
305 
306         String actual = testWriter.toString();
307         String expected = getSection1Block(title);
308 
309         assertEquals(expected, actual, "Wrong section1 block!");
310     }
311 
312     /**
313      * Checks that the sequence <code>[section2(), sectionTitle2(),
314      * text(title), sectionTitle2_(), section2_()]</code>,
315      * invoked on the current sink, produces the same result as
316      * {@link #getSection2Block getSection2Block}(title).
317      */
318     @Test
319     public void testSection2() {
320         String title = "Title2";
321         sink.section2();
322         sink.header();
323         sink.sectionTitle2();
324         sink.text(title);
325         sink.sectionTitle2_();
326         sink.header_();
327         sink.section2_();
328         sink.flush();
329         sink.close();
330 
331         String actual = testWriter.toString();
332         String expected = getSection2Block(title);
333 
334         assertEquals(expected, actual, "Wrong section2 block!");
335     }
336 
337     /**
338      * Checks that the sequence <code>[section3(), sectionTitle3(),
339      * text(title), sectionTitle3_(), section3_()]</code>,
340      * invoked on the current sink, produces the same result as
341      * {@link #getSection3Block getSection3Block}(title).
342      */
343     @Test
344     public void testSection3() {
345         String title = "Title3";
346         sink.section3();
347         sink.header();
348         sink.sectionTitle3();
349         sink.text(title);
350         sink.sectionTitle3_();
351         sink.header_();
352         sink.section3_();
353         sink.flush();
354         sink.close();
355 
356         String actual = testWriter.toString();
357         String expected = getSection3Block(title);
358 
359         assertEquals(expected, actual, "Wrong section3 block!");
360     }
361 
362     /**
363      * Checks that the sequence <code>[section4(), sectionTitle4(),
364      * text(title), sectionTitle4_(), section4_()]</code>,
365      * invoked on the current sink, produces the same result as
366      * {@link #getSection4Block getSection4Block}(title).
367      *
368      */
369     @Test
370     public void testSection4() {
371         String title = "Title4";
372         sink.section4();
373         sink.header();
374         sink.sectionTitle4();
375         sink.text(title);
376         sink.sectionTitle4_();
377         sink.header_();
378         sink.section4_();
379         sink.flush();
380         sink.close();
381 
382         String actual = testWriter.toString();
383         String expected = getSection4Block(title);
384 
385         assertEquals(expected, actual, "Wrong section4 block!");
386     }
387 
388     /**
389      * Checks that the sequence <code>[section5(), sectionTitle5(),
390      * text(title), sectionTitle5_(), section5_()]</code>,
391      * invoked on the current sink, produces the same result as
392      * {@link #getSection5Block getSection5Block}(title).
393      */
394     @Test
395     public void testSection5() {
396         String title = "Title5";
397         sink.section5();
398         sink.header();
399         sink.sectionTitle5();
400         sink.text(title);
401         sink.sectionTitle5_();
402         sink.header_();
403         sink.section5_();
404         sink.flush();
405         sink.close();
406 
407         String actual = testWriter.toString();
408         String expected = getSection5Block(title);
409 
410         assertEquals(expected, actual, "Wrong section5 block!");
411     }
412 
413     /**
414      * Checks that the sequence <code>[section6(), sectionTitle6(),
415      * text(title), sectionTitle6_(), section6_()]</code>,
416      * invoked on the current sink, produces the same result as
417      * {@link #getSection6Block}.
418      */
419     @Test
420     public void testSection6() {
421         String title = "Title6";
422         sink.section6();
423         sink.header();
424         sink.sectionTitle6();
425         sink.text(title);
426         sink.sectionTitle6_();
427         sink.header_();
428         sink.section6_();
429         sink.flush();
430         sink.close();
431 
432         String actual = testWriter.toString();
433         String expected = getSection6Block(title);
434 
435         assertEquals(expected, actual, "Wrong section6 block!");
436     }
437 
438     /**
439      * Checks that the sequence <code>[header(), header_()]</code>,
440      * invoked on the current sink, produces the same result as
441      * {@link #getHeaderBlock getHeaderBlock()}.
442      */
443     @Test
444     public void testHeader() {
445         sink.header();
446         sink.header_();
447         sink.flush();
448         sink.close();
449 
450         String actual = testWriter.toString();
451         String expected = getHeaderBlock();
452 
453         assertEquals(expected, actual, "Wrong header!");
454     }
455 
456     /**
457      * Checks that the sequence <code>[content(), content(), content_(), content_()]</code>,
458      * invoked on the current sink, produces the same result as
459      * {@link #getContentBlock getContentBlock()}.
460      */
461     @Test
462     public void testContent() {
463         sink.content();
464         sink.content();
465         sink.content_();
466         sink.content_();
467         sink.flush();
468         sink.close();
469 
470         String actual = testWriter.toString();
471         String expected = getContentBlock();
472 
473         assertEquals(expected, actual, "Wrong content!");
474     }
475 
476     /**
477      * Checks that the sequence <code>[footer(), footer_()]</code>,
478      * invoked on the current sink, produces the same result as
479      * {@link #getHeaderBlock getHeaderBlock()}.
480      */
481     @Test
482     public void testFooter() {
483         sink.footer();
484         sink.footer_();
485         sink.flush();
486         sink.close();
487 
488         String actual = testWriter.toString();
489         String expected = getFooterBlock();
490 
491         assertEquals(expected, actual, "Wrong footer!");
492     }
493 
494     /**
495      * Checks that the sequence <code>[list(), listItem(), text(item),
496      * listItem_(), list_()]</code>, invoked on the current sink, produces
497      * the same result as {@link #getListBlock getListBlock}(item).
498      *
499      */
500     @Test
501     public void testList() {
502         String item = "list_item";
503         sink.list();
504         sink.listItem();
505         sink.text(item);
506         sink.listItem_();
507         sink.list_();
508         sink.flush();
509         sink.close();
510 
511         String actual = testWriter.toString();
512         String expected = getListBlock(item);
513 
514         assertEquals(expected, actual, "Wrong list!");
515     }
516 
517     /**
518      * Checks that the sequence <code>
519      * [numberedList(Sink.NUMBERING_LOWER_ROMAN), numberedListItem(),
520      * text(item), numberedListItem_(), numberedList_()]</code>,
521      * invoked on the current sink, produces the same result as
522      * {@link #getNumberedListBlock getNumberedListBlock}(item).
523      */
524     @Test
525     public void testNumberedList() {
526         String item = "numbered_list_item";
527         sink.numberedList(Sink.NUMBERING_LOWER_ROMAN);
528         sink.numberedListItem();
529         sink.text(item);
530         sink.numberedListItem_();
531         sink.numberedList_();
532         sink.flush();
533         sink.close();
534 
535         String actual = testWriter.toString();
536         String expected = getNumberedListBlock(item);
537 
538         assertEquals(expected, actual, "Wrong numbered list!");
539     }
540 
541     /**
542      * Checks that the sequence <code>[definitionList(), definitionListItem(),
543      * definedTerm(), text(definum), definedTerm_(), definition(),
544      * text(definition), definition_(), definitionListItem_(),
545      * definitionList_()]</code>, invoked on the current sink, produces the same
546      * result as {@link #getDefinitionListBlock getDefinitionListBlock}
547      * (definum, definition).
548      */
549     @Test
550     public void testDefinitionList() {
551         String definum = "definum";
552         String definition = "definition";
553         sink.definitionList();
554         sink.definitionListItem();
555         sink.definedTerm();
556         sink.text(definum);
557         sink.definedTerm_();
558         sink.definition();
559         sink.text(definition);
560         sink.definition_();
561         sink.definitionListItem_();
562         sink.definitionList_();
563         sink.flush();
564         sink.close();
565 
566         String actual = testWriter.toString();
567         String expected = getDefinitionListBlock(definum, definition);
568 
569         assertEquals(expected, actual, "Wrong definition list!");
570     }
571 
572     /**
573      * Checks that the sequence <code>[figure(), figureGraphics(source),
574      * figureCaption(), text(caption), figureCaption_(), figure_()]</code>,
575      * invoked on the current sink, produces the same result as
576      * {@link #getFigureBlock getFigureBlock}(source, caption).
577      */
578     @Test
579     public void testFigure() {
580         String source = "figure.jpg";
581         String caption = "Figure_caption";
582         sink.figure();
583         sink.figureGraphics(source);
584         sink.figureCaption();
585         sink.text(caption);
586         sink.figureCaption_();
587         sink.figure_();
588         sink.flush();
589         sink.close();
590 
591         String actual = testWriter.toString();
592         String expected = getFigureBlock(source, caption);
593 
594         if (isXmlSink()) {
595             assertThat(wrapXml(actual), isIdenticalTo(wrapXml(expected)));
596         } else {
597             assertEquals(expected, actual);
598         }
599     }
600 
601     @Test
602     public void testFigureWithoutCaption() {
603         String source = "figure.jpg";
604         sink.figure();
605         sink.figureGraphics(source);
606         sink.figure_();
607         sink.flush();
608         sink.close();
609 
610         String actual = testWriter.toString();
611         String expected = getFigureBlock(source, null);
612 
613         if (isXmlSink()) {
614             assertThat(wrapXml(actual), isIdenticalTo(wrapXml(expected)));
615         } else {
616             assertEquals(expected, actual);
617         }
618     }
619 
620     @Test
621     public void testFigureFromUrl() {
622         String source = "http://www.gravatar.com/avatar/cdbe99fe3d6af6a18dd8c35b0687a50b?d=mm&s=60";
623         sink.figure();
624         sink.figureGraphics(source);
625         sink.figure_();
626         sink.flush();
627         sink.close();
628 
629         String actual = testWriter.toString();
630         String expected = getFigureBlock(source, null);
631 
632         if (isXmlSink()) {
633             assertThat(wrapXml(actual), isIdenticalTo(wrapXml(expected)));
634         } else {
635             assertEquals(expected, actual);
636         }
637     }
638 
639     /**
640      * Checks that the sequence <code>[table(),
641      * tableRows(Sink.JUSTIFY_CENTER, false), tableRow(), tableCell(),
642      * text(cell), tableCell_(), tableRow_(), tableRows_(), tableCaption(),
643      * text(caption), tableCaption_(), table_()]</code>,
644      * invoked on the current sink, produces the same result as
645      * {@link #getTableBlock getTableBlock}(cell, caption).
646      */
647     @Test
648     public void testTable() {
649         String cell = "cell";
650         String caption = "Table_caption";
651         int[] justify = {Sink.JUSTIFY_CENTER};
652         sink.table();
653         sink.tableRows(justify, false);
654         sink.tableRow();
655         sink.tableCell();
656         sink.text(cell);
657         sink.tableCell_();
658         sink.tableRow_();
659         sink.tableRows_();
660         sink.tableCaption();
661         sink.text(caption);
662         sink.tableCaption_();
663         sink.table_();
664         sink.flush();
665         sink.close();
666 
667         String actual = testWriter.toString();
668         String expected = getTableBlock(cell, caption);
669 
670         if (isXmlSink()) {
671             assertThat(wrapXml(actual), isIdenticalTo(wrapXml(expected)));
672         } else {
673             assertEquals(expected, actual);
674         }
675     }
676 
677     /**
678      * Checks that the sequence of table with header methods
679      * invoked on the current sink, produces the same result as
680      * {@link #getTableWithHeaderBlock(String...)}.
681      */
682     @Test
683     public void testTableWithHeader() {
684         int[] justify = {Sink.JUSTIFY_LEFT, Sink.JUSTIFY_RIGHT, Sink.JUSTIFY_CENTER};
685         sink.table();
686         sink.tableRows(justify, false);
687         try (IntStream cellStream = getCellStreamForNewRow(3)) {
688             cellStream.forEach(col -> {
689                 sink.tableHeaderCell();
690                 sink.text("header_" + col);
691                 sink.tableHeaderCell_();
692             });
693         }
694         try (IntStream cellStream = getCellStreamForNewRow(3)) {
695             cellStream.forEach(col -> {
696                 sink.tableCell();
697                 sink.text("row1_" + col);
698                 sink.tableCell_();
699             });
700         }
701         try (IntStream cellStream = getCellStreamForNewRow(3)) {
702             cellStream.forEach(col -> {
703                 sink.tableCell();
704                 sink.text("row2_" + col);
705                 sink.tableCell_();
706             });
707         }
708 
709         sink.tableRows_();
710         sink.table_();
711         sink.flush();
712         sink.close();
713 
714         String actual = testWriter.toString();
715         String expected = getTableWithHeaderBlock("header_", "row1_", "row2_");
716 
717         if (isXmlSink()) {
718             assertThat(wrapXml(actual), isIdenticalTo(wrapXml(expected)));
719         } else {
720             assertEquals(expected, actual);
721         }
722     }
723 
724     private IntStream getCellStreamForNewRow(int numColumns) {
725         sink.tableRow();
726         return IntStream.range(0, numColumns).onClose(() -> sink.tableRow_());
727     }
728 
729     /**
730      * Checks that the sequence <code>[paragraph(), text(text),
731      * paragraph_()]</code>, invoked on the current sink, produces
732      * the same result as {@link #getParagraphBlock getParagraphBlock}(text).
733      */
734     @Test
735     public void testParagraph() {
736         String text = "Text";
737         sink.paragraph();
738         sink.text(text);
739         sink.paragraph_();
740         sink.flush();
741         sink.close();
742 
743         String actual = testWriter.toString();
744         String expected = getParagraphBlock(text);
745 
746         assertEquals(expected, actual, "Wrong paragraph!");
747     }
748 
749     /**
750      * Checks that the sequence <code>[data(), text(text),
751      * data_()]</code>, invoked on the current sink, produces
752      * the same result as {@link #getDataBlock getDataBlock}(text).
753      */
754     @Test
755     public void testData() {
756         String value = "Value";
757         String text = "Text";
758         sink.data(value);
759         sink.text(text);
760         sink.data_();
761         sink.flush();
762         sink.close();
763 
764         String actual = testWriter.toString();
765         String expected = getDataBlock(value, text);
766 
767         assertEquals(expected, actual, "Wrong data!");
768     }
769 
770     /**
771      * Checks that the sequence <code>[time(), text(text),
772      * time_()]</code>, invoked on the current sink, produces
773      * the same result as {@link #getTimeBlock getTimeBlock}(text).
774      */
775     @Test
776     public void testTime() {
777         String datetime = "DateTime";
778         String text = "Text";
779         sink.time(datetime);
780         sink.text(text);
781         sink.time_();
782         sink.flush();
783         sink.close();
784 
785         String actual = testWriter.toString();
786         String expected = getTimeBlock(datetime, text);
787 
788         assertEquals(expected, actual, "Wrong time!");
789     }
790 
791     /**
792      * Checks that the sequence <code>[address(), text(text),
793      * address_()]</code>, invoked on the current sink, produces
794      * the same result as {@link #getAddressBlock getAddressBlock}(text).
795      */
796     @Test
797     public void testAddress() {
798         String text = "Text";
799         sink.address();
800         sink.text(text);
801         sink.address_();
802         sink.flush();
803         sink.close();
804 
805         String actual = testWriter.toString();
806         String expected = getAddressBlock(text);
807 
808         assertEquals(expected, actual, "Wrong address!");
809     }
810 
811     /**
812      * Checks that the sequence <code>[blockquote(), text(text),
813      * blockquote_()]</code>, invoked on the current sink, produces
814      * the same result as {@link #getBlockquoteBlock}(text).
815      */
816     @Test
817     public void testBlockquote() {
818         String text = "Text";
819         sink.blockquote();
820         sink.text(text);
821         sink.blockquote_();
822         sink.flush();
823         sink.close();
824 
825         String actual = testWriter.toString();
826         String expected = getBlockquoteBlock(text);
827 
828         assertEquals(expected, actual, "Wrong blockquote!");
829     }
830 
831     /**
832      * Checks that the sequence <code>[division(), text(text),
833      * division_()]</code>, invoked on the current sink, produces
834      * the same result as {@link #getDivisionBlock getDivisionBlock}(text).
835      */
836     @Test
837     public void testDivider() {
838         String text = "Text";
839         sink.division();
840         sink.text(text);
841         sink.division_();
842         sink.flush();
843         sink.close();
844 
845         String actual = testWriter.toString();
846         String expected = getDivisionBlock(text);
847 
848         assertEquals(expected, actual, "Wrong division!");
849     }
850 
851     /**
852      * Checks that the sequence <code>[verbatim(SinkEventAttributeSet.SOURCE), text(text),
853      * verbatim_()]</code>, invoked on the current sink, produces the
854      * same result as {@link #getVerbatimSourceBlock getVerbatimSourceBlock}(text).
855      */
856     @Test
857     public void testVerbatimSource() {
858         String text = "Text";
859         sink.verbatim(SinkEventAttributeSet.SOURCE);
860         sink.text(text);
861         sink.verbatim_();
862         sink.flush();
863         sink.close();
864 
865         String actual = testWriter.toString();
866         String expected = getVerbatimSourceBlock(text);
867 
868         assertEquals(expected, actual, "Wrong verbatim!");
869     }
870 
871     /**
872      * Checks that the sequence <code>[horizontalRule()]</code>,
873      * invoked on the current sink, produces the same result as
874      * {@link #getHorizontalRuleBlock getHorizontalRuleBlock()}.
875      */
876     @Test
877     public void testHorizontalRule() {
878         sink.horizontalRule();
879         sink.flush();
880         sink.close();
881 
882         String actual = testWriter.toString();
883         String expected = getHorizontalRuleBlock();
884 
885         assertEquals(expected, actual, "Wrong horizontal rule!");
886     }
887 
888     /**
889      * Checks that the sequence <code>[pageBreak()]</code>,
890      * invoked on the current sink, produces the same result as
891      * {@link #getPageBreakBlock getPageBreakBlock()}.
892      */
893     @Test
894     public void testPageBreak() {
895         sink.pageBreak();
896         sink.flush();
897         sink.close();
898 
899         String actual = testWriter.toString();
900         String expected = getPageBreakBlock();
901 
902         assertEquals(expected, actual, "Wrong pageBreak!");
903     }
904 
905     /**
906      * Checks that the sequence <code>[anchor(anchor), text(anchor),
907      * anchor_()]</code>, invoked on the current sink, produces the same
908      * result as {@link #getAnchorBlock getAnchorBlock}(anchor).
909      */
910     @Test
911     public void testAnchor() {
912         String anchor = "Anchor";
913         sink.anchor(anchor);
914         sink.text(anchor);
915         sink.anchor_();
916         sink.flush();
917         sink.close();
918 
919         String actual = testWriter.toString();
920         String expected = getAnchorBlock(anchor);
921 
922         assertEquals(expected, actual, "Wrong anchor!");
923     }
924 
925     /**
926      * Checks that the sequence <code>[link(link), text(text),
927      * link_()]</code>, invoked on the current sink, produces the same
928      * result as {@link #getLinkBlock getLinkBlock}(link, text).
929      */
930     @Test
931     public void testLink() {
932         String link = "#Link";
933         String text = "Text";
934         sink.link(link);
935         sink.text(text);
936         sink.link_();
937         sink.flush();
938         sink.close();
939 
940         String actual = testWriter.toString();
941         String expected = getLinkBlock(link, text);
942 
943         assertEquals(expected, actual, "Wrong link!");
944     }
945 
946     /**
947      * Checks that the sequence <code>[inline(), text(text), inline_()]</code>,
948      * invoked on the current sink, produces the same result as
949      * {@link #getInlineBlock getInlineBlock}(text).
950      */
951     @Test
952     public void testInline() {
953         String text = "Inline";
954         sink.inline();
955         sink.text(text);
956         sink.inline_();
957         sink.flush();
958         sink.close();
959 
960         String actual = testWriter.toString();
961         String expected = getInlineBlock(text);
962 
963         assertEquals(expected, actual, "Wrong inline!");
964     }
965 
966     /**
967      * Checks that the sequence <code>[inline(bold), text(text), inline_()]</code>,
968      * invoked on the current sink, produces the same result as
969      * {@link #getInlineBoldBlock getInlineBoldBlock}(text).
970      */
971     @Test
972     public void testInlineBold() {
973         String text = "InlineBold";
974         sink.inline(SinkEventAttributeSet.Semantics.BOLD);
975         sink.text(text);
976         sink.inline_();
977         sink.flush();
978         sink.close();
979 
980         String actual = testWriter.toString();
981         String expected = getInlineBoldBlock(text);
982 
983         assertEquals(expected, actual, "Wrong inline bold!");
984     }
985 
986     /**
987      * Checks that the sequence <code>[inline(italic), text(text), inline_()]</code>,
988      * invoked on the current sink, produces the same result as
989      * {@link #getInlineBoldBlock getInlineBoldBlock}(text).
990      */
991     @Test
992     public void testInlineItalic() {
993         String text = "InlineItalic";
994         sink.inline(SinkEventAttributeSet.Semantics.ITALIC);
995         sink.text(text);
996         sink.inline_();
997         sink.flush();
998         sink.close();
999 
1000         String actual = testWriter.toString();
1001         String expected = getInlineItalicBlock(text);
1002 
1003         assertEquals(expected, actual, "Wrong inline italic!");
1004     }
1005 
1006     /**
1007      * Checks that the sequence <code>[inline(code), text(text), inline_()]</code>,
1008      * invoked on the current sink, produces the same result as
1009      * {@link #getInlineBoldBlock getInlineBoldBlock}(text).
1010      */
1011     @Test
1012     public void testInlineCode() {
1013         String text = "InlineCode";
1014         sink.inline(SinkEventAttributeSet.Semantics.CODE);
1015         sink.text(text);
1016         sink.inline_();
1017         sink.flush();
1018         sink.close();
1019 
1020         String actual = testWriter.toString();
1021         String expected = getInlineCodeBlock(text);
1022 
1023         assertEquals(expected, actual, "Wrong inline code!");
1024     }
1025 
1026     /**
1027      * Checks that the sequence <code>[lineBreak()]</code>,
1028      * invoked on the current sink, produces the same result as
1029      * {@link #getLineBreakBlock getLineBreakBlock()}.
1030      */
1031     @Test
1032     public void testLineBreak() {
1033         sink.lineBreak();
1034         sink.flush();
1035         sink.close();
1036 
1037         String actual = testWriter.toString();
1038         String expected = getLineBreakBlock();
1039 
1040         assertEquals(expected, actual, "Wrong lineBreak!");
1041     }
1042 
1043     /**
1044      * Checks that the sequence <code>[lineBreakOpportunity()]</code>,
1045      * invoked on the current sink, produces the same result as
1046      * {@link #getLineBreakOpportunityBlock getLineBreakOpportunityBlock()}.
1047      */
1048     @Test
1049     public void testLineBreakOpportunity() {
1050         sink.lineBreakOpportunity();
1051         sink.flush();
1052         sink.close();
1053 
1054         String actual = testWriter.toString();
1055         String expected = getLineBreakOpportunityBlock();
1056 
1057         assertEquals(expected, actual, "Wrong lineBreakOpportunity!");
1058     }
1059 
1060     /**
1061      * Checks that the sequence <code>[nonBreakingSpace()]</code>,
1062      * invoked on the current sink, produces the same result as
1063      * {@link #getNonBreakingSpaceBlock getNonBreakingSpaceBlock()}.
1064      */
1065     @Test
1066     public void testNonBreakingSpace() {
1067         sink.nonBreakingSpace();
1068         sink.flush();
1069         sink.close();
1070 
1071         String actual = testWriter.toString();
1072         String expected = getNonBreakingSpaceBlock();
1073 
1074         assertEquals(expected, actual, "Wrong nonBreakingSpace!");
1075     }
1076 
1077     /**
1078      * Checks that the sequence <code>[text(text)]</code>,
1079      * invoked on the current sink, produces the same result as
1080      * {@link #getTextBlock getTextBlock()}(text).
1081      */
1082     @Test
1083     public void testText() {
1084         String text = "~,_=,_-,_+,_*,_[,_],_<,_>,_{,_},_\\";
1085         sink.text(text);
1086         sink.flush();
1087         sink.close();
1088 
1089         String actual = testWriter.toString();
1090         String expected = getTextBlock(text);
1091 
1092         assertEquals(expected, actual, "Wrong text!");
1093     }
1094 
1095     /**
1096      * Checks that the sequence <code>[rawText(text)]</code>,
1097      * invoked on the current sink, produces the same result as
1098      * {@link #getRawTextBlock getRawTextBlock}(text).
1099      */
1100     @Test
1101     public void testRawText() {
1102         String text = "~,_=,_-,_+,_*,_[,_],_<,_>,_{,_},_\\";
1103         sink.rawText(text);
1104         sink.flush();
1105         sink.close();
1106 
1107         String actual = testWriter.toString();
1108         String expected = getRawTextBlock(text);
1109 
1110         assertEquals(expected, actual, "Wrong rawText!");
1111     }
1112 
1113     /**
1114      * Checks that the sequence <code>[comment(comment)]</code>,
1115      * invoked on the current sink, produces the same result as
1116      * {@link #getCommentBlock getCommentBlock}(comment).
1117      * @since 1.1.1
1118      */
1119     @Test
1120     public void testComment() {
1121         String comment = "Simple comment with ----";
1122         sink.comment(comment);
1123         sink.flush();
1124         sink.close();
1125 
1126         String actual = testWriter.toString();
1127         String expected = getCommentBlock(comment);
1128 
1129         assertEquals(expected, actual, "Wrong comment!");
1130 
1131         testWriter.reset();
1132         sink = createSink(testWriter);
1133 
1134         comment = "-";
1135         sink.comment(comment);
1136         sink.flush();
1137         sink.close();
1138 
1139         actual = testWriter.toString();
1140         expected = getCommentBlock(comment);
1141 
1142         assertEquals(expected, actual, "Wrong comment!");
1143     }
1144 
1145     // ----------------------------------------------------------------------
1146     // Utility methods
1147     // ----------------------------------------------------------------------
1148 
1149     /**
1150      * Returns the sink that is currently being tested.
1151      * @return The current test sink.
1152      */
1153     protected Sink getSink() {
1154         return sink;
1155     }
1156 
1157     /**
1158      * Returns a String representation of all events that have been written to the sink.
1159      * @return The Sink content as a String.
1160      */
1161     protected String getSinkContent() {
1162         return testWriter.toString();
1163     }
1164 
1165     /**
1166      * Returns the directory where all sink test output will go.
1167      * @return The test output directory.
1168      */
1169     protected String getOutputDir() {
1170         return "sink/";
1171     }
1172 
1173     // ----------------------------------------------------------------------
1174     // Abstract methods the individual SinkTests must provide
1175     // ----------------------------------------------------------------------
1176 
1177     /**
1178      * This method allows to use the correct Writer in {@link #testTestDocument()}.
1179      *
1180      * @return <code>true</code> if the Sink is an XML one, <code>false</code> otherwise.
1181      * @see #testTestDocument()
1182      */
1183     protected abstract boolean isXmlSink();
1184 
1185     /**
1186      * Return a new instance of the sink that is being tested.
1187      * @param writer The writer for the sink.
1188      * @return A new sink.
1189      */
1190     protected abstract Sink createSink(Writer writer);
1191 
1192     /**
1193      * Returns a title block generated by this sink.
1194      * @param title The title to use.
1195      * @return The result of invoking a title block on the current sink.
1196      * @see #testTitle()
1197      */
1198     protected abstract String getTitleBlock(String title);
1199 
1200     /**
1201      * Returns an author block generated by this sink.
1202      * @param author The author to use.
1203      * @return The result of invoking an author block on the current sink.
1204      * @see #testAuthor()
1205      */
1206     protected abstract String getAuthorBlock(String author);
1207 
1208     /**
1209      * Returns a date block generated by this sink.
1210      * @param date The date to use.
1211      * @return The result of invoking a date block on the current sink.
1212      * @see #testDate()
1213      */
1214     protected abstract String getDateBlock(String date);
1215 
1216     /**
1217      * Returns a head block generated by this sink.
1218      * @return The result of invoking a head block on the current sink.
1219      * @see #testHead()
1220      */
1221     protected abstract String getHeadBlock();
1222 
1223     /**
1224      * Returns a body block generated by this sink.
1225      * @return The result of invoking a body block on the current sink.
1226      * @see #testBody()
1227      */
1228     protected abstract String getBodyBlock();
1229 
1230     /**
1231      * Returns an article block generated by this sink.
1232      * @return The result of invoking an article block on the current sink.
1233      * @see #testArticle()
1234      */
1235     protected abstract String getArticleBlock();
1236 
1237     /**
1238      * Returns an navigation block generated by this sink.
1239      * @return The result of invoking an navigation block on the current sink.
1240      * @see #testNavigation()
1241      */
1242     protected abstract String getNavigationBlock();
1243 
1244     /**
1245      * Returns a sidebar block generated by this sink.
1246      * @return The result of invoking an sidebar block on the current sink.
1247      * @see #testSidebar()
1248      */
1249     protected abstract String getSidebarBlock();
1250 
1251     /**
1252      * Returns a SectionTitle block generated by this sink.
1253      * @param title The title to use.
1254      * @return The result of invoking a SectionTitle block on the current sink.
1255      * @see #testSectionTitle()
1256      */
1257     protected abstract String getSectionTitleBlock(String title);
1258 
1259     /**
1260      * Returns a Section1 block generated by this sink.
1261      * @param title The title to use.
1262      * @return The result of invoking a Section1 block on the current sink.
1263      * @see #testSection1()
1264      */
1265     protected abstract String getSection1Block(String title);
1266 
1267     /**
1268      * Returns a Section2 block generated by this sink.
1269      * @param title The title to use.
1270      * @return The result of invoking a Section2 block on the current sink.
1271      * @see #testSection2()
1272      */
1273     protected abstract String getSection2Block(String title);
1274 
1275     /**
1276      * Returns a Section3 block generated by this sink.
1277      * @param title The title to use.
1278      * @return The result of invoking a Section3 block on the current sink.
1279      * @see #testSection3()
1280      */
1281     protected abstract String getSection3Block(String title);
1282 
1283     /**
1284      * Returns a Section4 block generated by this sink.
1285      * @param title The title to use.
1286      * @return The result of invoking a Section4 block on the current sink.
1287      * @see #testSection4()
1288      */
1289     protected abstract String getSection4Block(String title);
1290 
1291     /**
1292      * Returns a Section5 block generated by this sink.
1293      * @param title The title to use.
1294      * @return The result of invoking a Section5 block on the current sink.
1295      * @see #testSection5()
1296      */
1297     protected abstract String getSection5Block(String title);
1298 
1299     /**
1300      * Returns a Section6 block generated by this sink.
1301      * @param title The title to use.
1302      * @return The result of invoking a Section6 block on the current sink.
1303      * @see #testSection6()
1304      */
1305     protected abstract String getSection6Block(String title);
1306 
1307     /**
1308      * Returns a header block generated by this sink.
1309      * @return The result of invoking a header block on the current sink.
1310      * @see #testHeader()
1311      */
1312     protected abstract String getHeaderBlock();
1313 
1314     /**
1315      * Returns a content block generated by this sink.
1316      * @return The result of invoking a content block on the current sink.
1317      * @see #testContent()
1318      */
1319     protected abstract String getContentBlock();
1320 
1321     /**
1322      * Returns a footer block generated by this sink.
1323      * @return The result of invoking a footer block on the current sink.
1324      * @see #testFooter()
1325      */
1326     protected abstract String getFooterBlock();
1327 
1328     /**
1329      * Returns a list block generated by this sink.
1330      * @param item The item to use.
1331      * @return The result of invoking a list block on the current sink.
1332      * @see #testList()
1333      */
1334     protected abstract String getListBlock(String item);
1335 
1336     /**
1337      * Returns a NumberedList block generated by this sink.
1338      * @param item The item to use.
1339      * @return The result of invoking a NumberedList block on the current sink.
1340      * @see #testNumberedList()
1341      */
1342     protected abstract String getNumberedListBlock(String item);
1343 
1344     /**
1345      * Returns a DefinitionList block generated by this sink.
1346      * @param definum The term to define.
1347      * @param definition The definition.
1348      * @return The result of invoking a DefinitionList block on the current sink.
1349      * @see #testDefinitionList()
1350      */
1351     protected abstract String getDefinitionListBlock(String definum, String definition);
1352 
1353     /**
1354      * Returns a Figure block generated by this sink.
1355      * @param source The figure source string.
1356      * @param caption The caption to use (may be null).
1357      * @return The result of invoking a Figure block on the current sink.
1358      * @see #testFigure()
1359      */
1360     protected abstract String getFigureBlock(String source, String caption);
1361 
1362     /**
1363      * Returns a Table block generated by this sink.
1364      * @param cell A table cell to use.
1365      * @param caption The caption to use (may be null).
1366      * @return The result of invoking a Table block on the current sink.
1367      * @see #testTable()
1368      */
1369     protected abstract String getTableBlock(String cell, String caption);
1370 
1371     /**
1372      * Returns a Table with header block on the current sink.
1373      * @param rowPrefixes the text prefix used in the individual rows.
1374      * @return the result of invoking a Table with header block on the current sink.
1375      * @see #testTableWithHeader()
1376      */
1377     protected abstract String getTableWithHeaderBlock(String... rowPrefixes);
1378 
1379     /**
1380      * Returns a Paragraph block generated by this sink.
1381      * @param text The text to use.
1382      * @return The result of invoking a Paragraph block on the current sink.
1383      * @see #testParagraph()
1384      */
1385     protected abstract String getParagraphBlock(String text);
1386 
1387     /**
1388      * Returns a Data block generated by this sink.
1389      * @param value The value to use.
1390      * @param text The text to use.
1391      * @return The result of invoking a Data block on the current sink.
1392      * @see #testData()
1393      */
1394     protected abstract String getDataBlock(String value, String text);
1395 
1396     /**
1397      * Returns a Time block generated by this sink.
1398      * @param datetime The datetime to use.
1399      * @param text The text to use.
1400      * @return The result of invoking a Time block on the current sink.
1401      * @see #testTime()
1402      */
1403     protected abstract String getTimeBlock(String datetime, String text);
1404 
1405     /**
1406      * Returns an Address block generated by this sink.
1407      * @param text The text to use.
1408      * @return The result of invoking an Address block on the current sink.
1409      * @see #testAddress()
1410      */
1411     protected abstract String getAddressBlock(String text);
1412 
1413     /**
1414      * Returns a Blockquote block generated by this sink.
1415      * @param text The text to use.
1416      * @return The result of invoking a Blockquote block on the current sink.
1417      * @see #testBlockquote()
1418      */
1419     protected abstract String getBlockquoteBlock(String text);
1420 
1421     /**
1422      * Returns a Division block generated by this sink.
1423      * @param text The text to use.
1424      * @return The result of invoking a Division block on the current sink.
1425      * @see #testDivider()
1426      */
1427     protected abstract String getDivisionBlock(String text);
1428 
1429     /**
1430      * Returns a Verbatim block generated by this sink.
1431      * @param text The text to use.
1432      * @return The result of invoking a Verbatim block on the current sink.
1433      * @see #testVerbatimSource()
1434      */
1435     protected abstract String getVerbatimSourceBlock(String text);
1436 
1437     /**
1438      * Returns a HorizontalRule block generated by this sink.
1439      * @return The result of invoking a HorizontalRule block on the current sink.
1440      * @see #testHorizontalRule()
1441      */
1442     protected abstract String getHorizontalRuleBlock();
1443 
1444     /**
1445      * Returns a PageBreak block generated by this sink.
1446      * @return The result of invoking a PageBreak block on the current sink.
1447      * @see #testPageBreak()
1448      */
1449     protected abstract String getPageBreakBlock();
1450 
1451     /**
1452      * Returns a Anchor block generated by this sink.
1453      * @param anchor The anchor to use.
1454      * @return The result of invoking a Anchor block on the current sink.
1455      * @see #testAnchor()
1456      */
1457     protected abstract String getAnchorBlock(String anchor);
1458 
1459     /**
1460      * Returns a Link block generated by this sink.
1461      * @param link The link to use.
1462      * @param text The link text.
1463      * @return The result of invoking a Link block on the current sink.
1464      * @see #testLink()
1465      */
1466     protected abstract String getLinkBlock(String link, String text);
1467 
1468     /**
1469      * Returns an Inline block generated by this sink.
1470      * @param text The text to use.
1471      * @return The result of invoking a Inline block on the current sink.
1472      * @see #testInline()
1473      */
1474     protected abstract String getInlineBlock(String text);
1475 
1476     /**
1477      * Returns an Inline italic block generated by this sink.
1478      * @param text The text to use.
1479      * @return The result of invoking a Inline italic block on the current sink.
1480      * @see #testInlineItalic()
1481      */
1482     protected abstract String getInlineItalicBlock(String text);
1483 
1484     /**
1485      * Returns an Inline bold block generated by this sink.
1486      * @param text The text to use.
1487      * @return The result of invoking a Inline bold block on the current sink.
1488      * @see #testInlineBold()
1489      */
1490     protected abstract String getInlineBoldBlock(String text);
1491 
1492     /**
1493      * Returns an Inline code block generated by this sink.
1494      * @param text The text to use.
1495      * @return The result of invoking a Inline code block on the current sink.
1496      * @see #testInlineBold()
1497      */
1498     protected abstract String getInlineCodeBlock(String text);
1499 
1500     /**
1501      * Returns a LineBreak block generated by this sink.
1502      * @return The result of invoking a LineBreak block on the current sink.
1503      * @see #testLineBreak()
1504      */
1505     protected abstract String getLineBreakBlock();
1506 
1507     /**
1508      * Returns a LineBreakOpportunity block generated by this sink.
1509      * @return The result of invoking a LineBreakOpportunity block on the
1510      * current sink.
1511      * @see #testLineBreakOpportunity()
1512      */
1513     protected abstract String getLineBreakOpportunityBlock();
1514 
1515     /**
1516      * Returns a NonBreakingSpace block generated by this sink.
1517      * @return The result of invoking a NonBreakingSpace block
1518      * on the current sink.
1519      * @see #testNonBreakingSpace()
1520      */
1521     protected abstract String getNonBreakingSpaceBlock();
1522 
1523     /**
1524      * Returns a Text block generated by this sink.
1525      * @param text The text to use.
1526      * @return The result of invoking a Text block on the current sink.
1527      * @see #testText()
1528      */
1529     protected abstract String getTextBlock(String text);
1530 
1531     /**
1532      * Returns a RawText block generated by this sink.
1533      * @param text The text to use.
1534      * @return The result of invoking a RawText block on the current sink.
1535      * @see #testRawText()
1536      */
1537     protected abstract String getRawTextBlock(String text);
1538 
1539     /**
1540      * Returns a comment block generated by this sink.
1541      * @param text The text to use.
1542      * @return The result of invoking a comment block on the current sink.
1543      * @see #testComment()
1544      * @since 1.1.1
1545      */
1546     protected abstract String getCommentBlock(String text);
1547 
1548     protected final void verifyValignSup(String text) {
1549         sink.text("ValignSup", new SinkEventAttributeSet(SinkEventAttributes.VALIGN, "sup"));
1550         sink.flush();
1551         sink.close();
1552 
1553         String actual = testWriter.toString();
1554 
1555         assertEquals("Wrong valign sup!", text, actual);
1556     }
1557 
1558     protected final void verifyValignSub(String text) {
1559         sink.text("ValignSub", new SinkEventAttributeSet(SinkEventAttributes.VALIGN, "sub"));
1560         sink.flush();
1561         sink.close();
1562 
1563         String actual = testWriter.toString();
1564 
1565         assertEquals("Wrong valign sub!", text, actual);
1566     }
1567 
1568     protected final void verifyDecorationUnderline(String text) {
1569         sink.text("DecorationUnderline", new SinkEventAttributeSet(SinkEventAttributes.DECORATION, "underline"));
1570         sink.flush();
1571         sink.close();
1572 
1573         String actual = testWriter.toString();
1574 
1575         assertEquals("Wrong decoration underline!", text, actual);
1576     }
1577 
1578     protected final void verifyDecorationLineThrough(String text) {
1579         sink.text("DecorationLineThrough", new SinkEventAttributeSet(SinkEventAttributes.DECORATION, "line-through"));
1580         sink.flush();
1581         sink.close();
1582 
1583         String actual = testWriter.toString();
1584 
1585         assertEquals("Wrong decoration line-through!", text, actual);
1586     }
1587 }