]> Git — Sourcephile - haskell/symantic-document.git/blob - test/HUnit.hs
plain: fix flushing in align and ul/ol
[haskell/symantic-document.git] / test / HUnit.hs
1 {-# LANGUAGE OverloadedStrings #-}
2 module HUnit where
3
4 import Test.Tasty
5 import Test.Tasty.HUnit
6
7 import Data.Foldable (Foldable(..))
8 import Data.Function (($), (.))
9 import Data.Functor ((<$>))
10 import Data.Int (Int)
11 import Data.Maybe (Maybe(..))
12 import Data.Monoid (Monoid(..))
13 import Data.Ord (Ord(..))
14 import Data.Semigroup (Semigroup(..))
15 import Data.String (String, IsString(..))
16 import Prelude ((+))
17 import Text.Show (Show(..))
18 import qualified Data.List as List
19
20 import Symantic.Document.API
21 import Symantic.Document.Plain
22 import Symantic.Document.AnsiText
23
24 -- * Tests
25 hunits :: TestTree
26 hunits = testGroup "HUnit" $
27 [ hunitPlain
28 ]
29
30 hunitPlain :: TestTree
31 hunitPlain = testList "Plain"
32 [ newline ==> "\n"
33 , "hello\nworld" ==> "hello\nworld"
34 , 10`maxWidth` breakpoints ["hello", "world"] ==> "helloworld"
35 , 9`maxWidth` breakpoints ["hello", "world"] ==> "hello\nworld"
36 , 6`maxWidth` breakpoints ["he", "ll", "o!"] ==> "hello!"
37 , 6`maxWidth` breakpoints ["he", "ll", "o!", "wo", "rl", "d!"] ==> "hello!\nworld!"
38 , 5`maxWidth` breakpoints ["hello", "world"] ==> "hello\nworld"
39 , 5`maxWidth` breakpoints ["he", "llo", "world"] ==> "hello\nworld"
40 , 5`maxWidth` breakpoints ["he", "ll", "o!"] ==> "hell\no!"
41 , 4`maxWidth` breakpoints ["hello", "world"] ==> "hello\nworld"
42 , 4`maxWidth` breakpoints ["he", "ll", "o!"] ==> "hell\no!"
43 , 4`maxWidth` breakpoints ["he", "llo", "world"] ==> "he\nllo\nworld"
44 , 4`maxWidth` breakpoints ["he", "llo", "w", "orld"] ==> "he\nllow\norld"
45 , 4`maxWidth` breakpoints ["he", "ll", "o!", "wo", "rl", "d!"] ==> "hell\no!wo\nrld!"
46 , 3`maxWidth` breakpoints ["hello", "world"] ==> "hello\nworld"
47 , 3`maxWidth` breakpoints ["he", "ll"] ==> "he\nll"
48 , 3`maxWidth` breakpoints ["he", "ll", "o!"] ==> "he\nll\no!"
49 , 1`maxWidth` breakpoints ["he", "ll", "o!"] ==> "he\nll\no!"
50 , 4`maxWidth` mconcat ["__", align $ breakpoints ["he", "ll", "o!", "wo", "rl", "d!"]]
51 ==> "__he\n ll\n o!\n wo\n rl\n d!"
52 , 6`maxWidth` mconcat ["__", align $ breakpoints ["he", "ll", "o!", "wo", "rl", "d!"]]
53 ==> "__hell\n o!wo\n rld!"
54 , 16`maxWidth` mconcat ["__", listHorV ["hello", "world"]] ==> "__[hello, world]"
55 , 4`maxWidth` mconcat ["__", listHorV ["hello", "world"]] ==> "__[ hello\n , world\n ]"
56 , 11`maxWidth` breakspaces ["hello", "world"] ==> "hello world"
57 , 10`maxWidth` breakspaces ["hello", "world"] ==> "hello\nworld"
58 , 6`maxWidth` breakspaces ["hel", "lo", "wo", "rld"] ==> "hel lo\nwo rld"
59 , 6`maxWidth` breakspaces ["hel", "lo", "wo", "rld", "HEL", "LO", "WO", "RLD"] ==> "hel lo\nwo rld\nHEL LO\nWO RLD"
60 , 5`maxWidth` breakspaces ["hello", "world"] ==> "hello\nworld"
61 , 19`maxWidth` fun (fun $ fun $ fun $ fun $ listHorV ["abcdefg", "abcdefg"])
62 ==> "function(function(\n function(\n function(\n function(\n [ abcdefg\n , abcdefg\n ]\n )\n )\n )\n ))"
63 , 19`maxWidth` fun (fun $ fun $ fun $ fun $ listHorV ["abcdefgh", "abcdefgh"])
64 ==> "function(\n function(\n function(\n function(\n function(\n [ abcdefgh\n , abcdefgh\n ]\n )\n )\n )\n )\n )"
65 , 7`maxWidth` ("hello"<>breakspace<>"world") ==> "hello\nworld"
66 , 7`maxWidth` ("hello "<>"world") ==> "hello\nworld"
67 , " "<> "hello\nworld\n!" ==> " hello\nworld\n!"
68 , "__"<>align "hello\nworld\n!" ==> "__hello\n world\n !"
69 , hang 2 "hello\nworld\n!" ==> "hello\n world\n !"
70 , hang 2 "hello\nworld\n!"<>"\nhello\n!" ==> "hello\n world\n !\nhello\n!"
71 , "let " <> align (catV $
72 (\(name, typ) -> fill 6 name <+> "::" <+> typ)
73 <$> [ ("abcdef","Doc")
74 , ("abcde","Int -> Doc -> Doc")
75 , ("abcdefghi","Doc") ])
76 ==> "let abcdef :: Doc\n abcde :: Int -> Doc -> Doc\n abcdefghi :: Doc"
77 , "let " <> align (catV $
78 (\(name, typ) -> breakfill 6 name <> " ::" <+> typ)
79 <$> [ ("abcdef","Doc")
80 , ("abcde","Int -> Doc -> Doc")
81 , ("abcdefghi","Doc") ])
82 ==> "let abcdef :: Doc\n abcde :: Int -> Doc -> Doc\n abcdefghi\n :: Doc"
83 , "let " <> align (catV $
84 (\(name, typ) -> breakfill 6 name <> " ::" <+> typ)
85 <$> [("abcdefghi","Doc ->\nDoc")])
86 ==> "let abcdefghi\n :: Doc ->\n Doc"
87 , "let " <> align (catV $
88 (\(name, typ) -> breakfill 6 name <> align (" ::" <+> typ))
89 <$> [("abcdefghi","Doc ->\nDoc")])
90 ==> "let abcdefghi\n :: Doc ->\n Doc"
91 , 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"
92 , 10 `maxWidth` "a b "<>"12"<>align (" 34 5") ==> "a b 12 34\n 5"
93 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align "") ==> "a b 12 34"
94 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " ") ==> "a b 12 34 "
95 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 5") ==> "a b 12 34\n 5"
96 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 56") ==> "a b 12\n 34\n 56"
97 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 567") ==> "a b\n12 34 567"
98 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 5678") ==> "a b\n12 34 5678"
99 , 10 `maxWidth` "a b "<>"12"<>align (" 34" <> align " 56789") ==> "a b\n12 34\n 56789"
100 , 10 `maxWidth` ("1234567890" <> " ") <> "1" ==> "1234567890\n1"
101 , 10 `maxWidth` nestedAlign 6 ==> "1 2 3 4 5\n 6"
102 , 10 `maxWidth` nestedAlign 7 ==> "1 2 3 4\n 5\n 6\n 7"
103 , 10 `maxWidth` nestedAlign 8 ==> "1 2 3\n 4\n 5\n 6\n 7\n 8"
104 , 10 `maxWidth` nestedAlign 9 ==> "1 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9"
105 , 10 `maxWidth` nestedAlign 10 ==> "1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n 10"
106 -- justify justifies
107 , 10 `maxWidth` justify "1 2 3 4 5 6" ==> "1 2 3 4 5\n6"
108 -- justify compresses spaces
109 , 10 `maxWidth` justify "1 2 3 4 5 6" ==> "1 2 3 4 5\n6"
110 , 10 `maxWidth` justify " 1 2 3 4 5 6 7 8 9" ==> " 1 2 3 4 5\n6 7 8 9"
111 -- justify respects concatenating words
112 , 10 `maxWidth` justify (setWidth (Just 11) ("1 2 3"<>"4 5 6 7")) ==> "1 2 34 5 6\n7"
113 -- justify flushes the buffer before
114 , 10 `maxWidth` "__" <> align (justify "1 2 3 4 5") ==> "__1 2 3 4\n 5"
115 -- justify does not overflow the alignment
116 , 10 `maxWidth` justify (nestedAlign 6) ==> "1 2 3 4 5\n 6"
117 , 10 `maxWidth` justify ("a b\n" <> nestedAlign 2) ==> "a b\n1 2"
118 , 10 `maxWidth` justify (bold ("12 34 56 78 "<> underline "90" <> " 123 456 789"))
119 ==> "\ESC[1m12 34 56\n78 \ESC[4m90\ESC[0;1m 123\n456 789\ESC[0m"
120 -- align flushes the buffer
121 , 10 `maxWidth` justify (ul ["1 2 3 4 5 6 7 8 9"])
122 ==> "- 1 2 3 4\n\
123 \ 5 6 7 8\n\
124 \ 9"
125 -- ul/ol is mempty when no item
126 , ul [] ==> ""
127 , ol [] ==> ""
128 -- ul flushes the buffer
129 , 10 `maxWidth` justify (let i = "1 2 3 4 5 6 7 8 9" in ul [i, i])
130 ==> "- 1 2 3 4\n\
131 \ 5 6 7 8\n\
132 \ 9\n\
133 \- 1 2 3 4\n\
134 \ 5 6 7 8\n\
135 \ 9"
136 , 10 `maxWidth` justify (let i = "1 2 3 4 5 6 7 8 9" in
137 ul [ul [i, i], ul [i, i]])
138 ==> "- - 1 2 3\n\
139 \ 4 5 6\n\
140 \ 7 8 9\n\
141 \ - 1 2 3\n\
142 \ 4 5 6\n\
143 \ 7 8 9\n\
144 \- - 1 2 3\n\
145 \ 4 5 6\n\
146 \ 7 8 9\n\
147 \ - 1 2 3\n\
148 \ 4 5 6\n\
149 \ 7 8 9"
150 , 10 `maxWidth` justify (let i = "1 2 3 4 5 6 7 8 9" in
151 ol [ol [i, i], ol [i, i]])
152 ==> "1. 1. 1 2\n\
153 \ 3 4\n\
154 \ 5 6\n\
155 \ 7 8\n\
156 \ 9\n\
157 \ 2. 1 2\n\
158 \ 3 4\n\
159 \ 5 6\n\
160 \ 7 8\n\
161 \ 9\n\
162 \2. 1. 1 2\n\
163 \ 3 4\n\
164 \ 5 6\n\
165 \ 7 8\n\
166 \ 9\n\
167 \ 2. 1 2\n\
168 \ 3 4\n\
169 \ 5 6\n\
170 \ 7 8\n\
171 \ 9"
172 -- breakspace backtracking is bounded by the removable indentation
173 -- (hence it can actually wrap a few words in reasonable time).
174 , 80 `maxWidth`
175 "Lorem ipsum dolor sit amet, Nulla nec tortor. Donec id elit quis purus\
176 \ consectetur consequat. Nam congue semper tellus. Sed erat dolor,\
177 \ dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante.\
178 \ Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod,\
179 \ vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus,\
180 \ pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque\
181 \ quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur\
182 \ adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis,\
183 \ posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur\
184 \ consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit\
185 \ amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
186 \ scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
187 \ facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel,\
188 \ malesuada ac, mattis nec, quam. Nam molestie scelerisque quam.\
189 \ Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur\
190 \ adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis,\
191 \ posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur\
192 \ consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet,\
193 \ venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
194 \ scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
195 \ facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel,\
196 \ malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam\
197 \ feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing\
198 \ elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede.\
199 \ Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam\
200 \ congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare,\
201 \ ultrices ut, nisi."
202 ==> "Lorem ipsum dolor sit amet, Nulla nec tortor. Donec id elit quis\
203 \ purus\nconsectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus\
204 \ sit\namet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
205 \ scelerisque\ndui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
206 \ facilisis id,\nsem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada\
207 \ ac, mattis nec,\nquam. Nam molestie scelerisque quam. Nullam feugiat cursus\
208 \ lacus.orem ipsum\ndolor sit amet, consectetur adipiscing elit. Donec libero\
209 \ risus, commodo vitae,\npharetra mollis, posuere eu, pede. Nulla nec tortor.\
210 \ Donec id elit quis purus\nconsectetur consequat. Nam congue semper tellus. Sed\
211 \ erat dolor, dapibus sit\namet, venenatis ornare, ultrices ut, nisi. Aliquam\
212 \ ante. Suspendisse scelerisque\ndui nec velit. Duis augue augue, gravida\
213 \ euismod, vulputate ac, facilisis id,\nsem. Morbi in orci. Nulla purus lacus,\
214 \ pulvinar vel, malesuada ac, mattis nec,\nquam. Nam molestie scelerisque quam.\
215 \ Nullam feugiat cursus lacus.orem ipsum\ndolor sit amet, consectetur adipiscing\
216 \ elit. Donec libero risus, commodo vitae,\npharetra mollis, posuere eu, pede.\
217 \ Nulla nec tortor. Donec id elit quis purus\nconsectetur consequat. Nam congue\
218 \ semper tellus. Sed erat dolor, dapibus sit\namet, venenatis ornare, ultrices\
219 \ ut, nisi. Aliquam ante. Suspendisse scelerisque\ndui nec velit. Duis augue\
220 \ augue, gravida euismod, vulputate ac, facilisis id,\nsem. Morbi in orci. Nulla\
221 \ purus lacus, pulvinar vel, malesuada ac, mattis nec,\nquam. Nam molestie\
222 \ scelerisque quam. Nullam feugiat cursus lacus.orem ipsum\ndolor sit amet,\
223 \ consectetur adipiscing elit. Donec libero risus, commodo vitae,\npharetra\
224 \ mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis\
225 \ purus\nconsectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus\
226 \ sit\namet, venenatis ornare, ultrices ut, nisi."
227 , 80 `maxWidth` justify
228 "Lorem ipsum dolor sit amet, Nulla nec tortor. Donec id elit quis purus\
229 \ consectetur consequat. Nam congue semper tellus. Sed erat dolor,\
230 \ dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante.\
231 \ Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod,\
232 \ vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus,\
233 \ pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque\
234 \ quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur\
235 \ adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis,\
236 \ posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur\
237 \ consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit\
238 \ amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
239 \ scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
240 \ facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel,\
241 \ malesuada ac, mattis nec, quam. Nam molestie scelerisque quam.\
242 \ Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur\
243 \ adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis,\
244 \ posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur\
245 \ consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet,\
246 \ venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse\
247 \ scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac,\
248 \ facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel,\
249 \ malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam\
250 \ feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing\
251 \ elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede.\
252 \ Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam\
253 \ congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare,\
254 \ ultrices ut, nisi."
255 ==> "Lorem ipsum dolor sit amet, Nulla nec tortor. Donec id elit quis purus\n\
256 \consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit\n\
257 \amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque\n\
258 \dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id,\n\
259 \sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec,\n\
260 \quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum\n\
261 \dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae,\n\
262 \pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus\n\
263 \consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit\n\
264 \amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque\n\
265 \dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id,\n\
266 \sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec,\n\
267 \quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum\n\
268 \dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae,\n\
269 \pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus\n\
270 \consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit\n\
271 \amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque\n\
272 \dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id,\n\
273 \sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec,\n\
274 \quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum\n\
275 \dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae,\n\
276 \pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus\n\
277 \consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit\n\
278 \amet, venenatis ornare, ultrices ut, nisi."
279 ]
280 where
281 (==>) :: IsString d => d ~ String => AnsiText (Plain d) -> d -> Assertion; infix 0 ==>
282 p ==> exp = got @?= exp
283 where got = runPlain $ runAnsiText p
284
285 testList :: String -> [Assertion] -> TestTree
286 testList n as = testGroup n $ List.zipWith testCase (show <$> [1::Int ..]) as
287
288 breakpoints :: Wrappable d => Monoid d => [d] -> d
289 breakpoints = intercalate breakpoint
290
291 breakspaces :: Wrappable d => Monoid d => [d] -> d
292 breakspaces = intercalate breakspace
293
294 infix 1 `maxWidth`
295 maxWidth :: Wrappable d => Width -> d -> d
296 maxWidth = setWidth . Just
297
298 nestedAlign ::
299 From (Line String) d =>
300 Spaceable d => Indentable d => Wrappable d =>
301 Int -> d
302 nestedAlign n = go 1
303 where
304 go i =
305 from (Line (show i)) <>
306 (if n <= i then mempty
307 else align (breakspace <> go (i+1)))
308
309 listHorV :: IsString d => Indentable d => Wrappable d => [d] -> d
310 listHorV [] = "[]"
311 listHorV [d] = "["<>d<>"]"
312 listHorV ds =
313 breakalt
314 ("[" <> intercalate ("," <> space) ds <> "]")
315 (align $ "[" <> space
316 <> foldr1 (\a acc -> a <> newline <> "," <> space <> acc) ds
317 <> newline <> "]")
318
319 fun :: IsString d => Indentable d => Wrappable d => d -> d
320 fun d = "function(" <> incrIndent 2 (breakalt d (newline<>d<>newline)) <> ")"
321
322 t1 = 10 `maxWidth` justify (let i = "1 2 3 4 5 6 7 8 9" in ol [ol [i, i], ol [i, i]])