using Glass.Markdown; using System; using System.Collections.Generic; using UnitTestSharp; namespace Glass.UnitTests { public class MarkdownParserTests : TestFixture { private static string Lines(params string[] lines) { return string.Join("\n", lines); } [IgnoreFixture] public class BlockFixture : TestFixture { [IgnoreTest] protected void CheckBlocks(string markdown, params MarkdownBlock[] expected) { CheckEqual(expected, MarkdownParser.Parse(markdown)); } } public class ParseTests : BlockFixture { public void NullThrows() { CheckThrow(typeof(ArgumentNullException)); MarkdownParser.Parse(null); } public void EmptyTextHasNoBlocks() { CheckBlocks(string.Empty); } public void OnlyBlankLinesHaveNoBlocks() { CheckBlocks(Lines(string.Empty, " ", "\t", string.Empty)); } public void ALineIsAParagraph() { CheckBlocks("Hello there.", new MarkdownParagraph("Hello there.")); } public void LinesWithoutABlankBetweenJoinWithASpace() { CheckBlocks(Lines("one", "two", "three"), new MarkdownParagraph("one two three")); } public void ABlankLineStartsAnotherParagraph() { CheckBlocks( Lines("one", string.Empty, "two"), new MarkdownParagraph("one"), new MarkdownParagraph("two")); } public void ManyBlankLinesCountAsOne() { CheckBlocks( Lines("one", string.Empty, string.Empty, string.Empty, "two"), new MarkdownParagraph("one"), new MarkdownParagraph("two")); } public void RunsOfSpacesAndTabsBecomeOneSpace() { CheckBlocks("Great. Next\t\tone.", new MarkdownParagraph("Great. Next one.")); } public void LeadingAndTrailingWhitespaceIsDropped() { CheckBlocks(Lines(" padded ", " also "), new MarkdownParagraph("padded also")); } public void WindowsAndOldMacLineEndingsBreakLinesToo() { CheckBlocks("one\r\ntwo\r\rthree", new MarkdownParagraph("one two"), new MarkdownParagraph("three")); } public void InlineMarkupIsLeftInTheText() { const string Marked = "some **bold** and `code` and *this*"; CheckBlocks(Marked, new MarkdownParagraph(Marked)); } } public class HeadingTests : BlockFixture { public void HashesSetTheLevel() { CheckBlocks( Lines("# one", "## two", "### three", "#### four", "##### five", "###### six"), new MarkdownHeading(1, "one"), new MarkdownHeading(2, "two"), new MarkdownHeading(3, "three"), new MarkdownHeading(4, "four"), new MarkdownHeading(5, "five"), new MarkdownHeading(6, "six")); } public void SevenHashesAreATextParagraph() { CheckBlocks("####### seven", new MarkdownParagraph("####### seven")); } public void HashesNeedASpaceAfterThem() { CheckBlocks("#nope", new MarkdownParagraph("#nope")); } public void ThreeSpacesOfIndentAreAllowed() { CheckBlocks(" ## indented", new MarkdownHeading(2, "indented")); } public void FourSpacesOfIndentAreAParagraph() { CheckBlocks(" ## indented", new MarkdownParagraph("## indented")); } public void ClosingHashesAreDropped() { CheckBlocks("## Heading ##", new MarkdownHeading(2, "Heading")); } public void HashesWithoutASpaceBeforeThemStay() { CheckBlocks("## C#", new MarkdownHeading(2, "C#")); } public void ALoneHashIsAnEmptyHeading() { CheckBlocks("#", new MarkdownHeading(1, string.Empty)); } public void HashesAroundNothingAreAnEmptyHeading() { CheckBlocks("## ##", new MarkdownHeading(2, string.Empty)); } public void ExtraSpacesAroundTheTextAreDropped() { CheckBlocks("# spaced out ", new MarkdownHeading(1, "spaced out")); } public void EndsAParagraphWithoutABlankLine() { CheckBlocks(Lines("text", "# Heading", "more"), new MarkdownParagraph("text"), new MarkdownHeading(1, "Heading"), new MarkdownParagraph("more")); } } public class ItemTests : BlockFixture { public void DashesStarsAndPlusesAreBullets() { CheckBlocks( Lines("- one", "* two", "+ three"), new MarkdownBulletItem("one"), new MarkdownBulletItem("two"), new MarkdownBulletItem("three")); } public void ABulletNeedsASpaceAfterTheMarker() { CheckBlocks("*not emphasis* here", new MarkdownParagraph("*not emphasis* here")); } public void ALoneMarkerIsAnEmptyBullet() { CheckBlocks("-", new MarkdownBulletItem(string.Empty)); } public void NumbersAreKeptAsWritten() { CheckBlocks( Lines("1. one", "5. five", "12. twelve", "3. three"), new MarkdownNumberedItem(1, "one"), new MarkdownNumberedItem(5, "five"), new MarkdownNumberedItem(12, "twelve"), new MarkdownNumberedItem(3, "three")); } public void ACloseParenthesisWorksLikeAPeriod() { CheckBlocks("2) two", new MarkdownNumberedItem(2, "two")); } public void LeadingZerosAreDropped() { CheckBlocks("007. agent", new MarkdownNumberedItem(7, "agent")); } public void TenDigitsAreAParagraph() { CheckBlocks("1234567890. big", new MarkdownParagraph("1234567890. big")); } public void ANumberNeedsASpaceAfterThePeriod() { CheckBlocks("3.5 is not an item", new MarkdownParagraph("3.5 is not an item")); } public void NumbersInsideTextAreNotItems() { CheckBlocks("2 + 3. These add up.", new MarkdownParagraph("2 + 3. These add up.")); } public void LinesThatDoNotStartAnotherBlockContinueTheItem() { CheckBlocks(Lines("1. first line", " and more", "- bullet", " also more"), new MarkdownNumberedItem(1, "first line and more"), new MarkdownBulletItem("bullet also more")); } public void ABlankLineEndsTheItem() { CheckBlocks(Lines("- item", string.Empty, "after"), new MarkdownBulletItem("item"), new MarkdownParagraph("after")); } public void AnItemEndsAParagraphWithoutABlankLine() { CheckBlocks(Lines("text", "- item"), new MarkdownParagraph("text"), new MarkdownBulletItem("item")); } public void ItemsSeparatedByBlankLinesStaySeparate() { CheckBlocks(Lines("1. a", string.Empty, "2. b"), new MarkdownNumberedItem(1, "a"), new MarkdownNumberedItem(2, "b")); } } public class RuleTests : BlockFixture { public void ThreeOrMoreOfOneCharacterIsARule() { CheckBlocks( Lines("---", "***", "___", "-----"), new MarkdownRule(), new MarkdownRule(), new MarkdownRule(), new MarkdownRule()); } public void SpacesBetweenTheCharactersAreAllowed() { CheckBlocks(Lines("- - -", " * * * "), new MarkdownRule(), new MarkdownRule()); } public void TwoCharactersAreNot() { CheckBlocks("--", new MarkdownParagraph("--")); } public void MixedCharactersAreNot() { CheckBlocks("-*-", new MarkdownParagraph("-*-")); } public void BeatsABulletMarker() { CheckBlocks("- - -", new MarkdownRule()); } public void EndsAParagraphWithoutABlankLine() { CheckBlocks(Lines("text", "---", "more"), new MarkdownParagraph("text"), new MarkdownRule(), new MarkdownParagraph("more")); } } public class ImageTests : BlockFixture { public void AloneItIsAnImage() { CheckBlocks("![Main window](MainWindow.png)", new MarkdownImage("Main window", "MainWindow.png")); } public void TheDescriptionCanBeEmpty() { CheckBlocks("![](a.png)", new MarkdownImage(string.Empty, "a.png")); } public void ATitleIsIgnored() { CheckBlocks("![alt](a.png \"A title\")", new MarkdownImage("alt", "a.png")); } public void SurroundingSpacesAreIgnored() { CheckBlocks(" ![alt](a.png) ", new MarkdownImage("alt", "a.png")); } public void InsideTextItStaysText() { CheckBlocks("See ![alt](a.png) here", new MarkdownParagraph("See ![alt](a.png) here")); } public void InsideAnItemItStaysText() { CheckBlocks("- ![alt](a.png)", new MarkdownBulletItem("![alt](a.png)")); } public void JoinedWithAnotherLineItIsText() { CheckBlocks(Lines("![alt](a.png)", "caption"), new MarkdownParagraph("![alt](a.png) caption")); } public void ASourceWithASpaceIsText() { CheckBlocks("![alt](my file.png)", new MarkdownParagraph("![alt](my file.png)")); } } public class CodeBlockTests : BlockFixture { public void BackticksFenceTheLines() { CheckBlocks(Lines("```", "a", "b", "```"), new MarkdownCodeBlock(string.Empty, "a\nb")); } public void TildesFenceToo() { CheckBlocks(Lines("~~~", "a", "~~~"), new MarkdownCodeBlock(string.Empty, "a")); } public void TheFirstWordAfterTheFenceIsTheLanguage() { CheckBlocks(Lines("``` csharp extra", "x", "```"), new MarkdownCodeBlock("csharp", "x")); } public void LinesKeepTheirSpacingAndBlankLines() { CheckBlocks(Lines("```", " indented text", string.Empty, "end", "```"), new MarkdownCodeBlock(string.Empty, " indented text\n\nend")); } public void MarkdownInsideIsNotRead() { CheckBlocks(Lines("```", "# not a heading", "- not a bullet", "---", "```"), new MarkdownCodeBlock(string.Empty, "# not a heading\n- not a bullet\n---")); } public void AnUnclosedFenceRunsToTheEnd() { CheckBlocks(Lines("```", "a", "b"), new MarkdownCodeBlock(string.Empty, "a\nb")); } public void AnEmptyFenceIsAnEmptyBlock() { CheckBlocks(Lines("```", "```"), new MarkdownCodeBlock(string.Empty, string.Empty)); } public void ALongerFenceNeedsAsLongAClosingOne() { CheckBlocks(Lines("````", "```", "inside", "```", "````"), new MarkdownCodeBlock(string.Empty, "```\ninside\n```")); } public void AFenceOfTheOtherCharacterDoesNotClose() { CheckBlocks(Lines("```", "~~~", "```"), new MarkdownCodeBlock(string.Empty, "~~~")); } public void TheOpeningIndentIsRemovedFromEachLine() { CheckBlocks(Lines(" ```", " a", " b", " c", " ```"), new MarkdownCodeBlock(string.Empty, "a\n b\nc")); } public void EndsAParagraphWithoutABlankLine() { CheckBlocks(Lines("text", "```", "a", "```", "more"), new MarkdownParagraph("text"), new MarkdownCodeBlock(string.Empty, "a"), new MarkdownParagraph("more")); } } public class DocumentTests : BlockFixture { public void BlocksComeBackInOrder() { CheckBlocks( Lines( "## Main window", string.Empty, "![Main window](MainWindow.png)", string.Empty, "After starting a game, you see this.", string.Empty, "1. Play/Pause button - toggles the game.", string.Empty, "2 + 3. Meters.", string.Empty, "---"), new MarkdownHeading(2, "Main window"), new MarkdownImage("Main window", "MainWindow.png"), new MarkdownParagraph("After starting a game, you see this."), new MarkdownNumberedItem(1, "Play/Pause button - toggles the game."), new MarkdownParagraph("2 + 3. Meters."), new MarkdownRule()); } } } }