tilia-0.0.1.0: tests/Tilia/Doc/InternalSpec.hs
{-# LANGUAGE OverloadedStrings #-}
-- | The span algebra and the rendering engine's primitives.
module Tilia.Doc.InternalSpec (spec) where
import Data.Text (Text)
import Test.Hspec
import Tilia.Doc
import Tilia.Doc.Combinators
import Tilia.Doc.Internal (groupLayout)
import Tilia.Span
spec :: Spec
spec = do
describe "Span" $ do
it "recognises a single-line span" $
isSingleLine (mkSpan (3, 1) (3, 40)) `shouldBe` True
it "recognises a multi-line span" $
isSingleLine (mkSpan (3, 1) (4, 1)) `shouldBe` False
it "unions to cover both operands" $
mkSpan (1, 5) (1, 9) <> mkSpan (3, 2) (4, 1)
`shouldBe` mkSpan (1, 5) (4, 1)
it "takes the earlier start column when starts share a line" $
mkSpan (1, 9) (1, 20) <> mkSpan (1, 3) (1, 5)
`shouldBe` mkSpan (1, 3) (1, 20)
describe "groupLayout" $ do
it "goes flat with no span" $
groupLayout Nothing `shouldBe` Flat
it "goes flat for a single-line span" $
groupLayout (Just (mkSpan (1, 1) (1, 9))) `shouldBe` Flat
it "goes broken for a multi-line span" $
groupLayout (Just (mkSpan (1, 1) (2, 9))) `shouldBe` Broken
describe "atoms" $ do
it "renders nothing for an empty document" $
out mempty `shouldBe` ""
it "terminates output with a newline" $
out (txt "x") `shouldBe` "x\n"
it "collapses repeated spaces" $
out (txt "a" <> space <> space <> txt "b") `shouldBe` "a b\n"
it "drops a space before a line break" $
out (txt "a" <> space <> hardBreak <> txt "b") `shouldBe` "a\nb\n"
it "drops a leading space" $
out (space <> txt "a") `shouldBe` "a\n"
it "ignores an empty fragment" $
out (txt "a" <> txt "" <> txt "b") `shouldBe` "ab\n"
describe "blank lines" $ do
it "collapses runs" $
out (txt "a" <> blankLine <> blankLine <> txt "b")
`shouldBe` "a\n\nb\n"
it "drops a leading blank line" $
out (blankLine <> txt "a") `shouldBe` "a\n"
it "drops a trailing blank line" $
out (txt "a" <> blankLine) `shouldBe` "a\n"
it "separates when there is content on both sides" $
out (txt "a" <> blankLine <> txt "b") `shouldBe` "a\n\nb\n"
it "caps a run of hard breaks at one blank line" $ do
out (txt "a" <> hardBreak <> hardBreak <> txt "b")
`shouldBe` "a\n\nb\n"
out (txt "a" <> hardBreak <> hardBreak <> hardBreak <> txt "b")
`shouldBe` "a\n\nb\n"
out (txt "a" <> mconcat (replicate 8 hardBreak) <> txt "b")
`shouldBe` "a\n\nb\n"
it "caps a mixture of hard breaks and blank lines" $
out (txt "a" <> hardBreak <> blankLine <> hardBreak <> blankLine <> txt "b")
`shouldBe` "a\n\nb\n"
it "still breaks once for a single hard break" $
out (txt "a" <> hardBreak <> txt "b") `shouldBe` "a\nb\n"
describe "indentation" $ do
it "indents by one step" $
out (broken (txt "a" <> indent (breakOrSpace <> txt "b")))
`shouldBe` "a\n b\n"
it "nests relative to the enclosing level" $
out (broken (txt "a" <> indent (breakOrSpace <> txt "b" <> indent (breakOrSpace <> txt "c"))))
`shouldBe` "a\n b\n c\n"
it "aligns to the current column" $
out (broken (txt "ab" <> space <> align (txt "c" <> breakOrSpace <> txt "d")))
`shouldBe` "ab c\n d\n"
it "leaves no trailing whitespace on an empty line" $
out (broken (indent (txt "a" <> hardBreak <> hardBreak <> txt "b")))
`shouldBe` " a\n\n b\n"
it "does not indent a line with nothing on it" $
out (broken (indent (txt "a" <> hardBreak)))
`shouldBe` " a\n"
out :: Doc -> Text
out = printDoc defaultRenderOptions