packages feed

mmark-ext-0.3.0.0: tests/Text/MMark/Extension/FootnotesSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Text.MMark.Extension.FootnotesSpec (spec) where

import Data.Text (Text)
import Test.Hspec
import Text.MMark qualified as MMark
import Text.MMark.Extension.Footnotes
import Text.MMark.Extension.TestUtils

spec :: Spec
spec =
  describe "footnotes" $ do
    let to = withExt footnotes
    context "when link has no scheme"
      $ it "has no effect"
      $ "Link [link](1)."
        `to` "<p>Link <a href=\"1\">link</a>.</p>\n"
    context "when link has not \"footnote\" scheme"
      $ it "has no effect"
      $ "Link [link](https:1)"
        `to` "<p>Link <a href=\"https:1\">link</a></p>\n"
    context "when link has \"footnote\" scheme"
      $ it "transforms the link correctly"
      $ "Link [link](footnote:1)"
        `to` "<p>Link <a href=\"#fn1\" id=\"fnref1\"><sup>1</sup></a></p>\n"
    context "when block quotes are not formatted correctly"
      $ it "has no effect"
      $ "> blah"
        `to` "<blockquote>\n<p>blah</p>\n</blockquote>\n"
    context "when block quotes are formatted correctly"
      $ it "transforms them into footnotes"
      $ "> footnotes\n>\n> 1. Something.\n"
        `to` "<ol>\n<li id=\"fn1\">\nSomething.\n<a href=\"#fnref1\">↩</a></li>\n</ol>\n"
    context "validation" $ do
      it "accepts a document whose footnotes all line up" $
        check "Text [1](footnote:1).\n\n> footnotes\n>\n> 1. The note.\n"
          `shouldReturn` []
      it "reports a reference to a footnote that does not exist" $
        check "Text [2](footnote:2).\n\n> footnotes\n>\n> 1. The note.\n"
          `shouldReturn` ["1:6: there is no footnote 2", "5:6: nothing refers to footnote 1"]
      it "reports a footnote nothing refers to" $
        check "Text.\n\n> footnotes\n>\n> 1. Orphan.\n"
          `shouldReturn` ["5:6: nothing refers to footnote 1"]
      it "reports a footnote that is referred to more than once" $
        check "A [1](footnote:1) and B [1](footnote:1).\n\n> footnotes\n>\n> 1. N.\n"
          `shouldReturn` [ "1:25: footnote 1 is referred to more than once, which would give the references the same id"
                         ]
      it "reports a reference whose path is not a number" $
        check "Text [x](footnote:abc).\n\n> footnotes\n>\n> 1. N.\n"
          `shouldReturn` [ "1:6: a footnote reference must have a single number as its path",
                           "5:6: nothing refers to footnote 1"
                         ]
      it "reaches references nested inside other inlines" $
        check "T [1](footnote:1) *and [2](footnote:2)*.\n\n> footnotes\n>\n> 1. A.\n> 2. B.\n"
          `shouldReturn` []
      it "reports every problem exactly once" $
        check "[9](footnote:9)\n\nSome text.\n\nMore text.\n"
          `shouldReturn` ["1:1: there is no footnote 9"]
      -- The footnotes of the second section are the same numbers as those
      -- of the first, so they are not counted twice; the document is
      -- already reported as having more than one section.
      it "reports a second footnote section" $
        check "> footnotes\n>\n> 1. A.\n\n> footnotes\n>\n> 1. B.\n"
          `shouldReturn` [ "3:6: nothing refers to footnote 1",
                           "5:1: there is more than one footnote section"
                         ]

-- | Validate the footnotes of a document, returning one @line:col: message@
-- string per reported problem.
check :: Text -> IO [Text]
check input = do
  Right doc <- pure (MMark.parse "" input)
  checkErrors (validateFootnotes (MMark.runScanner footnoteScanner doc)) input