]> Git — Sourcephile - comptalang.git/blob - lib/Test/Main.hs
Correction : Format.Ledger.Read : posting_type davantage laxiste
[comptalang.git] / lib / Test / Main.hs
1 {-# LANGUAGE TupleSections #-}
2 {-# LANGUAGE OverloadedStrings #-}
3
4 import Prelude
5 import Test.HUnit
6 import Test.Framework.Providers.HUnit (hUnitTestToTests)
7 import Test.Framework.Runners.Console (defaultMain)
8
9 import Control.Applicative ((<*))
10 import Control.Monad.IO.Class (liftIO)
11 import Data.Decimal (DecimalRaw(..))
12 import qualified Data.Either
13 import qualified Data.List
14 import Data.List.NonEmpty (NonEmpty(..))
15 import qualified Data.Map.Strict as Data.Map
16 import Data.Text (Text)
17 import qualified Data.Time.Calendar as Time
18 import qualified Data.Time.LocalTime as Time
19 import qualified Text.Parsec as P
20 import qualified Text.Parsec.Pos as P
21 -- import qualified Text.PrettyPrint.Leijen.Text as PP
22
23 import qualified Hcompta.Model.Account as Account
24 import qualified Hcompta.Model.Amount as Amount
25 import qualified Hcompta.Model.Amount.Style as Amount.Style
26 import qualified Hcompta.Model.Date as Date
27 import qualified Hcompta.Model.Transaction as Transaction
28 import qualified Hcompta.Model.Transaction.Posting as Posting
29 import qualified Hcompta.Calc.Balance as Calc.Balance
30 import qualified Hcompta.Format.Ledger.Read as Format.Ledger.Read
31 import qualified Hcompta.Format.Ledger.Journal as Format.Ledger.Journal
32 import qualified Hcompta.Format.Ledger.Write as Format.Ledger.Write
33 import qualified Hcompta.Lib.TreeMap as Lib.TreeMap
34
35 --instance Eq Text.Parsec.ParseError where
36 -- (==) = const (const False)
37
38 main :: IO ()
39 main = defaultMain $ hUnitTestToTests test_Hcompta
40
41 test_Hcompta :: Test
42 test_Hcompta =
43 TestList
44 [ "Model" ~: TestList
45 [ "Account" ~: TestList
46 [ "foldr" ~: TestList
47 [ "[A]" ~:
48 (reverse $ Account.foldr ("A":|[]) (:) []) ~?= ["A":|[]]
49 , "[A, B]" ~:
50 (reverse $ Account.foldr ("A":|["B"]) (:) []) ~?= ["A":|[], "A":|["B"]]
51 , "[A, B, C]" ~:
52 (reverse $ Account.foldr ("A":|["B", "C"]) (:) []) ~?= ["A":|[], "A":|["B"], "A":|["B", "C"]]
53 ]
54 , "ascending" ~: TestList
55 [ "[A]" ~:
56 Account.ascending ("A":|[]) ~?= Nothing
57 , "[A, B]" ~:
58 Account.ascending ("A":|["B"]) ~?= Just ("A":|[])
59 , "[A, B, C]" ~:
60 Account.ascending ("A":|["B", "C"]) ~?= Just ("A":|["B"])
61 ]
62 ]
63 , "Amount" ~: TestList
64 [ "+" ~: TestList
65 [ "$1 + 1$ = $2" ~:
66 (+)
67 (Amount.nil
68 { Amount.quantity = Decimal 0 1
69 , Amount.style = Amount.Style.nil
70 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
71 }
72 , Amount.unit = "$"
73 })
74 (Amount.nil
75 { Amount.quantity = Decimal 0 1
76 , Amount.style = Amount.Style.nil
77 { Amount.Style.unit_side = Just $ Amount.Style.Side_Right
78 }
79 , Amount.unit = "$"
80 })
81 ~?=
82 (Amount.nil
83 { Amount.quantity = Decimal 0 2
84 , Amount.style = Amount.Style.nil
85 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
86 }
87 , Amount.unit = "$"
88 })
89 ]
90 , "from_List" ~: TestList
91 [ "from_List [$1, 1$] = $2" ~:
92 Amount.from_List
93 [ Amount.nil
94 { Amount.quantity = Decimal 0 1
95 , Amount.style = Amount.Style.nil
96 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
97 }
98 , Amount.unit = "$"
99 }
100 , Amount.nil
101 { Amount.quantity = Decimal 0 1
102 , Amount.style = Amount.Style.nil
103 { Amount.Style.unit_side = Just $ Amount.Style.Side_Right
104 }
105 , Amount.unit = "$"
106 }
107 ]
108 ~?=
109 Data.Map.fromList
110 [ ("$", Amount.nil
111 { Amount.quantity = Decimal 0 2
112 , Amount.style = Amount.Style.nil
113 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
114 }
115 , Amount.unit = "$"
116 })
117 ]
118 ]
119 ]
120 ]
121 , "Calc" ~: TestList
122 [ "Balance" ~: TestList
123 [ "posting" ~: TestList
124 [ "[A+$1] = A+$1 & $+1" ~:
125 (Calc.Balance.posting
126 (Posting.nil ("A":|[]))
127 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
128 }
129 Calc.Balance.nil)
130 ~?=
131 Calc.Balance.Balance
132 { Calc.Balance.by_account =
133 Lib.TreeMap.from_List const
134 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
135 , Calc.Balance.by_unit =
136 Data.Map.fromList $
137 Data.List.map Calc.Balance.assoc_unit_sum $
138 [ Calc.Balance.Unit_Sum
139 { Calc.Balance.amount = Amount.usd $ 1
140 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
141 ["A":|[]]
142 }
143 ]
144 }
145 , "[A+$1, A-$1] = {A+$0, $+0}" ~:
146 (Data.List.foldl
147 (flip Calc.Balance.posting)
148 Calc.Balance.nil
149 [ (Posting.nil ("A":|[]))
150 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
151 }
152 , (Posting.nil ("A":|[]))
153 { Posting.amounts=Amount.from_List [ Amount.usd $ -1 ]
154 }
155 ])
156 ~?=
157 Calc.Balance.Balance
158 { Calc.Balance.by_account =
159 Lib.TreeMap.from_List const
160 [ ("A":|[], Amount.from_List [ Amount.usd $ 0 ]) ]
161 , Calc.Balance.by_unit =
162 Data.Map.fromList $
163 Data.List.map Calc.Balance.assoc_unit_sum $
164 [ Calc.Balance.Unit_Sum
165 { Calc.Balance.amount = Amount.usd $ 0
166 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
167 ["A":|[]]
168 }
169 ]
170 }
171 , "[A+$1, A-€1] = {A+$1-€1, $+1 €-1}" ~:
172 (Data.List.foldl
173 (flip Calc.Balance.posting)
174 Calc.Balance.nil
175 [ (Posting.nil ("A":|[]))
176 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
177 }
178 , (Posting.nil ("A":|[]))
179 { Posting.amounts=Amount.from_List [ Amount.eur $ -1 ]
180 }
181 ])
182 ~?=
183 Calc.Balance.Balance
184 { Calc.Balance.by_account =
185 Lib.TreeMap.from_List const
186 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ -1 ]) ]
187 , Calc.Balance.by_unit =
188 Data.Map.fromList $
189 Data.List.map Calc.Balance.assoc_unit_sum $
190 [ Calc.Balance.Unit_Sum
191 { Calc.Balance.amount = Amount.usd $ 1
192 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
193 ["A":|[]]
194 }
195 , Calc.Balance.Unit_Sum
196 { Calc.Balance.amount = Amount.eur $ -1
197 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
198 ["A":|[]]
199 }
200 ]
201 }
202 , "[A+$1, B-$1] = {A+$1 B-$1, $+0}" ~:
203 (Data.List.foldl
204 (flip Calc.Balance.posting)
205 Calc.Balance.nil
206 [ (Posting.nil ("A":|[]))
207 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
208 }
209 , (Posting.nil ("B":|[]))
210 { Posting.amounts=Amount.from_List [ Amount.usd $ -1 ]
211 }
212 ])
213 ~?=
214 Calc.Balance.Balance
215 { Calc.Balance.by_account =
216 Lib.TreeMap.from_List const
217 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
218 , ("B":|[], Amount.from_List [ Amount.usd $ -1 ])
219 ]
220 , Calc.Balance.by_unit =
221 Data.Map.fromList $
222 Data.List.map Calc.Balance.assoc_unit_sum $
223 [ Calc.Balance.Unit_Sum
224 { Calc.Balance.amount = Amount.usd $ 0
225 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
226 ["A":|[], "B":|[]]
227 }
228 ]
229 }
230 , "[A+$1+€2, A-$1-€2] = {A+$0+€0, $+0 €+0}" ~:
231 (Data.List.foldl
232 (flip Calc.Balance.posting)
233 Calc.Balance.nil
234 [ (Posting.nil ("A":|[]))
235 { Posting.amounts=Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2 ]
236 }
237 , (Posting.nil ("A":|[]))
238 { Posting.amounts=Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2 ]
239 }
240 ])
241 ~?=
242 Calc.Balance.Balance
243 { Calc.Balance.by_account =
244 Lib.TreeMap.from_List const
245 [ ("A":|[], Amount.from_List [ Amount.usd $ 0, Amount.eur $ 0 ])
246 ]
247 , Calc.Balance.by_unit =
248 Data.Map.fromList $
249 Data.List.map Calc.Balance.assoc_unit_sum $
250 [ Calc.Balance.Unit_Sum
251 { Calc.Balance.amount = Amount.usd $ 0
252 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
253 ["A":|[]]
254 }
255 , Calc.Balance.Unit_Sum
256 { Calc.Balance.amount = Amount.eur $ 0
257 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
258 ["A":|[]]
259 }
260 ]
261 }
262 , "[A+$1+€2+£3, B-$1-2€-£3] = {A+$1+€2+£3 B-$1-€2-£3, $+0 €+0 £+0}" ~:
263 (Data.List.foldl
264 (flip Calc.Balance.posting)
265 Calc.Balance.nil
266 [ (Posting.nil ("A":|[]))
267 { Posting.amounts=Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ]
268 }
269 , (Posting.nil ("B":|[]))
270 { Posting.amounts=Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ]
271 }
272 ])
273 ~?=
274 Calc.Balance.Balance
275 { Calc.Balance.by_account =
276 Lib.TreeMap.from_List const
277 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ])
278 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ])
279 ]
280 , Calc.Balance.by_unit =
281 Data.Map.fromList $
282 Data.List.map Calc.Balance.assoc_unit_sum $
283 [ Calc.Balance.Unit_Sum
284 { Calc.Balance.amount = Amount.usd $ 0
285 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
286 ["A":|[], "B":|[]]
287 }
288 , Calc.Balance.Unit_Sum
289 { Calc.Balance.amount = Amount.eur $ 0
290 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
291 ["A":|[], "B":|[]]
292 }
293 , Calc.Balance.Unit_Sum
294 { Calc.Balance.amount = Amount.gbp $ 0
295 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
296 ["A":|[], "B":|[]]
297 }
298 ]
299 }
300 ]
301 , "union" ~: TestList
302 [ "nil nil = nil" ~:
303 Calc.Balance.union
304 Calc.Balance.nil
305 Calc.Balance.nil
306 ~?=
307 Calc.Balance.nil
308 , "{A+$1, $+1} {A+$1, $+1} = {A+$2, $+2}" ~:
309 Calc.Balance.union
310 (Calc.Balance.Balance
311 { Calc.Balance.by_account =
312 Lib.TreeMap.from_List const
313 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
314 , Calc.Balance.by_unit =
315 Data.Map.fromList $
316 Data.List.map Calc.Balance.assoc_unit_sum $
317 [ Calc.Balance.Unit_Sum
318 { Calc.Balance.amount = Amount.usd $ 1
319 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
320 ["A":|[]]
321 }
322 ]
323 })
324 (Calc.Balance.Balance
325 { Calc.Balance.by_account =
326 Lib.TreeMap.from_List const
327 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
328 , Calc.Balance.by_unit =
329 Data.Map.fromList $
330 Data.List.map Calc.Balance.assoc_unit_sum $
331 [ Calc.Balance.Unit_Sum
332 { Calc.Balance.amount = Amount.usd $ 1
333 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
334 ["A":|[]]
335 }
336 ]
337 })
338 ~?=
339 Calc.Balance.Balance
340 { Calc.Balance.by_account =
341 Lib.TreeMap.from_List const
342 [ ("A":|[], Amount.from_List [ Amount.usd $ 2 ]) ]
343 , Calc.Balance.by_unit =
344 Data.Map.fromList $
345 Data.List.map Calc.Balance.assoc_unit_sum $
346 [ Calc.Balance.Unit_Sum
347 { Calc.Balance.amount = Amount.usd $ 2
348 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
349 ["A":|[]]
350 }
351 ]
352 }
353 , "{A+$1, $+1} {B+$1, $+1} = {A+$1 B+$1, $+2}" ~:
354 Calc.Balance.union
355 (Calc.Balance.Balance
356 { Calc.Balance.by_account =
357 Lib.TreeMap.from_List const
358 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
359 , Calc.Balance.by_unit =
360 Data.Map.fromList $
361 Data.List.map Calc.Balance.assoc_unit_sum $
362 [ Calc.Balance.Unit_Sum
363 { Calc.Balance.amount = Amount.usd $ 1
364 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
365 ["A":|[]]
366 }
367 ]
368 })
369 (Calc.Balance.Balance
370 { Calc.Balance.by_account =
371 Lib.TreeMap.from_List const
372 [ ("B":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
373 , Calc.Balance.by_unit =
374 Data.Map.fromList $
375 Data.List.map Calc.Balance.assoc_unit_sum $
376 [ Calc.Balance.Unit_Sum
377 { Calc.Balance.amount = Amount.usd $ 1
378 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
379 ["B":|[]]
380 }
381 ]
382 })
383 ~?=
384 Calc.Balance.Balance
385 { Calc.Balance.by_account =
386 Lib.TreeMap.from_List const
387 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
388 , ("B":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
389 , Calc.Balance.by_unit =
390 Data.Map.fromList $
391 Data.List.map Calc.Balance.assoc_unit_sum $
392 [ Calc.Balance.Unit_Sum
393 { Calc.Balance.amount = Amount.usd $ 2
394 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
395 ["A":|[], "B":|[]]
396 }
397 ]
398 }
399 , "{A+$1, $+1} {B+€1, €+1} = {A+$1 B+€1, $+1 €+1}" ~:
400 Calc.Balance.union
401 (Calc.Balance.Balance
402 { Calc.Balance.by_account =
403 Lib.TreeMap.from_List const
404 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
405 , Calc.Balance.by_unit =
406 Data.Map.fromList $
407 Data.List.map Calc.Balance.assoc_unit_sum $
408 [ Calc.Balance.Unit_Sum
409 { Calc.Balance.amount = Amount.usd $ 1
410 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
411 ["A":|[]]
412 }
413 ]
414 })
415 (Calc.Balance.Balance
416 { Calc.Balance.by_account =
417 Lib.TreeMap.from_List const
418 [ ("B":|[], Amount.from_List [ Amount.eur $ 1 ]) ]
419 , Calc.Balance.by_unit =
420 Data.Map.fromList $
421 Data.List.map Calc.Balance.assoc_unit_sum $
422 [ Calc.Balance.Unit_Sum
423 { Calc.Balance.amount = Amount.eur $ 1
424 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
425 ["B":|[]]
426 }
427 ]
428 })
429 ~?=
430 Calc.Balance.Balance
431 { Calc.Balance.by_account =
432 Lib.TreeMap.from_List const
433 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
434 , ("B":|[], Amount.from_List [ Amount.eur $ 1 ]) ]
435 , Calc.Balance.by_unit =
436 Data.Map.fromList $
437 Data.List.map Calc.Balance.assoc_unit_sum $
438 [ Calc.Balance.Unit_Sum
439 { Calc.Balance.amount = Amount.usd $ 1
440 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
441 ["A":|[]]
442 }
443 , Calc.Balance.Unit_Sum
444 { Calc.Balance.amount = Amount.eur $ 1
445 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
446 ["B":|[]]
447 }
448 ]
449 }
450 ]
451 , "expand" ~: TestList
452 [ "nil_By_Account" ~:
453 Calc.Balance.expand
454 Calc.Balance.nil_By_Account
455 ~?=
456 Lib.TreeMap.empty
457 , "A+$1 = A+$1" ~:
458 Calc.Balance.expand
459 (Lib.TreeMap.from_List const
460 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ])
461 ~?=
462 (Lib.TreeMap.from_List const
463 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
464 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
465 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
466 })
467 ])
468 , "A/A+$1 = A+$1 A/A+$1" ~:
469 Calc.Balance.expand
470 (Lib.TreeMap.from_List const
471 [ ("A":|["A"], Amount.from_List [ Amount.usd $ 1 ]) ])
472 ~?=
473 (Lib.TreeMap.from_List const
474 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
475 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
476 , Calc.Balance.exclusive = Amount.from_List []
477 })
478 , ("A":|["A"], Calc.Balance.Account_Sum_Expanded
479 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
480 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
481 })
482 ])
483 , "A/B+$1 = A+$1 A/B+$1" ~:
484 Calc.Balance.expand
485 (Lib.TreeMap.from_List const
486 [ ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ]) ])
487 ~?=
488 (Lib.TreeMap.from_List const
489 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
490 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
491 , Calc.Balance.exclusive = Amount.from_List []
492 })
493 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
494 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
495 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
496 })
497 ])
498 , "A/B/C+$1 = A+$1 A/B+$1 A/B/C+$1" ~:
499 Calc.Balance.expand
500 (Lib.TreeMap.from_List const
501 [ ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ]) ])
502 ~?=
503 (Lib.TreeMap.from_List const
504 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
505 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
506 , Calc.Balance.exclusive = Amount.from_List []
507 })
508 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
509 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
510 , Calc.Balance.exclusive = Amount.from_List []
511 })
512 , ("A":|["B", "C"], Calc.Balance.Account_Sum_Expanded
513 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
514 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
515 })
516 ])
517 , "A+$1 A/B+$1 = A+$2 A/B+$1" ~:
518 Calc.Balance.expand
519 (Lib.TreeMap.from_List const
520 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
521 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
522 ])
523 ~?=
524 (Lib.TreeMap.from_List const
525 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
526 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 2 ]
527 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
528 })
529 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
530 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
531 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
532 })
533 ])
534 , "A+$1 A/B+$1 A/B/C+$1 = A+$3 A/B+$2 A/B/C+$1" ~:
535 Calc.Balance.expand
536 (Lib.TreeMap.from_List const
537 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
538 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
539 , ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ])
540 ])
541 ~?=
542 (Lib.TreeMap.from_List const
543 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
544 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 3 ]
545 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
546 })
547 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
548 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 2 ]
549 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
550 })
551 , ("A":|["B", "C"], Calc.Balance.Account_Sum_Expanded
552 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
553 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
554 })
555 ])
556 , "A+$1 A/B+$1 A/B/C+$1 A/B/C/D+$1 = A+$4 A/B+$3 A/B/C+$2 A/B/C/D+$1" ~:
557 Calc.Balance.expand
558 (Lib.TreeMap.from_List const
559 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
560 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
561 , ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ])
562 , ("A":|["B", "C", "D"], Amount.from_List [ Amount.usd $ 1 ])
563 ])
564 ~?=
565 (Lib.TreeMap.from_List const
566 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
567 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 4 ]
568 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
569 })
570 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
571 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 3 ]
572 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
573 })
574 , ("A":|["B", "C"], Calc.Balance.Account_Sum_Expanded
575 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 2 ]
576 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
577 })
578 , ("A":|["B", "C", "D"], Calc.Balance.Account_Sum_Expanded
579 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
580 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
581 })
582 ])
583 , "A+$1 A/B+$1 A/BB+$1 AA/B+$1 = A+$3 A/B+$1 A/BB+$1 AA+$1 AA/B+$1" ~:
584 Calc.Balance.expand
585 (Lib.TreeMap.from_List const
586 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
587 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
588 , ("A":|["BB"], Amount.from_List [ Amount.usd $ 1 ])
589 , ("AA":|["B"], Amount.from_List [ Amount.usd $ 1 ])
590 ])
591 ~?=
592 (Lib.TreeMap.from_List const
593 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
594 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 3 ]
595 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
596 })
597 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
598 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
599 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
600 })
601 , ("A":|["BB"], Calc.Balance.Account_Sum_Expanded
602 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
603 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
604 })
605 , ("AA":|[], Calc.Balance.Account_Sum_Expanded
606 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
607 , Calc.Balance.exclusive = Amount.from_List []
608 })
609 , ("AA":|["B"], Calc.Balance.Account_Sum_Expanded
610 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
611 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
612 })
613 ])
614 ]
615 , "is_equilibrable" ~: TestList
616 [ "nil" ~: TestCase $
617 (@=?) True $
618 Calc.Balance.is_equilibrable $
619 Calc.Balance.equilibre $
620 Calc.Balance.nil
621 , "{A+$0, $+0}" ~: TestCase $
622 (@=?) True $
623 Calc.Balance.is_equilibrable $
624 Calc.Balance.equilibre $
625 Calc.Balance.Balance
626 { Calc.Balance.by_account =
627 Lib.TreeMap.from_List const
628 [ ("A":|[], Amount.from_List [ Amount.usd $ 0 ])
629 ]
630 , Calc.Balance.by_unit =
631 Data.Map.fromList $
632 Data.List.map Calc.Balance.assoc_unit_sum $
633 [ Calc.Balance.Unit_Sum
634 { Calc.Balance.amount = Amount.usd $ 0
635 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
636 ["A":|[]]
637 }
638 ]
639 }
640 , "{A+$1, $+1}" ~: TestCase $
641 (@=?) False $
642 Calc.Balance.is_equilibrable $
643 Calc.Balance.equilibre $
644 Calc.Balance.Balance
645 { Calc.Balance.by_account =
646 Lib.TreeMap.from_List const
647 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
648 ]
649 , Calc.Balance.by_unit =
650 Data.Map.fromList $
651 Data.List.map Calc.Balance.assoc_unit_sum $
652 [ Calc.Balance.Unit_Sum
653 { Calc.Balance.amount = Amount.usd $ 1
654 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
655 ["A":|[]]
656 }
657 ]
658 }
659 , "{A+$0+€0, $0 €+0}" ~: TestCase $
660 (@=?) True $
661 Calc.Balance.is_equilibrable $
662 Calc.Balance.equilibre $
663 Calc.Balance.Balance
664 { Calc.Balance.by_account =
665 Lib.TreeMap.from_List const
666 [ ("A":|[], Amount.from_List [ Amount.usd $ 0, Amount.eur $ 0 ])
667 ]
668 , Calc.Balance.by_unit =
669 Data.Map.fromList $
670 Data.List.map Calc.Balance.assoc_unit_sum $
671 [ Calc.Balance.Unit_Sum
672 { Calc.Balance.amount = Amount.usd $ 0
673 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
674 ["A":|[]]
675 }
676 , Calc.Balance.Unit_Sum
677 { Calc.Balance.amount = Amount.eur $ 0
678 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
679 ["A":|[]]
680 }
681 ]
682 }
683 , "{A+$1, B-$1, $+0}" ~: TestCase $
684 (@=?) True $
685 Calc.Balance.is_equilibrable $
686 Calc.Balance.equilibre $
687 Calc.Balance.Balance
688 { Calc.Balance.by_account =
689 Lib.TreeMap.from_List const
690 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
691 , ("B":|[], Amount.from_List [ Amount.usd $ -1 ])
692 ]
693 , Calc.Balance.by_unit =
694 Data.Map.fromList $
695 Data.List.map Calc.Balance.assoc_unit_sum $
696 [ Calc.Balance.Unit_Sum
697 { Calc.Balance.amount = Amount.usd $ 0
698 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
699 ["A":|[], "B":|[]]
700 }
701 ]
702 }
703 , "{A+$1 B, $+1}" ~: TestCase $
704 (@=?) True $
705 Calc.Balance.is_equilibrable $
706 Calc.Balance.equilibre $
707 Calc.Balance.Balance
708 { Calc.Balance.by_account =
709 Lib.TreeMap.from_List const
710 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
711 , ("B":|[], Amount.from_List [])
712 ]
713 , Calc.Balance.by_unit =
714 Data.Map.fromList $
715 Data.List.map Calc.Balance.assoc_unit_sum $
716 [ Calc.Balance.Unit_Sum
717 { Calc.Balance.amount = Amount.usd $ 1
718 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
719 ["A":|[]]
720 }
721 ]
722 }
723 , "{A+$1 B+€1, $+1 €+1}" ~: TestCase $
724 (@=?) True $
725 Calc.Balance.is_equilibrable $
726 Calc.Balance.equilibre $
727 Calc.Balance.Balance
728 { Calc.Balance.by_account =
729 Lib.TreeMap.from_List const
730 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
731 , ("B":|[], Amount.from_List [ Amount.eur $ 1 ])
732 ]
733 , Calc.Balance.by_unit =
734 Data.Map.fromList $
735 Data.List.map Calc.Balance.assoc_unit_sum $
736 [ Calc.Balance.Unit_Sum
737 { Calc.Balance.amount = Amount.usd $ 1
738 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
739 ["A":|[]]
740 }
741 , Calc.Balance.Unit_Sum
742 { Calc.Balance.amount = Amount.eur $ 1
743 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
744 ["B":|[]]
745 }
746 ]
747 }
748 , "{A+$1 B-$1+€1, $+0 €+1}" ~: TestCase $
749 (@=?) True $
750 Calc.Balance.is_equilibrable $
751 Calc.Balance.equilibre $
752 Calc.Balance.Balance
753 { Calc.Balance.by_account =
754 Lib.TreeMap.from_List const
755 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
756 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ 1 ])
757 ]
758 , Calc.Balance.by_unit =
759 Data.Map.fromList $
760 Data.List.map Calc.Balance.assoc_unit_sum $
761 [ Calc.Balance.Unit_Sum
762 { Calc.Balance.amount = Amount.usd $ 0
763 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
764 ["A":|[], "B":|[]]
765 }
766 , Calc.Balance.Unit_Sum
767 { Calc.Balance.amount = Amount.eur $ 1
768 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
769 ["B":|[]]
770 }
771 ]
772 }
773 , "{A+$1+€2+£3 B-$1-€2-£3, $+0 €+0 £+0}" ~: TestCase $
774 (@=?) True $
775 Calc.Balance.is_equilibrable $
776 Calc.Balance.equilibre $
777 Calc.Balance.Balance
778 { Calc.Balance.by_account =
779 Lib.TreeMap.from_List const
780 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ])
781 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ])
782 ]
783 , Calc.Balance.by_unit =
784 Data.Map.fromList $
785 Data.List.map Calc.Balance.assoc_unit_sum $
786 [ Calc.Balance.Unit_Sum
787 { Calc.Balance.amount = Amount.usd $ 0
788 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
789 ["A":|[], "B":|[]]
790 }
791 , Calc.Balance.Unit_Sum
792 { Calc.Balance.amount = Amount.eur $ 0
793 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
794 ["A":|[], "B":|[]]
795 }
796 , Calc.Balance.Unit_Sum
797 { Calc.Balance.amount = Amount.gbp $ 0
798 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
799 ["A":|[], "B":|[]]
800 }
801 ]
802 }
803 ]
804 ]
805 ]
806 , "Format" ~: TestList
807 [ "Ledger" ~: TestList
808 [ "Read" ~: TestList
809 [ "account_name" ~: TestList
810 [ "\"\"" ~:
811 (Data.Either.rights $
812 [P.runParser
813 (Format.Ledger.Read.account_name <* P.eof)
814 () "" (""::Text)])
815 ~?=
816 []
817 , "\"A\"" ~:
818 (Data.Either.rights $
819 [P.runParser
820 (Format.Ledger.Read.account_name <* P.eof)
821 () "" ("A"::Text)])
822 ~?=
823 ["A"]
824 , "\"AA\"" ~:
825 (Data.Either.rights $
826 [P.runParser
827 (Format.Ledger.Read.account_name <* P.eof)
828 () "" ("AA"::Text)])
829 ~?=
830 ["AA"]
831 , "\" \"" ~:
832 (Data.Either.rights $
833 [P.runParser
834 (Format.Ledger.Read.account_name <* P.eof)
835 () "" (" "::Text)])
836 ~?=
837 []
838 , "\":\"" ~:
839 (Data.Either.rights $
840 [P.runParser
841 (Format.Ledger.Read.account_name <* P.eof)
842 () "" (":"::Text)])
843 ~?=
844 []
845 , "\"A:\"" ~:
846 (Data.Either.rights $
847 [P.runParser
848 (Format.Ledger.Read.account_name <* P.eof)
849 () "" ("A:"::Text)])
850 ~?=
851 []
852 , "\":A\"" ~:
853 (Data.Either.rights $
854 [P.runParser
855 (Format.Ledger.Read.account_name <* P.eof)
856 () "" (":A"::Text)])
857 ~?=
858 []
859 , "\"A \"" ~:
860 (Data.Either.rights $
861 [P.runParser
862 (Format.Ledger.Read.account_name <* P.eof)
863 () "" ("A "::Text)])
864 ~?=
865 []
866 , "\"A \"" ~:
867 (Data.Either.rights $
868 [P.runParser
869 (Format.Ledger.Read.account_name)
870 () "" ("A "::Text)])
871 ~?=
872 ["A"]
873 , "\"A A\"" ~:
874 (Data.Either.rights $
875 [P.runParser
876 (Format.Ledger.Read.account_name <* P.eof)
877 () "" ("A A"::Text)])
878 ~?=
879 ["A A"]
880 , "\"A \"" ~:
881 (Data.Either.rights $
882 [P.runParser
883 (Format.Ledger.Read.account_name <* P.eof)
884 () "" ("A "::Text)])
885 ~?=
886 []
887 , "\"A \\n\"" ~:
888 (Data.Either.rights $
889 [P.runParser
890 (Format.Ledger.Read.account_name <* P.eof)
891 () "" ("A \n"::Text)])
892 ~?=
893 []
894 , "\"(A)A\"" ~:
895 (Data.Either.rights $
896 [P.runParser
897 (Format.Ledger.Read.account_name <* P.eof)
898 () "" ("(A)A"::Text)])
899 ~?=
900 ["(A)A"]
901 , "\"( )A\"" ~:
902 (Data.Either.rights $
903 [P.runParser
904 (Format.Ledger.Read.account_name <* P.eof)
905 () "" ("( )A"::Text)])
906 ~?=
907 ["( )A"]
908 , "\"(A) A\"" ~:
909 (Data.Either.rights $
910 [P.runParser
911 (Format.Ledger.Read.account_name <* P.eof)
912 () "" ("(A) A"::Text)])
913 ~?=
914 ["(A) A"]
915 , "\"[ ]A\"" ~:
916 (Data.Either.rights $
917 [P.runParser
918 (Format.Ledger.Read.account_name <* P.eof)
919 () "" ("[ ]A"::Text)])
920 ~?=
921 ["[ ]A"]
922 , "\"(A) \"" ~:
923 (Data.Either.rights $
924 [P.runParser
925 (Format.Ledger.Read.account_name <* P.eof)
926 () "" ("(A) "::Text)])
927 ~?=
928 []
929 , "\"(A)\"" ~:
930 (Data.Either.rights $
931 [P.runParser
932 (Format.Ledger.Read.account_name <* P.eof)
933 () "" ("(A)"::Text)])
934 ~?=
935 ["(A)"]
936 , "\"A(A)\"" ~:
937 (Data.Either.rights $
938 [P.runParser
939 (Format.Ledger.Read.account_name <* P.eof)
940 () "" ("A(A)"::Text)])
941 ~?=
942 [("A(A)"::Text)]
943 , "\"[A]A\"" ~:
944 (Data.Either.rights $
945 [P.runParser
946 (Format.Ledger.Read.account_name <* P.eof)
947 () "" ("[A]A"::Text)])
948 ~?=
949 ["[A]A"]
950 , "\"[A] A\"" ~:
951 (Data.Either.rights $
952 [P.runParser
953 (Format.Ledger.Read.account_name <* P.eof)
954 () "" ("[A] A"::Text)])
955 ~?=
956 ["[A] A"]
957 , "\"[A] \"" ~:
958 (Data.Either.rights $
959 [P.runParser
960 (Format.Ledger.Read.account_name <* P.eof)
961 () "" ("[A] "::Text)])
962 ~?=
963 []
964 , "\"[A]\"" ~:
965 (Data.Either.rights $
966 [P.runParser
967 (Format.Ledger.Read.account_name <* P.eof)
968 () "" ("[A]"::Text)])
969 ~?=
970 ["[A]"]
971 ]
972 , "account" ~: TestList
973 [ "\"\"" ~:
974 (Data.Either.rights $
975 [P.runParser
976 (Format.Ledger.Read.account <* P.eof)
977 () "" (""::Text)])
978 ~?=
979 []
980 , "\"A\"" ~:
981 (Data.Either.rights $
982 [P.runParser
983 (Format.Ledger.Read.account <* P.eof)
984 () "" ("A"::Text)])
985 ~?=
986 ["A":|[]]
987 , "\"A:\"" ~:
988 (Data.Either.rights $
989 [P.runParser
990 (Format.Ledger.Read.account <* P.eof)
991 () "" ("A:"::Text)])
992 ~?=
993 []
994 , "\":A\"" ~:
995 (Data.Either.rights $
996 [P.runParser
997 (Format.Ledger.Read.account <* P.eof)
998 () "" (":A"::Text)])
999 ~?=
1000 []
1001 , "\"A \"" ~:
1002 (Data.Either.rights $
1003 [P.runParser
1004 (Format.Ledger.Read.account <* P.eof)
1005 () "" ("A "::Text)])
1006 ~?=
1007 []
1008 , "\" A\"" ~:
1009 (Data.Either.rights $
1010 [P.runParser
1011 (Format.Ledger.Read.account <* P.eof)
1012 () "" (" A"::Text)])
1013 ~?=
1014 []
1015 , "\"A:B\"" ~:
1016 (Data.Either.rights $
1017 [P.runParser
1018 (Format.Ledger.Read.account <* P.eof)
1019 () "" ("A:B"::Text)])
1020 ~?=
1021 ["A":|["B"]]
1022 , "\"A:B:C\"" ~:
1023 (Data.Either.rights $
1024 [P.runParser
1025 (Format.Ledger.Read.account <* P.eof)
1026 () "" ("A:B:C"::Text)])
1027 ~?=
1028 ["A":|["B", "C"]]
1029 , "\"Aa:Bbb:Cccc\"" ~:
1030 (Data.Either.rights $
1031 [P.runParser
1032 (Format.Ledger.Read.account <* P.eof)
1033 () "" ("Aa:Bbb:Cccc"::Text)])
1034 ~?=
1035 ["Aa":|["Bbb", "Cccc"]]
1036 , "\"A a : B b b : C c c c\"" ~:
1037 (Data.Either.rights $
1038 [P.runParser
1039 (Format.Ledger.Read.account <* P.eof)
1040 () "" ("A a : B b b : C c c c"::Text)])
1041 ~?=
1042 ["A a ":|[" B b b ", " C c c c"]]
1043 , "\"A: :C\"" ~:
1044 (Data.Either.rights $
1045 [P.runParser
1046 (Format.Ledger.Read.account <* P.eof)
1047 () "" ("A: :C"::Text)])
1048 ~?=
1049 ["A":|[" ", "C"]]
1050 , "\"A::C\"" ~:
1051 (Data.Either.rights $
1052 [P.runParser
1053 (Format.Ledger.Read.account <* P.eof)
1054 () "" ("A::C"::Text)])
1055 ~?=
1056 []
1057 , "\"A:B:(C)\"" ~:
1058 (Data.Either.rights $
1059 [P.runParser
1060 (Format.Ledger.Read.account <* P.eof)
1061 () "" ("A:B:(C)"::Text)])
1062 ~?=
1063 ["A":|["B", "(C)"]]
1064 ]
1065 , "posting_type" ~: TestList
1066 [ "A" ~:
1067 Format.Ledger.Read.posting_type
1068 ("A":|[])
1069 ~?=
1070 (Posting.Type_Regular, "A":|[])
1071 , "(" ~:
1072 Format.Ledger.Read.posting_type
1073 ("(":|[])
1074 ~?=
1075 (Posting.Type_Regular, "(":|[])
1076 , ")" ~:
1077 Format.Ledger.Read.posting_type
1078 (")":|[])
1079 ~?=
1080 (Posting.Type_Regular, ")":|[])
1081 , "()" ~:
1082 Format.Ledger.Read.posting_type
1083 ("()":|[])
1084 ~?=
1085 (Posting.Type_Regular, "()":|[])
1086 , "( )" ~:
1087 Format.Ledger.Read.posting_type
1088 ("( )":|[])
1089 ~?=
1090 (Posting.Type_Regular, "( )":|[])
1091 , "(A)" ~:
1092 Format.Ledger.Read.posting_type
1093 ("(A)":|[])
1094 ~?=
1095 (Posting.Type_Virtual, "A":|[])
1096 , "(A:B:C)" ~:
1097 Format.Ledger.Read.posting_type
1098 ("(A":|["B", "C)"])
1099 ~?=
1100 (Posting.Type_Virtual, "A":|["B", "C"])
1101 , "A:B:C" ~:
1102 Format.Ledger.Read.posting_type
1103 ("A":|["B", "C"])
1104 ~?=
1105 (Posting.Type_Regular, "A":|["B", "C"])
1106 , "(A):B:C" ~:
1107 Format.Ledger.Read.posting_type
1108 ("(A)":|["B", "C"])
1109 ~?=
1110 (Posting.Type_Regular, "(A)":|["B", "C"])
1111 , "A:(B):C" ~:
1112 Format.Ledger.Read.posting_type
1113 ("A":|["(B)", "C"])
1114 ~?=
1115 (Posting.Type_Regular, "A":|["(B)", "C"])
1116 , "A:B:(C)" ~:
1117 Format.Ledger.Read.posting_type
1118 ("A":|["B", "(C)"])
1119 ~?=
1120 (Posting.Type_Regular, "A":|["B", "(C)"])
1121 , "[" ~:
1122 Format.Ledger.Read.posting_type
1123 ("[":|[])
1124 ~?=
1125 (Posting.Type_Regular, "[":|[])
1126 , "]" ~:
1127 Format.Ledger.Read.posting_type
1128 ("]":|[])
1129 ~?=
1130 (Posting.Type_Regular, "]":|[])
1131 , "[]" ~:
1132 Format.Ledger.Read.posting_type
1133 ("[]":|[])
1134 ~?=
1135 (Posting.Type_Regular, "[]":|[])
1136 , "[ ]" ~:
1137 Format.Ledger.Read.posting_type
1138 ("[ ]":|[])
1139 ~?=
1140 (Posting.Type_Regular, "[ ]":|[])
1141 , "[A]" ~:
1142 Format.Ledger.Read.posting_type
1143 ("[A]":|[])
1144 ~?=
1145 (Posting.Type_Virtual_Balanced, "A":|[])
1146 , "[A:B:C]" ~:
1147 Format.Ledger.Read.posting_type
1148 ("[A":|["B", "C]"])
1149 ~?=
1150 (Posting.Type_Virtual_Balanced, "A":|["B", "C"])
1151 , "A:B:C" ~:
1152 Format.Ledger.Read.posting_type
1153 ("A":|["B", "C"])
1154 ~?=
1155 (Posting.Type_Regular, "A":|["B", "C"])
1156 , "[A]:B:C" ~:
1157 Format.Ledger.Read.posting_type
1158 ("[A]":|["B", "C"])
1159 ~?=
1160 (Posting.Type_Regular, "[A]":|["B", "C"])
1161 , "A:[B]:C" ~:
1162 Format.Ledger.Read.posting_type
1163 ("A":|["[B]", "C"])
1164 ~?=
1165 (Posting.Type_Regular, "A":|["[B]", "C"])
1166 , "A:B:[C]" ~:
1167 Format.Ledger.Read.posting_type
1168 ("A":|["B", "[C]"])
1169 ~?=
1170 (Posting.Type_Regular, "A":|["B", "[C]"])
1171 ]
1172 , "amount" ~: TestList
1173 [ "\"\" = Left" ~:
1174 (Data.Either.rights $
1175 [P.runParser
1176 (Format.Ledger.Read.amount <* P.eof)
1177 () "" (""::Text)])
1178 ~?=
1179 []
1180 , "\"0\" = Right 0" ~:
1181 (Data.Either.rights $
1182 [P.runParser
1183 (Format.Ledger.Read.amount <* P.eof)
1184 () "" ("0"::Text)])
1185 ~?=
1186 [Amount.nil
1187 { Amount.quantity = Decimal 0 0
1188 }]
1189 , "\"00\" = Right 0" ~:
1190 (Data.Either.rights $
1191 [P.runParser
1192 (Format.Ledger.Read.amount <* P.eof)
1193 () "" ("00"::Text)])
1194 ~?=
1195 [Amount.nil
1196 { Amount.quantity = Decimal 0 0
1197 }]
1198 , "\"0.\" = Right 0." ~:
1199 (Data.Either.rights $
1200 [P.runParser
1201 (Format.Ledger.Read.amount <* P.eof)
1202 () "" ("0."::Text)])
1203 ~?=
1204 [Amount.nil
1205 { Amount.quantity = Decimal 0 0
1206 , Amount.style =
1207 Amount.Style.nil
1208 { Amount.Style.fractioning = Just '.'
1209 }
1210 }]
1211 , "\".0\" = Right 0.0" ~:
1212 (Data.Either.rights $
1213 [P.runParser
1214 (Format.Ledger.Read.amount <* P.eof)
1215 () "" (".0"::Text)])
1216 ~?=
1217 [Amount.nil
1218 { Amount.quantity = Decimal 0 0
1219 , Amount.style =
1220 Amount.Style.nil
1221 { Amount.Style.fractioning = Just '.'
1222 , Amount.Style.precision = 1
1223 }
1224 }]
1225 , "\"0,\" = Right 0," ~:
1226 (Data.Either.rights $
1227 [P.runParser
1228 (Format.Ledger.Read.amount <* P.eof)
1229 () "" ("0,"::Text)])
1230 ~?=
1231 [Amount.nil
1232 { Amount.quantity = Decimal 0 0
1233 , Amount.style =
1234 Amount.Style.nil
1235 { Amount.Style.fractioning = Just ','
1236 }
1237 }]
1238 , "\",0\" = Right 0,0" ~:
1239 (Data.Either.rights $
1240 [P.runParser
1241 (Format.Ledger.Read.amount <* P.eof)
1242 () "" (",0"::Text)])
1243 ~?=
1244 [Amount.nil
1245 { Amount.quantity = Decimal 0 0
1246 , Amount.style =
1247 Amount.Style.nil
1248 { Amount.Style.fractioning = Just ','
1249 , Amount.Style.precision = 1
1250 }
1251 }]
1252 , "\"0_\" = Left" ~:
1253 (Data.Either.rights $
1254 [P.runParser
1255 (Format.Ledger.Read.amount <* P.eof)
1256 () "" ("0_"::Text)])
1257 ~?=
1258 []
1259 , "\"_0\" = Left" ~:
1260 (Data.Either.rights $
1261 [P.runParser
1262 (Format.Ledger.Read.amount <* P.eof)
1263 () "" ("_0"::Text)])
1264 ~?=
1265 []
1266 , "\"0.0\" = Right 0.0" ~:
1267 (Data.Either.rights $
1268 [P.runParser
1269 (Format.Ledger.Read.amount <* P.eof)
1270 () "" ("0.0"::Text)])
1271 ~?=
1272 [Amount.nil
1273 { Amount.quantity = Decimal 0 0
1274 , Amount.style =
1275 Amount.Style.nil
1276 { Amount.Style.fractioning = Just '.'
1277 , Amount.Style.precision = 1
1278 }
1279 }]
1280 , "\"00.00\" = Right 0.00" ~:
1281 (Data.Either.rights $
1282 [P.runParser
1283 (Format.Ledger.Read.amount <* P.eof)
1284 () "" ("00.00"::Text)])
1285 ~?=
1286 [Amount.nil
1287 { Amount.quantity = Decimal 0 0
1288 , Amount.style =
1289 Amount.Style.nil
1290 { Amount.Style.fractioning = Just '.'
1291 , Amount.Style.precision = 2
1292 }
1293 }]
1294 , "\"0,0\" = Right 0,0" ~:
1295 (Data.Either.rights $
1296 [P.runParser
1297 (Format.Ledger.Read.amount <* P.eof)
1298 () "" ("0,0"::Text)])
1299 ~?=
1300 [Amount.nil
1301 { Amount.quantity = Decimal 0 0
1302 , Amount.style =
1303 Amount.Style.nil
1304 { Amount.Style.fractioning = Just ','
1305 , Amount.Style.precision = 1
1306 }
1307 }]
1308 , "\"00,00\" = Right 0,00" ~:
1309 (Data.Either.rights $
1310 [P.runParser
1311 (Format.Ledger.Read.amount <* P.eof)
1312 () "" ("00,00"::Text)])
1313 ~?=
1314 [Amount.nil
1315 { Amount.quantity = Decimal 0 0
1316 , Amount.style =
1317 Amount.Style.nil
1318 { Amount.Style.fractioning = Just ','
1319 , Amount.Style.precision = 2
1320 }
1321 }]
1322 , "\"0_0\" = Right 0" ~:
1323 (Data.Either.rights $
1324 [P.runParser
1325 (Format.Ledger.Read.amount <* P.eof)
1326 () "" ("0_0"::Text)])
1327 ~?=
1328 [Amount.nil
1329 { Amount.quantity = Decimal 0 0
1330 , Amount.style =
1331 Amount.Style.nil
1332 { Amount.Style.fractioning = Nothing
1333 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [1]
1334 , Amount.Style.precision = 0
1335 }
1336 }]
1337 , "\"00_00\" = Right 0" ~:
1338 (Data.Either.rights $
1339 [P.runParser
1340 (Format.Ledger.Read.amount <* P.eof)
1341 () "" ("00_00"::Text)])
1342 ~?=
1343 [Amount.nil
1344 { Amount.quantity = Decimal 0 0
1345 , Amount.style =
1346 Amount.Style.nil
1347 { Amount.Style.fractioning = Nothing
1348 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [2]
1349 , Amount.Style.precision = 0
1350 }
1351 }]
1352 , "\"0,000.00\" = Right 0,000.00" ~:
1353 (Data.Either.rights $
1354 [P.runParser
1355 (Format.Ledger.Read.amount <* P.eof)
1356 () "" ("0,000.00"::Text)])
1357 ~?=
1358 [Amount.nil
1359 { Amount.quantity = Decimal 0 0
1360 , Amount.style =
1361 Amount.Style.nil
1362 { Amount.Style.fractioning = Just '.'
1363 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
1364 , Amount.Style.precision = 2
1365 }
1366 }]
1367 , "\"0.000,00\" = Right 0.000,00" ~:
1368 (Data.Either.rights $
1369 [P.runParser
1370 (Format.Ledger.Read.amount)
1371 () "" ("0.000,00"::Text)])
1372 ~?=
1373 [Amount.nil
1374 { Amount.quantity = Decimal 0 0
1375 , Amount.style =
1376 Amount.Style.nil
1377 { Amount.Style.fractioning = Just ','
1378 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
1379 , Amount.Style.precision = 2
1380 }
1381 }]
1382 , "\"1,000.00\" = Right 1,000.00" ~:
1383 (Data.Either.rights $
1384 [P.runParser
1385 (Format.Ledger.Read.amount <* P.eof)
1386 () "" ("1,000.00"::Text)])
1387 ~?=
1388 [Amount.nil
1389 { Amount.quantity = Decimal 0 1000
1390 , Amount.style =
1391 Amount.Style.nil
1392 { Amount.Style.fractioning = Just '.'
1393 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
1394 , Amount.Style.precision = 2
1395 }
1396 }]
1397 , "\"1.000,00\" = Right 1.000,00" ~:
1398 (Data.Either.rights $
1399 [P.runParser
1400 (Format.Ledger.Read.amount)
1401 () "" ("1.000,00"::Text)])
1402 ~?=
1403 [Amount.nil
1404 { Amount.quantity = Decimal 0 1000
1405 , Amount.style =
1406 Amount.Style.nil
1407 { Amount.Style.fractioning = Just ','
1408 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
1409 , Amount.Style.precision = 2
1410 }
1411 }]
1412 , "\"1,000.00.\" = Left" ~:
1413 (Data.Either.rights $
1414 [P.runParser
1415 (Format.Ledger.Read.amount)
1416 () "" ("1,000.00."::Text)])
1417 ~?=
1418 []
1419 , "\"1.000,00,\" = Left" ~:
1420 (Data.Either.rights $
1421 [P.runParser
1422 (Format.Ledger.Read.amount)
1423 () "" ("1.000,00,"::Text)])
1424 ~?=
1425 []
1426 , "\"1,000.00_\" = Left" ~:
1427 (Data.Either.rights $
1428 [P.runParser
1429 (Format.Ledger.Read.amount)
1430 () "" ("1,000.00_"::Text)])
1431 ~?=
1432 []
1433 , "\"12\" = Right 12" ~:
1434 (Data.Either.rights $
1435 [P.runParser
1436 (Format.Ledger.Read.amount <* P.eof)
1437 () "" ("123"::Text)])
1438 ~?=
1439 [Amount.nil
1440 { Amount.quantity = Decimal 0 123
1441 }]
1442 , "\"1.2\" = Right 1.2" ~:
1443 (Data.Either.rights $
1444 [P.runParser
1445 (Format.Ledger.Read.amount <* P.eof)
1446 () "" ("1.2"::Text)])
1447 ~?=
1448 [Amount.nil
1449 { Amount.quantity = Decimal 1 12
1450 , Amount.style =
1451 Amount.Style.nil
1452 { Amount.Style.fractioning = Just '.'
1453 , Amount.Style.precision = 1
1454 }
1455 }]
1456 , "\"1,2\" = Right 1,2" ~:
1457 (Data.Either.rights $
1458 [P.runParser
1459 (Format.Ledger.Read.amount <* P.eof)
1460 () "" ("1,2"::Text)])
1461 ~?=
1462 [Amount.nil
1463 { Amount.quantity = Decimal 1 12
1464 , Amount.style =
1465 Amount.Style.nil
1466 { Amount.Style.fractioning = Just ','
1467 , Amount.Style.precision = 1
1468 }
1469 }]
1470 , "\"12.23\" = Right 12.23" ~:
1471 (Data.Either.rights $
1472 [P.runParser
1473 (Format.Ledger.Read.amount <* P.eof)
1474 () "" ("12.34"::Text)])
1475 ~?=
1476 [Amount.nil
1477 { Amount.quantity = Decimal 2 1234
1478 , Amount.style =
1479 Amount.Style.nil
1480 { Amount.Style.fractioning = Just '.'
1481 , Amount.Style.precision = 2
1482 }
1483 }]
1484 , "\"12,23\" = Right 12,23" ~:
1485 (Data.Either.rights $
1486 [P.runParser
1487 (Format.Ledger.Read.amount <* P.eof)
1488 () "" ("12,34"::Text)])
1489 ~?=
1490 [Amount.nil
1491 { Amount.quantity = Decimal 2 1234
1492 , Amount.style =
1493 Amount.Style.nil
1494 { Amount.Style.fractioning = Just ','
1495 , Amount.Style.precision = 2
1496 }
1497 }]
1498 , "\"1_2\" = Right 1_2" ~:
1499 (Data.Either.rights $
1500 [P.runParser
1501 (Format.Ledger.Read.amount <* P.eof)
1502 () "" ("1_2"::Text)])
1503 ~?=
1504 [Amount.nil
1505 { Amount.quantity = Decimal 0 12
1506 , Amount.style =
1507 Amount.Style.nil
1508 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [1]
1509 , Amount.Style.precision = 0
1510 }
1511 }]
1512 , "\"1_23\" = Right 1_23" ~:
1513 (Data.Either.rights $
1514 [P.runParser
1515 (Format.Ledger.Read.amount <* P.eof)
1516 () "" ("1_23"::Text)])
1517 ~?=
1518 [Amount.nil
1519 { Amount.quantity = Decimal 0 123
1520 , Amount.style =
1521 Amount.Style.nil
1522 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [2]
1523 , Amount.Style.precision = 0
1524 }
1525 }]
1526 , "\"1_23_456\" = Right 1_23_456" ~:
1527 (Data.Either.rights $
1528 [P.runParser
1529 (Format.Ledger.Read.amount <* P.eof)
1530 () "" ("1_23_456"::Text)])
1531 ~?=
1532 [Amount.nil
1533 { Amount.quantity = Decimal 0 123456
1534 , Amount.style =
1535 Amount.Style.nil
1536 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [3, 2]
1537 , Amount.Style.precision = 0
1538 }
1539 }]
1540 , "\"1_23_456.7890_12345_678901\" = Right 1_23_456.7890_12345_678901" ~:
1541 (Data.Either.rights $
1542 [P.runParser
1543 (Format.Ledger.Read.amount <* P.eof)
1544 () "" ("1_23_456.7890_12345_678901"::Text)])
1545 ~?=
1546 [Amount.nil
1547 { Amount.quantity = Decimal 15 123456789012345678901
1548 , Amount.style =
1549 Amount.Style.nil
1550 { Amount.Style.fractioning = Just '.'
1551 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [3, 2]
1552 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping '_' [4, 5, 6]
1553 , Amount.Style.precision = 15
1554 }
1555 }]
1556 , "\"123456_78901_2345.678_90_1\" = Right 123456_78901_2345.678_90_1" ~:
1557 (Data.Either.rights $
1558 [P.runParser
1559 (Format.Ledger.Read.amount <* P.eof)
1560 () "" ("123456_78901_2345.678_90_1"::Text)])
1561 ~?=
1562 [Amount.nil
1563 { Amount.quantity = Decimal 6 123456789012345678901
1564 , Amount.style =
1565 Amount.Style.nil
1566 { Amount.Style.fractioning = Just '.'
1567 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [4, 5, 6]
1568 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping '_' [3, 2]
1569 , Amount.Style.precision = 6
1570 }
1571 }]
1572 , "\"$1\" = Right $1" ~:
1573 (Data.Either.rights $
1574 [P.runParser
1575 (Format.Ledger.Read.amount <* P.eof)
1576 () "" ("$1"::Text)])
1577 ~?=
1578 [Amount.nil
1579 { Amount.quantity = Decimal 0 1
1580 , Amount.style =
1581 Amount.Style.nil
1582 { Amount.Style.fractioning = Nothing
1583 , Amount.Style.grouping_integral = Nothing
1584 , Amount.Style.grouping_fractional = Nothing
1585 , Amount.Style.precision = 0
1586 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1587 , Amount.Style.unit_spaced = Just False
1588 }
1589 , Amount.unit = "$"
1590 }]
1591 , "\"1$\" = Right 1$" ~:
1592 (Data.Either.rights $
1593 [P.runParser
1594 (Format.Ledger.Read.amount <* P.eof)
1595 () "" ("1$"::Text)])
1596 ~?=
1597 [Amount.nil
1598 { Amount.quantity = Decimal 0 1
1599 , Amount.style =
1600 Amount.Style.nil
1601 { Amount.Style.fractioning = Nothing
1602 , Amount.Style.grouping_integral = Nothing
1603 , Amount.Style.grouping_fractional = Nothing
1604 , Amount.Style.precision = 0
1605 , Amount.Style.unit_side = Just Amount.Style.Side_Right
1606 , Amount.Style.unit_spaced = Just False
1607 }
1608 , Amount.unit = "$"
1609 }]
1610 , "\"$ 1\" = Right $ 1" ~:
1611 (Data.Either.rights $
1612 [P.runParser
1613 (Format.Ledger.Read.amount <* P.eof)
1614 () "" ("$ 1"::Text)])
1615 ~?=
1616 [Amount.nil
1617 { Amount.quantity = Decimal 0 1
1618 , Amount.style =
1619 Amount.Style.nil
1620 { Amount.Style.fractioning = Nothing
1621 , Amount.Style.grouping_integral = Nothing
1622 , Amount.Style.grouping_fractional = Nothing
1623 , Amount.Style.precision = 0
1624 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1625 , Amount.Style.unit_spaced = Just True
1626 }
1627 , Amount.unit = "$"
1628 }]
1629 , "\"1 $\" = Right 1 $" ~:
1630 (Data.Either.rights $
1631 [P.runParser
1632 (Format.Ledger.Read.amount <* P.eof)
1633 () "" ("1 $"::Text)])
1634 ~?=
1635 [Amount.nil
1636 { Amount.quantity = Decimal 0 1
1637 , Amount.style =
1638 Amount.Style.nil
1639 { Amount.Style.fractioning = Nothing
1640 , Amount.Style.grouping_integral = Nothing
1641 , Amount.Style.grouping_fractional = Nothing
1642 , Amount.Style.precision = 0
1643 , Amount.Style.unit_side = Just Amount.Style.Side_Right
1644 , Amount.Style.unit_spaced = Just True
1645 }
1646 , Amount.unit = "$"
1647 }]
1648 , "\"-$1\" = Right $-1" ~:
1649 (Data.Either.rights $
1650 [P.runParser
1651 (Format.Ledger.Read.amount <* P.eof)
1652 () "" ("-$1"::Text)])
1653 ~?=
1654 [Amount.nil
1655 { Amount.quantity = Decimal 0 (-1)
1656 , Amount.style =
1657 Amount.Style.nil
1658 { Amount.Style.fractioning = Nothing
1659 , Amount.Style.grouping_integral = Nothing
1660 , Amount.Style.grouping_fractional = Nothing
1661 , Amount.Style.precision = 0
1662 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1663 , Amount.Style.unit_spaced = Just False
1664 }
1665 , Amount.unit = "$"
1666 }]
1667 , "\"\\\"4 2\\\"1\" = Right \\\"4 2\\\"1" ~:
1668 (Data.Either.rights $
1669 [P.runParser
1670 (Format.Ledger.Read.amount <* P.eof)
1671 () "" ("\"4 2\"1"::Text)])
1672 ~?=
1673 [Amount.nil
1674 { Amount.quantity = Decimal 0 1
1675 , Amount.style =
1676 Amount.Style.nil
1677 { Amount.Style.fractioning = Nothing
1678 , Amount.Style.grouping_integral = Nothing
1679 , Amount.Style.grouping_fractional = Nothing
1680 , Amount.Style.precision = 0
1681 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1682 , Amount.Style.unit_spaced = Just False
1683 }
1684 , Amount.unit = "4 2"
1685 }]
1686 , "\"1\\\"4 2\\\"\" = Right 1\\\"4 2\\\"" ~:
1687 (Data.Either.rights $
1688 [P.runParser
1689 (Format.Ledger.Read.amount <* P.eof)
1690 () "" ("1\"4 2\""::Text)])
1691 ~?=
1692 [Amount.nil
1693 { Amount.quantity = Decimal 0 1
1694 , Amount.style =
1695 Amount.Style.nil
1696 { Amount.Style.fractioning = Nothing
1697 , Amount.Style.grouping_integral = Nothing
1698 , Amount.Style.grouping_fractional = Nothing
1699 , Amount.Style.precision = 0
1700 , Amount.Style.unit_side = Just Amount.Style.Side_Right
1701 , Amount.Style.unit_spaced = Just False
1702 }
1703 , Amount.unit = "4 2"
1704 }]
1705 , "\"$1.000,00\" = Right $1.000,00" ~:
1706 (Data.Either.rights $
1707 [P.runParser
1708 (Format.Ledger.Read.amount <* P.eof)
1709 () "" ("$1.000,00"::Text)])
1710 ~?=
1711 [Amount.nil
1712 { Amount.quantity = Decimal 0 1000
1713 , Amount.style =
1714 Amount.Style.nil
1715 { Amount.Style.fractioning = Just ','
1716 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
1717 , Amount.Style.grouping_fractional = Nothing
1718 , Amount.Style.precision = 2
1719 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1720 , Amount.Style.unit_spaced = Just False
1721 }
1722 , Amount.unit = "$"
1723 }]
1724 , "\"1.000,00$\" = Right 1.000,00$" ~:
1725 (Data.Either.rights $
1726 [P.runParser
1727 (Format.Ledger.Read.amount <* P.eof)
1728 () "" ("1.000,00$"::Text)])
1729 ~?=
1730 [Amount.nil
1731 { Amount.quantity = Decimal 0 1000
1732 , Amount.style =
1733 Amount.Style.nil
1734 { Amount.Style.fractioning = Just ','
1735 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
1736 , Amount.Style.grouping_fractional = Nothing
1737 , Amount.Style.precision = 2
1738 , Amount.Style.unit_side = Just Amount.Style.Side_Right
1739 , Amount.Style.unit_spaced = Just False
1740 }
1741 , Amount.unit = "$"
1742 }]
1743 ]
1744 , "comment" ~: TestList
1745 [ "; some comment = Right \" some comment\"" ~:
1746 (Data.Either.rights $
1747 [P.runParser
1748 (Format.Ledger.Read.comment <* P.eof)
1749 () "" ("; some comment"::Text)])
1750 ~?=
1751 [ " some comment" ]
1752 , "; some comment \\n = Right \" some comment \"" ~:
1753 (Data.Either.rights $
1754 [P.runParser
1755 (Format.Ledger.Read.comment <* P.newline <* P.eof)
1756 () "" ("; some comment \n"::Text)])
1757 ~?=
1758 [ " some comment " ]
1759 , "; some comment \\r\\n = Right \" some comment \"" ~:
1760 (Data.Either.rights $
1761 [P.runParser
1762 (Format.Ledger.Read.comment <* P.string "\r\n" <* P.eof)
1763 () "" ("; some comment \r\n"::Text)])
1764 ~?=
1765 [ " some comment " ]
1766 ]
1767 , "comments" ~: TestList
1768 [ "; some comment\\n ; some other comment = Right [\" some comment\", \" some other comment\"]" ~:
1769 (Data.Either.rights $
1770 [P.runParser
1771 (Format.Ledger.Read.comments <* P.eof)
1772 () "" ("; some comment\n ; some other comment"::Text)])
1773 ~?=
1774 [ [" some comment", " some other comment"] ]
1775 , "; some comment \\n = Right \" some comment \"" ~:
1776 (Data.Either.rights $
1777 [P.runParser
1778 (Format.Ledger.Read.comments <* P.string "\n" <* P.eof)
1779 () "" ("; some comment \n"::Text)])
1780 ~?=
1781 [ [" some comment "] ]
1782 ]
1783 , "date" ~: TestList
1784 [ "2000/01/01" ~:
1785 (Data.Either.rights $
1786 [P.runParser
1787 (Format.Ledger.Read.date Nothing <* P.eof)
1788 () "" ("2000/01/01"::Text)])
1789 ~?=
1790 [ Time.ZonedTime
1791 (Time.LocalTime
1792 (Time.fromGregorian 2000 01 01)
1793 (Time.TimeOfDay 0 0 0))
1794 (Time.utc)]
1795 , "2000/01/01 some text" ~:
1796 (Data.Either.rights $
1797 [P.runParser
1798 (Format.Ledger.Read.date Nothing)
1799 () "" ("2000/01/01 some text"::Text)])
1800 ~?=
1801 [ Time.ZonedTime
1802 (Time.LocalTime
1803 (Time.fromGregorian 2000 01 01)
1804 (Time.TimeOfDay 0 0 0))
1805 (Time.utc)]
1806 , "2000/01/01 12:34" ~:
1807 (Data.Either.rights $
1808 [P.runParser
1809 (Format.Ledger.Read.date Nothing <* P.eof)
1810 () "" ("2000/01/01 12:34"::Text)])
1811 ~?=
1812 [ Time.ZonedTime
1813 (Time.LocalTime
1814 (Time.fromGregorian 2000 01 01)
1815 (Time.TimeOfDay 12 34 0))
1816 (Time.utc)]
1817 , "2000/01/01 12:34:56" ~:
1818 (Data.Either.rights $
1819 [P.runParser
1820 (Format.Ledger.Read.date Nothing <* P.eof)
1821 () "" ("2000/01/01 12:34:56"::Text)])
1822 ~?=
1823 [ Time.ZonedTime
1824 (Time.LocalTime
1825 (Time.fromGregorian 2000 01 01)
1826 (Time.TimeOfDay 12 34 56))
1827 (Time.utc)]
1828 , "2000/01/01 12:34 CET" ~:
1829 (Data.Either.rights $
1830 [P.runParser
1831 (Format.Ledger.Read.date Nothing <* P.eof)
1832 () "" ("2000/01/01 12:34 CET"::Text)])
1833 ~?=
1834 [ Time.ZonedTime
1835 (Time.LocalTime
1836 (Time.fromGregorian 2000 01 01)
1837 (Time.TimeOfDay 12 34 0))
1838 (Time.TimeZone 60 True "CET")]
1839 , "2000/01/01 12:34 +0130" ~:
1840 (Data.Either.rights $
1841 [P.runParser
1842 (Format.Ledger.Read.date Nothing <* P.eof)
1843 () "" ("2000/01/01 12:34 +0130"::Text)])
1844 ~?=
1845 [ Time.ZonedTime
1846 (Time.LocalTime
1847 (Time.fromGregorian 2000 01 01)
1848 (Time.TimeOfDay 12 34 0))
1849 (Time.TimeZone 90 False "+0130")]
1850 , "2000/01/01 12:34:56 CET" ~:
1851 (Data.Either.rights $
1852 [P.runParser
1853 (Format.Ledger.Read.date Nothing <* P.eof)
1854 () "" ("2000/01/01 12:34:56 CET"::Text)])
1855 ~?=
1856 [ Time.ZonedTime
1857 (Time.LocalTime
1858 (Time.fromGregorian 2000 01 01)
1859 (Time.TimeOfDay 12 34 56))
1860 (Time.TimeZone 60 True "CET")]
1861 , "2001/02/29" ~:
1862 (Data.Either.rights $
1863 [P.runParser
1864 (Format.Ledger.Read.date Nothing <* P.eof)
1865 () "" ("2001/02/29"::Text)])
1866 ~?=
1867 []
1868 , "01/01" ~:
1869 (Data.Either.rights $
1870 [P.runParser
1871 (Format.Ledger.Read.date (Just 2000) <* P.eof)
1872 () "" ("01/01"::Text)])
1873 ~?=
1874 [ Time.ZonedTime
1875 (Time.LocalTime
1876 (Time.fromGregorian 2000 01 01)
1877 (Time.TimeOfDay 0 0 0))
1878 (Time.utc)]
1879 ]
1880 , "tag_value" ~: TestList
1881 [ "," ~:
1882 (Data.Either.rights $
1883 [P.runParser
1884 (Format.Ledger.Read.tag_value <* P.eof)
1885 () "" (","::Text)])
1886 ~?=
1887 [","]
1888 , ",\\n" ~:
1889 (Data.Either.rights $
1890 [P.runParser
1891 (Format.Ledger.Read.tag_value <* P.char '\n' <* P.eof)
1892 () "" (",\n"::Text)])
1893 ~?=
1894 [","]
1895 , ",x" ~:
1896 (Data.Either.rights $
1897 [P.runParser
1898 (Format.Ledger.Read.tag_value <* P.eof)
1899 () "" (",x"::Text)])
1900 ~?=
1901 [",x"]
1902 , ",x:" ~:
1903 (Data.Either.rights $
1904 [P.runParser
1905 (Format.Ledger.Read.tag_value <* P.string ",x:" <* P.eof)
1906 () "" (",x:"::Text)])
1907 ~?=
1908 [""]
1909 , "v, v, n:" ~:
1910 (Data.Either.rights $
1911 [P.runParser
1912 (Format.Ledger.Read.tag_value <* P.string ", n:" <* P.eof)
1913 () "" ("v, v, n:"::Text)])
1914 ~?=
1915 ["v, v"]
1916 ]
1917 , "tag" ~: TestList
1918 [ "Name:" ~:
1919 (Data.Either.rights $
1920 [P.runParser
1921 (Format.Ledger.Read.tag <* P.eof)
1922 () "" ("Name:"::Text)])
1923 ~?=
1924 [("Name", "")]
1925 , "Name:Value" ~:
1926 (Data.Either.rights $
1927 [P.runParser
1928 (Format.Ledger.Read.tag <* P.eof)
1929 () "" ("Name:Value"::Text)])
1930 ~?=
1931 [("Name", "Value")]
1932 , "Name:Value\\n" ~:
1933 (Data.Either.rights $
1934 [P.runParser
1935 (Format.Ledger.Read.tag <* P.string "\n" <* P.eof)
1936 () "" ("Name:Value\n"::Text)])
1937 ~?=
1938 [("Name", "Value")]
1939 , "Name:Val ue" ~:
1940 (Data.Either.rights $
1941 [P.runParser
1942 (Format.Ledger.Read.tag <* P.eof)
1943 () "" ("Name:Val ue"::Text)])
1944 ~?=
1945 [("Name", "Val ue")]
1946 , "Name:," ~:
1947 (Data.Either.rights $
1948 [P.runParser
1949 (Format.Ledger.Read.tag <* P.eof)
1950 () "" ("Name:,"::Text)])
1951 ~?=
1952 [("Name", ",")]
1953 , "Name:Val,ue" ~:
1954 (Data.Either.rights $
1955 [P.runParser
1956 (Format.Ledger.Read.tag <* P.eof)
1957 () "" ("Name:Val,ue"::Text)])
1958 ~?=
1959 [("Name", "Val,ue")]
1960 , "Name:Val,ue:" ~:
1961 (Data.Either.rights $
1962 [P.runParser
1963 (Format.Ledger.Read.tag <* P.string ",ue:" <* P.eof)
1964 () "" ("Name:Val,ue:"::Text)])
1965 ~?=
1966 [("Name", "Val")]
1967 ]
1968 , "tags" ~: TestList
1969 [ "Name:" ~:
1970 (Data.Either.rights $
1971 [P.runParser
1972 (Format.Ledger.Read.tags <* P.eof)
1973 () "" ("Name:"::Text)])
1974 ~?=
1975 [Data.Map.fromList
1976 [ ("Name", [""])
1977 ]
1978 ]
1979 , "Name:," ~:
1980 (Data.Either.rights $
1981 [P.runParser
1982 (Format.Ledger.Read.tags <* P.eof)
1983 () "" ("Name:,"::Text)])
1984 ~?=
1985 [Data.Map.fromList
1986 [ ("Name", [","])
1987 ]
1988 ]
1989 , "Name:,Name:" ~:
1990 (Data.Either.rights $
1991 [P.runParser
1992 (Format.Ledger.Read.tags <* P.eof)
1993 () "" ("Name:,Name:"::Text)])
1994 ~?=
1995 [Data.Map.fromList
1996 [ ("Name", ["", ""])
1997 ]
1998 ]
1999 , "Name:,Name2:" ~:
2000 (Data.Either.rights $
2001 [P.runParser
2002 (Format.Ledger.Read.tags <* P.eof)
2003 () "" ("Name:,Name2:"::Text)])
2004 ~?=
2005 [Data.Map.fromList
2006 [ ("Name", [""])
2007 , ("Name2", [""])
2008 ]
2009 ]
2010 , "Name: , Name2:" ~:
2011 (Data.Either.rights $
2012 [P.runParser
2013 (Format.Ledger.Read.tags <* P.eof)
2014 () "" ("Name: , Name2:"::Text)])
2015 ~?=
2016 [Data.Map.fromList
2017 [ ("Name", [" "])
2018 , ("Name2", [""])
2019 ]
2020 ]
2021 , "Name:,Name2:,Name3:" ~:
2022 (Data.Either.rights $
2023 [P.runParser
2024 (Format.Ledger.Read.tags <* P.eof)
2025 () "" ("Name:,Name2:,Name3:"::Text)])
2026 ~?=
2027 [Data.Map.fromList
2028 [ ("Name", [""])
2029 , ("Name2", [""])
2030 , ("Name3", [""])
2031 ]
2032 ]
2033 , "Name:Val ue,Name2:V a l u e,Name3:V al ue" ~:
2034 (Data.Either.rights $
2035 [P.runParser
2036 (Format.Ledger.Read.tags <* P.eof)
2037 () "" ("Name:Val ue,Name2:V a l u e,Name3:V al ue"::Text)])
2038 ~?=
2039 [Data.Map.fromList
2040 [ ("Name", ["Val ue"])
2041 , ("Name2", ["V a l u e"])
2042 , ("Name3", ["V al ue"])
2043 ]
2044 ]
2045 ]
2046 , "posting" ~: TestList
2047 [ " A:B:C = Right A:B:C" ~:
2048 (Data.Either.rights $
2049 [P.runParser
2050 (Format.Ledger.Read.posting <* P.eof)
2051 Format.Ledger.Read.nil_Context "" (" A:B:C"::Text)])
2052 ~?=
2053 [ ( (Posting.nil ("A":|["B", "C"]))
2054 { Posting.sourcepos = P.newPos "" 1 1
2055 }
2056 , Posting.Type_Regular
2057 )
2058 ]
2059 , " !A:B:C = Right !A:B:C" ~:
2060 (Data.List.map fst $
2061 Data.Either.rights $
2062 [P.runParser
2063 (Format.Ledger.Read.posting <* P.eof)
2064 Format.Ledger.Read.nil_Context "" (" !A:B:C"::Text)])
2065 ~?=
2066 [ (Posting.nil ("A":|["B", "C"]))
2067 { Posting.sourcepos = P.newPos "" 1 1
2068 , Posting.status = True
2069 }
2070 ]
2071 , " *A:B:C = Right *A:B:C" ~:
2072 (Data.List.map fst $
2073 Data.Either.rights $
2074 [P.runParser
2075 (Format.Ledger.Read.posting <* P.eof)
2076 Format.Ledger.Read.nil_Context "" (" *A:B:C"::Text)])
2077 ~?=
2078 [ (Posting.nil ("A":|["B", "C"]))
2079 { Posting.amounts = Data.Map.fromList []
2080 , Posting.comments = []
2081 , Posting.dates = []
2082 , Posting.status = True
2083 , Posting.sourcepos = P.newPos "" 1 1
2084 , Posting.tags = Data.Map.fromList []
2085 }
2086 ]
2087 , " A:B:C $1 = Right A:B:C $1" ~:
2088 (Data.List.map fst $
2089 Data.Either.rights $
2090 [P.runParser
2091 (Format.Ledger.Read.posting <* P.eof)
2092 Format.Ledger.Read.nil_Context "" (" A:B:C $1"::Text)])
2093 ~?=
2094 [ (Posting.nil ("A":|["B","C $1"]))
2095 { Posting.sourcepos = P.newPos "" 1 1
2096 }
2097 ]
2098 , " A:B:C $1 = Right A:B:C $1" ~:
2099 (Data.List.map fst $
2100 Data.Either.rights $
2101 [P.runParser
2102 (Format.Ledger.Read.posting <* P.eof)
2103 Format.Ledger.Read.nil_Context "" (" A:B:C $1"::Text)])
2104 ~?=
2105 [ (Posting.nil ("A":|["B", "C"]))
2106 { Posting.amounts = Data.Map.fromList
2107 [ ("$", Amount.nil
2108 { Amount.quantity = 1
2109 , Amount.style = Amount.Style.nil
2110 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2111 , Amount.Style.unit_spaced = Just False
2112 }
2113 , Amount.unit = "$"
2114 })
2115 ]
2116 , Posting.sourcepos = P.newPos "" 1 1
2117 }
2118 ]
2119 , " A:B:C $1 + 1€ = Right A:B:C $1 + 1€" ~:
2120 (Data.List.map fst $
2121 Data.Either.rights $
2122 [P.runParser
2123 (Format.Ledger.Read.posting <* P.eof)
2124 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1€"::Text)])
2125 ~?=
2126 [ (Posting.nil ("A":|["B", "C"]))
2127 { Posting.amounts = Data.Map.fromList
2128 [ ("$", Amount.nil
2129 { Amount.quantity = 1
2130 , Amount.style = Amount.Style.nil
2131 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2132 , Amount.Style.unit_spaced = Just False
2133 }
2134 , Amount.unit = "$"
2135 })
2136 , ("€", Amount.nil
2137 { Amount.quantity = 1
2138 , Amount.style = Amount.Style.nil
2139 { Amount.Style.unit_side = Just Amount.Style.Side_Right
2140 , Amount.Style.unit_spaced = Just False
2141 }
2142 , Amount.unit = "€"
2143 })
2144 ]
2145 , Posting.sourcepos = P.newPos "" 1 1
2146 }
2147 ]
2148 , " A:B:C $1 + 1$ = Right A:B:C $2" ~:
2149 (Data.List.map fst $
2150 Data.Either.rights $
2151 [P.runParser
2152 (Format.Ledger.Read.posting <* P.eof)
2153 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1$"::Text)])
2154 ~?=
2155 [ (Posting.nil ("A":|["B", "C"]))
2156 { Posting.amounts = Data.Map.fromList
2157 [ ("$", Amount.nil
2158 { Amount.quantity = 2
2159 , Amount.style = Amount.Style.nil
2160 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2161 , Amount.Style.unit_spaced = Just False
2162 }
2163 , Amount.unit = "$"
2164 })
2165 ]
2166 , Posting.sourcepos = P.newPos "" 1 1
2167 }
2168 ]
2169 , " A:B:C $1 + 1$ + 1$ = Right A:B:C $3" ~:
2170 (Data.List.map fst $
2171 Data.Either.rights $
2172 [P.runParser
2173 (Format.Ledger.Read.posting <* P.eof)
2174 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1$ + 1$"::Text)])
2175 ~?=
2176 [ (Posting.nil ("A":|["B", "C"]))
2177 { Posting.amounts = Data.Map.fromList
2178 [ ("$", Amount.nil
2179 { Amount.quantity = 3
2180 , Amount.style = Amount.Style.nil
2181 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2182 , Amount.Style.unit_spaced = Just False
2183 }
2184 , Amount.unit = "$"
2185 })
2186 ]
2187 , Posting.sourcepos = P.newPos "" 1 1
2188 }
2189 ]
2190 , " A:B:C ; some comment = Right A:B:C ; some comment" ~:
2191 (Data.List.map fst $
2192 Data.Either.rights $
2193 [P.runParser
2194 (Format.Ledger.Read.posting <* P.eof)
2195 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment"::Text)])
2196 ~?=
2197 [ (Posting.nil ("A":|["B", "C"]))
2198 { Posting.amounts = Data.Map.fromList []
2199 , Posting.comments = [" some comment"]
2200 , Posting.sourcepos = P.newPos "" 1 1
2201 }
2202 ]
2203 , " A:B:C ; some comment\\n ; some other comment = Right A:B:C ; some comment\\n ; some other comment" ~:
2204 (Data.List.map fst $
2205 Data.Either.rights $
2206 [P.runParser
2207 (Format.Ledger.Read.posting <* P.eof)
2208 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment\n ; some other comment"::Text)])
2209 ~?=
2210 [ (Posting.nil ("A":|["B", "C"]))
2211 { Posting.amounts = Data.Map.fromList []
2212 , Posting.comments = [" some comment", " some other comment"]
2213 , Posting.sourcepos = P.newPos "" 1 1
2214 }
2215 ]
2216 , " A:B:C $1 ; some comment = Right A:B:C $1 ; some comment" ~:
2217 (Data.List.map fst $
2218 Data.Either.rights $
2219 [P.runParser
2220 (Format.Ledger.Read.posting)
2221 Format.Ledger.Read.nil_Context "" (" A:B:C $1 ; some comment"::Text)])
2222 ~?=
2223 [ (Posting.nil ("A":|["B", "C"]))
2224 { Posting.amounts = Data.Map.fromList
2225 [ ("$", Amount.nil
2226 { Amount.quantity = 1
2227 , Amount.style = Amount.Style.nil
2228 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2229 , Amount.Style.unit_spaced = Just False
2230 }
2231 , Amount.unit = "$"
2232 })
2233 ]
2234 , Posting.comments = [" some comment"]
2235 , Posting.sourcepos = P.newPos "" 1 1
2236 }
2237 ]
2238 , " A:B:C ; N:V = Right A:B:C ; N:V" ~:
2239 (Data.List.map fst $
2240 Data.Either.rights $
2241 [P.runParser
2242 (Format.Ledger.Read.posting <* P.eof)
2243 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V"::Text)])
2244 ~?=
2245 [ (Posting.nil ("A":|["B", "C"]))
2246 { Posting.comments = [" N:V"]
2247 , Posting.sourcepos = P.newPos "" 1 1
2248 , Posting.tags = Data.Map.fromList
2249 [ ("N", ["V"])
2250 ]
2251 }
2252 ]
2253 , " A:B:C ; some comment N:V = Right A:B:C ; some comment N:V" ~:
2254 (Data.List.map fst $
2255 Data.Either.rights $
2256 [P.runParser
2257 (Format.Ledger.Read.posting <* P.eof)
2258 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment N:V"::Text)])
2259 ~?=
2260 [ (Posting.nil ("A":|["B", "C"]))
2261 { Posting.comments = [" some comment N:V"]
2262 , Posting.sourcepos = P.newPos "" 1 1
2263 , Posting.tags = Data.Map.fromList
2264 [ ("N", ["V"])
2265 ]
2266 }
2267 ]
2268 , " A:B:C ; some comment N:V v, N2:V2 v2 = Right A:B:C ; some comment N:V v, N2:V2 v2" ~:
2269 (Data.List.map fst $
2270 Data.Either.rights $
2271 [P.runParser
2272 (Format.Ledger.Read.posting )
2273 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment N:V v, N2:V2 v2"::Text)])
2274 ~?=
2275 [ (Posting.nil ("A":|["B", "C"]))
2276 { Posting.comments = [" some comment N:V v, N2:V2 v2"]
2277 , Posting.sourcepos = P.newPos "" 1 1
2278 , Posting.tags = Data.Map.fromList
2279 [ ("N", ["V v"])
2280 , ("N2", ["V2 v2"])
2281 ]
2282 }
2283 ]
2284 , " A:B:C ; N:V\\n ; N:V2 = Right A:B:C ; N:V\\n ; N:V2" ~:
2285 (Data.List.map fst $
2286 Data.Either.rights $
2287 [P.runParser
2288 (Format.Ledger.Read.posting <* P.eof)
2289 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V\n ; N:V2"::Text)])
2290 ~?=
2291 [ (Posting.nil ("A":|["B", "C"]))
2292 { Posting.comments = [" N:V", " N:V2"]
2293 , Posting.sourcepos = P.newPos "" 1 1
2294 , Posting.tags = Data.Map.fromList
2295 [ ("N", ["V", "V2"])
2296 ]
2297 }
2298 ]
2299 , " A:B:C ; N:V\\n ; N2:V = Right A:B:C ; N:V\\n ; N2:V" ~:
2300 (Data.List.map fst $
2301 Data.Either.rights $
2302 [P.runParser
2303 (Format.Ledger.Read.posting <* P.eof)
2304 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V\n ; N2:V"::Text)])
2305 ~?=
2306 [ (Posting.nil ("A":|["B", "C"]))
2307 { Posting.comments = [" N:V", " N2:V"]
2308 , Posting.sourcepos = P.newPos "" 1 1
2309 , Posting.tags = Data.Map.fromList
2310 [ ("N", ["V"])
2311 , ("N2", ["V"])
2312 ]
2313 }
2314 ]
2315 , " A:B:C ; date:2001/01/01 = Right A:B:C ; date:2001/01/01" ~:
2316 (Data.List.map fst $
2317 Data.Either.rights $
2318 [P.runParser
2319 (Format.Ledger.Read.posting <* P.eof)
2320 Format.Ledger.Read.nil_Context "" (" A:B:C ; date:2001/01/01"::Text)])
2321 ~?=
2322 [ (Posting.nil ("A":|["B", "C"]))
2323 { Posting.comments = [" date:2001/01/01"]
2324 , Posting.dates =
2325 [ Time.ZonedTime
2326 (Time.LocalTime
2327 (Time.fromGregorian 2001 01 01)
2328 (Time.TimeOfDay 0 0 0))
2329 Time.utc
2330 ]
2331 , Posting.sourcepos = P.newPos "" 1 1
2332 , Posting.tags = Data.Map.fromList
2333 [ ("date", ["2001/01/01"])
2334 ]
2335 }
2336 ]
2337 , " (A:B:C) = Right (A:B:C)" ~:
2338 (Data.Either.rights $
2339 [P.runParser
2340 (Format.Ledger.Read.posting <* P.eof)
2341 Format.Ledger.Read.nil_Context "" (" (A:B:C)"::Text)])
2342 ~?=
2343 [ ( (Posting.nil ("A":|["B", "C"]))
2344 { Posting.sourcepos = P.newPos "" 1 1
2345 }
2346 , Posting.Type_Virtual
2347 )
2348 ]
2349 , " [A:B:C] = Right [A:B:C]" ~:
2350 (Data.Either.rights $
2351 [P.runParser
2352 (Format.Ledger.Read.posting <* P.eof)
2353 Format.Ledger.Read.nil_Context "" (" [A:B:C]"::Text)])
2354 ~?=
2355 [ ( (Posting.nil ("A":|["B", "C"]))
2356 { Posting.sourcepos = P.newPos "" 1 1
2357 }
2358 , Posting.Type_Virtual_Balanced
2359 )
2360 ]
2361 ]
2362 , "transaction" ~: TestList
2363 [ "2000/01/01 some description\\n A:B:C $1\\n a:b:c" ~:
2364 (Data.Either.rights $
2365 [P.runParser
2366 (Format.Ledger.Read.transaction <* P.eof)
2367 Format.Ledger.Read.nil_Context "" ("2000/01/01 some description\n A:B:C $1\n a:b:c"::Text)])
2368 ~?=
2369 [ Transaction.nil
2370 { Transaction.dates=
2371 ( Time.ZonedTime
2372 (Time.LocalTime
2373 (Time.fromGregorian 2000 01 01)
2374 (Time.TimeOfDay 0 0 0))
2375 (Time.utc)
2376 , [] )
2377 , Transaction.description="some description"
2378 , Transaction.postings = Posting.from_List
2379 [ (Posting.nil ("A":|["B", "C"]))
2380 { Posting.amounts = Data.Map.fromList
2381 [ ("$", Amount.nil
2382 { Amount.quantity = 1
2383 , Amount.style = Amount.Style.nil
2384 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2385 , Amount.Style.unit_spaced = Just False
2386 }
2387 , Amount.unit = "$"
2388 })
2389 ]
2390 , Posting.sourcepos = P.newPos "" 2 1
2391 }
2392 , (Posting.nil ("a":|["b", "c"]))
2393 { Posting.sourcepos = P.newPos "" 3 1
2394 }
2395 ]
2396 , Transaction.sourcepos = P.newPos "" 1 1
2397 }
2398 ]
2399 , "2000/01/01 some description\\n A:B:C $1\\n a:b:c\\n" ~:
2400 (Data.Either.rights $
2401 [P.runParser
2402 (Format.Ledger.Read.transaction <* P.newline <* P.eof)
2403 Format.Ledger.Read.nil_Context "" ("2000/01/01 some description\n A:B:C $1\n a:b:c\n"::Text)])
2404 ~?=
2405 [ Transaction.nil
2406 { Transaction.dates=
2407 ( Time.ZonedTime
2408 (Time.LocalTime
2409 (Time.fromGregorian 2000 01 01)
2410 (Time.TimeOfDay 0 0 0))
2411 (Time.utc)
2412 , [] )
2413 , Transaction.description="some description"
2414 , Transaction.postings = Posting.from_List
2415 [ (Posting.nil ("A":|["B", "C"]))
2416 { Posting.amounts = Data.Map.fromList
2417 [ ("$", Amount.nil
2418 { Amount.quantity = 1
2419 , Amount.style = Amount.Style.nil
2420 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2421 , Amount.Style.unit_spaced = Just False
2422 }
2423 , Amount.unit = "$"
2424 })
2425 ]
2426 , Posting.sourcepos = P.newPos "" 2 1
2427 }
2428 , (Posting.nil ("a":|["b", "c"]))
2429 { Posting.sourcepos = P.newPos "" 3 1
2430 }
2431 ]
2432 , Transaction.sourcepos = P.newPos "" 1 1
2433 }
2434 ]
2435 , "2000/01/01 some description ; some comment\\n ; some other;comment\\n ; some Tag:\\n ; some last comment\\n A:B:C $1\\n a:b:c" ~:
2436 (Data.Either.rights $
2437 [P.runParser
2438 (Format.Ledger.Read.transaction <* P.eof)
2439 Format.Ledger.Read.nil_Context "" ("2000/01/01 some description ; some comment\n ; some other;comment\n ; some Tag:\n ; some last comment\n A:B:C $1\n a:b:c"::Text)])
2440 ~?=
2441 [ Transaction.nil
2442 { Transaction.comments_after =
2443 [ " some comment"
2444 , " some other;comment"
2445 , " some Tag:"
2446 , " some last comment"
2447 ]
2448 , Transaction.dates=
2449 ( Time.ZonedTime
2450 (Time.LocalTime
2451 (Time.fromGregorian 2000 01 01)
2452 (Time.TimeOfDay 0 0 0))
2453 (Time.utc)
2454 , [] )
2455 , Transaction.description="some description"
2456 , Transaction.postings = Posting.from_List
2457 [ (Posting.nil ("A":|["B", "C"]))
2458 { Posting.amounts = Data.Map.fromList
2459 [ ("$", Amount.nil
2460 { Amount.quantity = 1
2461 , Amount.style = Amount.Style.nil
2462 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2463 , Amount.Style.unit_spaced = Just False
2464 }
2465 , Amount.unit = "$"
2466 })
2467 ]
2468 , Posting.sourcepos = P.newPos "" 5 1
2469 }
2470 , (Posting.nil ("a":|["b", "c"]))
2471 { Posting.sourcepos = P.newPos "" 6 1
2472 , Posting.tags = Data.Map.fromList []
2473 }
2474 ]
2475 , Transaction.sourcepos = P.newPos "" 1 1
2476 , Transaction.tags = Data.Map.fromList
2477 [ ("Tag", [""])
2478 ]
2479 }
2480 ]
2481 ]
2482 , "journal" ~: TestList
2483 [ "2000/01/01 1° description\\n A:B:C $1\\n a:b:c\\n2000/01/02 2° description\\n A:B:C $1\\n x:y:z" ~: TestCase $ do
2484 jnl <- liftIO $
2485 P.runParserT
2486 (Format.Ledger.Read.journal "" {-<* P.eof-})
2487 Format.Ledger.Read.nil_Context "" ("2000/01/01 1° description\n A:B:C $1\n a:b:c\n2000/01/02 2° description\n A:B:C $1\n x:y:z"::Text)
2488 (Data.List.map
2489 (\j -> j{Format.Ledger.Journal.last_read_time=
2490 Format.Ledger.Journal.last_read_time Format.Ledger.Journal.nil}) $
2491 Data.Either.rights [jnl])
2492 @?=
2493 [ Format.Ledger.Journal.nil
2494 { Format.Ledger.Journal.transactions = Transaction.from_List
2495 [ Transaction.nil
2496 { Transaction.dates=
2497 ( Time.ZonedTime
2498 (Time.LocalTime
2499 (Time.fromGregorian 2000 01 01)
2500 (Time.TimeOfDay 0 0 0))
2501 (Time.utc)
2502 , [] )
2503 , Transaction.description="1° description"
2504 , Transaction.postings = Posting.from_List
2505 [ (Posting.nil ("A":|["B", "C"]))
2506 { Posting.amounts = Data.Map.fromList
2507 [ ("$", Amount.nil
2508 { Amount.quantity = 1
2509 , Amount.style = Amount.Style.nil
2510 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2511 , Amount.Style.unit_spaced = Just False
2512 }
2513 , Amount.unit = "$"
2514 })
2515 ]
2516 , Posting.sourcepos = P.newPos "" 2 1
2517 }
2518 , (Posting.nil ("a":|["b", "c"]))
2519 { Posting.sourcepos = P.newPos "" 3 1
2520 }
2521 ]
2522 , Transaction.sourcepos = P.newPos "" 1 1
2523 }
2524 , Transaction.nil
2525 { Transaction.dates=
2526 ( Time.ZonedTime
2527 (Time.LocalTime
2528 (Time.fromGregorian 2000 01 02)
2529 (Time.TimeOfDay 0 0 0))
2530 (Time.utc)
2531 , [] )
2532 , Transaction.description="2° description"
2533 , Transaction.postings = Posting.from_List
2534 [ (Posting.nil ("A":|["B", "C"]))
2535 { Posting.amounts = Data.Map.fromList
2536 [ ("$", Amount.nil
2537 { Amount.quantity = 1
2538 , Amount.style = Amount.Style.nil
2539 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2540 , Amount.Style.unit_spaced = Just False
2541 }
2542 , Amount.unit = "$"
2543 })
2544 ]
2545 , Posting.sourcepos = P.newPos "" 5 1
2546 }
2547 , (Posting.nil ("x":|["y", "z"]))
2548 { Posting.sourcepos = P.newPos "" 6 1
2549 }
2550 ]
2551 , Transaction.sourcepos = P.newPos "" 4 1
2552 }
2553 ]
2554 }
2555 ]
2556 ]
2557 ]
2558 , "Write" ~: TestList
2559 [ "account" ~: TestList
2560 [ "A" ~:
2561 ((Format.Ledger.Write.show False $
2562 Format.Ledger.Write.account Posting.Type_Regular $
2563 "A":|[])
2564 ~?=
2565 "A")
2566 , "A:B:C" ~:
2567 ((Format.Ledger.Write.show False $
2568 Format.Ledger.Write.account Posting.Type_Regular $
2569 "A":|["B", "C"])
2570 ~?=
2571 "A:B:C")
2572 , "(A:B:C)" ~:
2573 ((Format.Ledger.Write.show False $
2574 Format.Ledger.Write.account Posting.Type_Virtual $
2575 "A":|["B", "C"])
2576 ~?=
2577 "(A:B:C)")
2578 , "[A:B:C]" ~:
2579 ((Format.Ledger.Write.show False $
2580 Format.Ledger.Write.account Posting.Type_Virtual_Balanced $
2581 "A":|["B", "C"])
2582 ~?=
2583 "[A:B:C]")
2584 ]
2585 , "amount" ~: TestList
2586 [ "nil" ~:
2587 ((Format.Ledger.Write.show False $
2588 Format.Ledger.Write.amount
2589 Amount.nil)
2590 ~?=
2591 "0")
2592 , "nil @ prec=2" ~:
2593 ((Format.Ledger.Write.show False $
2594 Format.Ledger.Write.amount
2595 Amount.nil
2596 { Amount.style = Amount.Style.nil
2597 { Amount.Style.precision = 2 }
2598 })
2599 ~?=
2600 "0.00")
2601 , "123" ~:
2602 ((Format.Ledger.Write.show False $
2603 Format.Ledger.Write.amount
2604 Amount.nil
2605 { Amount.quantity = Decimal 0 123
2606 })
2607 ~?=
2608 "123")
2609 , "-123" ~:
2610 ((Format.Ledger.Write.show False $
2611 Format.Ledger.Write.amount
2612 Amount.nil
2613 { Amount.quantity = Decimal 0 (- 123)
2614 })
2615 ~?=
2616 "-123")
2617 , "12.3 @ prec=0" ~:
2618 ((Format.Ledger.Write.show False $
2619 Format.Ledger.Write.amount
2620 Amount.nil
2621 { Amount.quantity = Decimal 1 123
2622 , Amount.style = Amount.Style.nil
2623 { Amount.Style.fractioning = Just '.'
2624 }
2625 })
2626 ~?=
2627 "12")
2628 , "12.5 @ prec=0" ~:
2629 ((Format.Ledger.Write.show False $
2630 Format.Ledger.Write.amount
2631 Amount.nil
2632 { Amount.quantity = Decimal 1 125
2633 , Amount.style = Amount.Style.nil
2634 { Amount.Style.fractioning = Just '.'
2635 }
2636 })
2637 ~?=
2638 "13")
2639 , "12.3 @ prec=1" ~:
2640 ((Format.Ledger.Write.show False $
2641 Format.Ledger.Write.amount
2642 Amount.nil
2643 { Amount.quantity = Decimal 1 123
2644 , Amount.style = Amount.Style.nil
2645 { Amount.Style.fractioning = Just '.'
2646 , Amount.Style.precision = 1
2647 }
2648 })
2649 ~?=
2650 "12.3")
2651 , "1,234.56 @ prec=2" ~:
2652 ((Format.Ledger.Write.show False $
2653 Format.Ledger.Write.amount
2654 Amount.nil
2655 { Amount.quantity = Decimal 2 123456
2656 , Amount.style = Amount.Style.nil
2657 { Amount.Style.fractioning = Just '.'
2658 , Amount.Style.precision = 2
2659 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
2660 }
2661 })
2662 ~?=
2663 "1,234.56")
2664 , "123,456,789,01,2.3456789 @ prec=7" ~:
2665 ((Format.Ledger.Write.show False $
2666 Format.Ledger.Write.amount
2667 Amount.nil
2668 { Amount.quantity = Decimal 7 1234567890123456789
2669 , Amount.style = Amount.Style.nil
2670 { Amount.Style.fractioning = Just '.'
2671 , Amount.Style.precision = 7
2672 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [1, 2, 3]
2673 }
2674 })
2675 ~?=
2676 "123,456,789,01,2.3456789")
2677 , "1234567.8,90,123,456,789 @ prec=12" ~:
2678 ((Format.Ledger.Write.show False $
2679 Format.Ledger.Write.amount
2680 Amount.nil
2681 { Amount.quantity = Decimal 12 1234567890123456789
2682 , Amount.style = Amount.Style.nil
2683 { Amount.Style.fractioning = Just '.'
2684 , Amount.Style.precision = 12
2685 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [1, 2, 3]
2686 }
2687 })
2688 ~?=
2689 "1234567.8,90,123,456,789")
2690 , "1,2,3,4,5,6,7,89,012.3456789 @ prec=7" ~:
2691 ((Format.Ledger.Write.show False $
2692 Format.Ledger.Write.amount
2693 Amount.nil
2694 { Amount.quantity = Decimal 7 1234567890123456789
2695 , Amount.style = Amount.Style.nil
2696 { Amount.Style.fractioning = Just '.'
2697 , Amount.Style.precision = 7
2698 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3, 2, 1]
2699 }
2700 })
2701 ~?=
2702 "1,2,3,4,5,6,7,89,012.3456789")
2703 , "1234567.890,12,3,4,5,6,7,8,9 @ prec=12" ~:
2704 ((Format.Ledger.Write.show False $
2705 Format.Ledger.Write.amount
2706 Amount.nil
2707 { Amount.quantity = Decimal 12 1234567890123456789
2708 , Amount.style = Amount.Style.nil
2709 { Amount.Style.fractioning = Just '.'
2710 , Amount.Style.precision = 12
2711 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [3, 2, 1]
2712 }
2713 })
2714 ~?=
2715 "1234567.890,12,3,4,5,6,7,8,9")
2716 ]
2717 , "amount_length" ~: TestList
2718 [ "nil" ~:
2719 ((Format.Ledger.Write.amount_length
2720 Amount.nil)
2721 ~?=
2722 1)
2723 , "nil @ prec=2" ~:
2724 ((Format.Ledger.Write.amount_length
2725 Amount.nil
2726 { Amount.style = Amount.Style.nil
2727 { Amount.Style.precision = 2 }
2728 })
2729 ~?=
2730 4)
2731 , "123" ~:
2732 ((Format.Ledger.Write.amount_length
2733 Amount.nil
2734 { Amount.quantity = Decimal 0 123
2735 })
2736 ~?=
2737 3)
2738 , "-123" ~:
2739 ((Format.Ledger.Write.amount_length
2740 Amount.nil
2741 { Amount.quantity = Decimal 0 (- 123)
2742 })
2743 ~?=
2744 4)
2745 , "12.3 @ prec=0" ~:
2746 ((Format.Ledger.Write.amount_length
2747 Amount.nil
2748 { Amount.quantity = Decimal 1 123
2749 , Amount.style = Amount.Style.nil
2750 { Amount.Style.fractioning = Just '.'
2751 }
2752 })
2753 ~?=
2754 2)
2755 , "12.5 @ prec=0" ~:
2756 ((Format.Ledger.Write.amount_length
2757 Amount.nil
2758 { Amount.quantity = Decimal 1 125
2759 , Amount.style = Amount.Style.nil
2760 { Amount.Style.fractioning = Just '.'
2761 }
2762 })
2763 ~?=
2764 2)
2765 , "12.3 @ prec=1" ~:
2766 ((Format.Ledger.Write.amount_length
2767 Amount.nil
2768 { Amount.quantity = Decimal 1 123
2769 , Amount.style = Amount.Style.nil
2770 { Amount.Style.fractioning = Just '.'
2771 , Amount.Style.precision = 1
2772 }
2773 })
2774 ~?=
2775 4)
2776 , "1,234.56 @ prec=2" ~:
2777 ((Format.Ledger.Write.amount_length
2778 Amount.nil
2779 { Amount.quantity = Decimal 2 123456
2780 , Amount.style = Amount.Style.nil
2781 { Amount.Style.fractioning = Just '.'
2782 , Amount.Style.precision = 2
2783 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
2784 }
2785 })
2786 ~?=
2787 8)
2788 , "123,456,789,01,2.3456789 @ prec=7" ~:
2789 ((Format.Ledger.Write.amount_length
2790 Amount.nil
2791 { Amount.quantity = Decimal 7 1234567890123456789
2792 , Amount.style = Amount.Style.nil
2793 { Amount.Style.fractioning = Just '.'
2794 , Amount.Style.precision = 7
2795 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [1, 2, 3]
2796 }
2797 })
2798 ~?=
2799 24)
2800 , "1234567.8,90,123,456,789 @ prec=12" ~:
2801 ((Format.Ledger.Write.amount_length
2802 Amount.nil
2803 { Amount.quantity = Decimal 12 1234567890123456789
2804 , Amount.style = Amount.Style.nil
2805 { Amount.Style.fractioning = Just '.'
2806 , Amount.Style.precision = 12
2807 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [1, 2, 3]
2808 }
2809 })
2810 ~?=
2811 24)
2812 , "1,2,3,4,5,6,7,89,012.3456789 @ prec=7" ~:
2813 ((Format.Ledger.Write.amount_length
2814 Amount.nil
2815 { Amount.quantity = Decimal 7 1234567890123456789
2816 , Amount.style = Amount.Style.nil
2817 { Amount.Style.fractioning = Just '.'
2818 , Amount.Style.precision = 7
2819 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3, 2, 1]
2820 }
2821 })
2822 ~?=
2823 28)
2824 , "1234567.890,12,3,4,5,6,7,8,9 @ prec=12" ~:
2825 ((Format.Ledger.Write.amount_length
2826 Amount.nil
2827 { Amount.quantity = Decimal 12 1234567890123456789
2828 , Amount.style = Amount.Style.nil
2829 { Amount.Style.fractioning = Just '.'
2830 , Amount.Style.precision = 12
2831 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [3, 2, 1]
2832 }
2833 })
2834 ~?=
2835 28)
2836 ]
2837 , "date" ~: TestList
2838 [ "nil" ~:
2839 ((Format.Ledger.Write.show False $
2840 Format.Ledger.Write.date
2841 Date.nil)
2842 ~?=
2843 "1970/01/01")
2844 , "2000/01/01 12:34:51 CET" ~:
2845 (Format.Ledger.Write.show False $
2846 Format.Ledger.Write.date $
2847 Time.ZonedTime
2848 (Time.LocalTime
2849 (Time.fromGregorian 2000 01 01)
2850 (Time.TimeOfDay 12 34 51))
2851 (Time.TimeZone 60 False "CET"))
2852 ~?=
2853 "2000/01/01 12:34:51 CET"
2854 , "2000/01/01 12:34:51 +0100" ~:
2855 (Format.Ledger.Write.show False $
2856 Format.Ledger.Write.date $
2857 Time.ZonedTime
2858 (Time.LocalTime
2859 (Time.fromGregorian 2000 01 01)
2860 (Time.TimeOfDay 12 34 51))
2861 (Time.TimeZone 60 False ""))
2862 ~?=
2863 "2000/01/01 12:34:51 +0100"
2864 , "2000/01/01 01:02:03" ~:
2865 (Format.Ledger.Write.show False $
2866 Format.Ledger.Write.date $
2867 Time.ZonedTime
2868 (Time.LocalTime
2869 (Time.fromGregorian 2000 01 01)
2870 (Time.TimeOfDay 1 2 3))
2871 (Time.utc))
2872 ~?=
2873 "2000/01/01 01:02:03"
2874 , "01/01 01:02" ~:
2875 (Format.Ledger.Write.show False $
2876 Format.Ledger.Write.date $
2877 Time.ZonedTime
2878 (Time.LocalTime
2879 (Time.fromGregorian 0 01 01)
2880 (Time.TimeOfDay 1 2 0))
2881 (Time.utc))
2882 ~?=
2883 "01/01 01:02"
2884 , "01/01 01:00" ~:
2885 (Format.Ledger.Write.show False $
2886 Format.Ledger.Write.date $
2887 Time.ZonedTime
2888 (Time.LocalTime
2889 (Time.fromGregorian 0 01 01)
2890 (Time.TimeOfDay 1 0 0))
2891 (Time.utc))
2892 ~?=
2893 "01/01 01:00"
2894 , "01/01 00:01" ~:
2895 (Format.Ledger.Write.show False $
2896 Format.Ledger.Write.date $
2897 Time.ZonedTime
2898 (Time.LocalTime
2899 (Time.fromGregorian 0 01 01)
2900 (Time.TimeOfDay 0 1 0))
2901 (Time.utc))
2902 ~?=
2903 "01/01 00:01"
2904 , "01/01" ~:
2905 (Format.Ledger.Write.show False $
2906 Format.Ledger.Write.date $
2907 Time.ZonedTime
2908 (Time.LocalTime
2909 (Time.fromGregorian 0 01 01)
2910 (Time.TimeOfDay 0 0 0))
2911 (Time.utc))
2912 ~?=
2913 "01/01"
2914 ]
2915 , "transaction" ~: TestList
2916 [ "nil" ~:
2917 ((Format.Ledger.Write.show False $
2918 Format.Ledger.Write.transaction
2919 Transaction.nil)
2920 ~?=
2921 "1970/01/01\n")
2922 , "2000/01/01 some description\\n\\ta:b:c\\n\\t\\t; first comment\\n\\t\\t; second comment\\n\\t\\t; third comment\\n\\tA:B:C $1" ~:
2923 ((Format.Ledger.Write.show False $
2924 Format.Ledger.Write.transaction $
2925 Transaction.nil
2926 { Transaction.dates=
2927 ( Time.ZonedTime
2928 (Time.LocalTime
2929 (Time.fromGregorian 2000 01 01)
2930 (Time.TimeOfDay 0 0 0))
2931 (Time.utc)
2932 , [] )
2933 , Transaction.description="some description"
2934 , Transaction.postings = Posting.from_List
2935 [ (Posting.nil ("A":|["B", "C"]))
2936 { Posting.amounts = Data.Map.fromList
2937 [ ("$", Amount.nil
2938 { Amount.quantity = 1
2939 , Amount.style = Amount.Style.nil
2940 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2941 , Amount.Style.unit_spaced = Just False
2942 }
2943 , Amount.unit = "$"
2944 })
2945 ]
2946 }
2947 , (Posting.nil ("a":|["b", "c"]))
2948 { Posting.comments = ["first comment","second comment","third comment"]
2949 }
2950 ]
2951 })
2952 ~?=
2953 "2000/01/01 some description\n\ta:b:c\n\t\t; first comment\n\t\t; second comment\n\t\t; third comment\n\tA:B:C $1")
2954 , "2000/01/01 some description\\n\\tA:B:C $1\\n\\tAA:BB:CC $123" ~:
2955 ((Format.Ledger.Write.show False $
2956 Format.Ledger.Write.transaction $
2957 Transaction.nil
2958 { Transaction.dates=
2959 ( Time.ZonedTime
2960 (Time.LocalTime
2961 (Time.fromGregorian 2000 01 01)
2962 (Time.TimeOfDay 0 0 0))
2963 (Time.utc)
2964 , [] )
2965 , Transaction.description="some description"
2966 , Transaction.postings = Posting.from_List
2967 [ (Posting.nil ("A":|["B", "C"]))
2968 { Posting.amounts = Data.Map.fromList
2969 [ ("$", Amount.nil
2970 { Amount.quantity = 1
2971 , Amount.style = Amount.Style.nil
2972 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2973 , Amount.Style.unit_spaced = Just False
2974 }
2975 , Amount.unit = "$"
2976 })
2977 ]
2978 }
2979 , (Posting.nil ("AA":|["BB", "CC"]))
2980 { Posting.amounts = Data.Map.fromList
2981 [ ("$", Amount.nil
2982 { Amount.quantity = 123
2983 , Amount.style = Amount.Style.nil
2984 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2985 , Amount.Style.unit_spaced = Just False
2986 }
2987 , Amount.unit = "$"
2988 })
2989 ]
2990 }
2991 ]
2992 })
2993 ~?=
2994 "2000/01/01 some description\n\tA:B:C $1\n\tAA:BB:CC $123")
2995 ]
2996 ]
2997 ]
2998 ]
2999 ]