| /******************************************************************************* |
| * Copyright (c) 2012, 2015 Stefan Seelmann and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Stefan Seelmann - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.internal.wikitext.markdown.tests; |
| |
| import java.io.IOException; |
| import java.util.List; |
| |
| import org.eclipse.mylyn.wikitext.parser.DocumentBuilder.SpanType; |
| import org.eclipse.mylyn.wikitext.toolkit.RecordingDocumentBuilder.Event; |
| |
| /** |
| * Tests for Markdown block elements. Follows specification at |
| * <a>http://daringfireball.net/projects/markdown/syntax#block</a>. |
| * |
| * @author Stefan Seelmann |
| */ |
| public class MarkdownLanguageBlockElementsTest extends MarkdownLanguageTestBase { |
| |
| /* |
| * Paragraphs and Line Breaks. A paragraph is simply one or more consecutive lines of text, separated by one or more |
| * blank lines. (A blank line is any line that looks like a blank line — a line containing nothing but spaces or |
| * tabs is considered blank.) Normal paragraphs should not be indented with spaces or tabs. |
| */ |
| public void testParagraphWithOneLine() { |
| String markup = "a paragraph"; |
| String expectedHtml = "<p>a paragraph</p>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testParagraphWithMulitpleLines() { |
| String markup = "a paragraph\nwith multiple\nlines"; |
| String expectedHtml = "<p>a paragraph\nwith multiple\nlines</p>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testParagraphsSeparatedBySingleBlankLine() { |
| String markup = "a paragraph\n\nanother paragraph\n"; |
| String expectedHtml = "<p>a paragraph</p><p>another paragraph</p>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testParagraphsSeparatedByMulitpleBlankLines() { |
| String markup = "a paragraph\n\n\nanother paragraph\n\n"; |
| String expectedHtml = "<p>a paragraph</p><p>another paragraph</p>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testParagraphsSeparatedByMulitpleBlankLinesWithSpacesAndTabs() { |
| String markup = "a paragraph\n \n\t\nanother paragraph"; |
| String expectedHtml = "<p>a paragraph</p><p>another paragraph</p>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * When you do want to insert a <br /> |
| * break tag using Markdown, you end a line with two or more spaces, then type return. |
| */ |
| public void testLineBreakInParagraph() { |
| String markup = "line 1 \nline 2 \nline 3"; |
| String expectedHtml = "<p>line 1<br/>\nline 2<br/>\nline 3</p>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Blockquotes. Markdown uses email-style > characters for blockquoting. It looks best if you hard wrap the text and |
| * put a > before every line. |
| */ |
| public void testBlockquoteWithQuoteCharInEachLine() { |
| String markup = "> Lorem ipsum dolor sit amet, \n> consetetur adipisici elit."; |
| String expectedHtml = "<blockquote><p>Lorem ipsum dolor sit amet, \nconsetetur adipisici elit.</p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Markdown allows you to be lazy and only put the > before the first line of a hard-wrapped paragraph. |
| */ |
| public void testBlockquoteWithSingleQuoteChar() { |
| String markup = "> Lorem ipsum dolor sit amet, \nconsetetur adipisici elit."; |
| String expectedHtml = "<blockquote><p>Lorem ipsum dolor sit amet, \nconsetetur adipisici elit.</p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by adding additional levels of >. |
| */ |
| public void testNestedBlockquotesTwoLevels() { |
| String markup = "> A1\n>\n> > B1\n> > B2\n>\n> A2"; |
| String expectedHtml = "<blockquote><p>A1</p><blockquote><p>B1\nB2</p></blockquote><p>A2</p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testNestedBlockquotesThreeLevels() { |
| String markup = "> A1\n>\n> > B1\n> >\n> > > C1\n>\n> A2"; |
| String expectedHtml = "<blockquote><p>A1</p><blockquote><p>B1</p><blockquote><p>C1</p></blockquote></blockquote><p>A2</p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Blockquotes can contain other Markdown elements, including headers, lists, and code blocks. |
| */ |
| public void testBlockquotesContainingParagraphs() { |
| String markup = ">a\n>b\n>\n>c"; |
| String expectedHtml = "<blockquote><p>a\nb</p><p>c</p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingHeader() { |
| String markup = ">#H1"; |
| String expectedHtml = "<blockquote><h1 id=\"h1\">H1</h1></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingUnderlinedHeader1() { |
| String markup = ">H1\n>==="; |
| String expectedHtml = "<blockquote><h1 id=\"h1\">H1</h1></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingUnderlinedHeader2() { |
| String markup = ">H2\n>---"; |
| String expectedHtml = "<blockquote><h2 id=\"h2\">H2</h2></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingInlineLink() { |
| String markup = ">[Link](http://www.example.com)"; |
| String expectedHtml = "<blockquote><p><a href=\"http://www.example.com\">Link</a></p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingReferenceLink() { |
| String markup = ">[Link][link]\n>\n>[link]: http://www.example.com"; |
| String expectedHtml = "<blockquote><p><a href=\"http://www.example.com\">Link</a></p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingHorizontalRule() { |
| String markup = ">---"; |
| String expectedHtml = "<blockquote><hr/></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingHorizontalRuleIsNotInterpretedAsUnderlinedHeader() { |
| String markup = ">No H2.\n>\n>---"; |
| String expectedHtml = "<blockquote><p>No H2.</p><hr/></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingCodeBlock() { |
| String markup = "> code\n> block"; |
| String expectedHtml = "<blockquote><pre><code>code\nblock</code></pre></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingInlineHTML() { |
| String markup = "> <input type=\"button\" value=\"Click\"/>"; |
| String expectedHtml = "<blockquote><input type=\"button\" value=\"Click\"/></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingList() { |
| String markup = "> * Black\n> * White"; |
| String expectedHtml = "<blockquote><ul><li>Black</li><li>White</li></ul></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquotesContainingListWithWrappedItem() { |
| String markup = "> * Wrapped\n line\n> * Next\nitem"; |
| String expectedHtml = "<blockquote><ul><li>Wrapped\n line</li><li>Next\nitem</li></ul></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testBlockquoteSimple() { |
| String markup = "> a\n> b"; |
| String expectedHtml = "<blockquote><p>a\nb</p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Unordered lists use asterisks, pluses, and hyphens - interchangably - as list markers. |
| */ |
| public void testUnorderedListUsingAsteriskMarker() { |
| String markup = "* Red\n* Green\n* Blue"; |
| String expectedHtml = "<ul><li>Red</li><li>Green</li><li>Blue</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testUnorderedListUsingPlusMarkers() { |
| String markup = "+ Red\n+ Green\n+ Blue"; |
| String expectedHtml = "<ul><li>Red</li><li>Green</li><li>Blue</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testUnorderedListUsingHyphenMarkers() { |
| String markup = "- Red\n- Green\n- Blue"; |
| String expectedHtml = "<ul><li>Red</li><li>Green</li><li>Blue</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testUnorderedListUsingMixedMarkers() { |
| String markup = "* Red\n- Green\n+ Blue"; |
| String expectedHtml = "<ul><li>Red</li><li>Green</li><li>Blue</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testUnorderedListWithCodeBlockAfterwards() { |
| String markup = "* Red\n\n\n should be code\n"; |
| String expectedHtml = "<ul><li>Red</li></ul><pre><code>should be code</code></pre>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testUnorderedListWithParagraphAfterwards() { |
| String markup = "* first item\n\nThis is not a list anymore"; |
| String expectedHtml = "<ul><li>first item</li></ul><p>This is not a list anymore</p>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Unordered lists, that are nested |
| */ |
| public void testUnorderedListWhichIsNested() { |
| String markup = "* Item 1\n * Item 1.1"; |
| String expectedHtml = "<ul><li>Item 1</li><ul><li>Item 1.1</li></ul></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testUnorderedListWhichIsNestedUsingMixedMarkers() { |
| String markup = "* Item 1\n + Item 1.1\n - Item 1.1.1\n * Item 1.2\n* Item 2"; |
| String expectedHtml = "<ul><li>Item 1</li><ul><li>Item 1.1</li><ul><li>Item 1.1.1</li></ul>" |
| + "<li>Item 1.2</li></ul><li>Item 2</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testOrderedNestedListUsingSequentialNumbers() { |
| String markup = "1. Item 1\n 1. Item 1.1"; |
| String expectedHtml = "<ol><li>Item 1</li><ol><li>Item 1.1</li></ol></ol>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testOrderedNestedListUsingSameNumbers() { |
| String markup = "1. Item 1\n 1. Item 1.1\n 1. Item 1.1.1\n 1. Item 1.2\n1. Item 2"; |
| String expectedHtml = "<ol><li>Item 1</li><ol><li>Item 1.1</li><ol><li>Item 1.1.1</li></ol>" |
| + "<li>Item 1.2</li></ol><li>Item 2</li></ol>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testNestedListsMixingUnorderedAndOrdered() { |
| String markup = "* Item 1\n 1. Item 1.1\n * Item 1.1.1"; |
| String expectedHtml = "<ul><li>Item 1</li><ol><li>Item 1.1</li><ul><li>Item 1.1.1</li></ul></ol></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testUnorderedListUsingMultipleParagraphs() { |
| String markup = "* This is a list item with two paragraphs.\n" + "\n" |
| + " This is the second paragraph in the list item. You're\n" |
| + "only required to indent the first line. Lorem ipsum dolor\n" |
| + "sit amet, consectetuer adipiscing elit."; |
| String expectedHtml = "<ul><li>This is a list item with two paragraphs.\n" |
| + "<p>This is the second paragraph in the list item. You're\n" |
| + "only required to indent the first line. Lorem ipsum dolor\n" |
| + "sit amet, consectetuer adipiscing elit.</p></li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testOrderListUsingMultipleParagraphs() { |
| String markup = "1. This is a list item with two paragraphs. Lorem ipsum dolor\n" |
| + " sit amet, consectetuer adipiscing elit. Aliquam hendrerit\n" + " mi posuere lectus.\n\n" // end of paragraph |
| + " Vestibulum enim wisi, viverra nec, fringilla in, laoreet\n" |
| + " vitae, risus. Donec sit amet nisl. Aliquam semper ipsum\n" + " sit amet velit.\n\n" // end of paragraph and list item |
| + "2. Suspendisse id sem consectetuer libero luctus adipiscing.\n\n" |
| + "3. Third Item with an empty line separated."; |
| String expectedHtml = "<ol><li>This is a list item with two paragraphs. Lorem ipsum dolor\n" |
| + "sit amet, consectetuer adipiscing elit. Aliquam hendrerit\n" + "mi posuere lectus.\n" |
| + "<p>Vestibulum enim wisi, viverra nec, fringilla in, laoreet\n" |
| + "vitae, risus. Donec sit amet nisl. Aliquam semper ipsum\n" + "sit amet velit.</p></li>" |
| + "<li>Suspendisse id sem consectetuer libero luctus adipiscing.</li>" |
| + "<li>Third Item with an empty line separated.</li></ol>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Ordered lists use numbers followed by periods. |
| */ |
| public void testOrderedListUsingSequentialNumbers() { |
| String markup = "1. Bird\n2. McHale\n3. Parish"; |
| String expectedHtml = "<ol><li>Bird</li><li>McHale</li><li>Parish</li></ol>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * It's important to note that the actual numbers you use to mark the list |
| * have no effect on the HTML output Markdown produces. |
| */ |
| public void testOrderedListUsingSameNumbers() { |
| String markup = "1. Bird\n1. McHale\n1. Parish"; |
| String expectedHtml = "<ol><li>Bird</li><li>McHale</li><li>Parish</li></ol>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * List markers typically start at the left margin, but may be indented by up to three spaces. |
| */ |
| public void testListMarkersIndentedBySpaces() { |
| String markup = " * Red\n * Green\n * Blue"; |
| String expectedHtml = "<ul><li>Red</li><li>Green</li><li>Blue</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testListMarkersIndentedByMoreThanThreeSpacesIsNotRecognizedAsList() { |
| String markup = " * Red\n * Green\n * Blue"; |
| String expectedHtml = "<pre><code>* Red\n * Green\n * Blue</code></pre>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * List markers must be followed by one or more spaces or a tab. |
| */ |
| public void testListMarkersFollowedBySpaces() { |
| String markup = "* Red\n* Green\n* Blue"; |
| String expectedHtml = "<ul><li>Red</li><li>Green</li><li>Blue</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testListMarkersFollowedByTab() { |
| String markup = "1.\tBird\n1.\tMcHale\n1.\tParish"; |
| String expectedHtml = "<ol><li>Bird</li><li>McHale</li><li>Parish</li></ol>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testListMarkersNotFollowedBySpaceOrTabIsNotRecognizedAsList() { |
| String markup = "*Red\n*Green\n*Blue"; |
| String expectedHtml = "<p>*Red\n*Green\n*Blue</p>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * To make lists look nice, you can wrap items with hanging indents. |
| */ |
| public void testListWithWrappedItemAndHangingIndents() { |
| String markup = "* Lorem ipsum\n sit amet.\n* Donec sit\n amet nisl."; |
| String expectedHtml = "<ul><li>Lorem ipsum\nsit amet.</li><li>Donec sit\namet nisl.</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * But if you want to be lazy, you don't have to. |
| */ |
| public void testListWithWrappedItemAndNoHangingIndents() { |
| String markup = "* Lorem ipsum\nsit amet.\n* Donec sit\namet nisl."; |
| String expectedHtml = "<ul><li>Lorem ipsum\nsit amet.</li><li>Donec sit\namet nisl.</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testListContentOffsets() { |
| String markup = " * Lorem ipsum *sit* amet."; |
| List<Event> events = parseToEvents(markup); |
| |
| Event spanEvent = findEvent(events, SpanType.EMPHASIS); |
| assertEquals(1, spanEvent.locator.getLineNumber()); |
| assertEquals(16, spanEvent.locator.getLineCharacterOffset()); |
| assertEquals(21, spanEvent.locator.getLineSegmentEndOffset()); |
| } |
| |
| public void testListIndentationWithMultipleLines() throws IOException { |
| String input = "1. one\n\n2. two\na"; |
| String expectedHtml = "<ol><li>one</li><li>two\na</li></ol>"; |
| parseAndAssert(input, expectedHtml); |
| } |
| |
| /* |
| * Markdown wraps a code block in both pre and code tags. To produce a code block in Markdown, simply indent every |
| * line of the block by at least 4 spaces or 1 tab. |
| */ |
| public void testCodeBlockIndentedByFourSpaces() { |
| String markup = " This is a code block."; |
| String expectedHtml = "<pre><code>This is a code block.</code></pre>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testCodeBlockIndentedByOneTab() { |
| String markup = "\tThis is a code block."; |
| String expectedHtml = "<pre><code>This is a code block.</code></pre>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * One level of indentation - 4 spaces or 1 tab - is removed from each line of the code block. |
| */ |
| public void testCodeBlockMultiLineIndentedByFourSpaces() { |
| String markup = " aaa\n bbb\n ccc\n \n continue after empty line"; |
| String expectedHtml = "<pre><code>aaa\n bbb\n ccc\n\ncontinue after empty line</code></pre>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testCodeBlockMultiLineIndentedByOneTab() { |
| String markup = "\taaa\n\t\tbbb\n\t\t\tccc\n\t\n\tcontinue after empty line"; |
| String expectedHtml = "<pre><code>aaa\n bbb\n ccc\n\ncontinue after empty line</code></pre>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Within a code block, ampersands (&) and angle brackets (< and >) are automatically converted into HTML entities. |
| */ |
| public void testSpecialCharactersAreConvertedInCodeBlock() { |
| String markup = " <div class=\"footer\">\n © 2004 Foo Bar\n </div>"; |
| String expectedHtml = "<pre><code><div class=\"footer\">\n&copy; 2004 Foo Bar\n</div></code></pre>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Regular Markdown syntax is not processed within code blocks. |
| */ |
| public void testNoProcessingInCodeBlock() { |
| String markup = " ### Header 3\n Lorem *ipsum*"; |
| String expectedHtml = "<pre><code>### Header 3\nLorem *ipsum*</code></pre>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| /* |
| * Horizontal Rules. You can produce a horizontal rule tag ( hr/ ) by placing three or more hyphens, asterisks, or |
| * underscores on a line by themselves. If you wish, you may use spaces between the hyphens or asterisks. |
| */ |
| public void testHorizontalRulesWithAsterisksAndSpaces() { |
| parseAndAssert("* * *", "<hr/>"); |
| } |
| |
| public void testHorizontalRulesWithAsterisks() { |
| parseAndAssert("***", "<hr/>"); |
| } |
| |
| public void testHorizontalRulesWithMoreAsterisks() { |
| parseAndAssert("*****", "<hr/>"); |
| } |
| |
| public void testHorizontalRulesWithHyphensAndSpaces() { |
| parseAndAssert("- - -", "<hr/>"); |
| } |
| |
| public void testHorizontalRulesWithHyphens() { |
| parseAndAssert("---------------------------------------", "<hr/>"); |
| } |
| |
| public void testHorizontalRulesWithUnderscores() { |
| parseAndAssert("___", "<hr/>"); |
| } |
| |
| public void testParagraphsBrokenByHorizontalRuleBlock() { |
| String markup = "a paragraph\nfollowed by a horizontal rule\n---"; |
| String expectedHtml = "<p>a paragraph\nfollowed by a horizontal rule</p><hr/>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testParagraphsBrokenByHeadingBlock() { |
| String markup = "a paragraph\n# A header"; |
| String expectedHtml = "<p>a paragraph</p><h1 id=\"a-header\">A header</h1>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testParagraphsBrokenByQuoteBlock() { |
| String markup = "a paragraph\n> a quote block paragraph"; |
| String expectedHtml = "<p>a paragraph</p><blockquote><p>a quote block paragraph</p></blockquote>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testParagraphsBrokenByUListBlock() { |
| String markup = "a paragraph\n- a list item"; |
| String expectedHtml = "<p>a paragraph</p><ul><li>a list item</li></ul>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| public void testParagraphsBrokenByOListBlock() { |
| String markup = "a paragraph\n1. a list item"; |
| String expectedHtml = "<p>a paragraph</p><ol><li>a list item</li></ol>"; |
| parseAndAssert(markup, expectedHtml); |
| } |
| |
| } |