packages feed

tilia-0.0.1.0: tests/Tilia/Doc/CombinatorsSpec.hs

{-# LANGUAGE OverloadedStrings #-}

-- | The vocabulary printing code is written in.
module Tilia.Doc.CombinatorsSpec (spec) where

import Data.Text (Text)
import Test.Hspec
import Tilia.Doc
import Tilia.Doc.Combinators
import Tilia.Span

spec :: Spec
spec = do
  describe "groups" $ do
    it "becomes a space when flat" $
      out (flat (txt "a" <> breakOrSpace <> txt "b")) `shouldBe` "a b\n"
    it "becomes a break when broken" $
      out (broken (txt "a" <> breakOrSpace <> txt "b")) `shouldBe` "a\nb\n"
    it "leaves nothing when flat" $
      out (flat (txt "a" <> breakOrNothing <> txt "b")) `shouldBe` "ab\n"
    it "becomes a break when broken, leaving nothing behind" $
      out (broken (txt "a" <> breakOrNothing <> txt "b")) `shouldBe` "a\nb\n"
    it "follows a single-line span" $
      out (group (mkSpan (1, 1) (1, 9)) (txt "a" <> breakOrSpace <> txt "b"))
        `shouldBe` "a b\n"
    it "follows a multi-line span" $
      out (group (mkSpan (1, 1) (2, 9)) (txt "a" <> breakOrSpace <> txt "b"))
        `shouldBe` "a\nb\n"
    it "lets an inner group override the enclosing layout" $
      out (flat (txt "a" <> broken (breakOrSpace <> txt "b")))
        `shouldBe` "a\nb\n"
    it "ignores a hard line's enclosing layout" $
      out (flat (txt "a" <> hardBreak <> txt "b")) `shouldBe` "a\nb\n"

  describe "variant" $ do
    it "takes the first branch when flat" $
      out (flat (variant (txt "one") (txt "many"))) `shouldBe` "one\n"
    it "takes the second branch when broken" $
      out (broken (variant (txt "one") (txt "many"))) `shouldBe` "many\n"
    it "follows the span like any other group" $ do
      let v = variant (txt "one") (txt "many")
      out (group (mkSpan (1, 1) (1, 9)) v) `shouldBe` "one\n"
      out (group (mkSpan (1, 1) (2, 9)) v) `shouldBe` "many\n"

  describe "provenance" $
    it "does not affect layout" $ do
      let d = txt "a" <> breakOrSpace <> txt "b"
          s = mkSpan (1, 1) (1, 9)
      out (flat (located s d)) `shouldBe` out (flat d)

  describe "combining" $ do
    it "separates with commaSep when flat" $
      out (flat (commaSep [txt "a", txt "b", txt "c"]))
        `shouldBe` "a, b, c\n"
    it "keeps commas on the line above when broken" $
      out (broken (commaSep [txt "a", txt "b"]))
        `shouldBe` "a,\nb\n"
    it "punctuates all but the last" $
      out (flat (hsep (punctuate comma [txt "a", txt "b", txt "c"])))
        `shouldBe` "a, b, c\n"
    it "handles an empty list" $
      out (flat (commaSep [])) `shouldBe` ""
    it "handles a single element" $
      out (broken (commaSep [txt "a"])) `shouldBe` "a\n"
    it "joins with hsep" $
      out (flat (hsep [txt "a", txt "b"])) `shouldBe` "a b\n"
    it "joins with vsep" $
      out (flat (vsep [txt "a", txt "b"])) `shouldBe` "a\nb\n"

  describe "brackets" $ do
    it "adds nothing when flat" $
      out (flat (parens (commaSep [txt "a", txt "b"])))
        `shouldBe` "(a, b)\n"
    it "keeps the opening bracket company when broken" $
      out (broken (parens (commaSep [txt "a", txt "b"])))
        `shouldBe` "( a,\n  b\n)\n"
    it "lines the body up under itself" $
      out (broken (brackets (commaSep [txt "a", txt "b", txt "c"])))
        `shouldBe` "[ a,\n  b,\n  c\n]\n"
    it "keeps the closing bracket in when asked" $
      out (broken (parensWith Indented (commaSep [txt "a", txt "b"])))
        `shouldBe` "( a,\n  b\n  )\n"
    it "renders an empty bracket pair flat" $
      out (flat (brackets mempty)) `shouldBe` "[]\n"
    it "spaces the unboxed pair" $
      out (flat (unboxed (commaSep [txt "a", txt "b"])))
        `shouldBe` "(# a, b #)\n"
    it "gives a spaced pair its own lines when broken" $
      out (broken (unboxed (commaSep [txt "a", txt "b"])))
        `shouldBe` "(#\n  a,\n  b\n#)\n"
    it "wraps in backticks" $
      out (flat (backticks (txt "div"))) `shouldBe` "`div`\n"

  describe "conditionals" $ do
    it "includes when the condition holds" $
      out (flat (txt "a" <> includeWhen True (space <> txt "b")))
        `shouldBe` "a b\n"
    it "omits when it does not" $
      out (flat (txt "a" <> includeWhen False (space <> txt "b")))
        `shouldBe` "a\n"
    it "inverts with includeUnless" $
      out (flat (includeUnless True (txt "a"))) `shouldBe` ""

out :: Doc -> Text
out = printDoc defaultRenderOptions