1 {-# LANGUAGE TupleSections #-}
2 {-# LANGUAGE OverloadedStrings #-}
6 import Test.Framework.Providers.HUnit (hUnitTestToTests)
7 import Test.Framework.Runners.Console (defaultMain)
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
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
35 --instance Eq Text.Parsec.ParseError where
36 -- (==) = const (const False)
39 main = defaultMain $ hUnitTestToTests test_Hcompta
45 [ "TreeMap" ~: TestList
46 [ "insert" ~: TestList
48 (Lib.TreeMap.insert const ((0::Int):|[]) () Lib.TreeMap.empty)
50 (Lib.TreeMap.TreeMap $
52 [ ((0::Int), Lib.TreeMap.leaf ())
55 (Lib.TreeMap.insert const ((0::Int):|1:[]) () Lib.TreeMap.empty)
57 (Lib.TreeMap.TreeMap $
59 [ ((0::Int), Lib.TreeMap.Node
60 { Lib.TreeMap.node_value = Nothing
61 , Lib.TreeMap.node_size = 1
62 , Lib.TreeMap.node_descendants =
63 Lib.TreeMap.singleton ((1::Int):|[]) ()
70 , "map_by_depth_first" ~: TestList
73 , "flatten" ~: TestList
74 [ "[0, 0/1, 0/1/2]" ~:
75 (Lib.TreeMap.flatten id $
76 Lib.TreeMap.from_List const
88 , "[1, 1/2, 1/22, 1/2/3, 1/2/33, 11, 11/2, 11/2/3, 11/2/33]" ~:
89 (Lib.TreeMap.flatten id $
90 Lib.TreeMap.from_List const
112 , ((11:|2:33:[]), ())
117 , "Model" ~: TestList
118 [ "Account" ~: TestList
119 [ "foldr" ~: TestList
121 (reverse $ Account.foldr ("A":|[]) (:) []) ~?= ["A":|[]]
123 (reverse $ Account.foldr ("A":|["B"]) (:) []) ~?= ["A":|[], "A":|["B"]]
125 (reverse $ Account.foldr ("A":|["B", "C"]) (:) []) ~?= ["A":|[], "A":|["B"], "A":|["B", "C"]]
127 , "ascending" ~: TestList
129 Account.ascending ("A":|[]) ~?= Nothing
131 Account.ascending ("A":|["B"]) ~?= Just ("A":|[])
133 Account.ascending ("A":|["B", "C"]) ~?= Just ("A":|["B"])
136 , "Amount" ~: TestList
141 { Amount.quantity = Decimal 0 1
142 , Amount.style = Amount.Style.nil
143 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
148 { Amount.quantity = Decimal 0 1
149 , Amount.style = Amount.Style.nil
150 { Amount.Style.unit_side = Just $ Amount.Style.Side_Right
156 { Amount.quantity = Decimal 0 2
157 , Amount.style = Amount.Style.nil
158 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
163 , "from_List" ~: TestList
164 [ "from_List [$1, 1$] = $2" ~:
167 { Amount.quantity = Decimal 0 1
168 , Amount.style = Amount.Style.nil
169 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
174 { Amount.quantity = Decimal 0 1
175 , Amount.style = Amount.Style.nil
176 { Amount.Style.unit_side = Just $ Amount.Style.Side_Right
184 { Amount.quantity = Decimal 0 2
185 , Amount.style = Amount.Style.nil
186 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
195 [ "Balance" ~: TestList
196 [ "posting" ~: TestList
197 [ "[A+$1] = A+$1 & $+1" ~:
198 (Calc.Balance.posting
199 (Posting.nil ("A":|[]))
200 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
205 { Calc.Balance.by_account =
206 Lib.TreeMap.from_List const
207 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
208 , Calc.Balance.by_unit =
210 Data.List.map Calc.Balance.assoc_unit_sum $
211 [ Calc.Balance.Unit_Sum
212 { Calc.Balance.amount = Amount.usd $ 1
213 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
218 , "[A+$1, A-$1] = {A+$0, $+0}" ~:
220 (flip Calc.Balance.posting)
222 [ (Posting.nil ("A":|[]))
223 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
225 , (Posting.nil ("A":|[]))
226 { Posting.amounts=Amount.from_List [ Amount.usd $ -1 ]
231 { Calc.Balance.by_account =
232 Lib.TreeMap.from_List const
233 [ ("A":|[], Amount.from_List [ Amount.usd $ 0 ]) ]
234 , Calc.Balance.by_unit =
236 Data.List.map Calc.Balance.assoc_unit_sum $
237 [ Calc.Balance.Unit_Sum
238 { Calc.Balance.amount = Amount.usd $ 0
239 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
244 , "[A+$1, A-€1] = {A+$1-€1, $+1 €-1}" ~:
246 (flip Calc.Balance.posting)
248 [ (Posting.nil ("A":|[]))
249 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
251 , (Posting.nil ("A":|[]))
252 { Posting.amounts=Amount.from_List [ Amount.eur $ -1 ]
257 { Calc.Balance.by_account =
258 Lib.TreeMap.from_List const
259 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ -1 ]) ]
260 , Calc.Balance.by_unit =
262 Data.List.map Calc.Balance.assoc_unit_sum $
263 [ Calc.Balance.Unit_Sum
264 { Calc.Balance.amount = Amount.usd $ 1
265 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
268 , Calc.Balance.Unit_Sum
269 { Calc.Balance.amount = Amount.eur $ -1
270 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
275 , "[A+$1, B-$1] = {A+$1 B-$1, $+0}" ~:
277 (flip Calc.Balance.posting)
279 [ (Posting.nil ("A":|[]))
280 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
282 , (Posting.nil ("B":|[]))
283 { Posting.amounts=Amount.from_List [ Amount.usd $ -1 ]
288 { Calc.Balance.by_account =
289 Lib.TreeMap.from_List const
290 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
291 , ("B":|[], Amount.from_List [ Amount.usd $ -1 ])
293 , Calc.Balance.by_unit =
295 Data.List.map Calc.Balance.assoc_unit_sum $
296 [ Calc.Balance.Unit_Sum
297 { Calc.Balance.amount = Amount.usd $ 0
298 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
305 (flip Calc.Balance.posting)
307 [ (Posting.nil ("A":|[]))
308 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
310 , (Posting.nil ("B":|[]))
311 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ]
316 { Calc.Balance.by_account =
317 Lib.TreeMap.from_List const
318 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
319 , ("B":|[], Amount.from_List [ Amount.usd $ 1 ])
321 , Calc.Balance.by_unit =
323 Data.List.map Calc.Balance.assoc_unit_sum $
324 [ Calc.Balance.Unit_Sum
325 { Calc.Balance.amount = Amount.usd $ 2
326 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
331 , "[A+$1+€2, A-$1-€2] = {A+$0+€0, $+0 €+0}" ~:
333 (flip Calc.Balance.posting)
335 [ (Posting.nil ("A":|[]))
336 { Posting.amounts=Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2 ]
338 , (Posting.nil ("A":|[]))
339 { Posting.amounts=Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2 ]
344 { Calc.Balance.by_account =
345 Lib.TreeMap.from_List const
346 [ ("A":|[], Amount.from_List [ Amount.usd $ 0, Amount.eur $ 0 ])
348 , Calc.Balance.by_unit =
350 Data.List.map Calc.Balance.assoc_unit_sum $
351 [ Calc.Balance.Unit_Sum
352 { Calc.Balance.amount = Amount.usd $ 0
353 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
356 , Calc.Balance.Unit_Sum
357 { Calc.Balance.amount = Amount.eur $ 0
358 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
363 , "[A+$1+€2+£3, B-$1-2€-£3] = {A+$1+€2+£3 B-$1-€2-£3, $+0 €+0 £+0}" ~:
365 (flip Calc.Balance.posting)
367 [ (Posting.nil ("A":|[]))
368 { Posting.amounts=Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ]
370 , (Posting.nil ("B":|[]))
371 { Posting.amounts=Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ]
376 { Calc.Balance.by_account =
377 Lib.TreeMap.from_List const
378 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ])
379 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ])
381 , Calc.Balance.by_unit =
383 Data.List.map Calc.Balance.assoc_unit_sum $
384 [ Calc.Balance.Unit_Sum
385 { Calc.Balance.amount = Amount.usd $ 0
386 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
389 , Calc.Balance.Unit_Sum
390 { Calc.Balance.amount = Amount.eur $ 0
391 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
394 , Calc.Balance.Unit_Sum
395 { Calc.Balance.amount = Amount.gbp $ 0
396 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
402 , "union" ~: TestList
409 , "{A+$1, $+1} {A+$1, $+1} = {A+$2, $+2}" ~:
411 (Calc.Balance.Balance
412 { Calc.Balance.by_account =
413 Lib.TreeMap.from_List const
414 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
415 , Calc.Balance.by_unit =
417 Data.List.map Calc.Balance.assoc_unit_sum $
418 [ Calc.Balance.Unit_Sum
419 { Calc.Balance.amount = Amount.usd $ 1
420 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
425 (Calc.Balance.Balance
426 { Calc.Balance.by_account =
427 Lib.TreeMap.from_List const
428 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
429 , Calc.Balance.by_unit =
431 Data.List.map Calc.Balance.assoc_unit_sum $
432 [ Calc.Balance.Unit_Sum
433 { Calc.Balance.amount = Amount.usd $ 1
434 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
441 { Calc.Balance.by_account =
442 Lib.TreeMap.from_List const
443 [ ("A":|[], Amount.from_List [ Amount.usd $ 2 ]) ]
444 , Calc.Balance.by_unit =
446 Data.List.map Calc.Balance.assoc_unit_sum $
447 [ Calc.Balance.Unit_Sum
448 { Calc.Balance.amount = Amount.usd $ 2
449 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
454 , "{A+$1, $+1} {B+$1, $+1} = {A+$1 B+$1, $+2}" ~:
456 (Calc.Balance.Balance
457 { Calc.Balance.by_account =
458 Lib.TreeMap.from_List const
459 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
460 , Calc.Balance.by_unit =
462 Data.List.map Calc.Balance.assoc_unit_sum $
463 [ Calc.Balance.Unit_Sum
464 { Calc.Balance.amount = Amount.usd $ 1
465 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
470 (Calc.Balance.Balance
471 { Calc.Balance.by_account =
472 Lib.TreeMap.from_List const
473 [ ("B":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
474 , Calc.Balance.by_unit =
476 Data.List.map Calc.Balance.assoc_unit_sum $
477 [ Calc.Balance.Unit_Sum
478 { Calc.Balance.amount = Amount.usd $ 1
479 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
486 { Calc.Balance.by_account =
487 Lib.TreeMap.from_List const
488 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
489 , ("B":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
490 , Calc.Balance.by_unit =
492 Data.List.map Calc.Balance.assoc_unit_sum $
493 [ Calc.Balance.Unit_Sum
494 { Calc.Balance.amount = Amount.usd $ 2
495 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
500 , "{A+$1, $+1} {B+€1, €+1} = {A+$1 B+€1, $+1 €+1}" ~:
502 (Calc.Balance.Balance
503 { Calc.Balance.by_account =
504 Lib.TreeMap.from_List const
505 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
506 , Calc.Balance.by_unit =
508 Data.List.map Calc.Balance.assoc_unit_sum $
509 [ Calc.Balance.Unit_Sum
510 { Calc.Balance.amount = Amount.usd $ 1
511 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
516 (Calc.Balance.Balance
517 { Calc.Balance.by_account =
518 Lib.TreeMap.from_List const
519 [ ("B":|[], Amount.from_List [ Amount.eur $ 1 ]) ]
520 , Calc.Balance.by_unit =
522 Data.List.map Calc.Balance.assoc_unit_sum $
523 [ Calc.Balance.Unit_Sum
524 { Calc.Balance.amount = Amount.eur $ 1
525 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
532 { Calc.Balance.by_account =
533 Lib.TreeMap.from_List const
534 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
535 , ("B":|[], Amount.from_List [ Amount.eur $ 1 ]) ]
536 , Calc.Balance.by_unit =
538 Data.List.map Calc.Balance.assoc_unit_sum $
539 [ Calc.Balance.Unit_Sum
540 { Calc.Balance.amount = Amount.usd $ 1
541 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
544 , Calc.Balance.Unit_Sum
545 { Calc.Balance.amount = Amount.eur $ 1
546 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
552 , "expanded" ~: TestList
553 [ "nil_By_Account" ~:
554 Calc.Balance.expanded
555 Calc.Balance.nil_By_Account
559 Calc.Balance.expanded
560 (Lib.TreeMap.from_List const
561 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ])
563 (Lib.TreeMap.from_List const
564 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
565 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
566 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
569 , "A/A+$1 = A+$1 A/A+$1" ~:
570 Calc.Balance.expanded
571 (Lib.TreeMap.from_List const
572 [ ("A":|["A"], Amount.from_List [ Amount.usd $ 1 ]) ])
574 (Lib.TreeMap.from_List const
575 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
576 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
577 , Calc.Balance.exclusive = Amount.from_List []
579 , ("A":|["A"], Calc.Balance.Account_Sum_Expanded
580 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
581 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
584 , "A/B+$1 = A+$1 A/B+$1" ~:
585 Calc.Balance.expanded
586 (Lib.TreeMap.from_List const
587 [ ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ]) ])
589 (Lib.TreeMap.from_List const
590 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
591 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
592 , Calc.Balance.exclusive = Amount.from_List []
594 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
595 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
596 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
599 , "A/B/C+$1 = A+$1 A/B+$1 A/B/C+$1" ~:
600 Calc.Balance.expanded
601 (Lib.TreeMap.from_List const
602 [ ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ]) ])
604 (Lib.TreeMap.from_List const
605 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
606 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
607 , Calc.Balance.exclusive = Amount.from_List []
609 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
610 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
611 , Calc.Balance.exclusive = Amount.from_List []
613 , ("A":|["B", "C"], Calc.Balance.Account_Sum_Expanded
614 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
615 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
618 , "A+$1 A/B+$1 = A+$2 A/B+$1" ~:
619 Calc.Balance.expanded
620 (Lib.TreeMap.from_List const
621 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
622 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
625 (Lib.TreeMap.from_List const
626 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
627 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 2 ]
628 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
630 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
631 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
632 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
635 , "A+$1 A/B+$1 A/B/C+$1 = A+$3 A/B+$2 A/B/C+$1" ~:
636 Calc.Balance.expanded
637 (Lib.TreeMap.from_List const
638 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
639 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
640 , ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ])
643 (Lib.TreeMap.from_List const
644 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
645 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 3 ]
646 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
648 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
649 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 2 ]
650 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
652 , ("A":|["B", "C"], Calc.Balance.Account_Sum_Expanded
653 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
654 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
657 , "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" ~:
658 Calc.Balance.expanded
659 (Lib.TreeMap.from_List const
660 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
661 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
662 , ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ])
663 , ("A":|["B", "C", "D"], Amount.from_List [ Amount.usd $ 1 ])
666 (Lib.TreeMap.from_List const
667 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
668 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 4 ]
669 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
671 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
672 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 3 ]
673 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
675 , ("A":|["B", "C"], Calc.Balance.Account_Sum_Expanded
676 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 2 ]
677 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
679 , ("A":|["B", "C", "D"], Calc.Balance.Account_Sum_Expanded
680 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
681 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
684 , "A+$1 A/B+$1 A/BB+$1 AA/B+$1 = A+$3 A/B+$1 A/BB+$1 AA+$1 AA/B+$1" ~:
685 Calc.Balance.expanded
686 (Lib.TreeMap.from_List const
687 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
688 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
689 , ("A":|["BB"], Amount.from_List [ Amount.usd $ 1 ])
690 , ("AA":|["B"], Amount.from_List [ Amount.usd $ 1 ])
693 (Lib.TreeMap.from_List const
694 [ ("A":|[], Calc.Balance.Account_Sum_Expanded
695 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 3 ]
696 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
698 , ("A":|["B"], Calc.Balance.Account_Sum_Expanded
699 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
700 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
702 , ("A":|["BB"], Calc.Balance.Account_Sum_Expanded
703 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
704 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
706 , ("AA":|[], Calc.Balance.Account_Sum_Expanded
707 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
708 , Calc.Balance.exclusive = Amount.from_List []
710 , ("AA":|["B"], Calc.Balance.Account_Sum_Expanded
711 { Calc.Balance.inclusive = Amount.from_List [ Amount.usd $ 1 ]
712 , Calc.Balance.exclusive = Amount.from_List [ Amount.usd $ 1 ]
716 , "deviation" ~: TestList
718 (Calc.Balance.deviation $
720 { Calc.Balance.by_account =
721 Lib.TreeMap.from_List const
722 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
723 , ("B":|[], Amount.from_List [])
725 , Calc.Balance.by_unit =
727 Data.List.map Calc.Balance.assoc_unit_sum $
728 [ Calc.Balance.Unit_Sum
729 { Calc.Balance.amount = Amount.usd $ 1
730 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
736 (Calc.Balance.Deviation $
738 Data.List.map Calc.Balance.assoc_unit_sum $
739 [ Calc.Balance.Unit_Sum
740 { Calc.Balance.amount = Amount.usd $ 1
741 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
745 , "{A+$1 B+$1, $2}" ~:
746 (Calc.Balance.deviation $
748 { Calc.Balance.by_account =
749 Lib.TreeMap.from_List const
750 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
751 , ("B":|[], Amount.from_List [ Amount.usd $ 1 ])
753 , Calc.Balance.by_unit =
755 Data.List.map Calc.Balance.assoc_unit_sum $
756 [ Calc.Balance.Unit_Sum
757 { Calc.Balance.amount = Amount.usd $ 2
758 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
766 (Calc.Balance.Deviation $
768 Data.List.map Calc.Balance.assoc_unit_sum $
769 [ Calc.Balance.Unit_Sum
770 { Calc.Balance.amount = Amount.usd $ 2
771 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
777 , "is_equilibrium_inferrable" ~: TestList
778 [ "nil" ~: TestCase $
780 Calc.Balance.is_equilibrium_inferrable $
781 Calc.Balance.deviation $
783 , "{A+$0, $+0}" ~: TestCase $
785 Calc.Balance.is_equilibrium_inferrable $
786 Calc.Balance.deviation $
788 { Calc.Balance.by_account =
789 Lib.TreeMap.from_List const
790 [ ("A":|[], Amount.from_List [ Amount.usd $ 0 ])
792 , Calc.Balance.by_unit =
794 Data.List.map Calc.Balance.assoc_unit_sum $
795 [ Calc.Balance.Unit_Sum
796 { Calc.Balance.amount = Amount.usd $ 0
797 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
802 , "{A+$1, $+1}" ~: TestCase $
804 Calc.Balance.is_equilibrium_inferrable $
805 Calc.Balance.deviation $
807 { Calc.Balance.by_account =
808 Lib.TreeMap.from_List const
809 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
811 , Calc.Balance.by_unit =
813 Data.List.map Calc.Balance.assoc_unit_sum $
814 [ Calc.Balance.Unit_Sum
815 { Calc.Balance.amount = Amount.usd $ 1
816 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
821 , "{A+$0+€0, $0 €+0}" ~: TestCase $
823 Calc.Balance.is_equilibrium_inferrable $
824 Calc.Balance.deviation $
826 { Calc.Balance.by_account =
827 Lib.TreeMap.from_List const
828 [ ("A":|[], Amount.from_List [ Amount.usd $ 0, Amount.eur $ 0 ])
830 , Calc.Balance.by_unit =
832 Data.List.map Calc.Balance.assoc_unit_sum $
833 [ Calc.Balance.Unit_Sum
834 { Calc.Balance.amount = Amount.usd $ 0
835 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
838 , Calc.Balance.Unit_Sum
839 { Calc.Balance.amount = Amount.eur $ 0
840 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
845 , "{A+$1, B-$1, $+0}" ~: TestCase $
847 Calc.Balance.is_equilibrium_inferrable $
848 Calc.Balance.deviation $
850 { Calc.Balance.by_account =
851 Lib.TreeMap.from_List const
852 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
853 , ("B":|[], Amount.from_List [ Amount.usd $ -1 ])
855 , Calc.Balance.by_unit =
857 Data.List.map Calc.Balance.assoc_unit_sum $
858 [ Calc.Balance.Unit_Sum
859 { Calc.Balance.amount = Amount.usd $ 0
860 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
865 , "{A+$1 B, $+1}" ~: TestCase $
867 Calc.Balance.is_equilibrium_inferrable $
868 Calc.Balance.deviation $
870 { Calc.Balance.by_account =
871 Lib.TreeMap.from_List const
872 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
873 , ("B":|[], Amount.from_List [])
875 , Calc.Balance.by_unit =
877 Data.List.map Calc.Balance.assoc_unit_sum $
878 [ Calc.Balance.Unit_Sum
879 { Calc.Balance.amount = Amount.usd $ 1
880 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
885 , "{A+$1 B+€1, $+1 €+1}" ~: TestCase $
887 Calc.Balance.is_equilibrium_inferrable $
888 Calc.Balance.deviation $
890 { Calc.Balance.by_account =
891 Lib.TreeMap.from_List const
892 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
893 , ("B":|[], Amount.from_List [ Amount.eur $ 1 ])
895 , Calc.Balance.by_unit =
897 Data.List.map Calc.Balance.assoc_unit_sum $
898 [ Calc.Balance.Unit_Sum
899 { Calc.Balance.amount = Amount.usd $ 1
900 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
903 , Calc.Balance.Unit_Sum
904 { Calc.Balance.amount = Amount.eur $ 1
905 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
910 , "{A+$1 B-$1+€1, $+0 €+1}" ~: TestCase $
912 Calc.Balance.is_equilibrium_inferrable $
913 Calc.Balance.deviation $
915 { Calc.Balance.by_account =
916 Lib.TreeMap.from_List const
917 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
918 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ 1 ])
920 , Calc.Balance.by_unit =
922 Data.List.map Calc.Balance.assoc_unit_sum $
923 [ Calc.Balance.Unit_Sum
924 { Calc.Balance.amount = Amount.usd $ 0
925 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
928 , Calc.Balance.Unit_Sum
929 { Calc.Balance.amount = Amount.eur $ 1
930 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
935 , "{A+$1+€2+£3 B-$1-€2-£3, $+0 €+0 £+0}" ~: TestCase $
937 Calc.Balance.is_equilibrium_inferrable $
938 Calc.Balance.deviation $
940 { Calc.Balance.by_account =
941 Lib.TreeMap.from_List const
942 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ])
943 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ])
945 , Calc.Balance.by_unit =
947 Data.List.map Calc.Balance.assoc_unit_sum $
948 [ Calc.Balance.Unit_Sum
949 { Calc.Balance.amount = Amount.usd $ 0
950 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
953 , Calc.Balance.Unit_Sum
954 { Calc.Balance.amount = Amount.eur $ 0
955 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
958 , Calc.Balance.Unit_Sum
959 { Calc.Balance.amount = Amount.gbp $ 0
960 , Calc.Balance.accounts = Data.Map.fromList $ Data.List.map (,())
966 , "infer_equilibrium" ~: TestList
968 (snd $ Calc.Balance.infer_equilibrium $
970 [ (Posting.nil ("A":|[]))
971 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ] }
972 , (Posting.nil ("B":|[]))
973 { Posting.amounts=Amount.from_List [] }
978 [ (Posting.nil ("A":|[]))
979 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ] }
980 , (Posting.nil ("B":|[]))
981 { Posting.amounts=Amount.from_List [ Amount.usd $ -1 ] }
984 (snd $ Calc.Balance.infer_equilibrium $
986 [ (Posting.nil ("A":|[]))
987 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ] }
988 , (Posting.nil ("B":|[]))
989 { Posting.amounts=Amount.from_List [ Amount.eur $ -1 ] }
994 [ (Posting.nil ("A":|[]))
995 { Posting.amounts=Amount.from_List [ Amount.eur $ 1 ] }
996 , (Posting.nil ("A":|[]))
997 { Posting.amounts=Amount.from_List [ Amount.usd $ 1] }
998 , (Posting.nil ("B":|[]))
999 { Posting.amounts=Amount.from_List [ Amount.usd $ -1 ] }
1000 , (Posting.nil ("B":|[]))
1001 { Posting.amounts=Amount.from_List [ Amount.eur $ -1 ] }
1004 (snd $ Calc.Balance.infer_equilibrium $
1006 [ (Posting.nil ("A":|[]))
1007 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ] }
1008 , (Posting.nil ("B":|[]))
1009 { Posting.amounts=Amount.from_List [ Amount.usd $ 1 ] }
1013 [ Calc.Balance.Unit_Sum
1014 { Calc.Balance.amount = Amount.usd $ 2
1015 , Calc.Balance.accounts = Data.Map.fromList []}
1020 , "Format" ~: TestList
1021 [ "Ledger" ~: TestList
1022 [ "Read" ~: TestList
1023 [ "account_name" ~: TestList
1025 (Data.Either.rights $
1027 (Format.Ledger.Read.account_name <* P.eof)
1032 (Data.Either.rights $
1034 (Format.Ledger.Read.account_name <* P.eof)
1039 (Data.Either.rights $
1041 (Format.Ledger.Read.account_name <* P.eof)
1042 () "" ("AA"::Text)])
1046 (Data.Either.rights $
1048 (Format.Ledger.Read.account_name <* P.eof)
1053 (Data.Either.rights $
1055 (Format.Ledger.Read.account_name <* P.eof)
1060 (Data.Either.rights $
1062 (Format.Ledger.Read.account_name <* P.eof)
1063 () "" ("A:"::Text)])
1067 (Data.Either.rights $
1069 (Format.Ledger.Read.account_name <* P.eof)
1070 () "" (":A"::Text)])
1074 (Data.Either.rights $
1076 (Format.Ledger.Read.account_name <* P.eof)
1077 () "" ("A "::Text)])
1081 (Data.Either.rights $
1083 (Format.Ledger.Read.account_name)
1084 () "" ("A "::Text)])
1088 (Data.Either.rights $
1090 (Format.Ledger.Read.account_name <* P.eof)
1091 () "" ("A A"::Text)])
1095 (Data.Either.rights $
1097 (Format.Ledger.Read.account_name <* P.eof)
1098 () "" ("A "::Text)])
1102 (Data.Either.rights $
1104 (Format.Ledger.Read.account_name <* P.eof)
1105 () "" ("A \n"::Text)])
1109 (Data.Either.rights $
1111 (Format.Ledger.Read.account_name <* P.eof)
1112 () "" ("(A)A"::Text)])
1116 (Data.Either.rights $
1118 (Format.Ledger.Read.account_name <* P.eof)
1119 () "" ("( )A"::Text)])
1123 (Data.Either.rights $
1125 (Format.Ledger.Read.account_name <* P.eof)
1126 () "" ("(A) A"::Text)])
1130 (Data.Either.rights $
1132 (Format.Ledger.Read.account_name <* P.eof)
1133 () "" ("[ ]A"::Text)])
1137 (Data.Either.rights $
1139 (Format.Ledger.Read.account_name <* P.eof)
1140 () "" ("(A) "::Text)])
1144 (Data.Either.rights $
1146 (Format.Ledger.Read.account_name <* P.eof)
1147 () "" ("(A)"::Text)])
1151 (Data.Either.rights $
1153 (Format.Ledger.Read.account_name <* P.eof)
1154 () "" ("A(A)"::Text)])
1158 (Data.Either.rights $
1160 (Format.Ledger.Read.account_name <* P.eof)
1161 () "" ("[A]A"::Text)])
1165 (Data.Either.rights $
1167 (Format.Ledger.Read.account_name <* P.eof)
1168 () "" ("[A] A"::Text)])
1172 (Data.Either.rights $
1174 (Format.Ledger.Read.account_name <* P.eof)
1175 () "" ("[A] "::Text)])
1179 (Data.Either.rights $
1181 (Format.Ledger.Read.account_name <* P.eof)
1182 () "" ("[A]"::Text)])
1186 , "account" ~: TestList
1188 (Data.Either.rights $
1190 (Format.Ledger.Read.account <* P.eof)
1195 (Data.Either.rights $
1197 (Format.Ledger.Read.account <* P.eof)
1202 (Data.Either.rights $
1204 (Format.Ledger.Read.account <* P.eof)
1205 () "" ("A:"::Text)])
1209 (Data.Either.rights $
1211 (Format.Ledger.Read.account <* P.eof)
1212 () "" (":A"::Text)])
1216 (Data.Either.rights $
1218 (Format.Ledger.Read.account <* P.eof)
1219 () "" ("A "::Text)])
1223 (Data.Either.rights $
1225 (Format.Ledger.Read.account <* P.eof)
1226 () "" (" A"::Text)])
1230 (Data.Either.rights $
1232 (Format.Ledger.Read.account <* P.eof)
1233 () "" ("A:B"::Text)])
1237 (Data.Either.rights $
1239 (Format.Ledger.Read.account <* P.eof)
1240 () "" ("A:B:C"::Text)])
1243 , "\"Aa:Bbb:Cccc\"" ~:
1244 (Data.Either.rights $
1246 (Format.Ledger.Read.account <* P.eof)
1247 () "" ("Aa:Bbb:Cccc"::Text)])
1249 ["Aa":|["Bbb", "Cccc"]]
1250 , "\"A a : B b b : C c c c\"" ~:
1251 (Data.Either.rights $
1253 (Format.Ledger.Read.account <* P.eof)
1254 () "" ("A a : B b b : C c c c"::Text)])
1256 ["A a ":|[" B b b ", " C c c c"]]
1258 (Data.Either.rights $
1260 (Format.Ledger.Read.account <* P.eof)
1261 () "" ("A: :C"::Text)])
1265 (Data.Either.rights $
1267 (Format.Ledger.Read.account <* P.eof)
1268 () "" ("A::C"::Text)])
1272 (Data.Either.rights $
1274 (Format.Ledger.Read.account <* P.eof)
1275 () "" ("A:B:(C)"::Text)])
1279 , "posting_type" ~: TestList
1281 Format.Ledger.Read.posting_type
1284 (Posting.Type_Regular, "A":|[])
1286 Format.Ledger.Read.posting_type
1289 (Posting.Type_Regular, "(":|[])
1291 Format.Ledger.Read.posting_type
1294 (Posting.Type_Regular, ")":|[])
1296 Format.Ledger.Read.posting_type
1299 (Posting.Type_Regular, "()":|[])
1301 Format.Ledger.Read.posting_type
1304 (Posting.Type_Regular, "( )":|[])
1306 Format.Ledger.Read.posting_type
1309 (Posting.Type_Virtual, "A":|[])
1311 Format.Ledger.Read.posting_type
1314 (Posting.Type_Virtual, "A":|["B", "C"])
1316 Format.Ledger.Read.posting_type
1319 (Posting.Type_Regular, "A":|["B", "C"])
1321 Format.Ledger.Read.posting_type
1324 (Posting.Type_Regular, "(A)":|["B", "C"])
1326 Format.Ledger.Read.posting_type
1329 (Posting.Type_Regular, "A":|["(B)", "C"])
1331 Format.Ledger.Read.posting_type
1334 (Posting.Type_Regular, "A":|["B", "(C)"])
1336 Format.Ledger.Read.posting_type
1339 (Posting.Type_Regular, "[":|[])
1341 Format.Ledger.Read.posting_type
1344 (Posting.Type_Regular, "]":|[])
1346 Format.Ledger.Read.posting_type
1349 (Posting.Type_Regular, "[]":|[])
1351 Format.Ledger.Read.posting_type
1354 (Posting.Type_Regular, "[ ]":|[])
1356 Format.Ledger.Read.posting_type
1359 (Posting.Type_Virtual_Balanced, "A":|[])
1361 Format.Ledger.Read.posting_type
1364 (Posting.Type_Virtual_Balanced, "A":|["B", "C"])
1366 Format.Ledger.Read.posting_type
1369 (Posting.Type_Regular, "A":|["B", "C"])
1371 Format.Ledger.Read.posting_type
1374 (Posting.Type_Regular, "[A]":|["B", "C"])
1376 Format.Ledger.Read.posting_type
1379 (Posting.Type_Regular, "A":|["[B]", "C"])
1381 Format.Ledger.Read.posting_type
1384 (Posting.Type_Regular, "A":|["B", "[C]"])
1386 , "amount" ~: TestList
1388 (Data.Either.rights $
1390 (Format.Ledger.Read.amount <* P.eof)
1394 , "\"0\" = Right 0" ~:
1395 (Data.Either.rights $
1397 (Format.Ledger.Read.amount <* P.eof)
1401 { Amount.quantity = Decimal 0 0
1403 , "\"00\" = Right 0" ~:
1404 (Data.Either.rights $
1406 (Format.Ledger.Read.amount <* P.eof)
1407 () "" ("00"::Text)])
1410 { Amount.quantity = Decimal 0 0
1412 , "\"0.\" = Right 0." ~:
1413 (Data.Either.rights $
1415 (Format.Ledger.Read.amount <* P.eof)
1416 () "" ("0."::Text)])
1419 { Amount.quantity = Decimal 0 0
1422 { Amount.Style.fractioning = Just '.'
1425 , "\".0\" = Right 0.0" ~:
1426 (Data.Either.rights $
1428 (Format.Ledger.Read.amount <* P.eof)
1429 () "" (".0"::Text)])
1432 { Amount.quantity = Decimal 0 0
1435 { Amount.Style.fractioning = Just '.'
1436 , Amount.Style.precision = 1
1439 , "\"0,\" = Right 0," ~:
1440 (Data.Either.rights $
1442 (Format.Ledger.Read.amount <* P.eof)
1443 () "" ("0,"::Text)])
1446 { Amount.quantity = Decimal 0 0
1449 { Amount.Style.fractioning = Just ','
1452 , "\",0\" = Right 0,0" ~:
1453 (Data.Either.rights $
1455 (Format.Ledger.Read.amount <* P.eof)
1456 () "" (",0"::Text)])
1459 { Amount.quantity = Decimal 0 0
1462 { Amount.Style.fractioning = Just ','
1463 , Amount.Style.precision = 1
1466 , "\"0_\" = Left" ~:
1467 (Data.Either.rights $
1469 (Format.Ledger.Read.amount <* P.eof)
1470 () "" ("0_"::Text)])
1473 , "\"_0\" = Left" ~:
1474 (Data.Either.rights $
1476 (Format.Ledger.Read.amount <* P.eof)
1477 () "" ("_0"::Text)])
1480 , "\"0.0\" = Right 0.0" ~:
1481 (Data.Either.rights $
1483 (Format.Ledger.Read.amount <* P.eof)
1484 () "" ("0.0"::Text)])
1487 { Amount.quantity = Decimal 0 0
1490 { Amount.Style.fractioning = Just '.'
1491 , Amount.Style.precision = 1
1494 , "\"00.00\" = Right 0.00" ~:
1495 (Data.Either.rights $
1497 (Format.Ledger.Read.amount <* P.eof)
1498 () "" ("00.00"::Text)])
1501 { Amount.quantity = Decimal 0 0
1504 { Amount.Style.fractioning = Just '.'
1505 , Amount.Style.precision = 2
1508 , "\"0,0\" = Right 0,0" ~:
1509 (Data.Either.rights $
1511 (Format.Ledger.Read.amount <* P.eof)
1512 () "" ("0,0"::Text)])
1515 { Amount.quantity = Decimal 0 0
1518 { Amount.Style.fractioning = Just ','
1519 , Amount.Style.precision = 1
1522 , "\"00,00\" = Right 0,00" ~:
1523 (Data.Either.rights $
1525 (Format.Ledger.Read.amount <* P.eof)
1526 () "" ("00,00"::Text)])
1529 { Amount.quantity = Decimal 0 0
1532 { Amount.Style.fractioning = Just ','
1533 , Amount.Style.precision = 2
1536 , "\"0_0\" = Right 0" ~:
1537 (Data.Either.rights $
1539 (Format.Ledger.Read.amount <* P.eof)
1540 () "" ("0_0"::Text)])
1543 { Amount.quantity = Decimal 0 0
1546 { Amount.Style.fractioning = Nothing
1547 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [1]
1548 , Amount.Style.precision = 0
1551 , "\"00_00\" = Right 0" ~:
1552 (Data.Either.rights $
1554 (Format.Ledger.Read.amount <* P.eof)
1555 () "" ("00_00"::Text)])
1558 { Amount.quantity = Decimal 0 0
1561 { Amount.Style.fractioning = Nothing
1562 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [2]
1563 , Amount.Style.precision = 0
1566 , "\"0,000.00\" = Right 0,000.00" ~:
1567 (Data.Either.rights $
1569 (Format.Ledger.Read.amount <* P.eof)
1570 () "" ("0,000.00"::Text)])
1573 { Amount.quantity = Decimal 0 0
1576 { Amount.Style.fractioning = Just '.'
1577 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
1578 , Amount.Style.precision = 2
1581 , "\"0.000,00\" = Right 0.000,00" ~:
1582 (Data.Either.rights $
1584 (Format.Ledger.Read.amount)
1585 () "" ("0.000,00"::Text)])
1588 { Amount.quantity = Decimal 0 0
1591 { Amount.Style.fractioning = Just ','
1592 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
1593 , Amount.Style.precision = 2
1596 , "\"1,000.00\" = Right 1,000.00" ~:
1597 (Data.Either.rights $
1599 (Format.Ledger.Read.amount <* P.eof)
1600 () "" ("1,000.00"::Text)])
1603 { Amount.quantity = Decimal 0 1000
1606 { Amount.Style.fractioning = Just '.'
1607 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
1608 , Amount.Style.precision = 2
1611 , "\"1.000,00\" = Right 1.000,00" ~:
1612 (Data.Either.rights $
1614 (Format.Ledger.Read.amount)
1615 () "" ("1.000,00"::Text)])
1618 { Amount.quantity = Decimal 0 1000
1621 { Amount.Style.fractioning = Just ','
1622 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
1623 , Amount.Style.precision = 2
1626 , "\"1,000.00.\" = Left" ~:
1627 (Data.Either.rights $
1629 (Format.Ledger.Read.amount)
1630 () "" ("1,000.00."::Text)])
1633 , "\"1.000,00,\" = Left" ~:
1634 (Data.Either.rights $
1636 (Format.Ledger.Read.amount)
1637 () "" ("1.000,00,"::Text)])
1640 , "\"1,000.00_\" = Left" ~:
1641 (Data.Either.rights $
1643 (Format.Ledger.Read.amount)
1644 () "" ("1,000.00_"::Text)])
1647 , "\"12\" = Right 12" ~:
1648 (Data.Either.rights $
1650 (Format.Ledger.Read.amount <* P.eof)
1651 () "" ("123"::Text)])
1654 { Amount.quantity = Decimal 0 123
1656 , "\"1.2\" = Right 1.2" ~:
1657 (Data.Either.rights $
1659 (Format.Ledger.Read.amount <* P.eof)
1660 () "" ("1.2"::Text)])
1663 { Amount.quantity = Decimal 1 12
1666 { Amount.Style.fractioning = Just '.'
1667 , Amount.Style.precision = 1
1670 , "\"1,2\" = Right 1,2" ~:
1671 (Data.Either.rights $
1673 (Format.Ledger.Read.amount <* P.eof)
1674 () "" ("1,2"::Text)])
1677 { Amount.quantity = Decimal 1 12
1680 { Amount.Style.fractioning = Just ','
1681 , Amount.Style.precision = 1
1684 , "\"12.23\" = Right 12.23" ~:
1685 (Data.Either.rights $
1687 (Format.Ledger.Read.amount <* P.eof)
1688 () "" ("12.34"::Text)])
1691 { Amount.quantity = Decimal 2 1234
1694 { Amount.Style.fractioning = Just '.'
1695 , Amount.Style.precision = 2
1698 , "\"12,23\" = Right 12,23" ~:
1699 (Data.Either.rights $
1701 (Format.Ledger.Read.amount <* P.eof)
1702 () "" ("12,34"::Text)])
1705 { Amount.quantity = Decimal 2 1234
1708 { Amount.Style.fractioning = Just ','
1709 , Amount.Style.precision = 2
1712 , "\"1_2\" = Right 1_2" ~:
1713 (Data.Either.rights $
1715 (Format.Ledger.Read.amount <* P.eof)
1716 () "" ("1_2"::Text)])
1719 { Amount.quantity = Decimal 0 12
1722 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [1]
1723 , Amount.Style.precision = 0
1726 , "\"1_23\" = Right 1_23" ~:
1727 (Data.Either.rights $
1729 (Format.Ledger.Read.amount <* P.eof)
1730 () "" ("1_23"::Text)])
1733 { Amount.quantity = Decimal 0 123
1736 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [2]
1737 , Amount.Style.precision = 0
1740 , "\"1_23_456\" = Right 1_23_456" ~:
1741 (Data.Either.rights $
1743 (Format.Ledger.Read.amount <* P.eof)
1744 () "" ("1_23_456"::Text)])
1747 { Amount.quantity = Decimal 0 123456
1750 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [3, 2]
1751 , Amount.Style.precision = 0
1754 , "\"1_23_456.7890_12345_678901\" = Right 1_23_456.7890_12345_678901" ~:
1755 (Data.Either.rights $
1757 (Format.Ledger.Read.amount <* P.eof)
1758 () "" ("1_23_456.7890_12345_678901"::Text)])
1761 { Amount.quantity = Decimal 15 123456789012345678901
1764 { Amount.Style.fractioning = Just '.'
1765 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [3, 2]
1766 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping '_' [4, 5, 6]
1767 , Amount.Style.precision = 15
1770 , "\"123456_78901_2345.678_90_1\" = Right 123456_78901_2345.678_90_1" ~:
1771 (Data.Either.rights $
1773 (Format.Ledger.Read.amount <* P.eof)
1774 () "" ("123456_78901_2345.678_90_1"::Text)])
1777 { Amount.quantity = Decimal 6 123456789012345678901
1780 { Amount.Style.fractioning = Just '.'
1781 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [4, 5, 6]
1782 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping '_' [3, 2]
1783 , Amount.Style.precision = 6
1786 , "\"$1\" = Right $1" ~:
1787 (Data.Either.rights $
1789 (Format.Ledger.Read.amount <* P.eof)
1790 () "" ("$1"::Text)])
1793 { Amount.quantity = Decimal 0 1
1796 { Amount.Style.fractioning = Nothing
1797 , Amount.Style.grouping_integral = Nothing
1798 , Amount.Style.grouping_fractional = Nothing
1799 , Amount.Style.precision = 0
1800 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1801 , Amount.Style.unit_spaced = Just False
1805 , "\"1$\" = Right 1$" ~:
1806 (Data.Either.rights $
1808 (Format.Ledger.Read.amount <* P.eof)
1809 () "" ("1$"::Text)])
1812 { Amount.quantity = Decimal 0 1
1815 { Amount.Style.fractioning = Nothing
1816 , Amount.Style.grouping_integral = Nothing
1817 , Amount.Style.grouping_fractional = Nothing
1818 , Amount.Style.precision = 0
1819 , Amount.Style.unit_side = Just Amount.Style.Side_Right
1820 , Amount.Style.unit_spaced = Just False
1824 , "\"$ 1\" = Right $ 1" ~:
1825 (Data.Either.rights $
1827 (Format.Ledger.Read.amount <* P.eof)
1828 () "" ("$ 1"::Text)])
1831 { Amount.quantity = Decimal 0 1
1834 { Amount.Style.fractioning = Nothing
1835 , Amount.Style.grouping_integral = Nothing
1836 , Amount.Style.grouping_fractional = Nothing
1837 , Amount.Style.precision = 0
1838 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1839 , Amount.Style.unit_spaced = Just True
1843 , "\"1 $\" = Right 1 $" ~:
1844 (Data.Either.rights $
1846 (Format.Ledger.Read.amount <* P.eof)
1847 () "" ("1 $"::Text)])
1850 { Amount.quantity = Decimal 0 1
1853 { Amount.Style.fractioning = Nothing
1854 , Amount.Style.grouping_integral = Nothing
1855 , Amount.Style.grouping_fractional = Nothing
1856 , Amount.Style.precision = 0
1857 , Amount.Style.unit_side = Just Amount.Style.Side_Right
1858 , Amount.Style.unit_spaced = Just True
1862 , "\"-$1\" = Right $-1" ~:
1863 (Data.Either.rights $
1865 (Format.Ledger.Read.amount <* P.eof)
1866 () "" ("-$1"::Text)])
1869 { Amount.quantity = Decimal 0 (-1)
1872 { Amount.Style.fractioning = Nothing
1873 , Amount.Style.grouping_integral = Nothing
1874 , Amount.Style.grouping_fractional = Nothing
1875 , Amount.Style.precision = 0
1876 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1877 , Amount.Style.unit_spaced = Just False
1881 , "\"\\\"4 2\\\"1\" = Right \\\"4 2\\\"1" ~:
1882 (Data.Either.rights $
1884 (Format.Ledger.Read.amount <* P.eof)
1885 () "" ("\"4 2\"1"::Text)])
1888 { Amount.quantity = Decimal 0 1
1891 { Amount.Style.fractioning = Nothing
1892 , Amount.Style.grouping_integral = Nothing
1893 , Amount.Style.grouping_fractional = Nothing
1894 , Amount.Style.precision = 0
1895 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1896 , Amount.Style.unit_spaced = Just False
1898 , Amount.unit = "4 2"
1900 , "\"1\\\"4 2\\\"\" = Right 1\\\"4 2\\\"" ~:
1901 (Data.Either.rights $
1903 (Format.Ledger.Read.amount <* P.eof)
1904 () "" ("1\"4 2\""::Text)])
1907 { Amount.quantity = Decimal 0 1
1910 { Amount.Style.fractioning = Nothing
1911 , Amount.Style.grouping_integral = Nothing
1912 , Amount.Style.grouping_fractional = Nothing
1913 , Amount.Style.precision = 0
1914 , Amount.Style.unit_side = Just Amount.Style.Side_Right
1915 , Amount.Style.unit_spaced = Just False
1917 , Amount.unit = "4 2"
1919 , "\"$1.000,00\" = Right $1.000,00" ~:
1920 (Data.Either.rights $
1922 (Format.Ledger.Read.amount <* P.eof)
1923 () "" ("$1.000,00"::Text)])
1926 { Amount.quantity = Decimal 0 1000
1929 { Amount.Style.fractioning = Just ','
1930 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
1931 , Amount.Style.grouping_fractional = Nothing
1932 , Amount.Style.precision = 2
1933 , Amount.Style.unit_side = Just Amount.Style.Side_Left
1934 , Amount.Style.unit_spaced = Just False
1938 , "\"1.000,00$\" = Right 1.000,00$" ~:
1939 (Data.Either.rights $
1941 (Format.Ledger.Read.amount <* P.eof)
1942 () "" ("1.000,00$"::Text)])
1945 { Amount.quantity = Decimal 0 1000
1948 { Amount.Style.fractioning = Just ','
1949 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
1950 , Amount.Style.grouping_fractional = Nothing
1951 , Amount.Style.precision = 2
1952 , Amount.Style.unit_side = Just Amount.Style.Side_Right
1953 , Amount.Style.unit_spaced = Just False
1958 , "comment" ~: TestList
1959 [ "; some comment = Right \" some comment\"" ~:
1960 (Data.Either.rights $
1962 (Format.Ledger.Read.comment <* P.eof)
1963 () "" ("; some comment"::Text)])
1966 , "; some comment \\n = Right \" some comment \"" ~:
1967 (Data.Either.rights $
1969 (Format.Ledger.Read.comment <* P.newline <* P.eof)
1970 () "" ("; some comment \n"::Text)])
1972 [ " some comment " ]
1973 , "; some comment \\r\\n = Right \" some comment \"" ~:
1974 (Data.Either.rights $
1976 (Format.Ledger.Read.comment <* P.string "\r\n" <* P.eof)
1977 () "" ("; some comment \r\n"::Text)])
1979 [ " some comment " ]
1981 , "comments" ~: TestList
1982 [ "; some comment\\n ; some other comment = Right [\" some comment\", \" some other comment\"]" ~:
1983 (Data.Either.rights $
1985 (Format.Ledger.Read.comments <* P.eof)
1986 () "" ("; some comment\n ; some other comment"::Text)])
1988 [ [" some comment", " some other comment"] ]
1989 , "; some comment \\n = Right \" some comment \"" ~:
1990 (Data.Either.rights $
1992 (Format.Ledger.Read.comments <* P.string "\n" <* P.eof)
1993 () "" ("; some comment \n"::Text)])
1995 [ [" some comment "] ]
1997 , "date" ~: TestList
1999 (Data.Either.rights $
2001 (Format.Ledger.Read.date Nothing <* P.eof)
2002 () "" ("2000/01/01"::Text)])
2006 (Time.fromGregorian 2000 01 01)
2007 (Time.TimeOfDay 0 0 0))
2009 , "2000/01/01 some text" ~:
2010 (Data.Either.rights $
2012 (Format.Ledger.Read.date Nothing)
2013 () "" ("2000/01/01 some text"::Text)])
2017 (Time.fromGregorian 2000 01 01)
2018 (Time.TimeOfDay 0 0 0))
2020 , "2000/01/01 12:34" ~:
2021 (Data.Either.rights $
2023 (Format.Ledger.Read.date Nothing <* P.eof)
2024 () "" ("2000/01/01 12:34"::Text)])
2028 (Time.fromGregorian 2000 01 01)
2029 (Time.TimeOfDay 12 34 0))
2031 , "2000/01/01 12:34:56" ~:
2032 (Data.Either.rights $
2034 (Format.Ledger.Read.date Nothing <* P.eof)
2035 () "" ("2000/01/01 12:34:56"::Text)])
2039 (Time.fromGregorian 2000 01 01)
2040 (Time.TimeOfDay 12 34 56))
2042 , "2000/01/01 12:34 CET" ~:
2043 (Data.Either.rights $
2045 (Format.Ledger.Read.date Nothing <* P.eof)
2046 () "" ("2000/01/01 12:34 CET"::Text)])
2050 (Time.fromGregorian 2000 01 01)
2051 (Time.TimeOfDay 12 34 0))
2052 (Time.TimeZone 60 True "CET")]
2053 , "2000/01/01 12:34 +0130" ~:
2054 (Data.Either.rights $
2056 (Format.Ledger.Read.date Nothing <* P.eof)
2057 () "" ("2000/01/01 12:34 +0130"::Text)])
2061 (Time.fromGregorian 2000 01 01)
2062 (Time.TimeOfDay 12 34 0))
2063 (Time.TimeZone 90 False "+0130")]
2064 , "2000/01/01 12:34:56 CET" ~:
2065 (Data.Either.rights $
2067 (Format.Ledger.Read.date Nothing <* P.eof)
2068 () "" ("2000/01/01 12:34:56 CET"::Text)])
2072 (Time.fromGregorian 2000 01 01)
2073 (Time.TimeOfDay 12 34 56))
2074 (Time.TimeZone 60 True "CET")]
2076 (Data.Either.rights $
2078 (Format.Ledger.Read.date Nothing <* P.eof)
2079 () "" ("2001/02/29"::Text)])
2083 (Data.Either.rights $
2085 (Format.Ledger.Read.date (Just 2000) <* P.eof)
2086 () "" ("01/01"::Text)])
2090 (Time.fromGregorian 2000 01 01)
2091 (Time.TimeOfDay 0 0 0))
2094 , "tag_value" ~: TestList
2096 (Data.Either.rights $
2098 (Format.Ledger.Read.tag_value <* P.eof)
2103 (Data.Either.rights $
2105 (Format.Ledger.Read.tag_value <* P.char '\n' <* P.eof)
2106 () "" (",\n"::Text)])
2110 (Data.Either.rights $
2112 (Format.Ledger.Read.tag_value <* P.eof)
2113 () "" (",x"::Text)])
2117 (Data.Either.rights $
2119 (Format.Ledger.Read.tag_value <* P.string ",x:" <* P.eof)
2120 () "" (",x:"::Text)])
2124 (Data.Either.rights $
2126 (Format.Ledger.Read.tag_value <* P.string ", n:" <* P.eof)
2127 () "" ("v, v, n:"::Text)])
2133 (Data.Either.rights $
2135 (Format.Ledger.Read.tag <* P.eof)
2136 () "" ("Name:"::Text)])
2140 (Data.Either.rights $
2142 (Format.Ledger.Read.tag <* P.eof)
2143 () "" ("Name:Value"::Text)])
2146 , "Name:Value\\n" ~:
2147 (Data.Either.rights $
2149 (Format.Ledger.Read.tag <* P.string "\n" <* P.eof)
2150 () "" ("Name:Value\n"::Text)])
2154 (Data.Either.rights $
2156 (Format.Ledger.Read.tag <* P.eof)
2157 () "" ("Name:Val ue"::Text)])
2159 [("Name", "Val ue")]
2161 (Data.Either.rights $
2163 (Format.Ledger.Read.tag <* P.eof)
2164 () "" ("Name:,"::Text)])
2168 (Data.Either.rights $
2170 (Format.Ledger.Read.tag <* P.eof)
2171 () "" ("Name:Val,ue"::Text)])
2173 [("Name", "Val,ue")]
2175 (Data.Either.rights $
2177 (Format.Ledger.Read.tag <* P.string ",ue:" <* P.eof)
2178 () "" ("Name:Val,ue:"::Text)])
2182 , "tags" ~: TestList
2184 (Data.Either.rights $
2186 (Format.Ledger.Read.tags <* P.eof)
2187 () "" ("Name:"::Text)])
2194 (Data.Either.rights $
2196 (Format.Ledger.Read.tags <* P.eof)
2197 () "" ("Name:,"::Text)])
2204 (Data.Either.rights $
2206 (Format.Ledger.Read.tags <* P.eof)
2207 () "" ("Name:,Name:"::Text)])
2210 [ ("Name", ["", ""])
2214 (Data.Either.rights $
2216 (Format.Ledger.Read.tags <* P.eof)
2217 () "" ("Name:,Name2:"::Text)])
2224 , "Name: , Name2:" ~:
2225 (Data.Either.rights $
2227 (Format.Ledger.Read.tags <* P.eof)
2228 () "" ("Name: , Name2:"::Text)])
2235 , "Name:,Name2:,Name3:" ~:
2236 (Data.Either.rights $
2238 (Format.Ledger.Read.tags <* P.eof)
2239 () "" ("Name:,Name2:,Name3:"::Text)])
2247 , "Name:Val ue,Name2:V a l u e,Name3:V al ue" ~:
2248 (Data.Either.rights $
2250 (Format.Ledger.Read.tags <* P.eof)
2251 () "" ("Name:Val ue,Name2:V a l u e,Name3:V al ue"::Text)])
2254 [ ("Name", ["Val ue"])
2255 , ("Name2", ["V a l u e"])
2256 , ("Name3", ["V al ue"])
2260 , "posting" ~: TestList
2261 [ " A:B:C = Right A:B:C" ~:
2262 (Data.Either.rights $
2264 (Format.Ledger.Read.posting <* P.eof)
2265 Format.Ledger.Read.nil_Context "" (" A:B:C"::Text)])
2267 [ ( (Posting.nil ("A":|["B", "C"]))
2268 { Posting.sourcepos = P.newPos "" 1 1
2270 , Posting.Type_Regular
2273 , " !A:B:C = Right !A:B:C" ~:
2274 (Data.List.map fst $
2275 Data.Either.rights $
2277 (Format.Ledger.Read.posting <* P.eof)
2278 Format.Ledger.Read.nil_Context "" (" !A:B:C"::Text)])
2280 [ (Posting.nil ("A":|["B", "C"]))
2281 { Posting.sourcepos = P.newPos "" 1 1
2282 , Posting.status = True
2285 , " *A:B:C = Right *A:B:C" ~:
2286 (Data.List.map fst $
2287 Data.Either.rights $
2289 (Format.Ledger.Read.posting <* P.eof)
2290 Format.Ledger.Read.nil_Context "" (" *A:B:C"::Text)])
2292 [ (Posting.nil ("A":|["B", "C"]))
2293 { Posting.amounts = Data.Map.fromList []
2294 , Posting.comments = []
2295 , Posting.dates = []
2296 , Posting.status = True
2297 , Posting.sourcepos = P.newPos "" 1 1
2298 , Posting.tags = Data.Map.fromList []
2301 , " A:B:C $1 = Right A:B:C $1" ~:
2302 (Data.List.map fst $
2303 Data.Either.rights $
2305 (Format.Ledger.Read.posting <* P.eof)
2306 Format.Ledger.Read.nil_Context "" (" A:B:C $1"::Text)])
2308 [ (Posting.nil ("A":|["B","C $1"]))
2309 { Posting.sourcepos = P.newPos "" 1 1
2312 , " A:B:C $1 = Right A:B:C $1" ~:
2313 (Data.List.map fst $
2314 Data.Either.rights $
2316 (Format.Ledger.Read.posting <* P.eof)
2317 Format.Ledger.Read.nil_Context "" (" A:B:C $1"::Text)])
2319 [ (Posting.nil ("A":|["B", "C"]))
2320 { Posting.amounts = Data.Map.fromList
2322 { Amount.quantity = 1
2323 , Amount.style = Amount.Style.nil
2324 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2325 , Amount.Style.unit_spaced = Just False
2330 , Posting.sourcepos = P.newPos "" 1 1
2333 , " A:B:C $1 + 1€ = Right A:B:C $1 + 1€" ~:
2334 (Data.List.map fst $
2335 Data.Either.rights $
2337 (Format.Ledger.Read.posting <* P.eof)
2338 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1€"::Text)])
2340 [ (Posting.nil ("A":|["B", "C"]))
2341 { Posting.amounts = Data.Map.fromList
2343 { Amount.quantity = 1
2344 , Amount.style = Amount.Style.nil
2345 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2346 , Amount.Style.unit_spaced = Just False
2351 { Amount.quantity = 1
2352 , Amount.style = Amount.Style.nil
2353 { Amount.Style.unit_side = Just Amount.Style.Side_Right
2354 , Amount.Style.unit_spaced = Just False
2359 , Posting.sourcepos = P.newPos "" 1 1
2362 , " A:B:C $1 + 1$ = Right A:B:C $2" ~:
2363 (Data.List.map fst $
2364 Data.Either.rights $
2366 (Format.Ledger.Read.posting <* P.eof)
2367 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1$"::Text)])
2369 [ (Posting.nil ("A":|["B", "C"]))
2370 { Posting.amounts = Data.Map.fromList
2372 { Amount.quantity = 2
2373 , Amount.style = Amount.Style.nil
2374 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2375 , Amount.Style.unit_spaced = Just False
2380 , Posting.sourcepos = P.newPos "" 1 1
2383 , " A:B:C $1 + 1$ + 1$ = Right A:B:C $3" ~:
2384 (Data.List.map fst $
2385 Data.Either.rights $
2387 (Format.Ledger.Read.posting <* P.eof)
2388 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1$ + 1$"::Text)])
2390 [ (Posting.nil ("A":|["B", "C"]))
2391 { Posting.amounts = Data.Map.fromList
2393 { Amount.quantity = 3
2394 , Amount.style = Amount.Style.nil
2395 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2396 , Amount.Style.unit_spaced = Just False
2401 , Posting.sourcepos = P.newPos "" 1 1
2404 , " A:B:C ; some comment = Right A:B:C ; some comment" ~:
2405 (Data.List.map fst $
2406 Data.Either.rights $
2408 (Format.Ledger.Read.posting <* P.eof)
2409 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment"::Text)])
2411 [ (Posting.nil ("A":|["B", "C"]))
2412 { Posting.amounts = Data.Map.fromList []
2413 , Posting.comments = [" some comment"]
2414 , Posting.sourcepos = P.newPos "" 1 1
2417 , " A:B:C ; some comment\\n ; some other comment = Right A:B:C ; some comment\\n ; some other comment" ~:
2418 (Data.List.map fst $
2419 Data.Either.rights $
2421 (Format.Ledger.Read.posting <* P.eof)
2422 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment\n ; some other comment"::Text)])
2424 [ (Posting.nil ("A":|["B", "C"]))
2425 { Posting.amounts = Data.Map.fromList []
2426 , Posting.comments = [" some comment", " some other comment"]
2427 , Posting.sourcepos = P.newPos "" 1 1
2430 , " A:B:C $1 ; some comment = Right A:B:C $1 ; some comment" ~:
2431 (Data.List.map fst $
2432 Data.Either.rights $
2434 (Format.Ledger.Read.posting)
2435 Format.Ledger.Read.nil_Context "" (" A:B:C $1 ; some comment"::Text)])
2437 [ (Posting.nil ("A":|["B", "C"]))
2438 { Posting.amounts = Data.Map.fromList
2440 { Amount.quantity = 1
2441 , Amount.style = Amount.Style.nil
2442 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2443 , Amount.Style.unit_spaced = Just False
2448 , Posting.comments = [" some comment"]
2449 , Posting.sourcepos = P.newPos "" 1 1
2452 , " A:B:C ; N:V = Right A:B:C ; N:V" ~:
2453 (Data.List.map fst $
2454 Data.Either.rights $
2456 (Format.Ledger.Read.posting <* P.eof)
2457 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V"::Text)])
2459 [ (Posting.nil ("A":|["B", "C"]))
2460 { Posting.comments = [" N:V"]
2461 , Posting.sourcepos = P.newPos "" 1 1
2462 , Posting.tags = Data.Map.fromList
2467 , " A:B:C ; some comment N:V = Right A:B:C ; some comment N:V" ~:
2468 (Data.List.map fst $
2469 Data.Either.rights $
2471 (Format.Ledger.Read.posting <* P.eof)
2472 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment N:V"::Text)])
2474 [ (Posting.nil ("A":|["B", "C"]))
2475 { Posting.comments = [" some comment N:V"]
2476 , Posting.sourcepos = P.newPos "" 1 1
2477 , Posting.tags = Data.Map.fromList
2482 , " A:B:C ; some comment N:V v, N2:V2 v2 = Right A:B:C ; some comment N:V v, N2:V2 v2" ~:
2483 (Data.List.map fst $
2484 Data.Either.rights $
2486 (Format.Ledger.Read.posting )
2487 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment N:V v, N2:V2 v2"::Text)])
2489 [ (Posting.nil ("A":|["B", "C"]))
2490 { Posting.comments = [" some comment N:V v, N2:V2 v2"]
2491 , Posting.sourcepos = P.newPos "" 1 1
2492 , Posting.tags = Data.Map.fromList
2498 , " A:B:C ; N:V\\n ; N:V2 = Right A:B:C ; N:V\\n ; N:V2" ~:
2499 (Data.List.map fst $
2500 Data.Either.rights $
2502 (Format.Ledger.Read.posting <* P.eof)
2503 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V\n ; N:V2"::Text)])
2505 [ (Posting.nil ("A":|["B", "C"]))
2506 { Posting.comments = [" N:V", " N:V2"]
2507 , Posting.sourcepos = P.newPos "" 1 1
2508 , Posting.tags = Data.Map.fromList
2509 [ ("N", ["V", "V2"])
2513 , " A:B:C ; N:V\\n ; N2:V = Right A:B:C ; N:V\\n ; N2:V" ~:
2514 (Data.List.map fst $
2515 Data.Either.rights $
2517 (Format.Ledger.Read.posting <* P.eof)
2518 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V\n ; N2:V"::Text)])
2520 [ (Posting.nil ("A":|["B", "C"]))
2521 { Posting.comments = [" N:V", " N2:V"]
2522 , Posting.sourcepos = P.newPos "" 1 1
2523 , Posting.tags = Data.Map.fromList
2529 , " A:B:C ; date:2001/01/01 = Right A:B:C ; date:2001/01/01" ~:
2530 (Data.List.map fst $
2531 Data.Either.rights $
2533 (Format.Ledger.Read.posting <* P.eof)
2534 Format.Ledger.Read.nil_Context "" (" A:B:C ; date:2001/01/01"::Text)])
2536 [ (Posting.nil ("A":|["B", "C"]))
2537 { Posting.comments = [" date:2001/01/01"]
2541 (Time.fromGregorian 2001 01 01)
2542 (Time.TimeOfDay 0 0 0))
2545 , Posting.sourcepos = P.newPos "" 1 1
2546 , Posting.tags = Data.Map.fromList
2547 [ ("date", ["2001/01/01"])
2551 , " (A:B:C) = Right (A:B:C)" ~:
2552 (Data.Either.rights $
2554 (Format.Ledger.Read.posting <* P.eof)
2555 Format.Ledger.Read.nil_Context "" (" (A:B:C)"::Text)])
2557 [ ( (Posting.nil ("A":|["B", "C"]))
2558 { Posting.sourcepos = P.newPos "" 1 1
2560 , Posting.Type_Virtual
2563 , " [A:B:C] = Right [A:B:C]" ~:
2564 (Data.Either.rights $
2566 (Format.Ledger.Read.posting <* P.eof)
2567 Format.Ledger.Read.nil_Context "" (" [A:B:C]"::Text)])
2569 [ ( (Posting.nil ("A":|["B", "C"]))
2570 { Posting.sourcepos = P.newPos "" 1 1
2572 , Posting.Type_Virtual_Balanced
2576 , "transaction" ~: TestList
2577 [ "2000/01/01 some description\\n A:B:C $1\\n a:b:c" ~:
2578 (Data.Either.rights $
2580 (Format.Ledger.Read.transaction <* P.eof)
2581 Format.Ledger.Read.nil_Context "" ("2000/01/01 some description\n A:B:C $1\n a:b:c"::Text)])
2584 { Transaction.dates=
2587 (Time.fromGregorian 2000 01 01)
2588 (Time.TimeOfDay 0 0 0))
2591 , Transaction.description="some description"
2592 , Transaction.postings = Posting.from_List
2593 [ (Posting.nil ("A":|["B", "C"]))
2594 { Posting.amounts = Data.Map.fromList
2596 { Amount.quantity = 1
2597 , Amount.style = Amount.Style.nil
2598 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2599 , Amount.Style.unit_spaced = Just False
2604 , Posting.sourcepos = P.newPos "" 2 1
2606 , (Posting.nil ("a":|["b", "c"]))
2607 { Posting.sourcepos = P.newPos "" 3 1
2610 , Transaction.sourcepos = P.newPos "" 1 1
2613 , "2000/01/01 some description\\n A:B:C $1\\n a:b:c\\n" ~:
2614 (Data.Either.rights $
2616 (Format.Ledger.Read.transaction <* P.newline <* P.eof)
2617 Format.Ledger.Read.nil_Context "" ("2000/01/01 some description\n A:B:C $1\n a:b:c\n"::Text)])
2620 { Transaction.dates=
2623 (Time.fromGregorian 2000 01 01)
2624 (Time.TimeOfDay 0 0 0))
2627 , Transaction.description="some description"
2628 , Transaction.postings = Posting.from_List
2629 [ (Posting.nil ("A":|["B", "C"]))
2630 { Posting.amounts = Data.Map.fromList
2632 { Amount.quantity = 1
2633 , Amount.style = Amount.Style.nil
2634 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2635 , Amount.Style.unit_spaced = Just False
2640 , Posting.sourcepos = P.newPos "" 2 1
2642 , (Posting.nil ("a":|["b", "c"]))
2643 { Posting.sourcepos = P.newPos "" 3 1
2646 , Transaction.sourcepos = P.newPos "" 1 1
2649 , "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" ~:
2650 (Data.Either.rights $
2652 (Format.Ledger.Read.transaction <* P.eof)
2653 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)])
2656 { Transaction.comments_after =
2658 , " some other;comment"
2660 , " some last comment"
2662 , Transaction.dates=
2665 (Time.fromGregorian 2000 01 01)
2666 (Time.TimeOfDay 0 0 0))
2669 , Transaction.description="some description"
2670 , Transaction.postings = Posting.from_List
2671 [ (Posting.nil ("A":|["B", "C"]))
2672 { Posting.amounts = Data.Map.fromList
2674 { Amount.quantity = 1
2675 , Amount.style = Amount.Style.nil
2676 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2677 , Amount.Style.unit_spaced = Just False
2682 , Posting.sourcepos = P.newPos "" 5 1
2684 , (Posting.nil ("a":|["b", "c"]))
2685 { Posting.sourcepos = P.newPos "" 6 1
2686 , Posting.tags = Data.Map.fromList []
2689 , Transaction.sourcepos = P.newPos "" 1 1
2690 , Transaction.tags = Data.Map.fromList
2696 , "journal" ~: TestList
2697 [ "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
2700 (Format.Ledger.Read.journal "" {-<* P.eof-})
2701 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)
2703 (\j -> j{Format.Ledger.Journal.last_read_time=
2704 Format.Ledger.Journal.last_read_time Format.Ledger.Journal.nil}) $
2705 Data.Either.rights [jnl])
2707 [ Format.Ledger.Journal.nil
2708 { Format.Ledger.Journal.transactions = Transaction.from_List
2710 { Transaction.dates=
2713 (Time.fromGregorian 2000 01 01)
2714 (Time.TimeOfDay 0 0 0))
2717 , Transaction.description="1° description"
2718 , Transaction.postings = Posting.from_List
2719 [ (Posting.nil ("A":|["B", "C"]))
2720 { Posting.amounts = Data.Map.fromList
2722 { Amount.quantity = 1
2723 , Amount.style = Amount.Style.nil
2724 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2725 , Amount.Style.unit_spaced = Just False
2730 , Posting.sourcepos = P.newPos "" 2 1
2732 , (Posting.nil ("a":|["b", "c"]))
2733 { Posting.sourcepos = P.newPos "" 3 1
2736 , Transaction.sourcepos = P.newPos "" 1 1
2739 { Transaction.dates=
2742 (Time.fromGregorian 2000 01 02)
2743 (Time.TimeOfDay 0 0 0))
2746 , Transaction.description="2° description"
2747 , Transaction.postings = Posting.from_List
2748 [ (Posting.nil ("A":|["B", "C"]))
2749 { Posting.amounts = Data.Map.fromList
2751 { Amount.quantity = 1
2752 , Amount.style = Amount.Style.nil
2753 { Amount.Style.unit_side = Just Amount.Style.Side_Left
2754 , Amount.Style.unit_spaced = Just False
2759 , Posting.sourcepos = P.newPos "" 5 1
2761 , (Posting.nil ("x":|["y", "z"]))
2762 { Posting.sourcepos = P.newPos "" 6 1
2765 , Transaction.sourcepos = P.newPos "" 4 1
2772 , "Write" ~: TestList
2773 [ "account" ~: TestList
2775 ((Format.Ledger.Write.show False $
2776 Format.Ledger.Write.account Posting.Type_Regular $
2781 ((Format.Ledger.Write.show False $
2782 Format.Ledger.Write.account Posting.Type_Regular $
2787 ((Format.Ledger.Write.show False $
2788 Format.Ledger.Write.account Posting.Type_Virtual $
2793 ((Format.Ledger.Write.show False $
2794 Format.Ledger.Write.account Posting.Type_Virtual_Balanced $
2799 , "amount" ~: TestList
2801 ((Format.Ledger.Write.show False $
2802 Format.Ledger.Write.amount
2807 ((Format.Ledger.Write.show False $
2808 Format.Ledger.Write.amount
2810 { Amount.style = Amount.Style.nil
2811 { Amount.Style.precision = 2 }
2816 ((Format.Ledger.Write.show False $
2817 Format.Ledger.Write.amount
2819 { Amount.quantity = Decimal 0 123
2824 ((Format.Ledger.Write.show False $
2825 Format.Ledger.Write.amount
2827 { Amount.quantity = Decimal 0 (- 123)
2831 , "12.3 @ prec=0" ~:
2832 ((Format.Ledger.Write.show False $
2833 Format.Ledger.Write.amount
2835 { Amount.quantity = Decimal 1 123
2836 , Amount.style = Amount.Style.nil
2837 { Amount.Style.fractioning = Just '.'
2842 , "12.5 @ prec=0" ~:
2843 ((Format.Ledger.Write.show False $
2844 Format.Ledger.Write.amount
2846 { Amount.quantity = Decimal 1 125
2847 , Amount.style = Amount.Style.nil
2848 { Amount.Style.fractioning = Just '.'
2853 , "12.3 @ prec=1" ~:
2854 ((Format.Ledger.Write.show False $
2855 Format.Ledger.Write.amount
2857 { Amount.quantity = Decimal 1 123
2858 , Amount.style = Amount.Style.nil
2859 { Amount.Style.fractioning = Just '.'
2860 , Amount.Style.precision = 1
2865 , "1,234.56 @ prec=2" ~:
2866 ((Format.Ledger.Write.show False $
2867 Format.Ledger.Write.amount
2869 { Amount.quantity = Decimal 2 123456
2870 , Amount.style = Amount.Style.nil
2871 { Amount.Style.fractioning = Just '.'
2872 , Amount.Style.precision = 2
2873 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
2878 , "123,456,789,01,2.3456789 @ prec=7" ~:
2879 ((Format.Ledger.Write.show False $
2880 Format.Ledger.Write.amount
2882 { Amount.quantity = Decimal 7 1234567890123456789
2883 , Amount.style = Amount.Style.nil
2884 { Amount.Style.fractioning = Just '.'
2885 , Amount.Style.precision = 7
2886 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [1, 2, 3]
2890 "123,456,789,01,2.3456789")
2891 , "1234567.8,90,123,456,789 @ prec=12" ~:
2892 ((Format.Ledger.Write.show False $
2893 Format.Ledger.Write.amount
2895 { Amount.quantity = Decimal 12 1234567890123456789
2896 , Amount.style = Amount.Style.nil
2897 { Amount.Style.fractioning = Just '.'
2898 , Amount.Style.precision = 12
2899 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [1, 2, 3]
2903 "1234567.8,90,123,456,789")
2904 , "1,2,3,4,5,6,7,89,012.3456789 @ prec=7" ~:
2905 ((Format.Ledger.Write.show False $
2906 Format.Ledger.Write.amount
2908 { Amount.quantity = Decimal 7 1234567890123456789
2909 , Amount.style = Amount.Style.nil
2910 { Amount.Style.fractioning = Just '.'
2911 , Amount.Style.precision = 7
2912 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3, 2, 1]
2916 "1,2,3,4,5,6,7,89,012.3456789")
2917 , "1234567.890,12,3,4,5,6,7,8,9 @ prec=12" ~:
2918 ((Format.Ledger.Write.show False $
2919 Format.Ledger.Write.amount
2921 { Amount.quantity = Decimal 12 1234567890123456789
2922 , Amount.style = Amount.Style.nil
2923 { Amount.Style.fractioning = Just '.'
2924 , Amount.Style.precision = 12
2925 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [3, 2, 1]
2929 "1234567.890,12,3,4,5,6,7,8,9")
2931 , "amount_length" ~: TestList
2933 ((Format.Ledger.Write.amount_length
2938 ((Format.Ledger.Write.amount_length
2940 { Amount.style = Amount.Style.nil
2941 { Amount.Style.precision = 2 }
2946 ((Format.Ledger.Write.amount_length
2948 { Amount.quantity = Decimal 0 123
2953 ((Format.Ledger.Write.amount_length
2955 { Amount.quantity = Decimal 0 (- 123)
2959 , "12.3 @ prec=0" ~:
2960 ((Format.Ledger.Write.amount_length
2962 { Amount.quantity = Decimal 1 123
2963 , Amount.style = Amount.Style.nil
2964 { Amount.Style.fractioning = Just '.'
2969 , "12.5 @ prec=0" ~:
2970 ((Format.Ledger.Write.amount_length
2972 { Amount.quantity = Decimal 1 125
2973 , Amount.style = Amount.Style.nil
2974 { Amount.Style.fractioning = Just '.'
2979 , "12.3 @ prec=1" ~:
2980 ((Format.Ledger.Write.amount_length
2982 { Amount.quantity = Decimal 1 123
2983 , Amount.style = Amount.Style.nil
2984 { Amount.Style.fractioning = Just '.'
2985 , Amount.Style.precision = 1
2990 , "1,234.56 @ prec=2" ~:
2991 ((Format.Ledger.Write.amount_length
2993 { Amount.quantity = Decimal 2 123456
2994 , Amount.style = Amount.Style.nil
2995 { Amount.Style.fractioning = Just '.'
2996 , Amount.Style.precision = 2
2997 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
3002 , "123,456,789,01,2.3456789 @ prec=7" ~:
3003 ((Format.Ledger.Write.amount_length
3005 { Amount.quantity = Decimal 7 1234567890123456789
3006 , Amount.style = Amount.Style.nil
3007 { Amount.Style.fractioning = Just '.'
3008 , Amount.Style.precision = 7
3009 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [1, 2, 3]
3014 , "1234567.8,90,123,456,789 @ prec=12" ~:
3015 ((Format.Ledger.Write.amount_length
3017 { Amount.quantity = Decimal 12 1234567890123456789
3018 , Amount.style = Amount.Style.nil
3019 { Amount.Style.fractioning = Just '.'
3020 , Amount.Style.precision = 12
3021 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [1, 2, 3]
3026 , "1,2,3,4,5,6,7,89,012.3456789 @ prec=7" ~:
3027 ((Format.Ledger.Write.amount_length
3029 { Amount.quantity = Decimal 7 1234567890123456789
3030 , Amount.style = Amount.Style.nil
3031 { Amount.Style.fractioning = Just '.'
3032 , Amount.Style.precision = 7
3033 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3, 2, 1]
3038 , "1234567.890,12,3,4,5,6,7,8,9 @ prec=12" ~:
3039 ((Format.Ledger.Write.amount_length
3041 { Amount.quantity = Decimal 12 1234567890123456789
3042 , Amount.style = Amount.Style.nil
3043 { Amount.Style.fractioning = Just '.'
3044 , Amount.Style.precision = 12
3045 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [3, 2, 1]
3051 , "date" ~: TestList
3053 ((Format.Ledger.Write.show False $
3054 Format.Ledger.Write.date
3058 , "2000/01/01 12:34:51 CET" ~:
3059 (Format.Ledger.Write.show False $
3060 Format.Ledger.Write.date $
3063 (Time.fromGregorian 2000 01 01)
3064 (Time.TimeOfDay 12 34 51))
3065 (Time.TimeZone 60 False "CET"))
3067 "2000/01/01 12:34:51 CET"
3068 , "2000/01/01 12:34:51 +0100" ~:
3069 (Format.Ledger.Write.show False $
3070 Format.Ledger.Write.date $
3073 (Time.fromGregorian 2000 01 01)
3074 (Time.TimeOfDay 12 34 51))
3075 (Time.TimeZone 60 False ""))
3077 "2000/01/01 12:34:51 +0100"
3078 , "2000/01/01 01:02:03" ~:
3079 (Format.Ledger.Write.show False $
3080 Format.Ledger.Write.date $
3083 (Time.fromGregorian 2000 01 01)
3084 (Time.TimeOfDay 1 2 3))
3087 "2000/01/01 01:02:03"
3089 (Format.Ledger.Write.show False $
3090 Format.Ledger.Write.date $
3093 (Time.fromGregorian 0 01 01)
3094 (Time.TimeOfDay 1 2 0))
3099 (Format.Ledger.Write.show False $
3100 Format.Ledger.Write.date $
3103 (Time.fromGregorian 0 01 01)
3104 (Time.TimeOfDay 1 0 0))
3109 (Format.Ledger.Write.show False $
3110 Format.Ledger.Write.date $
3113 (Time.fromGregorian 0 01 01)
3114 (Time.TimeOfDay 0 1 0))
3119 (Format.Ledger.Write.show False $
3120 Format.Ledger.Write.date $
3123 (Time.fromGregorian 0 01 01)
3124 (Time.TimeOfDay 0 0 0))
3129 , "transaction" ~: TestList
3131 ((Format.Ledger.Write.show False $
3132 Format.Ledger.Write.transaction
3136 , "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" ~:
3137 ((Format.Ledger.Write.show False $
3138 Format.Ledger.Write.transaction $
3140 { Transaction.dates=
3143 (Time.fromGregorian 2000 01 01)
3144 (Time.TimeOfDay 0 0 0))
3147 , Transaction.description="some description"
3148 , Transaction.postings = Posting.from_List
3149 [ (Posting.nil ("A":|["B", "C"]))
3150 { Posting.amounts = Data.Map.fromList
3152 { Amount.quantity = 1
3153 , Amount.style = Amount.Style.nil
3154 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3155 , Amount.Style.unit_spaced = Just False
3161 , (Posting.nil ("a":|["b", "c"]))
3162 { Posting.comments = ["first comment","second comment","third comment"]
3167 "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")
3168 , "2000/01/01 some description\\n\\tA:B:C $1\\n\\tAA:BB:CC $123" ~:
3169 ((Format.Ledger.Write.show False $
3170 Format.Ledger.Write.transaction $
3172 { Transaction.dates=
3175 (Time.fromGregorian 2000 01 01)
3176 (Time.TimeOfDay 0 0 0))
3179 , Transaction.description="some description"
3180 , Transaction.postings = Posting.from_List
3181 [ (Posting.nil ("A":|["B", "C"]))
3182 { Posting.amounts = Data.Map.fromList
3184 { Amount.quantity = 1
3185 , Amount.style = Amount.Style.nil
3186 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3187 , Amount.Style.unit_spaced = Just False
3193 , (Posting.nil ("AA":|["BB", "CC"]))
3194 { Posting.amounts = Data.Map.fromList
3196 { Amount.quantity = 123
3197 , Amount.style = Amount.Style.nil
3198 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3199 , Amount.Style.unit_spaced = Just False
3208 "2000/01/01 some description\n\tA:B:C $1\n\tAA:BB:CC $123")