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 javax.swing.text.html.HTML.Attribute;
22  
23  import java.io.StringWriter;
24  import java.io.Writer;
25  
26  import org.apache.maven.doxia.markup.Markup;
27  import org.apache.maven.doxia.sink.Sink;
28  import org.apache.maven.doxia.sink.SinkEventAttributes;
29  import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet.Semantics;
30  import org.junit.jupiter.api.BeforeEach;
31  import org.junit.jupiter.api.Test;
32  
33  import static org.junit.jupiter.api.Assertions.*;
34  
35  /**
36   * Test for Xhtml5BaseSink.
37   */
38  public class Xhtml5BaseSinkTest {
39      protected static final String LS = Markup.EOL;
40      private final SinkEventAttributes attributes = SinkEventAttributeSet.BOLD;
41      private Writer writer;
42  
43      String EOL = System.lineSeparator();
44  
45      @BeforeEach
46      public void setUp() {
47          writer = new StringWriter();
48      }
49  
50      @Test
51      public void testSpaceAfterClosingTag() {
52          // DOXIA-189
53          try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
54              sink.paragraph();
55              sink.text("There should be no space before the ");
56              sink.italic();
57              sink.text("period");
58              sink.italic_();
59              sink.text(".");
60              sink.paragraph_();
61          }
62  
63          String actual = writer.toString();
64          String expected = "<p>There should be no space before the <i>period</i>.</p>";
65  
66          assertEquals(expected, actual);
67      }
68  
69      /**
70       */
71      @Test
72      public void testNestedTables() {
73          // DOXIA-177
74          try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
75  
76              sink.table();
77              sink.tableRows(new int[] {Sink.JUSTIFY_CENTER}, false);
78              sink.tableRow();
79              sink.tableCell();
80              sink.text("cell11");
81              sink.tableCell_();
82              sink.tableCell();
83              sink.text("cell12");
84              sink.tableCell_();
85              sink.tableRow_();
86  
87              sink.tableRow();
88              sink.tableCell();
89              sink.table(SinkEventAttributeSet.LEFT);
90              sink.tableRows(new int[] {Sink.JUSTIFY_LEFT}, false);
91              sink.tableRow();
92              sink.tableCell();
93              sink.text("nestedTable1Cell11");
94              sink.tableCell_();
95              sink.tableCell();
96              sink.text("nestedTable1Cell12");
97              sink.tableCell_();
98              sink.tableRow_();
99              sink.tableRow();
100             sink.tableCell();
101 
102             sink.table(SinkEventAttributeSet.RIGHT);
103             sink.tableRows(new int[] {Sink.JUSTIFY_RIGHT}, false);
104             sink.tableRow();
105             sink.tableCell();
106             sink.text("nestedTable2Cell11");
107             sink.tableCell_();
108             sink.tableCell();
109             sink.text("nestedTable2Cell12");
110             sink.tableCell_();
111             sink.tableRow_();
112             sink.tableRow();
113             sink.tableCell();
114             sink.text("nestedTable2Cell21");
115             sink.tableCell_();
116             sink.tableCell();
117             sink.text("nestedTable2Cell22");
118             sink.tableCell_();
119             sink.tableRow_();
120             sink.tableRows_();
121             sink.tableCaption();
122             sink.text("caption3");
123             sink.tableCaption_();
124             sink.table_();
125 
126             sink.tableCell_();
127             sink.tableCell();
128             sink.text("nestedTable1Cell22");
129             sink.tableCell_();
130             sink.tableRow_();
131             sink.tableRows_();
132             sink.tableCaption();
133             sink.text("caption2");
134             sink.tableCaption_();
135             sink.table_();
136 
137             sink.tableCell_();
138             sink.tableCell();
139             sink.text("cell22");
140             sink.tableCell_();
141             sink.tableRow_();
142             sink.tableRows_();
143             sink.tableCaption();
144             sink.text("caption&1");
145             sink.tableCaption_();
146             sink.table_();
147         }
148 
149         String actual = writer.toString();
150         assertTrue(actual.contains("<table class=\"bodyTable\">" + "<caption>caption&amp;1</caption>"));
151         assertTrue(actual.contains("<table class=\"bodyTable\">" + "<caption>caption2</caption>"));
152         assertTrue(actual.contains("<table class=\"bodyTable\">" + "<caption>caption3</caption>"));
153 
154         assertTrue(actual.contains("<td style=\"text-align: center;\">cell11</td>"));
155         assertTrue(actual.contains("<td style=\"text-align: left;\">nestedTable1Cell11</td>"));
156         assertTrue(actual.contains("<td style=\"text-align: right;\">nestedTable2Cell11</td>"));
157         assertTrue(actual.contains("<td>nestedTable1Cell22</td>"));
158         assertTrue(actual.contains("<td>cell22</td>"));
159     }
160 
161     /**
162      * Test of article method, of class Xhtml5BaseSink.
163      */
164     @Test
165     public void testArticle() {
166         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
167             sink.article();
168             sink.article_();
169         }
170 
171         assertEquals("<article></article>", writer.toString());
172 
173         writer = new StringWriter();
174 
175         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
176             sink.article(attributes);
177             sink.article_();
178         }
179 
180         assertEquals("<article style=\"bold\"></article>", writer.toString());
181     }
182 
183     /**
184      * Test of navigation method, of class Xhtml5BaseSink.
185      */
186     @Test
187     public void testNavigation() {
188         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
189             sink.navigation();
190             sink.navigation_();
191         }
192 
193         assertEquals("<nav></nav>", writer.toString());
194 
195         writer = new StringWriter();
196 
197         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
198             sink.navigation(attributes);
199             sink.navigation_();
200         }
201         assertEquals("<nav style=\"bold\"></nav>", writer.toString());
202     }
203 
204     /**
205      * Test of sidebar method, of class Xhtml5BaseSink.
206      */
207     @Test
208     public void testSidebar() {
209         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
210             sink.sidebar();
211             sink.sidebar_();
212         }
213 
214         assertEquals("<aside></aside>", writer.toString());
215 
216         writer = new StringWriter();
217 
218         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
219             sink.sidebar(attributes);
220             sink.sidebar_();
221         }
222 
223         assertEquals("<aside style=\"bold\"></aside>", writer.toString());
224     }
225 
226     /**
227      * Test of section method, of class Xhtml5BaseSink.
228      */
229     @Test
230     public void testSection() {
231         final int level = Xhtml5BaseSink.SECTION_LEVEL_1;
232 
233         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
234             sink.section(level, attributes);
235             sink.sectionTitle(level, attributes);
236             sink.sectionTitle_(level);
237             sink.section_(level);
238         }
239 
240         assertEquals("<section style=\"bold\">" + LS + "<h1 style=\"bold\"></h1></section>", writer.toString());
241     }
242 
243     /**
244      * Test of section method, of class Xhtml5BaseSink.
245      */
246     @Test
247     public void testSectionAttributes() {
248         final int level = Xhtml5BaseSink.SECTION_LEVEL_1;
249         final SinkEventAttributeSet set =
250                 new SinkEventAttributeSet("name", "section name", "class", "foo", "id", "bar");
251 
252         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
253             sink.section(level, set);
254             sink.sectionTitle(level, null);
255             sink.sectionTitle_(level);
256             sink.section_(level);
257         }
258 
259         assertEquals("<section class=\"foo\" id=\"bar\">" + LS + "<h1></h1></section>", writer.toString());
260     }
261 
262     /**
263      * Test of section1 method, of class Xhtml5BaseSink.
264      */
265     @Test
266     public void testSection1() {
267         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
268             sink.section1();
269             sink.sectionTitle1();
270             sink.sectionTitle1_();
271             sink.section1_();
272         }
273 
274         assertEquals("<section>" + LS + "<h1></h1></section>", writer.toString());
275     }
276 
277     /**
278      * Test of section2 method, of class Xhtml5BaseSink.
279      */
280     @Test
281     public void testSection2() {
282         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
283             sink.section2();
284             sink.sectionTitle2();
285             sink.sectionTitle2_();
286             sink.section2_();
287         }
288 
289         assertEquals("<section>" + LS + "<h2></h2></section>", writer.toString());
290     }
291 
292     /**
293      * Test of section3 method, of class Xhtml5BaseSink.
294      */
295     @Test
296     public void testSection3() {
297         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
298             sink.section3();
299             sink.sectionTitle3();
300             sink.sectionTitle3_();
301             sink.section3_();
302         }
303 
304         assertEquals("<section>" + LS + "<h3></h3></section>", writer.toString());
305     }
306 
307     /**
308      * Test of section4 method, of class Xhtml5BaseSink.
309      */
310     @Test
311     public void testSection4() {
312         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
313             sink.section4();
314             sink.sectionTitle4();
315             sink.sectionTitle4_();
316             sink.section4_();
317         }
318 
319         assertEquals("<section>" + LS + "<h4></h4></section>", writer.toString());
320     }
321 
322     /**
323      * Test of section5 method, of class Xhtml5BaseSink.
324      */
325     @Test
326     public void testSection5() {
327         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
328             sink.section5();
329             sink.sectionTitle5();
330             sink.sectionTitle5_();
331             sink.section5_();
332         }
333 
334         assertEquals("<section>" + LS + "<h5></h5></section>", writer.toString());
335     }
336 
337     /**
338      * Test of header method, of class Xhtml5BaseSink.
339      */
340     @Test
341     public void testHeader() {
342         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
343             sink.header();
344             sink.header_();
345         }
346 
347         assertEquals("<header></header>", writer.toString());
348 
349         writer = new StringWriter();
350 
351         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
352             sink.header(attributes);
353             sink.header_();
354         }
355 
356         assertEquals("<header style=\"bold\"></header>", writer.toString());
357     }
358 
359     /**
360      * Test of content method, of class Xhtml5BaseSink.
361      */
362     @Test
363     public void testContent() {
364         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
365             sink.content();
366             sink.content();
367             sink.content_();
368             sink.content_();
369         }
370 
371         assertEquals("<main>" + EOL + "<div class=\"content\"></div></main>", writer.toString());
372 
373         writer = new StringWriter();
374 
375         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
376             sink.content(attributes);
377             sink.content(attributes);
378             sink.content_();
379             sink.content_();
380         }
381 
382         assertEquals(
383                 "<main style=\"bold\">" + EOL + "<div style=\"bold\" class=\"content\"></div></main>",
384                 writer.toString());
385     }
386 
387     /**
388      * Test of footer method, of class Xhtml5BaseSink.
389      */
390     @Test
391     public void testFooter() {
392         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
393             sink.footer();
394             sink.footer_();
395         }
396 
397         assertEquals("<footer></footer>", writer.toString());
398 
399         writer = new StringWriter();
400 
401         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
402             sink.footer(attributes);
403             sink.footer_();
404         }
405 
406         assertEquals("<footer style=\"bold\"></footer>", writer.toString());
407     }
408 
409     /**
410      * Test of list method, of class Xhtml5BaseSink.
411      */
412     @Test
413     public void testList() {
414         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
415             sink.list();
416             sink.listItem();
417             sink.listItem_();
418             sink.list_();
419         }
420 
421         assertEquals("<ul>" + LS + "<li></li></ul>", writer.toString());
422 
423         writer = new StringWriter();
424 
425         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
426             sink.list(attributes);
427             sink.listItem(attributes);
428             sink.listItem_();
429             sink.list_();
430         }
431 
432         assertEquals("<ul style=\"bold\">" + LS + "<li style=\"bold\"></li></ul>", writer.toString());
433     }
434 
435     /**
436      * Test of numberedList method, of class Xhtml5BaseSink.
437      */
438     @Test
439     public void testNumberedList() {
440         final int numbering = Xhtml5BaseSink.NUMBERING_DECIMAL;
441 
442         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
443             sink.numberedList(numbering);
444             sink.numberedListItem();
445             sink.numberedListItem_();
446             sink.numberedList_();
447         }
448 
449         assertEquals("<ol style=\"list-style-type: decimal;\">" + LS + "<li></li></ol>", writer.toString());
450 
451         writer = new StringWriter();
452 
453         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
454             sink.numberedList(numbering, attributes);
455             sink.numberedListItem(attributes);
456             sink.numberedListItem_();
457             sink.numberedList_();
458         }
459 
460         assertEquals(
461                 "<ol style=\"list-style-type: decimal; bold\">" + LS + "<li style=\"bold\"></li></ol>",
462                 writer.toString());
463     }
464 
465     /**
466      * Test of definitionList method, of class Xhtml5BaseSink.
467      */
468     @Test
469     public void testDefinitionList() {
470         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
471             sink.definitionList();
472             sink.definedTerm();
473             sink.definedTerm_();
474             sink.definition();
475             sink.definition_();
476             sink.definitionList_();
477         }
478 
479         assertEquals("<dl>" + LS + "<dt></dt>" + LS + "<dd></dd></dl>", writer.toString());
480 
481         writer = new StringWriter();
482 
483         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
484             sink.definitionList(attributes);
485             sink.definedTerm(attributes);
486             sink.definedTerm_();
487             sink.definition(attributes);
488             sink.definition_();
489             sink.definitionList_();
490         }
491 
492         assertEquals(
493                 "<dl style=\"bold\">" + LS + "<dt style=\"bold\"></dt>" + LS + "<dd style=\"bold\"></dd></dl>",
494                 writer.toString());
495     }
496 
497     /**
498      * Test of figure method, of class Xhtml5BaseSink.
499      */
500     @Test
501     public void testFigure() {
502         final String src = "src.jpg";
503 
504         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
505             sink.figure(attributes);
506             sink.figureGraphics(src, attributes);
507             sink.figureCaption(attributes);
508             sink.figureCaption_();
509             sink.figure_();
510         }
511 
512         assertEquals(
513                 "<figure style=\"bold\">" + "<img src=\"src.jpg\" style=\"bold\" />"
514                         + "<figcaption style=\"bold\"></figcaption></figure>",
515                 writer.toString());
516     }
517 
518     /**
519      * Test of figureGraphics method, of class Xhtml5BaseSink.
520      */
521     @Test
522     public void testFigureGraphics() {
523         String src = "source.png";
524 
525         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
526             sink.figureGraphics(src, attributes);
527         }
528 
529         assertEquals("<img src=\"source.png\" style=\"bold\" />", writer.toString());
530     }
531 
532     /**
533      * Test of paragraph method, of class Xhtml5BaseSink.
534      */
535     @Test
536     public void testParagraph() {
537         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
538             sink.paragraph();
539             sink.paragraph_();
540         }
541 
542         assertEquals("<p></p>", writer.toString());
543 
544         writer = new StringWriter();
545 
546         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
547             sink.paragraph(attributes);
548             sink.paragraph_();
549         }
550 
551         assertEquals("<p style=\"bold\"></p>", writer.toString());
552     }
553 
554     /**
555      * Test of data method, of class Xhtml5BaseSink.
556      */
557     @Test
558     public void testData() {
559         String value = "value";
560 
561         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
562             sink.data(value, attributes);
563             sink.data_();
564         }
565 
566         assertEquals("<data value=\"value\" style=\"bold\"></data>", writer.toString());
567     }
568 
569     /**
570      * Test of time method, of class Xhtml5BaseSink.
571      */
572     @Test
573     public void testTime() {
574         String datetime = "datetime";
575 
576         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
577             sink.time(datetime, attributes);
578             sink.time_();
579         }
580 
581         assertEquals("<time datetime=\"datetime\" style=\"bold\"></time>", writer.toString());
582     }
583 
584     /**
585      * Test of address method, of class Xhtml5BaseSink.
586      */
587     @Test
588     public void testAddress() {
589         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
590             sink.address();
591             sink.address_();
592         }
593 
594         assertEquals("<address></address>", writer.toString());
595 
596         writer = new StringWriter();
597 
598         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
599             sink.address(attributes);
600             sink.address_();
601         }
602 
603         assertEquals("<address style=\"bold\"></address>", writer.toString());
604     }
605 
606     /**
607      * Test of blockquote method, of class Xhtml5BaseSink.
608      */
609     @Test
610     public void testBlockquote() {
611         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
612             sink.blockquote();
613             sink.blockquote_();
614         }
615 
616         assertEquals("<blockquote></blockquote>", writer.toString());
617 
618         writer = new StringWriter();
619 
620         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
621             sink.blockquote(attributes);
622             sink.blockquote_();
623         }
624 
625         assertEquals("<blockquote style=\"bold\"></blockquote>", writer.toString());
626     }
627 
628     /**
629      * Test of division method, of class Xhtml5BaseSink.
630      */
631     @Test
632     public void testDivision() {
633         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
634             sink.division();
635             sink.division_();
636         }
637 
638         assertEquals("<div></div>", writer.toString());
639 
640         writer = new StringWriter();
641 
642         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
643             sink.division(attributes);
644             sink.division_();
645         }
646 
647         assertEquals("<div style=\"bold\"></div>", writer.toString());
648     }
649 
650     /**
651      * Test of verbatim method, of class Xhtml5BaseSink.
652      */
653     @Test
654     public void testVerbatim() {
655         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
656             sink.verbatim(SinkEventAttributeSet.SOURCE);
657             sink.verbatim_();
658         }
659 
660         assertEquals("<pre><code></code></pre>", writer.toString());
661 
662         checkVerbatimAttributes(attributes, "<pre style=\"bold\"></pre>");
663 
664         final SinkEventAttributes att = new SinkEventAttributeSet(SinkEventAttributes.ID, "id");
665         checkVerbatimAttributes(att, "<pre id=\"id\"></pre>");
666 
667         att.addAttribute(Attribute.CLASS, "class");
668         checkVerbatimAttributes(att, "<pre id=\"id\" class=\"class\"></pre>");
669 
670         att.addAttribute(SinkEventAttributes.DECORATION, "source");
671         checkVerbatimAttributes(att, "<pre id=\"id\" class=\"class\"><code></code></pre>");
672 
673         att.removeAttribute(Attribute.CLASS.toString());
674         checkVerbatimAttributes(att, "<pre id=\"id\"><code></code></pre>");
675     }
676 
677     private void checkVerbatimAttributes(final SinkEventAttributes att, final String expected) {
678 
679         writer = new StringWriter();
680 
681         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
682             sink.verbatim(att);
683             sink.verbatim_();
684         }
685 
686         assertEquals(expected, writer.toString());
687     }
688 
689     /**
690      * Test of horizontalRule method, of class Xhtml5BaseSink.
691      */
692     @Test
693     public void testHorizontalRule() {
694         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
695             sink.horizontalRule();
696             sink.horizontalRule(attributes);
697         }
698 
699         assertEquals("<hr /><hr style=\"bold\" />", writer.toString());
700     }
701 
702     /**
703      * Test of table method, of class Xhtml5BaseSink.
704      */
705     @Test
706     public void testTable() {
707         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
708             sink.table(attributes);
709             sink.table_();
710         }
711 
712         assertEquals("</table>", writer.toString());
713     }
714 
715     /**
716      * Test of tableRows method, of class Xhtml5BaseSink.
717      */
718     @Test
719     public void testTableRows() {
720         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
721             sink.table();
722             sink.tableRows();
723             sink.tableRows_();
724             sink.table_();
725         }
726 
727         assertEquals("<table class=\"bodyTable\"></table>", writer.toString());
728     }
729 
730     /**
731      * Test of tableRow method, of class Xhtml5BaseSink.
732      */
733     @Test
734     public void testTableRow() {
735         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
736             sink.table();
737             sink.tableRows();
738             sink.tableRow(attributes);
739             sink.tableRow_();
740             sink.tableRow();
741             sink.tableRow_();
742             sink.tableRows_();
743             sink.table_();
744         }
745 
746         String xmlExpected = "<table class=\"bodyTable\">" + EOL + "<tr style=\"bold\" class=\"a\"></tr>" + EOL
747                 + "<tr class=\"b\"></tr></table>";
748 
749         assertEquals(xmlExpected, writer.toString());
750     }
751 
752     /**
753      * Test striping for hidden rows in tableRow method.
754      */
755     @Test
756     public void testHiddenTableRowStriping() {
757         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
758             SinkEventAttributeSet attributes2 = new SinkEventAttributeSet();
759             SinkEventAttributeSet attributes3 = new SinkEventAttributeSet();
760             attributes3.addAttributes(attributes);
761 
762             sink.table();
763             sink.tableRows();
764             sink.tableRow();
765             sink.tableRow_();
766             sink.tableRow(attributes);
767             sink.tableRow_();
768             attributes2.addAttribute(SinkEventAttributes.CLASS, "hidden xyz abc");
769             sink.tableRow(attributes2);
770             sink.tableRow_();
771             attributes2.addAttribute(SinkEventAttributes.CLASS, "abc hidden xyz");
772             sink.tableRow(attributes2);
773             sink.tableRow_();
774             sink.tableRow();
775             sink.tableRow_();
776             attributes2.addAttribute(SinkEventAttributes.CLASS, "not-hidden xyz");
777             sink.tableRow(attributes2);
778             sink.tableRow_();
779             attributes2.addAttribute(SinkEventAttributes.CLASS, "xyz not-hidden");
780             sink.tableRow(attributes2);
781             sink.tableRow_();
782             attributes3.addAttribute(SinkEventAttributes.CLASS, "xyz abc hidden");
783             sink.tableRow(attributes3);
784             sink.tableRow_();
785             attributes2.addAttribute(SinkEventAttributes.CLASS, "xyz hidden-not");
786             sink.tableRow(attributes2);
787             sink.tableRow_();
788             sink.tableRow();
789             sink.tableRow_();
790             sink.tableRows_();
791             sink.table_();
792         }
793 
794         StringBuilder expected = new StringBuilder("<table class=\"bodyTable\">");
795         expected.append(EOL).append("<tr class=\"a\"></tr>").append(EOL);
796         expected.append("<tr style=\"bold\" class=\"b\"></tr>").append(EOL);
797         expected.append("<tr class=\"a hidden xyz abc\"></tr>").append(EOL);
798         expected.append("<tr class=\"a abc hidden xyz\"></tr>").append(EOL);
799         expected.append("<tr class=\"a\"></tr>").append(EOL);
800         expected.append("<tr class=\"b not-hidden xyz\"></tr>").append(EOL);
801         expected.append("<tr class=\"a xyz not-hidden\"></tr>").append(EOL);
802         expected.append("<tr style=\"bold\" class=\"b xyz abc hidden\"></tr>").append(EOL);
803         expected.append("<tr class=\"b xyz hidden-not\"></tr>").append(EOL);
804         expected.append("<tr class=\"a\"></tr></table>");
805 
806         String xmlExpected = expected.toString();
807         assertEquals(xmlExpected, writer.toString());
808     }
809 
810     /**
811      * Test of tableCell method, of class Xhtml5BaseSink.
812      */
813     @Test
814     public void testTableCell() {
815         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
816             sink.tableCell(attributes);
817             sink.tableCell_();
818         }
819 
820         assertEquals("<td style=\"bold\"></td>", writer.toString());
821     }
822 
823     /**
824      * Test of tableHeaderCell method, of class Xhtml5BaseSink.
825      */
826     @Test
827     public void testTableHeaderCell() {
828         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
829             sink.tableHeaderCell(attributes);
830             sink.tableHeaderCell_();
831         }
832 
833         assertEquals("<th style=\"bold\"></th>", writer.toString());
834     }
835 
836     /**
837      * Test of tableCaption method, of class Xhtml5BaseSink.
838      */
839     @Test
840     public void testTableCaption() {
841         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
842             sink.table();
843             sink.tableRows();
844             sink.tableCaption(attributes);
845             sink.text("caption");
846             sink.tableCaption_();
847             sink.tableRows_();
848             sink.table_();
849         }
850 
851         assertEquals(
852                 "<table class=\"bodyTable\">" + "<caption style=\"bold\">caption</caption></table>", writer.toString());
853     }
854 
855     /**
856      * Test of anchor method, of class Xhtml5BaseSink.
857      */
858     @Test
859     public void testAnchor() {
860         String name = "anchor";
861         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
862             sink.anchor(name, attributes);
863             sink.anchor_();
864         }
865 
866         assertEquals("<a id=\"anchor\" style=\"bold\"></a>", writer.toString());
867     }
868 
869     /**
870      * Test of link method, of class Xhtml5BaseSink.
871      */
872     @Test
873     public void testLink() {
874         final String name = "link.html";
875 
876         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
877             sink.link(name, attributes);
878             sink.link_();
879         }
880 
881         assertEquals("<a style=\"bold\" href=\"link.html\"></a>", writer.toString());
882     }
883 
884     /**
885      * Test of link method for an external link.
886      */
887     @Test
888     public void testLinkExternal() {
889         final String name = "https://www.apache.org";
890 
891         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
892             sink.link(name, attributes);
893             sink.link_();
894         }
895 
896         assertEquals(
897                 "<a style=\"bold\" class=\"externalLink\" href=\"https://www.apache.org\"></a>", writer.toString());
898     }
899 
900     /**
901      * Test of link method for an external link when a css class is provided.
902      */
903     @Test
904     public void testLinkExternalClassExtend() {
905         final String name = "https://www.apache.org";
906         SinkEventAttributeSet attributes2 = new SinkEventAttributeSet();
907         attributes2.addAttributes(attributes);
908         attributes2.addAttribute(SinkEventAttributes.CLASS, "cs1 cs2");
909 
910         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
911             sink.link(name, attributes2);
912             sink.link_();
913         }
914 
915         assertEquals(
916                 "<a style=\"bold\" class=\"externalLink cs1 cs2\" href=\"https://www.apache.org\"></a>",
917                 writer.toString());
918     }
919 
920     /**
921      * Test of inline method, of class Xhtml5BaseSink.
922      */
923     @Test
924     public void testInline() {
925         String text = "a text & \u00c6";
926 
927         writer = new StringWriter();
928 
929         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
930             sink.inline(SinkEventAttributeSet.Semantics.EMPHASIS);
931             sink.inline(SinkEventAttributeSet.Semantics.STRONG);
932             sink.inline(SinkEventAttributeSet.Semantics.SMALL);
933             sink.inline(SinkEventAttributeSet.Semantics.LINE_THROUGH);
934             sink.inline(SinkEventAttributeSet.Semantics.CITATION);
935             sink.inline(SinkEventAttributeSet.Semantics.QUOTE);
936             sink.inline(SinkEventAttributeSet.Semantics.DEFINITION);
937             sink.inline(SinkEventAttributeSet.Semantics.ABBREVIATION);
938             sink.inline(SinkEventAttributeSet.Semantics.ITALIC);
939             sink.inline(SinkEventAttributeSet.Semantics.BOLD);
940             sink.inline(SinkEventAttributeSet.Semantics.CODE);
941             sink.inline(SinkEventAttributeSet.Semantics.VARIABLE);
942             sink.inline(SinkEventAttributeSet.Semantics.SAMPLE);
943             sink.inline(SinkEventAttributeSet.Semantics.KEYBOARD);
944             sink.inline(SinkEventAttributeSet.Semantics.SUPERSCRIPT);
945             sink.inline(SinkEventAttributeSet.Semantics.SUBSCRIPT);
946             sink.inline(SinkEventAttributeSet.Semantics.ANNOTATION);
947             sink.inline(SinkEventAttributeSet.Semantics.HIGHLIGHT);
948             sink.inline(SinkEventAttributeSet.Semantics.RUBY);
949             sink.inline(SinkEventAttributeSet.Semantics.RUBY_BASE);
950             sink.inline(SinkEventAttributeSet.Semantics.RUBY_TEXT);
951             sink.inline(SinkEventAttributeSet.Semantics.RUBY_TEXT_CONTAINER);
952             sink.inline(SinkEventAttributeSet.Semantics.RUBY_PARANTHESES);
953             sink.inline(SinkEventAttributeSet.Semantics.BIDIRECTIONAL_ISOLATION);
954             sink.inline(SinkEventAttributeSet.Semantics.BIDIRECTIONAL_OVERRIDE);
955             sink.inline(SinkEventAttributeSet.Semantics.PHRASE);
956             sink.inline(SinkEventAttributeSet.Semantics.INSERT);
957             sink.inline(SinkEventAttributeSet.Semantics.DELETE);
958             sink.text(text);
959             sink.inline_();
960             sink.inline_();
961             sink.inline_();
962             sink.inline_();
963             sink.inline_();
964             sink.inline_();
965             sink.inline_();
966             sink.inline_();
967             sink.inline_();
968             sink.inline_();
969             sink.inline_();
970             sink.inline_();
971             sink.inline_();
972             sink.inline_();
973             sink.inline_();
974             sink.inline_();
975             sink.inline_();
976             sink.inline_();
977             sink.inline_();
978             sink.inline_();
979             sink.inline_();
980             sink.inline_();
981             sink.inline_();
982             sink.inline_();
983             sink.inline_();
984             sink.inline_();
985             sink.inline_();
986             sink.inline_();
987         }
988 
989         assertEquals(
990                 "<em><strong><small><s><cite><q><dfn><abbr><i><b><code><var><samp><kbd><sup><sub><u><mark><ruby><rb><rt><rtc><rp><bdi><bdo><span><ins><del>a text &amp; &#xc6;</del></ins></span></bdo></bdi></rp></rtc></rt></rb></ruby></mark></u></sub></sup></kbd></samp></var></code></b></i></abbr></dfn></q></cite></s></small></strong></em>",
991                 writer.toString());
992     }
993 
994     /**
995      * Test of italic/bold/code method, of class Xhtml5BaseSink.
996      */
997     @Test
998     public void testItalic() {
999         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1000             sink.inline(SinkEventAttributeSet.Semantics.ITALIC);
1001             sink.inline_();
1002             sink.inline(SinkEventAttributeSet.Semantics.BOLD);
1003             sink.inline_();
1004             sink.inline(SinkEventAttributeSet.Semantics.CODE);
1005             sink.inline_();
1006         }
1007 
1008         assertEquals("<i></i><b></b><code></code>", writer.toString());
1009     }
1010 
1011     /**
1012      * Test of lineBreak/lineBreakOpportunity/pageBreak/nonBreakingSpace method, of class Xhtml5BaseSink.
1013      */
1014     @Test
1015     public void testLineBreak() {
1016         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1017             sink.lineBreak(attributes);
1018             sink.lineBreakOpportunity(attributes);
1019             sink.pageBreak();
1020             sink.nonBreakingSpace();
1021         }
1022 
1023         assertEquals("<br style=\"bold\" /><wbr style=\"bold\" /><!-- PB -->&#160;", writer.toString());
1024     }
1025 
1026     /**
1027      * Test of text method, of class Xhtml5BaseSink.
1028      */
1029     @Test
1030     public void testText() {
1031         String text = "a text & \u00c6";
1032 
1033         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1034             sink.text(text);
1035         }
1036 
1037         assertEquals("a text &amp; &#xc6;", writer.toString());
1038 
1039         writer = new StringWriter();
1040 
1041         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1042             sink.text(text, attributes);
1043         }
1044 
1045         assertEquals("a text &amp; &#xc6;", writer.toString());
1046     }
1047 
1048     /**
1049      * Test of text method, of class Xhtml5BaseSink.
1050      */
1051     @Test
1052     public void testTextWithAttributes() {
1053         String text = "text";
1054 
1055         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1056             sink.text(text, Semantics.STRONG);
1057         }
1058 
1059         assertEquals("<strong>text</strong>", writer.toString());
1060     }
1061 
1062     /**
1063      * Test of rawText method, of class Xhtml5BaseSink.
1064      */
1065     @Test
1066     public void testRawText() {
1067         String text = "raw text";
1068 
1069         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1070             sink.rawText(text);
1071         }
1072 
1073         assertEquals("raw text", writer.toString());
1074     }
1075 
1076     /**
1077      * Test of comment method, of class Xhtml5BaseSink.
1078      */
1079     @Test
1080     public void testComment() {
1081         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1082             sink.comment("a comment");
1083             sink.comment(" a comment");
1084             sink.comment("a comment ");
1085             sink.comment(" a comment ");
1086         }
1087 
1088         assertEquals("<!--a comment--><!-- a comment--><!--a comment --><!-- a comment -->", writer.toString());
1089     }
1090 
1091     /**
1092      * Test of unknown method, of class Xhtml5BaseSink.
1093      */
1094     @Test
1095     public void testUnknown() {
1096         final String name = "unknown";
1097         final Object[] requiredParams = null;
1098 
1099         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1100             sink.unknown(name, requiredParams, attributes);
1101         }
1102 
1103         assertEquals("", writer.toString());
1104     }
1105 
1106     /**
1107      * Test entities in attribute values.
1108      */
1109     @Test
1110     public void testAttributeEntities() {
1111         final Object[] startTag = new Object[] {Xhtml5BaseSink.TAG_TYPE_START};
1112         final Object[] endTag = new Object[] {Xhtml5BaseSink.TAG_TYPE_END};
1113         final String script = Xhtml5BaseSink.SCRIPT.toString();
1114         final SinkEventAttributes src =
1115                 new SinkEventAttributeSet(SinkEventAttributes.SRC, "http://ex.com/ex.js?v=l&l=e");
1116 
1117         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1118             sink.unknown(script, startTag, src);
1119             sink.unknown(script, endTag, null);
1120 
1121             sink.figureGraphics("http://ex.com/ex.jpg?v=l&l=e", src);
1122         }
1123 
1124         String result = writer.toString();
1125 
1126         assertTrue(result.contains("ex.js?v=l&amp;l=e"));
1127         assertTrue(result.contains("ex.jpg?v=l&amp;l=e"));
1128     }
1129 
1130     /**
1131      * Test of entity.
1132      */
1133     @Test
1134     public void testEntity() {
1135         // DOXIA-314
1136         String text = "a text '&#x1d7ed;'";
1137 
1138         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1139             sink.text(text);
1140         }
1141 
1142         assertEquals("a text '&#x1d7ed;'", writer.toString());
1143     }
1144 
1145     /**
1146      * Test unicode characters in tables. DOXIA-433.
1147      */
1148     @Test
1149     public void testSpecialCharacters() {
1150         try (Xhtml5BaseSink sink = new Xhtml5BaseSink(writer)) {
1151             sink.table();
1152             sink.tableRows();
1153             sink.tableRow(null);
1154             sink.tableCell();
1155             sink.text("\u2713", null);
1156             sink.tableCell_();
1157             sink.tableRow_();
1158             sink.tableRows_();
1159             sink.table_();
1160         }
1161 
1162         final String result = writer.toString();
1163 
1164         assertTrue(result.contains("&#x2713;"));
1165     }
1166 }