packages feed

symantic-document-1.2.2.20190627: test/HUnit.hs

{-# LANGUAGE OverloadedStrings #-}
module HUnit where

import Test.Tasty
import Test.Tasty.HUnit

import Data.Foldable (Foldable(..))
import Data.Function (($), (.))
import Data.Functor ((<$>))
import Data.Int (Int)
import Data.Maybe (Maybe(..))
import Data.Monoid (Monoid(..))
import Data.Ord (Ord(..))
import Data.Semigroup (Semigroup(..))
import Data.String (String, IsString(..))
import Prelude ((+))
import Text.Show (Show(..))
import qualified Data.List as List

import Symantic.Document.API
import Symantic.Document.Plain
import Symantic.Document.AnsiText

-- * Tests
hunits :: TestTree
hunits = testGroup "HUnit" $
 [ hunitPlain
 ]

hunitPlain :: TestTree
hunitPlain = testList "Plain"
 [ newline ==> "\n"
 , "hello\nworld" ==> "hello\nworld"
 , 10`maxWidth` breakpoints ["hello", "world"] ==> "helloworld"
 ,  9`maxWidth` breakpoints ["hello", "world"] ==> "hello\nworld"
 ,  6`maxWidth` breakpoints ["he", "ll", "o!"] ==> "hello!"
 ,  6`maxWidth` breakpoints ["he", "ll", "o!", "wo", "rl", "d!"] ==> "hello!\nworld!"
 ,  5`maxWidth` breakpoints ["hello", "world"] ==> "hello\nworld"
 ,  5`maxWidth` breakpoints ["he", "llo", "world"] ==> "hello\nworld"
 ,  5`maxWidth` breakpoints ["he", "ll", "o!"] ==> "hell\no!"
 ,  4`maxWidth` breakpoints ["hello", "world"] ==> "hello\nworld"
 ,  4`maxWidth` breakpoints ["he", "ll", "o!"] ==> "hell\no!"
 ,  4`maxWidth` breakpoints ["he", "llo", "world"] ==> "he\nllo\nworld"
 ,  4`maxWidth` breakpoints ["he", "llo", "w", "orld"] ==> "he\nllow\norld"
 ,  4`maxWidth` breakpoints ["he", "ll", "o!", "wo", "rl", "d!"] ==> "hell\no!wo\nrld!"
 ,  3`maxWidth` breakpoints ["hello", "world"] ==> "hello\nworld"
 ,  3`maxWidth` breakpoints ["he", "ll"] ==> "he\nll"
 ,  3`maxWidth` breakpoints ["he", "ll", "o!"] ==> "he\nll\no!"
 ,  1`maxWidth` breakpoints ["he", "ll", "o!"] ==> "he\nll\no!"
 ,  4`maxWidth` mconcat ["__", align $ breakpoints ["he", "ll", "o!", "wo", "rl", "d!"]]
    ==> "__he\n  ll\n  o!\n  wo\n  rl\n  d!"
 ,  6`maxWidth` mconcat ["__", align $ breakpoints ["he", "ll", "o!", "wo", "rl", "d!"]]
    ==> "__hell\n  o!wo\n  rld!"
 , 16`maxWidth` mconcat ["__", listHorV ["hello", "world"]] ==> "__[hello, world]"
 ,  4`maxWidth` mconcat ["__", listHorV ["hello", "world"]] ==> "__[ hello\n  , world\n  ]"
 , 11`maxWidth` breakspaces ["hello", "world"] ==> "hello world"
 , 10`maxWidth` breakspaces ["hello", "world"] ==> "hello\nworld"
 ,  6`maxWidth` breakspaces ["hel", "lo", "wo", "rld"] ==> "hel lo\nwo rld"
 ,  6`maxWidth` breakspaces ["hel", "lo", "wo", "rld", "HEL", "LO", "WO", "RLD"] ==> "hel lo\nwo rld\nHEL LO\nWO RLD"
 ,  5`maxWidth` breakspaces ["hello", "world"] ==> "hello\nworld"
 , 19`maxWidth` fun (fun $ fun $ fun $ fun $ listHorV ["abcdefg", "abcdefg"])
   ==> "function(function(\n    function(\n      function(\n        function(\n          [ abcdefg\n          , abcdefg\n          ]\n          )\n        )\n      )\n    ))"
 , 19`maxWidth` fun (fun $ fun $ fun $ fun $ listHorV ["abcdefgh", "abcdefgh"])
   ==> "function(\n  function(\n    function(\n      function(\n        function(\n          [ abcdefgh\n          , abcdefgh\n          ]\n          )\n        )\n      )\n    )\n  )"
 , 7`maxWidth` ("hello"<>breakspace<>"world") ==> "hello\nworld"
 , 7`maxWidth` ("hello "<>"world") ==> "hello\nworld"
 , "  "<> "hello\nworld\n!" ==> "  hello\nworld\n!"
 , "__"<>align "hello\nworld\n!" ==> "__hello\n  world\n  !"
 , hang 2 "hello\nworld\n!" ==> "hello\n  world\n  !"
 , hang 2 "hello\nworld\n!"<>"\nhello\n!" ==> "hello\n  world\n  !\nhello\n!"
 , "let " <> align (catV $
             (\(name, typ) -> fill 6 name <+> "::" <+> typ)
             <$> [ ("abcdef","Doc")
                 , ("abcde","Int -> Doc -> Doc")
                 , ("abcdefghi","Doc") ])
   ==> "let abcdef :: Doc\n    abcde  :: Int -> Doc -> Doc\n    abcdefghi :: Doc"
 , "let " <> align (catV $
             (\(name, typ) -> breakfill 6 name <> " ::" <+> typ)
             <$> [ ("abcdef","Doc")
                 , ("abcde","Int -> Doc -> Doc")
                 , ("abcdefghi","Doc") ])
   ==> "let abcdef :: Doc\n    abcde  :: Int -> Doc -> Doc\n    abcdefghi\n           :: Doc"
 , "let " <> align (catV $
             (\(name, typ) -> breakfill 6 name <> " ::" <+> typ)
             <$> [("abcdefghi","Doc ->\nDoc")])
   ==> "let abcdefghi\n           :: Doc ->\n    Doc"
 , "let " <> align (catV $
             (\(name, typ) -> breakfill 6 name <> align (" ::" <+> typ))
             <$> [("abcdefghi","Doc ->\nDoc")])
   ==> "let abcdefghi\n           :: Doc ->\n          Doc"
 , 10 `maxWidth` "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15" ==> "1 2 3 4 5\n6 7 8 9 10\n11 12 13\n14 15"
 , 10 `maxWidth` "a b "<>"12"<>align (" 34 5")                 ==> "a b 12 34\n      5"
 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align "")       ==> "a b 12 34"
 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " ")      ==> "a b 12 34 "
 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 5")     ==> "a b 12 34\n         5"
 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 56")    ==> "a b 12\n      34\n        56"
 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 567")   ==> "a b\n12 34 567"
 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 5678")  ==> "a b\n12 34 5678"
 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 56789") ==> "a b\n12 34\n     56789"
 , 10 `maxWidth` ("1234567890" <> " ") <> "1" ==> "1234567890\n1"
 , 10 `maxWidth` nestedAlign  6 ==> "1 2 3 4 5\n         6"
 , 10 `maxWidth` nestedAlign  7 ==> "1 2 3 4\n       5\n        6\n         7"
 , 10 `maxWidth` nestedAlign  8 ==> "1 2 3\n     4\n      5\n       6\n        7\n         8"
 , 10 `maxWidth` nestedAlign  9 ==> "1 2\n   3\n    4\n     5\n      6\n       7\n        8\n         9"
 , 10 `maxWidth` nestedAlign 10 ==> "1\n 2\n  3\n   4\n    5\n     6\n      7\n       8\n        9\n         10"
 -- justify justifies
 , 10 `maxWidth` justify "1 2 3 4 5 6" ==> "1 2  3 4 5\n6"
 -- justify compresses spaces
 , 10 `maxWidth` justify "1 2 3 4  5 6" ==> "1 2  3 4 5\n6"
 , 10 `maxWidth` justify " 1 2 3 4 5 6 7 8 9" ==> " 1 2 3 4 5\n6 7 8 9"
 -- justify respects concatenating words
 , 10 `maxWidth` justify (setWidth (Just 11) ("1 2 3"<>"4 5 6 7")) ==> "1 2  34 5 6\n7"
 -- justify flushes the buffer before
 , 10 `maxWidth` "__" <> align (justify "1 2 3 4 5") ==> "__1 2  3 4\n  5"
 -- justify does not overflow the alignment
 , 10 `maxWidth` justify (nestedAlign 6) ==> "1 2 3 4 5\n         6"
 , 10 `maxWidth` justify ("a b\n" <> nestedAlign 2) ==> "a        b\n1 2"
 , 10 `maxWidth` justify (bold ("12 34 56 78 "<> underline "90" <> " 123 456  789"))
   ==> "\ESC[1m12  34  56\n78 \ESC[4m90\ESC[0;1m  123\n456 789\ESC[0m"
 -- align flushes the buffer
 , 10 `maxWidth` justify (ul ["1 2 3 4 5 6 7 8 9"])
   ==> "- 1 2  3 4\n\
       \  5 6  7 8\n\
       \  9"
 -- ul/ol is mempty when no item
 , ul [] ==> ""
 , ol [] ==> ""
 -- ul flushes the buffer
 , 10 `maxWidth` justify (let i = "1 2 3 4 5 6 7 8 9" in ul [i, i])
   ==> "- 1 2  3 4\n\
       \  5 6  7 8\n\
       \  9\n\
       \- 1 2  3 4\n\
       \  5 6  7 8\n\
       \  9"
 , 10 `maxWidth` justify (let i = "1 2 3 4 5 6 7 8 9" in
   ul [ul [i, i], ul [i, i]])
   ==> "- - 1 2  3\n\
       \    4 5  6\n\
       \    7 8 9\n\
       \  - 1 2  3\n\
       \    4 5  6\n\
       \    7 8 9\n\
       \- - 1 2  3\n\
       \    4 5  6\n\
       \    7 8 9\n\
       \  - 1 2  3\n\
       \    4 5  6\n\
       \    7 8 9"
 , 10 `maxWidth` justify (let i = "1 2 3 4 5 6 7 8 9" in
   ol [ol [i, i], ol [i, i]])
   ==> "1. 1. 1  2\n\
       \      3  4\n\
       \      5  6\n\
       \      7  8\n\
       \      9\n\
       \   2. 1  2\n\
       \      3  4\n\
       \      5  6\n\
       \      7  8\n\
       \      9\n\
       \2. 1. 1  2\n\
       \      3  4\n\
       \      5  6\n\
       \      7  8\n\
       \      9\n\
       \   2. 1  2\n\
       \      3  4\n\
       \      5  6\n\
       \      7  8\n\
       \      9"
 -- breakspace backtracking is bounded by the removable indentation
 -- (hence it can actually wrap a few words in reasonable time).
 , 80 `maxWidth`
  "Lorem ipsum dolor sit amet,  Nulla nec tortor. Donec id elit quis purus\
  \ consectetur consequat. Nam congue semper tellus. Sed erat dolor,\
  \ dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante.\
  \ Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod,\
  \ vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus,\
  \ pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque\
  \ quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur\
  \ adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis,\
  \ posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur\
  \ consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit\
  \ amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
  \ scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
  \ facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel,\
  \ malesuada ac, mattis nec, quam. Nam molestie scelerisque quam.\
  \ Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur\
  \ adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis,\
  \ posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur\
  \ consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet,\
  \ venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
  \ scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
  \ facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel,\
  \ malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam\
  \ feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing\
  \ elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede.\
  \ Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam\
  \ congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare,\
  \ ultrices ut, nisi."
  ==> "Lorem ipsum dolor sit amet,  Nulla nec tortor. Donec id elit quis\
  \ purus\nconsectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus\
  \ sit\namet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
  \ scelerisque\ndui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
  \ facilisis id,\nsem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada\
  \ ac, mattis nec,\nquam. Nam molestie scelerisque quam. Nullam feugiat cursus\
  \ lacus.orem ipsum\ndolor sit amet, consectetur adipiscing elit. Donec libero\
  \ risus, commodo vitae,\npharetra mollis, posuere eu, pede. Nulla nec tortor.\
  \ Donec id elit quis purus\nconsectetur consequat. Nam congue semper tellus. Sed\
  \ erat dolor, dapibus sit\namet, venenatis ornare, ultrices ut, nisi. Aliquam\
  \ ante. Suspendisse scelerisque\ndui nec velit. Duis augue augue, gravida\
  \ euismod, vulputate ac, facilisis id,\nsem. Morbi in orci. Nulla purus lacus,\
  \ pulvinar vel, malesuada ac, mattis nec,\nquam. Nam molestie scelerisque quam.\
  \ Nullam feugiat cursus lacus.orem ipsum\ndolor sit amet, consectetur adipiscing\
  \ elit. Donec libero risus, commodo vitae,\npharetra mollis, posuere eu, pede.\
  \ Nulla nec tortor. Donec id elit quis purus\nconsectetur consequat. Nam congue\
  \ semper tellus. Sed erat dolor, dapibus sit\namet, venenatis ornare, ultrices\
  \ ut, nisi. Aliquam ante. Suspendisse scelerisque\ndui nec velit. Duis augue\
  \ augue, gravida euismod, vulputate ac, facilisis id,\nsem. Morbi in orci. Nulla\
  \ purus lacus, pulvinar vel, malesuada ac, mattis nec,\nquam. Nam molestie\
  \ scelerisque quam. Nullam feugiat cursus lacus.orem ipsum\ndolor sit amet,\
  \ consectetur adipiscing elit. Donec libero risus, commodo vitae,\npharetra\
  \ mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis\
  \ purus\nconsectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus\
  \ sit\namet, venenatis ornare, ultrices ut, nisi."
 , 80 `maxWidth` justify
  "Lorem ipsum dolor sit amet,  Nulla nec tortor. Donec id elit quis purus\
  \ consectetur consequat. Nam congue semper tellus. Sed erat dolor,\
  \ dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante.\
  \ Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod,\
  \ vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus,\
  \ pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque\
  \ quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur\
  \ adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis,\
  \ posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur\
  \ consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit\
  \ amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
  \ scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
  \ facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel,\
  \ malesuada ac, mattis nec, quam. Nam molestie scelerisque quam.\
  \ Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur\
  \ adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis,\
  \ posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur\
  \ consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet,\
  \ venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
  \ scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
  \ facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel,\
  \ malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam\
  \ feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing\
  \ elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede.\
  \ Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam\
  \ congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare,\
  \ ultrices ut, nisi."
  ==> "Lorem ipsum  dolor sit  amet,  Nulla  nec  tortor.  Donec  id  elit  quis  purus\n\
  \consectetur consequat.  Nam congue  semper tellus.  Sed erat  dolor, dapibus sit\n\
  \amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque\n\
  \dui nec  velit. Duis  augue augue,  gravida euismod, vulputate ac, facilisis id,\n\
  \sem. Morbi  in orci.  Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec,\n\
  \quam. Nam  molestie scelerisque  quam. Nullam  feugiat cursus  lacus.orem  ipsum\n\
  \dolor sit  amet, consectetur adipiscing elit. Donec libero risus, commodo vitae,\n\
  \pharetra mollis,  posuere eu,  pede. Nulla  nec tortor. Donec id elit quis purus\n\
  \consectetur consequat.  Nam congue  semper tellus.  Sed erat  dolor, dapibus sit\n\
  \amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque\n\
  \dui nec  velit. Duis  augue augue,  gravida euismod, vulputate ac, facilisis id,\n\
  \sem. Morbi  in orci.  Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec,\n\
  \quam. Nam  molestie scelerisque  quam. Nullam  feugiat cursus  lacus.orem  ipsum\n\
  \dolor sit  amet, consectetur adipiscing elit. Donec libero risus, commodo vitae,\n\
  \pharetra mollis,  posuere eu,  pede. Nulla  nec tortor. Donec id elit quis purus\n\
  \consectetur consequat.  Nam congue  semper tellus.  Sed erat  dolor, dapibus sit\n\
  \amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque\n\
  \dui nec  velit. Duis  augue augue,  gravida euismod, vulputate ac, facilisis id,\n\
  \sem. Morbi  in orci.  Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec,\n\
  \quam. Nam  molestie scelerisque  quam. Nullam  feugiat cursus  lacus.orem  ipsum\n\
  \dolor sit  amet, consectetur adipiscing elit. Donec libero risus, commodo vitae,\n\
  \pharetra mollis,  posuere eu,  pede. Nulla  nec tortor. Donec id elit quis purus\n\
  \consectetur consequat.  Nam congue  semper tellus.  Sed erat  dolor, dapibus sit\n\
  \amet, venenatis ornare, ultrices ut, nisi."                                       
 ]
	where
	(==>) :: IsString d => d ~ String => AnsiText (Plain d) -> d -> Assertion; infix 0 ==>
	p ==> exp = got @?= exp
		where got = runPlain $ runAnsiText p

