{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Text.MMarkSpec (spec) where import Data.Aeson import Data.Char import Data.List.NonEmpty (NonEmpty (..)) import Data.Monoid import Data.Text (Text) import Test.Hspec import Test.Hspec.Megaparsec import Text.MMark (MMarkErr (..)) import Text.MMark.Extension (Inline (..)) import Text.MMark.TestUtils import Text.Megaparsec (ErrorFancy (..)) import qualified Control.Foldl as L import qualified Data.List.NonEmpty as NE import qualified Data.Text as T import qualified Data.Text.IO as TIO import qualified Text.MMark as MMark import qualified Text.MMark.Extension as Ext spec :: Spec spec = parallel $ do describe "parse and render" $ do context "2.2 Tabs" $ do it "CM1" $ "\tfoo\tbaz\t\tbim" ==-> "
foo\tbaz\t\tbim\n
\n"
it "CM2" $
" \tfoo\tbaz\t\tbim" ==->
"foo\tbaz\t\tbim\n
\n"
it "CM3" $
" a\ta\n ὐ\ta" ==->
"a\ta\nὐ\ta\n
\n"
xit "CM4" $ -- FIXME pending lists
" - foo\n\n\tbar" ==->
"foo
\nbar
\nfoo
\n bar\n
\n\n\n" xit "CM7" $ -- FIXME pending lists "-\t\tfoo" ==-> "\nfoo\n
foo\n
\nfoo\nbar\n
\n"
xit "CM9" $ -- FIXME pending lists
" - foo\n - bar\n\t - baz" ==->
"+++
\n" it "CM15" $ "===" ==-> "===
\n" it "CM16" $ let s = "--\n**\n__\n" in s ~-> errFancy (posN 4 s) (nonFlanking "*") it "CM17" $ " ***\n ***\n ***" ==-> "***\n
\n"
it "CM19" $
let s = "Foo\n ***\n"
in s ~-> errFancy (posN 10 s) (nonFlanking "*")
it "CM20" $
"_____________________________________" ==->
"-
\n" xit "CM27" $ -- FIXME pending lists "- foo\n***\n- bar" ==-> "bar
\n" xit "CM30" $ -- FIXME pending lists "* Foo\n* * *\n* Bar" ==-> "## foo
\n" it "CM36" $ "# foo *bar* \\*baz\\*" ==-> "# foo\n
\n"
it "CM40" $
"foo\n # bar" ==-> "foo\n# bar
\n" it "CM41" $ "## foo ##\n ### bar ###" ==-> "Foo bar\n# baz\nBar foo
\n" it "CM49" $ let s = "## \n#\n### ###" in s ~~-> [ err (posN 3 s) (utok '\n' <> elabel "heading character" <> elabel "white space") , err (posN 5 s) (utok '\n' <> etok '#' <> elabel "white space") ] context "4.4 Indented code blocks" $ do it "CM76" $ " a simple\n indented code block" ==-> "a simple\n indented code block\n
\n"
xit "CM77" $ -- FIXME pending lists
" - foo\n\n bar" ==->
"foo
\nbar
\nfoo
\n<a/>\n*hi*\n\n- one\n
\n"
it "CM80" $
" chunk1\n\n chunk2\n \n \n \n chunk3" ==->
"chunk1\n\nchunk2\n\n\n\nchunk3\n
\n"
it "CM81" $
" chunk1\n \n chunk2" ==->
"chunk1\n \n chunk2\n
\n"
it "CM82" $
"Foo\n bar\n" ==->
"Foo\nbar
\n" it "CM83" $ " foo\nbar" ==-> "foo\n
\nbar
\n" xit "CM84" $ -- FIXME pending setext headings "# Heading\n foo\nHeading\n------\n foo\n----\n" ==-> "foo\n
\nfoo\n
\n foo\nbar\n
\n"
it "CM86" $
"\n \n foo\n \n" ==->
"foo\n
\n"
it "CM87" $
" foo " ==->
"foo \n
\n"
context "4.5 Fenced code blocks" $ do
it "CM88" $
"```\n<\n >\n```" ==->
"<\n >\n
\n"
it "CM89" $
"~~~\n<\n >\n~~~" ==->
"<\n >\n
\n"
it "CM90" $
"```\naaa\n~~~\n```" ==->
"aaa\n~~~\n
\n"
it "CM91" $
"~~~\naaa\n```\n~~~" ==->
"aaa\n```\n
\n"
it "CM92" $
"````\naaa\n```\n``````" ==->
"aaa\n```\n
\n"
it "CM93" $
"~~~~\naaa\n~~~\n~~~~" ==->
"aaa\n~~~\n
\n"
it "CM94" $
let s = "```"
in s ~-> err (posN 3 s)
(ueof <> etok '`' <> elabel "info string" <> elabel "newline")
it "CM95" $
let s = "`````\n\n```\naaa\n"
in s ~-> err (posN 15 s)
(ueof <> elabel "closing code fence" <> elabel "code block content")
xit "CM96" $ -- FIXME pending blockquotes
"> ```\n> aaa\n\nbbb" ==->
"\n\n\naaa\n
bbb
\n" it "CM97" $ "```\n\n \n```" ==-> "\n \n
\n"
it "CM98" $
"```\n```" ==->
"
\n"
it "CM99" $
" ```\n aaa\naaa\n```" ==->
"aaa\naaa\n
\n"
it "CM100" $
" ```\naaa\n aaa\naaa\n ```" ==->
"aaa\naaa\naaa\n
\n"
it "CM101" $
" ```\n aaa\n aaa\n aaa\n ```" ==->
"aaa\n aaa\naaa\n
\n"
it "CM102" $
" ```\n aaa\n ```" ==->
"```\naaa\n```\n
\n"
it "CM103" $
"```\naaa\n ```" ==->
"aaa\n
\n"
it "CM104" $
" ```\naaa\n ```" ==->
"aaa\n
\n"
it "CM105" $
let s = "```\naaa\n ```\n"
in s ~-> err (posN 16 s)
(ueof <> elabel "closing code fence" <> elabel "code block content")
it "CM106" $
"``` ```\naaa" ==->
"\naaa
foo\nbar
\nbaz
bar\n
\ndef foo(x)\n return 3\nend\n
\n"
it "CM111" $
"~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~" ==->
"def foo(x)\n return 3\nend\n
\n"
it "CM112" $
"````;\n````" ==->
"
\n"
it "CM113" $
"``` aa ```\nfoo" ==->
"aa
\nfoo
``` aaa\n
\n"
context "4.8 Paragraphs" $ do
it "CM180" $
"aaa\n\nbbb" ==->
"aaa
\nbbb
\n" it "CM181" $ "aaa\nbbb\n\nccc\nddd" ==-> "aaa\nbbb
\nccc\nddd
\n" it "CM182" $ "aaa\n\n\nbbb" ==-> "aaa
\nbbb
\n" it "CM183" $ " aaa\n bbb" ==-> "aaa\nbbb
\n" it "CM184" $ "aaa\n bbb\n ccc" ==-> "aaa\nbbb\nccc
\n" it "CM185" $ " aaa\nbbb" ==-> "aaa\nbbb
\n" it "CM186" $ " aaa\nbbb" ==-> "aaa\n
\nbbb
\n" it "CM187" $ "aaa \nbbb " ==-> "aaa\nbbb
\n" context "4.9 Blank lines" $ it "CM188" $ " \n\naaa\n \n\n# aaa\n\n " ==-> "aaa
\n!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~
\n" it "CM288" $ "\\\t\\A\\a\\ \\3\\φ\\«" ==-> "\\\t\\A\\a\\ \\3\\φ\\«
\n" it "CM289" $ "\\*not emphasized\\*\n\\*not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"
\n" it "CM290" $ let s = "\\\\*emphasis*" in s ~-> err (posN 2 s) (utok '*' <> eeib <> eric) xit "CM291" $ "foo\\\nbar" ==-> "foo
\nbar
\\[\\`
\\[\\]\n
\n"
it "CM294" $
"~~~\n\\[\\]\n~~~" ==->
"\\[\\]\n
\n"
it "CM295" $
"<a href="/bar/)">
\n" it "CM297" $ let s = "[foo](/bar\\* \"ti\\*tle\")" in s ~-> err (posN 10 s) (utok '\\' <> etok '#' <> etok '/' <> etok '?' <> euri <> eppi) xit "CM298" $ -- FIXME pending reference links "[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"" ==-> "\n" it "CM299" $ "``` foo\\+bar\nfoo\n```" ==-> "foo\n
\n"
context "6.2 Entity and numeric character references" $
xit "CM300" $ -- FIXME pending entity references
" & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸"
==-> "& © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸
\n" context "6.3 Code spans" $ do it "CM312" $ "`foo`" ==-> "foo
foo ` bar
``
foo
foo bar baz
a b
foo `` bar
<http://foo.bar.baz>
foo bar
\n" it "CM330" $ let s = "a * foo bar*\n" in s ~-> err (posN 2 s) (utok '*' <> eeib <> eric) it "CM331" $ let s = "a*\"foo\"*\n" in s ~-> err (posN 1 s) (utok '*' <> eeib <> eric) it "CM332" $ let s = "* a *\n" in s ~-> errFancy posI (nonFlanking "*") it "CM333" $ let s = "foo*bar*\n" in s ~-> err (posN 3 s) (utok '*' <> eeib <> eric) it "CM334" $ let s = "5*6*78\n" in s ~-> err (posN 1 s) (utok '*' <> eeib <> eric) it "CM335" $ "_foo bar_" ==-> "foo bar
\n" it "CM336" $ let s = "_ foo bar_\n" in s ~-> errFancy posI (nonFlanking "_") it "CM337" $ let s = "a_\"foo\"_\n" in s ~-> err (posN 1 s) (utok '_' <> eeib <> eric) it "CM338" $ let s = "foo_bar_\n" in s ~-> err (posN 3 s) (utok '_' <> eeib <> eric) it "CM339" $ let s = "5_6_78\n" in s ~-> err (posN 1 s) (utok '_' <> eeib <> eric) it "CM340" $ let s = "пристаням_стремятся_\n" in s ~-> err (posN 9 s) (utok '_' <> eeib <> eric) it "CM341" $ let s = "aa_\"bb\"_cc\n" in s ~-> err (posN 2 s) (utok '_' <> eeib <> eric) it "CM342" $ let s = "foo-_(bar)_\n" in s ~-> err (posN 4 s) (utok '_' <> eeib <> eric) it "CM343" $ let s = "_foo*\n" in s ~-> err (posN 4 s) (utok '*' <> etok '_' <> eric) it "CM344" $ let s = "*foo bar *\n" in s ~-> errFancy (posN 9 s) (nonFlanking "*") it "CM345" $ let s = "*foo bar\n*\n" in s ~-> errFancy (posN 9 s) (nonFlanking "*") it "CM346" $ let s = "*(*foo)\n" in s ~-> errFancy posI (nonFlanking "*") it "CM347" $ let s = "*(*foo*)*\n" in s ~-> errFancy posI (nonFlanking "*") it "CM348" $ let s = "*foo*bar\n" in s ~-> errFancy (posN 4 s) (nonFlanking "*") it "CM349" $ let s = "_foo bar _\n" in s ~-> errFancy (posN 9 s) (nonFlanking "_") it "CM350" $ let s = "_(_foo)\n" in s ~-> errFancy posI (nonFlanking "_") it "CM351" $ let s = "_(_foo_)_\n" in s ~-> errFancy posI (nonFlanking "_") it "CM352" $ let s = "_foo_bar\n" in s ~-> errFancy (posN 4 s) (nonFlanking "_") it "CM353" $ let s = "_пристаням_стремятся\n" in s ~-> errFancy (posN 10 s) (nonFlanking "_") it "CM354" $ let s = "_foo_bar_baz_\n" in s ~-> errFancy (posN 4 s) (nonFlanking "_") it "CM355" $ "_\\(bar\\)_.\n" ==-> "(bar).
\n" it "CM356" $ "**foo bar**\n" ==-> "foo bar
\n" it "CM357" $ let s = "** foo bar**\n" in s ~-> errFancy (posN 1 s) (nonFlanking "*") it "CM358" $ let s = "a**\"foo\"**\n" in s ~-> err (posN 1 s) (utok '*' <> eeib <> eric) it "CM359" $ let s = "foo**bar**\n" in s ~-> err (posN 3 s) (utok '*' <> eeib <> eric) it "CM360" $ "__foo bar__" ==-> "foo bar
\n" it "CM361" $ let s = "__ foo bar__\n" in s ~-> errFancy (posN 1 s) (nonFlanking "_") it "CM362" $ let s = "__\nfoo bar__\n" in s ~-> errFancy (posN 1 s) (nonFlanking "_") it "CM363" $ let s = "a__\"foo\"__\n" in s ~-> err (posN 1 s) (utok '_' <> eeib <> eric) it "CM364" $ let s = "foo__bar__\n" in s ~-> err (posN 3 s) (utok '_' <> eeib <> eric) it "CM365" $ let s = "5__6__78\n" in s ~-> err (posN 1 s) (utok '_' <> eeib <> eric) it "CM366" $ let s = "пристаням__стремятся__\n" in s ~-> err (posN 9 s) (utok '_' <> eeib <> eric) it "CM367" $ "__foo, __bar__, baz__" ==-> "foo, bar, baz
\n" it "CM368" $ "foo-__\\(bar\\)__" ==-> "foo-(bar)
\n" it "CM369" $ let s = "**foo bar **\n" in s ~-> errFancy (posN 11 s) (nonFlanking "*") it "CM370" $ let s = "**(**foo)\n" in s ~-> errFancy (posN 1 s) (nonFlanking "*") it "CM371" $ let s = "*(**foo**)*\n" in s ~-> errFancy posI (nonFlanking "*") xit "CM372" $ -- FIXME doesn't pass with current approach "**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**" ==-> "Gomphocarpus (Gomphocarpus physocarpus, syn.\nAsclepias physocarpa)
\n" it "CM373" $ "**foo \"*bar*\" foo**" ==-> "foo "bar" foo
\n" it "CM374" $ let s = "**foo**bar\n" in s ~-> errFancy (posN 5 s) (nonFlanking "**") it "CM375" $ let s = "__foo bar __\n" in s ~-> errFancy (posN 11 s) (nonFlanking "_") it "CM376" $ let s = "__(__foo)\n" in s ~-> errFancy (posN 1 s) (nonFlanking "_") it "CM377" $ let s = "_(__foo__)_\n" in s ~-> errFancy posI (nonFlanking "_") it "CM378" $ let s = "__foo__bar\n" in s ~-> errFancy (posN 5 s) (nonFlanking "__") it "CM379" $ let s = "__пристаням__стремятся\n" in s ~-> errFancy (posN 11 s) (nonFlanking "__") it "CM380" $ "__foo\\_\\_bar\\_\\_baz__" ==-> "foo__bar__baz
\n" it "CM381" $ "__\\(bar\\)__." ==-> "(bar).
\n" it "CM382" $ "*foo [bar](/url)*" ==-> "foo bar
\n" it "CM383" $ "*foo\nbar*" ==-> "foo\nbar
\n" it "CM384" $ "_foo __bar__ baz_" ==-> "foo bar baz
\n" it "CM385" $ "_foo _bar_ baz_" ==-> "foo bar baz
\n" it "CM386" $ let s = "__foo_ bar_" in s ~-> err (posN 5 s) (utoks "_ " <> etoks "__" <> eric) it "CM387" $ "*foo *bar**" ==-> "foo bar
\n" it "CM388" $ "*foo **bar** baz*" ==-> "foo bar baz
\n" it "CM389" $ let s = "*foo**bar**baz*\n" in s ~-> err (posN 5 s) (utok '*' <> eeib) it "CM390" $ "***foo** bar*\n" ==-> "foo bar
\n" it "CM391" $ "*foo **bar***\n" ==-> "foo bar
\n" it "CM392" $ let s = "*foo**bar***\n" in s ~-> err (posN 5 s) (utok '*' <> elabel "end of inline block") it "CM393" $ "*foo **bar *baz* bim** bop*\n" ==-> "foo bar baz bim bop
\n" it "CM394" $ "*foo [*bar*](/url)*\n" ==-> "foo bar
\n" it "CM395" $ let s = "** is not an empty emphasis\n" in s ~-> errFancy (posN 1 s) (nonFlanking "*") it "CM396" $ let s = "**** is not an empty strong emphasis\n" in s ~-> errFancy (posN 3 s) (nonFlanking "*") it "CM397" $ "**foo [bar](/url)**" ==-> "foo bar
\n" it "CM398" $ "**foo\nbar**" ==-> "foo\nbar
\n" it "CM399" $ "__foo _bar_ baz__" ==-> "foo bar baz
\n" it "CM400" $ "__foo __bar__ baz__" ==-> "foo bar baz
\n" it "CM401" $ "____foo__ bar__" ==-> "foo bar
\n" it "CM402" $ "**foo **bar****" ==-> "foo bar
\n" it "CM403" $ "**foo *bar* baz**" ==-> "foo bar baz
\n" it "CM404" $ let s = "**foo*bar*baz**\n" in s ~-> err (posN 5 s) (utoks "*b" <> etoks "**" <> eric) it "CM405" $ "***foo* bar**" ==-> "foo bar
\n" it "CM406" $ "**foo *bar***" ==-> "foo bar
\n" it "CM407" $ "**foo *bar **baz**\nbim* bop**" ==-> "foo bar baz\nbim bop
\n" it "CM408" $ "**foo [*bar*](/url)**" ==-> "foo bar
\n" it "CM409" $ let s = "__ is not an empty emphasis\n" in s ~-> errFancy (posN 1 s) (nonFlanking "_") it "CM410" $ let s = "____ is not an empty strong emphasis\n" in s ~-> errFancy (posN 3 s) (nonFlanking "_") it "CM411" $ let s = "foo ***\n" in s ~-> errFancy (posN 6 s) (nonFlanking "*") it "CM412" $ "foo *\\**" ==-> "foo *
\n" it "CM413" $ "foo *\\_*\n" ==-> "foo _
\n" it "CM414" $ let s = "foo *****\n" in s ~-> errFancy (posN 8 s) (nonFlanking "*") it "CM415" $ "foo **\\***" ==-> "foo *
\n" it "CM416" $ "foo **\\_**\n" ==-> "foo _
\n" it "CM417" $ let s = "**foo*\n" in s ~-> err (posN 5 s) (utok '*' <> etoks "**" <> eric) it "CM418" $ let s = "*foo**\n" in s ~-> err (posN 5 s) (utok '*' <> eeib) it "CM419" $ let s = "***foo**\n" in s ~-> err (posN 8 s) (ueib <> etok '*' <> eic) it "CM420" $ let s = "****foo*\n" in s ~-> err (posN 7 s) (utok '*' <> etoks "**" <> eric) it "CM421" $ let s = "**foo***\n" in s ~-> err (posN 7 s) (utok '*' <> eeib) it "CM422" $ let s = "*foo****\n" in s ~-> err (posN 5 s) (utok '*' <> eeib) it "CM423" $ let s = "foo ___\n" in s ~-> errFancy (posN 6 s) (nonFlanking "_") it "CM424" $ "foo _\\__" ==-> "foo _
\n" it "CM425" $ "foo _\\*_" ==-> "foo *
\n" it "CM426" $ let s = "foo _____\n" in s ~-> errFancy (posN 8 s) (nonFlanking "_") it "CM427" $ "foo __\\___" ==-> "foo _
\n" it "CM428" $ "foo __\\*__" ==-> "foo *
\n" it "CM429" $ let s = "__foo_\n" in s ~-> err (posN 5 s) (utok '_' <> etoks "__" <> eric) it "CM430" $ let s = "_foo__\n" in s ~-> err (posN 5 s) (utok '_' <> eeib) it "CM431" $ let s = "___foo__\n" in s ~-> err (posN 8 s) (ueib <> etok '_' <> eic) it "CM432" $ let s = "____foo_\n" in s ~-> err (posN 7 s) (utok '_' <> etoks "__" <> eric) it "CM433" $ let s = "__foo___\n" in s ~-> err (posN 7 s) (utok '_' <> eeib) it "CM434" $ let s = "_foo____\n" in s ~-> err (posN 5 s) (utok '_' <> eeib) it "CM435" $ "**foo**" ==-> "foo
\n" it "CM436" $ "*_foo_*" ==-> "foo
\n" it "CM437" $ "__foo__" ==-> "foo
\n" it "CM438" $ "_*foo*_" ==-> "foo
\n" it "CM439" $ "****foo****" ==-> "foo
\n" it "CM440" $ "____foo____" ==-> "foo
\n" it "CM441" $ "******foo******" ==-> "foo
\n" it "CM442" $ "***foo***" ==-> "foo
\n" it "CM443" $ "_____foo_____" ==-> "foo
\n" it "CM444" $ let s = "*foo _bar* baz_\n" in s ~-> err (posN 9 s) (utok '*' <> etok '_' <> eric) it "CM445" $ let s = "*foo __bar *baz bim__ bam*\n" in s ~-> err (posN 19 s) (utok '_' <> etok '*' <> eric) it "CM446" $ let s = "**foo **bar baz**\n" in s ~-> err (posN 17 s) (ueib <> etoks "**" <> eic) it "CM447" $ let s = "*foo *bar baz*\n" in s ~-> err (posN 14 s) (ueib <> etok '*' <> eic) it "CM448" $ let s = "*[bar*](/url)\n" in s ~-> err (posN 5 s) (utok '*' <> etok ']' <> eric) it "CM449" $ let s = "_foo [bar_](/url)\n" in s ~-> err (posN 9 s) (utok '_' <> etok ']' <> eric) xit "CM450" $ -- FIXME pending HTML inlines "*" ==-> "*
\n" xit "CM451" $ -- FIXME pending HTML inlines "**" ==-> "\n" xit "CM452" $ "__\n" ==-> "\n" it "CM453" $ "*a `*`*" ==-> "a *
a _
link))
\n" it "CM467" $ let s = "[link](foo\\(and\\(bar\\))" in s ~-> err (posN 10 s) (utok '\\' <> etok '#' <> etok '/' <> etok '?' <> euri <> eppi) it "CM468" $ "[link](foo<http://example.com/?search=>
\n" context "6.6 Images" $ do it "CM541" $ "![foo](/url \"title\")" ==-> "\n" it "CM542" $ "![foo *bar*](train.jpg \"train & tracks\")" ==-> "\n" it "CM543" $ let s = "![foo ![bar](/url)](/url2)\n" in s ~-> err (posN 6 s) (utok '!' <> etok ']') it "CM544" $ "![foo [bar](/url)](/url2)" ==-> "\n" it "CM545" pending it "CM546" pending it "CM547" $ "![foo](train.jpg)" ==-> "\n" it "CM548" $ "My ![foo bar](/path/to/train.jpg \"title\" )" ==-> "My
\n" it "CM549" $ "![foo](http://foo.bar.baz/test?q=hello&id=22&boolean
\n" it "CM565" $ "<http://../>
\n" it "CM570" $ "<http://foo.bar/baz bim>
\n" it "CM572" $ "<http://example.com/[>
\n" it "CM573" $ "<foo+@bar.example.com>
\n" it "CM576" $ "<>" ==-> "<>
\n" it "CM577" $ "< http://foo.bar >" ==-> "< http://foo.bar >
\n" it "CM578" $ "http://example.com
\n" it "CM581" $ "foo@bar.example.com" ==-> "foo@bar.example.com
\n" context "6.9 Hard line breaks" $ do -- NOTE We currently do not support hard line breaks represented in -- markup as space before newline. xit "CM603" $ "foo \nbaz" ==-> "foo
\nbaz
foo
\nbaz
foo
\nbaz
foo
\nbar
foo
\nbar
foo
\nbar
foo
\nbar
code span
code\\ span
foo\\
\n" xit "CM615" $ "foo " ==-> "foo
\n" it "CM616" $ "### foo\\" ==-> "foo\nbaz
\n" it "CM619" $ "foo \n baz" ==-> "foo\nbaz
\n" context "6.11 Textual content" $ do it "CM620" $ "hello $.;'there" ==-> "hello $.;'there
\n" it "CM621" $ "Foo χρῆν" ==-> "Foo χρῆν
\n" it "CM622" $ "Multiple spaces" ==-> "Multiple spaces
\n" -- NOTE I don't test these so extensively because they share -- implementation with emphasis and strong emphasis which are thoroughly -- tested already. context "strikeout" $ do it "works in simplest form" $ "It's ~~bad~~ news." ==-> "It's bad news.
It's bad news.
It's bad news.
It's bad news.
It's bad news.
\n" it "combines with emphasis" $ "**It's ~bad~** news." ==-> "It's bad news.
\n" context "superscript" $ do it "works in simplest form" $ "It's ^bad^ news." ==-> "It's bad news.
\n" it "combines with emphasis" $ "**It's ^bad^** news." ==-> "It's bad news.
\n" it "a composite, complex example" $ "***Something ~~~is not~~ going~ ^so well^** today*." ==-> "Something is not going so well today.
Here we go...
\n" describe "useExtensions" $ it "applies extensions in the right order" $ do doc <- mkDoc "Here we go." let exts = [ append_ext "3" , append_ext "2" , append_ext "1" ] toText (MMark.useExtensions exts doc) `shouldBe` "Here we go.123
\n" describe "runScanner and scanner" $ it "extracts information from markdown document" $ do doc <- mkDoc "Here we go, pals." let n = MMark.runScanner doc (length_scan (const True)) n `shouldBe` 17 describe "combining of scanners" $ it "combines scanners" $ do doc <- mkDoc "Here we go, pals." let scan = (,,) <$> length_scan (const True) <*> length_scan isSpace <*> length_scan isPunctuation r = MMark.runScanner doc scan r `shouldBe` (17, 3, 2) describe "projectYaml" $ do context "when document does not contain a YAML section" $ it "returns Nothing" $ do doc <- mkDoc "Here we go." MMark.projectYaml doc `shouldBe` Nothing context "when document contains a YAML section" $ do context "when it is valid" $ it "returns the YAML section" $ do doc <- mkDoc "---\nx: 100\ny: 200\n---Here we go." let r = object [ "x" .= Number 100 , "y" .= Number 200 ] MMark.projectYaml doc `shouldBe` Just r context "when it is invalid" $ it "signal correct parse error" $ let s = "---\nx: 100\ny: x:\n---Here we go." in s ~-> errFancy (posN 15 s) (fancy . ErrorCustom . YamlParseError $ "mapping values are not allowed in this context") ---------------------------------------------------------------------------- -- Testing extensions -- | Append given text to all 'Plain' blocks. append_ext :: Text -> MMark.Extension append_ext y = Ext.inlineTrans $ \case Plain x -> Plain (x <> y) other -> other ---------------------------------------------------------------------------- -- Testing scanners -- | Scan total number of characters satisfying a predicate in all 'Plain' -- inlines. length_scan :: (Char -> Bool) -> L.Fold (Ext.Block (NonEmpty Inline)) Int length_scan p = Ext.scanner 0 $ \n block -> getSum $ Sum n <> foldMap (foldMap f) block where f (Plain txt) = (Sum . T.length) (T.filter p txt) f _ = mempty ---------------------------------------------------------------------------- -- For testing with documents loaded externally -- | Load a complete markdown document from an external file and compare the -- final HTML rendering with contents of another file. withFiles :: FilePath -- ^ Markdown document -> FilePath -- ^ HTML document containing the correct result -> Expectation withFiles input output = do i <- TIO.readFile input o <- TIO.readFile output i ==-> o ---------------------------------------------------------------------------- -- Helpers -- | Unexpected end of inline block. ueib :: Ord t => ET t ueib = ulabel "end of inline block" -- | Expecting end of inline block. eeib :: Ord t => ET t eeib = elabel "end of inline block" -- | Expecting end of URI literal. euri :: Ord t => ET t euri = elabel "end of URI literal" -- | Expecting the rest of path piece. eppi :: Ord t => ET t eppi = elabel "the rest of path piece" -- | Expecting inline content. eic :: Ord t => ET t eic = elabel "inline content" -- | Expecting rest of inline content. Eric! eric :: Ord t => ET t eric = elabel "the rest of inline content" -- | Create a error component complaining that the given 'Text' is not in -- left- or right- flanking position. nonFlanking :: Text -> EF MMarkErr nonFlanking = fancy . ErrorCustom . NonFlankingDelimiterRun . NE.fromList . T.unpack