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.module.xhtml5;
20  
21  import java.io.StringWriter;
22  import java.io.Writer;
23  
24  import org.apache.maven.doxia.markup.HtmlMarkup;
25  import org.apache.maven.doxia.sink.Sink;
26  import org.apache.maven.doxia.sink.impl.AbstractSinkTest;
27  import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
28  import org.junit.jupiter.api.Test;
29  
30  import static org.apache.maven.doxia.util.HtmlTools.escapeHTML;
31  import static org.junit.jupiter.api.Assertions.assertEquals;
32  import static org.junit.jupiter.api.Assertions.assertTrue;
33  
34  public class Xhtml5SinkTest extends AbstractSinkTest {
35      /** {@inheritDoc} */
36      protected String outputExtension() {
37          return "html";
38      }
39  
40      /** {@inheritDoc} */
41      protected Sink createSink(Writer writer) {
42          return new Xhtml5Sink(writer, "UTF-8");
43      }
44  
45      /** {@inheritDoc} */
46      protected boolean isXmlSink() {
47          return true;
48      }
49  
50      /**
51       * Test link generation.
52       *
53       */
54      @Test
55      public void testLinks() {
56          Xhtml5Sink sink = null;
57          Writer writer = new StringWriter();
58          try {
59              sink = (Xhtml5Sink) createSink(writer);
60              sink.link("http:/www.xdoc.com");
61              sink.link_();
62              sink.link("./index.html#anchor");
63              sink.link_();
64              sink.link("../index.html#anchor");
65              sink.link_();
66              sink.link("index.html");
67              sink.link_();
68          } finally {
69              if (sink != null) {
70                  sink.close();
71              }
72          }
73  
74          String actual = writer.toString();
75          assertTrue(actual.contains("<a class=\"externalLink\" href=\"http:/www.xdoc.com\"></a>"));
76          assertTrue(actual.contains("<a href=\"./index.html#anchor\"></a>"));
77          assertTrue(actual.contains("<a href=\"../index.html#anchor\"></a>"));
78          assertTrue(actual.contains("<a href=\"index.html\"></a>"));
79      }
80  
81      /** {@inheritDoc} */
82      protected String getTitleBlock(String title) {
83          return "<title>" + title + "</title>";
84      }
85  
86      /** {@inheritDoc} */
87      protected String getAuthorBlock(String author) {
88          return author;
89      }
90  
91      /** {@inheritDoc} */
92      protected String getDateBlock(String date) {
93          return date;
94      }
95  
96      /** {@inheritDoc} */
97      protected String getHeadBlock() {
98          return "<!DOCTYPE html\">"
99                  + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<title></title>\n<meta charset=\"UTF-8\"/></head>";
100     }
101 
102     /** {@inheritDoc} */
103     protected String getBodyBlock() {
104         return "<body></body></html>";
105     }
106 
107     /** {@inheritDoc} */
108     protected String getArticleBlock() {
109         return "<article></article>";
110     }
111 
112     /** {@inheritDoc} */
113     protected String getNavigationBlock() {
114         return "<nav></nav>";
115     }
116 
117     /** {@inheritDoc} */
118     protected String getSidebarBlock() {
119         return "<aside></aside>";
120     }
121 
122     /** {@inheritDoc} */
123     protected String getSectionTitleBlock(String title) {
124         return title;
125     }
126 
127     /** {@inheritDoc} */
128     protected String getSection1Block(String title) {
129         return "<section><header>\n<h1>" + title + "</h1></header></section>";
130     }
131 
132     /** {@inheritDoc} */
133     protected String getSection2Block(String title) {
134         return "<section><header>\n<h2>" + title + "</h2></header></section>";
135     }
136 
137     /** {@inheritDoc} */
138     protected String getSection3Block(String title) {
139         return "<section><header>\n<h3>" + title + "</h3></header></section>";
140     }
141 
142     /** {@inheritDoc} */
143     protected String getSection4Block(String title) {
144         return "<section><header>\n<h4>" + title + "</h4></header></section>";
145     }
146 
147     /** {@inheritDoc} */
148     protected String getSection5Block(String title) {
149         return "<section><header>\n<h5>" + title + "</h5></header></section>";
150     }
151 
152     /** {@inheritDoc} */
153     protected String getSection6Block(String title) {
154         return "<section><header>\n<h6>" + title + "</h6></header></section>";
155     }
156 
157     /** {@inheritDoc} */
158     protected String getHeaderBlock() {
159         return "<header></header>";
160     }
161 
162     /** {@inheritDoc} */
163     protected String getContentBlock() {
164         return "<main>" + EOL + "<div class=\"content\"></div></main>";
165     }
166 
167     /** {@inheritDoc} */
168     protected String getFooterBlock() {
169         return "<footer></footer>";
170     }
171 
172     /** {@inheritDoc} */
173     protected String getListBlock(String item) {
174         return "<ul>\n<li>" + item + "</li></ul>";
175     }
176 
177     /** {@inheritDoc} */
178     protected String getNumberedListBlock(String item) {
179         return "<ol style=\"list-style-type: lower-roman;\">\n<li>" + item + "</li></ol>";
180     }
181 
182     /** {@inheritDoc} */
183     protected String getDefinitionListBlock(String definum, String definition) {
184         return "<dl>\n<dt>" + definum + "</dt>\n<dd>" + definition + "</dd></dl>";
185     }
186 
187     /** {@inheritDoc} */
188     protected String getFigureBlock(String source, String caption) {
189         String figureBlock = "<figure><img src=\"" + escapeHTML(source, true) + "\" />";
190         if (caption != null) {
191             figureBlock += "<figcaption>" + caption + "</figcaption>";
192         }
193         figureBlock += "</figure>";
194         return figureBlock;
195     }
196 
197     /** {@inheritDoc} */
198     protected String getTableBlock(String cell, String caption) {
199         return "<table class=\"bodyTable\">"
200                 + "<caption>Table caption</caption><tr class=\"a\">\n<td>cell</td></tr>"
201                 + "</table>";
202     }
203 
204     @Override
205     protected String getTableWithHeaderBlock(String... rowPrefixes) {
206         return "<table class=\"bodyTable\">\n"
207                 + "<tr class=\"a\">\n"
208                 + "<th>" + rowPrefixes[0] + "0</th>\n"
209                 + "<th>" + rowPrefixes[0] + "1</th>\n"
210                 + "<th>" + rowPrefixes[0] + "2</th></tr>\n"
211                 + "<tr class=\"b\">\n"
212                 + "<td style=\"text-align: left;\">" + rowPrefixes[1] + "0</td>\n"
213                 + "<td style=\"text-align: right;\">" + rowPrefixes[1] + "1</td>\n"
214                 + "<td style=\"text-align: center;\">" + rowPrefixes[1] + "2</td></tr>\n"
215                 + "<tr class=\"a\">\n"
216                 + "<td style=\"text-align: left;\">" + rowPrefixes[2] + "0</td>\n"
217                 + "<td style=\"text-align: right;\">" + rowPrefixes[2] + "1</td>\n"
218                 + "<td style=\"text-align: center;\">" + rowPrefixes[2] + "2</td></tr>"
219                 + "</table>";
220     }
221 
222     // Disable testTable until the order of attributes issue is clarified
223     // TODO: remove
224     /** {@inheritDoc} */
225     @Test
226     public void testTable() {
227         assertEquals("", "", "Dummy!");
228     }
229 
230     /** {@inheritDoc} */
231     protected String getParagraphBlock(String text) {
232         return "<p>" + text + "</p>";
233     }
234 
235     /** {@inheritDoc} */
236     protected String getDataBlock(String value, String text) {
237         return "<data value=\"" + value + "\">" + text + "</data>";
238     }
239 
240     /** {@inheritDoc} */
241     protected String getTimeBlock(String datetime, String text) {
242         return "<time datetime=\"" + datetime + "\">" + text + "</time>";
243     }
244 
245     /** {@inheritDoc} */
246     protected String getAddressBlock(String text) {
247         return "<address>" + text + "</address>";
248     }
249 
250     /** {@inheritDoc} */
251     protected String getBlockquoteBlock(String text) {
252         return "<blockquote>" + text + "</blockquote>";
253     }
254 
255     /** {@inheritDoc} */
256     protected String getDivisionBlock(String text) {
257         return "<div>" + text + "</div>";
258     }
259 
260     /** {@inheritDoc} */
261     protected String getVerbatimSourceBlock(String text) {
262         return "<pre><code>" + text + "</code></pre>";
263     }
264 
265     /** {@inheritDoc} */
266     protected String getHorizontalRuleBlock() {
267         return "<hr />";
268     }
269 
270     /** {@inheritDoc} */
271     protected String getPageBreakBlock() {
272         return "<!-- PB -->";
273     }
274 
275     /** {@inheritDoc} */
276     protected String getAnchorBlock(String anchor) {
277         return "<a id=\"" + anchor + "\">" + anchor + "</a>";
278     }
279 
280     /** {@inheritDoc} */
281     protected String getLinkBlock(String link, String text) {
282         return "<a href=\"" + link + "\">" + text + "</a>";
283     }
284 
285     /** {@inheritDoc} */
286     protected String getInlineBlock(String text) {
287         return text;
288     }
289 
290     /** {@inheritDoc} */
291     protected String getInlineItalicBlock(String text) {
292         return "<i>" + text + "</i>";
293     }
294 
295     /** {@inheritDoc} */
296     protected String getInlineBoldBlock(String text) {
297         return "<b>" + text + "</b>";
298     }
299 
300     /** {@inheritDoc} */
301     protected String getInlineCodeBlock(String text) {
302         return "<code>" + text + "</code>";
303     }
304 
305     /** {@inheritDoc} */
306     protected String getItalicBlock(String text) {
307         return "<i>" + text + "</i>";
308     }
309 
310     /** {@inheritDoc} */
311     protected String getBoldBlock(String text) {
312         return "<b>" + text + "</b>";
313     }
314 
315     /** {@inheritDoc} */
316     protected String getMonospacedBlock(String text) {
317         return "<code>" + text + "</code>";
318     }
319 
320     /** {@inheritDoc} */
321     protected String getLineBreakBlock() {
322         return "<br />";
323     }
324 
325     /** {@inheritDoc} */
326     protected String getLineBreakOpportunityBlock() {
327         return "<wbr />";
328     }
329 
330     /** {@inheritDoc} */
331     protected String getNonBreakingSpaceBlock() {
332         return "&#160;";
333     }
334 
335     /** {@inheritDoc} */
336     protected String getTextBlock(String text) {
337         // TODO: need to be able to retreive those from outside the sink
338         return "~,_=,_-,_+,_*,_[,_],_&lt;,_&gt;,_{,_},_\\";
339     }
340 
341     /** {@inheritDoc} */
342     protected String getRawTextBlock(String text) {
343         return text;
344     }
345 
346     /**
347      * Test entities is section titles and paragraphs.
348      */
349     @Test
350     public void testEntities() {
351         Xhtml5Sink sink = null;
352         Writer writer = new StringWriter();
353 
354         try {
355             sink = new Xhtml5Sink(writer);
356             sink.section(Sink.SECTION_LEVEL_1, null);
357             sink.header();
358             sink.sectionTitle(Sink.SECTION_LEVEL_1, null);
359             sink.text("&", null);
360             sink.sectionTitle_(Sink.SECTION_LEVEL_1);
361             sink.header_();
362             sink.paragraph(null);
363             sink.text("&", null);
364             sink.paragraph_();
365             sink.section_(Sink.SECTION_LEVEL_1);
366         } finally {
367             sink.close();
368         }
369 
370         assertEquals("<section><header>\n<h1>&amp;</h1></header>\n<p>&amp;</p></section>", writer.toString());
371     }
372 
373     /**
374      * Test head events.
375      */
376     @Test
377     public void testHead() {
378         Xhtml5Sink sink = null;
379         Writer writer = new StringWriter();
380 
381         try {
382             sink = new Xhtml5Sink(writer);
383             sink.head();
384             sink.title();
385             sink.text("Title");
386             sink.title_();
387             sink.comment("A comment");
388             sink.author();
389             // note: this is really illegal, there should be no un-resolved entities emitted into text()
390             sink.text("&#x123;&");
391             sink.author_();
392             SinkEventAttributeSet atts = new SinkEventAttributeSet(1);
393             atts.addAttribute("href", "http://maven.apache.org/");
394             sink.unknown("base", new Object[] {HtmlMarkup.TAG_TYPE_SIMPLE}, atts);
395             sink.head_();
396         } finally {
397             sink.close();
398         }
399 
400         String expected =
401                 "<head>\n<title>Title</title><!--A comment--><meta name=\"author\" content=\"&#x123;&amp;\" />"
402                         + "<base href=\"http://maven.apache.org/\" /></head>";
403         String actual = writer.toString();
404         assertTrue(actual.contains(expected), actual);
405     }
406 
407     /** {@inheritDoc} */
408     protected String getCommentBlock(String text) {
409         return "<!--" + toXmlComment(text) + "-->";
410     }
411 }