1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.module.markdown;
20
21 import javax.inject.Inject;
22
23 import java.io.IOException;
24 import java.io.Reader;
25 import java.io.StringReader;
26 import java.io.Writer;
27
28 import org.apache.commons.lang3.StringUtils;
29 import org.apache.maven.doxia.parser.ParseException;
30 import org.apache.maven.doxia.parser.Parser;
31 import org.apache.maven.doxia.sink.Sink;
32 import org.apache.maven.doxia.sink.impl.AbstractSinkTest;
33 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
34 import org.apache.maven.doxia.sink.impl.SinkEventTestingSink;
35 import org.apache.maven.doxia.util.HtmlTools;
36 import org.hamcrest.MatcherAssert;
37 import org.hamcrest.Matchers;
38 import org.junit.jupiter.api.Test;
39
40 import static org.junit.jupiter.api.Assertions.assertEquals;
41
42
43
44
45 public class MarkdownSinkTest extends AbstractSinkTest {
46 @Inject
47 protected MarkdownParser parser;
48
49
50 protected String outputExtension() {
51 return "md";
52 }
53
54
55 protected Sink createSink(Writer writer) {
56 return new MarkdownSink(writer);
57 }
58
59
60 protected boolean isXmlSink() {
61 return false;
62 }
63
64
65 protected String getTitleBlock(String title) {
66 return title;
67 }
68
69
70 protected String getAuthorBlock(String author) {
71 return getEscapedText(author);
72 }
73
74
75 protected String getDateBlock(String date) {
76 return date;
77 }
78
79
80 protected String getHeadBlock() {
81 return "";
82 }
83
84
85 protected String getBodyBlock() {
86 return "";
87 }
88
89
90 protected String getArticleBlock() {
91 return "";
92 }
93
94
95 protected String getNavigationBlock() {
96 return "";
97 }
98
99
100 protected String getSidebarBlock() {
101 return "";
102 }
103
104
105 protected String getSectionTitleBlock(String title) {
106 return title;
107 }
108
109 protected String getSectionBlock(String title, int level) {
110 return StringUtils.repeat(MarkdownMarkup.SECTION_TITLE_START_MARKUP, level) + SPACE + title + EOL + EOL;
111 }
112
113
114 protected String getSection1Block(String title) {
115 return getSectionBlock(title, 1);
116 }
117
118
119 protected String getSection2Block(String title) {
120 return getSectionBlock(title, 2);
121 }
122
123
124 protected String getSection3Block(String title) {
125 return getSectionBlock(title, 3);
126 }
127
128
129 protected String getSection4Block(String title) {
130 return getSectionBlock(title, 4);
131 }
132
133
134 protected String getSection5Block(String title) {
135 return getSectionBlock(title, 5);
136 }
137
138
139 protected String getSection6Block(String title) {
140 return getSectionBlock(title, 6);
141 }
142
143
144 protected String getHeaderBlock() {
145 return "";
146 }
147
148
149 protected String getContentBlock() {
150 return "";
151 }
152
153
154 protected String getFooterBlock() {
155 return "";
156 }
157
158
159 protected String getListBlock(String item) {
160 return MarkdownMarkup.LIST_UNORDERED_ITEM_START_MARKUP + getEscapedText(item) + EOL + EOL;
161 }
162
163
164 protected String getNumberedListBlock(String item) {
165 return MarkdownMarkup.LIST_ORDERED_ITEM_START_MARKUP + getEscapedText(item) + EOL + EOL;
166 }
167
168
169 protected String getDefinitionListBlock(String definum, String definition) {
170
171 return "<dl>" + EOL + "<dt>" + getEscapedText(definum) + "</dt>" + EOL + "<dd>" + getEscapedText(definition)
172 + "</dd>" + EOL + "</dl>" + EOL + EOL;
173 }
174
175
176 protected String getFigureBlock(String source, String caption) {
177 return "![" + (caption != null ? getEscapedText(caption) : "") + "](" + getEscapedText(source) + ")";
178 }
179
180
181 protected String getTableBlock(String cell, String caption) {
182 return MarkdownMarkup.TABLE_ROW_PREFIX + " " + MarkdownMarkup.TABLE_CELL_SEPARATOR_MARKUP + EOL
183 + MarkdownMarkup.TABLE_ROW_PREFIX
184 + ":---:" + MarkdownMarkup.TABLE_CELL_SEPARATOR_MARKUP + EOL + MarkdownMarkup.TABLE_ROW_PREFIX
185 + cell + MarkdownMarkup.TABLE_CELL_SEPARATOR_MARKUP + EOL;
186 }
187
188 @Override
189 protected String getTableWithHeaderBlock(String... rowPrefixes) {
190 StringBuilder expectedMarkup = new StringBuilder();
191 expectedMarkup.append(MarkdownMarkup.TABLE_ROW_PREFIX + getEscapedText(rowPrefixes[0]) + "0|"
192 + getEscapedText(rowPrefixes[0]) + "1|" + getEscapedText(rowPrefixes[0]) + "2|" + EOL);
193 expectedMarkup.append(MarkdownMarkup.TABLE_ROW_PREFIX + "---|---:|:---:|" + EOL);
194 for (int n = 1; n < rowPrefixes.length; n++) {
195 expectedMarkup.append(MarkdownMarkup.TABLE_ROW_PREFIX + getEscapedText(rowPrefixes[n]) + "0|"
196 + getEscapedText(rowPrefixes[n]) + "1|" + getEscapedText(rowPrefixes[n]) + "2|" + EOL);
197 }
198 return expectedMarkup.toString();
199 }
200
201
202 protected String getParagraphBlock(String text) {
203 return text + EOL + EOL;
204 }
205
206
207 protected String getDataBlock(String value, String text) {
208 return text;
209 }
210
211
212 protected String getTimeBlock(String datetime, String text) {
213 return text;
214 }
215
216
217 protected String getAddressBlock(String text) {
218 return text;
219 }
220
221
222 protected String getBlockquoteBlock(String text) {
223 return "> " + text + EOL;
224 }
225
226
227 protected String getDivisionBlock(String text) {
228 return text;
229 }
230
231
232 protected String getVerbatimSourceBlock(String text) {
233 return MarkdownMarkup.VERBATIM_START_MARKUP + EOL + text + EOL + MarkdownMarkup.VERBATIM_END_MARKUP + EOL + EOL;
234 }
235
236
237 protected String getHorizontalRuleBlock() {
238 return MarkdownMarkup.HORIZONTAL_RULE_MARKUP + EOL + EOL;
239 }
240
241
242 protected String getPageBreakBlock() {
243 return "";
244 }
245
246
247 protected String getAnchorBlock(String anchor) {
248 return anchor;
249 }
250
251
252 protected String getLinkBlock(String link, String text) {
253 String lnk = link.startsWith("#") ? link.substring(1) : link;
254 return MarkdownMarkup.LINK_START_1_MARKUP
255 + text
256 + MarkdownMarkup.LINK_START_2_MARKUP
257 + lnk
258 + MarkdownMarkup.LINK_END_MARKUP;
259 }
260
261
262 protected String getInlineBlock(String text) {
263 return text;
264 }
265
266
267 protected String getInlineItalicBlock(String text) {
268 return MarkdownMarkup.ITALIC_START_MARKUP + text + MarkdownMarkup.ITALIC_END_MARKUP;
269 }
270
271
272 protected String getInlineBoldBlock(String text) {
273 return MarkdownMarkup.BOLD_START_MARKUP + text + MarkdownMarkup.BOLD_END_MARKUP;
274 }
275
276
277 protected String getInlineCodeBlock(String text) {
278 return MarkdownMarkup.MONOSPACED_START_MARKUP + text + MarkdownMarkup.MONOSPACED_END_MARKUP;
279 }
280
281
282 protected String getItalicBlock(String text) {
283 return MarkdownMarkup.ITALIC_START_MARKUP + text + MarkdownMarkup.ITALIC_END_MARKUP;
284 }
285
286
287 protected String getBoldBlock(String text) {
288 return MarkdownMarkup.BOLD_START_MARKUP + text + MarkdownMarkup.BOLD_END_MARKUP;
289 }
290
291
292 protected String getMonospacedBlock(String text) {
293 return text;
294 }
295
296
297 protected String getLineBreakBlock() {
298 return "" + SPACE + SPACE + EOL;
299 }
300
301
302 protected String getLineBreakOpportunityBlock() {
303 return "";
304 }
305
306
307 protected String getNonBreakingSpaceBlock() {
308 return MarkdownMarkup.NON_BREAKING_SPACE_MARKUP;
309 }
310
311
312 protected String getTextBlock(String text) {
313
314
315
316
317 return "~,\\_=,\\_\\-,\\_\\+,\\_\\*,\\_\\[,\\_\\],\\_<,\\_>,\\_\\{,\\_\\},\\_\\\\";
318 }
319
320
321 protected String getRawTextBlock(String text) {
322 return text;
323 }
324
325
326
327
328
329
330 private String getEscapedText(String text) {
331 text = HtmlTools.escapeHTML(text, true);
332 return text.replaceAll("\\\\|\\`|\\*|_|\\{|\\}|\\[|\\]|\\(|\\)|#|\\+|\\-|\\.|\\!", "\\\\$0");
333 }
334
335
336 protected String getCommentBlock(String text) {
337 return "<!-- " + text + " -->";
338 }
339
340 @Test
341 public void testMultipleAuthors() {
342 final Sink sink = getSink();
343 sink.head();
344 sink.author();
345 sink.text("first author");
346 sink.author_();
347 sink.author();
348 sink.text("second author");
349 sink.author_();
350 sink.head_();
351 sink.flush();
352 sink.close();
353
354 String expected = MarkdownMarkup.METADATA_MARKUP + EOL
355 + "author: " + EOL
356 + " - first author" + EOL
357 + " - second author" + EOL
358 + MarkdownMarkup.METADATA_MARKUP + EOL + EOL;
359
360 assertEquals(expected, getSinkContent(), "Wrong metadata section");
361 }
362
363
364 @Test
365 public void testRoundtrip() throws IOException, ParseException {
366 parseFile(parser, "test", getSink());
367
368 final SinkEventTestingSink regeneratedSink = new SinkEventTestingSink();
369 try (Reader reader = new StringReader(getSinkContent())) {
370 parser.parse(reader, regeneratedSink);
371 }
372
373 final SinkEventTestingSink originalSink = new SinkEventTestingSink();
374 parseFile(parser, "test", originalSink);
375
376
377 try {
378 MatcherAssert.assertThat(
379 regeneratedSink.getEventList(),
380 Matchers.contains(originalSink.getEventList().toArray()));
381 } catch (AssertionError e) {
382
383 System.err.println(getSinkContent());
384 throw e;
385 }
386 }
387
388 private void parseFile(Parser parser, String file, Sink sink) throws ParseException, IOException {
389 try (Reader reader = getTestReader(file)) {
390 parser.parse(reader, sink);
391 }
392 }
393
394 @Test
395 public void testLinksParagraphsAndStylesInTableCells() {
396 final String linkTarget = "target";
397 final String linkText = "link";
398 final String paragraphText = "paragraph text with |";
399 final Sink sink = getSink();
400 sink.table();
401 sink.tableRows();
402 sink.tableRow();
403 sink.tableCell();
404 sink.link(linkTarget);
405 sink.text(linkText);
406 sink.link_();
407 sink.tableCell_();
408 sink.tableCell();
409 sink.paragraph();
410 sink.text(paragraphText);
411 sink.bold();
412 sink.text("bold");
413 sink.bold_();
414 sink.paragraph_();
415 sink.tableCell_();
416 sink.tableRow_();
417 sink.tableRows_();
418 sink.table_();
419 sink.flush();
420 sink.close();
421
422 String expected =
423 "| | |" + EOL + "|---|---|" + EOL + "|[link](target)|paragraph text with \\|**bold**|" + EOL;
424
425 assertEquals(expected, getSinkContent(), "Wrong link or paragraph markup in table cell");
426 }
427
428 @Test
429 public void testInlineCodeWithSpecialCharacters() {
430 String text = "Test&<>*_";
431 final Sink sink = getSink();
432 sink.inline(SinkEventAttributeSet.Semantics.CODE);
433 sink.text(text);
434 sink.inline_();
435 sink.flush();
436 sink.close();
437
438 String expected = "`" + text + "`";
439
440 assertEquals(expected, getSinkContent(), "Wrong inline code!");
441 }
442
443 @Test
444 public void testNestedListWithBlockquotesParagraphsAndCode() {
445 final Sink sink = getSink();
446 sink.list();
447
448 sink.listItem();
449 sink.text("item1");
450 sink.list();
451 sink.listItem();
452 sink.text("item1a");
453 sink.listItem_();
454 sink.list_();
455 sink.listItem_();
456
457 sink.listItem();
458 sink.blockquote();
459 sink.text("blockquote");
460 sink.blockquote_();
461 sink.listItem_();
462
463 sink.listItem();
464 sink.text("item3");
465 sink.paragraph();
466 sink.text("item3paragraph2");
467 sink.paragraph_();
468 sink.listItem_();
469
470 sink.listItem();
471 sink.text("item4");
472 sink.verbatim();
473 sink.text("item4verbatim");
474 sink.lineBreak();
475 sink.text("item4verbatimline2");
476 sink.verbatim_();
477 sink.listItem_();
478
479 sink.list_();
480 sink.flush();
481 sink.close();
482
483 String expected = "- item1" + EOL
484 + " - item1a" + EOL
485 + EOL
486 + "- " + EOL
487 + " > blockquote" + EOL
488 + "- item3" + EOL
489 + EOL
490 + " item3paragraph2" + EOL
491 + EOL
492 + "- item4" + EOL
493 + " ```" + EOL
494 + " item4verbatim" + EOL
495 + " item4verbatimline2" + EOL
496 + " ```" + EOL
497 + EOL;
498
499 assertEquals(expected, getSinkContent(), "Wrong inline code!");
500 }
501 }