testList :: String -> [Assertion] -> TestTree
testList n as = testGroup n $ List.zipWith testCase (show <$> [1::Int ..]) as

breakpoints :: Wrappable d => Monoid d => [d] -> d
breakpoints = intercalate breakpoint

breakspaces :: Wrappable d => Monoid d => [d] -> d
breakspaces = intercalate breakspace

infix 1 `maxWidth`
maxWidth :: Wrappable d => Width -> d -> d
maxWidth = setWidth . Just

nestedAlign ::
 From (Line String) d =>
 Spaceable d => Indentable d => Wrappable d =>
 Int -> d
nestedAlign n = go 1
	where
	go i =
		from (Line (show i)) <>
		(if n <= i then mempty
		else align (breakspace <> go (i+1)))

listHorV :: IsString d => Indentable d => Wrappable d => [d] -> d
listHorV [] = "[]"
listHorV [d] = "["<>d<>"]"
listHorV ds =
	breakalt
	 ("[" <> intercalate ("," <> space) ds <> "]")
	 (align $ "[" <> space
		 <> foldr1 (\a acc -> a <> newline <> "," <> space <> acc) ds
		 <> newline <> "]")

fun :: IsString d => Indentable d => Wrappable d => d -> d
fun d = "function(" <> incrIndent 2 (breakalt d (newline<>d<>newline)) <> ")"

t1 = 10 `maxWidth` justify (let i = "1 2 3 4 5 6 7 8 9" in ol [ol [i, i], ol [i, i]])