1 {-# LANGUAGE OverloadedStrings #-}
2 {-# LANGUAGE TupleSections #-}
5 import Test.HUnit hiding ((~?))
6 import Test.Framework.Providers.HUnit (hUnitTestToTests)
7 import Test.Framework.Runners.Console (defaultMain)
9 import Control.Applicative ((<*))
10 import Control.Arrow ((***))
11 import Control.Monad.IO.Class (liftIO)
12 import Data.Decimal (DecimalRaw(..))
13 import qualified Data.Either
14 import qualified Data.List
15 import Data.List.NonEmpty (NonEmpty(..))
16 import qualified Data.Map.Strict as Data.Map
17 import Data.Text (Text)
18 import qualified Data.Time.Calendar as Time
19 import qualified Data.Time.LocalTime as Time
20 import qualified Text.Parsec as P hiding (char, space, spaces, string)
21 import qualified Text.Parsec.Pos as P
22 -- import qualified Text.PrettyPrint.Leijen.Text as PP
24 import Hcompta.Account (Account)
25 import qualified Hcompta.Account as Account
26 import Hcompta.Amount (Amount)
27 import qualified Hcompta.Amount as Amount
28 import qualified Hcompta.Amount.Read as Amount.Read
29 import qualified Hcompta.Amount.Write as Amount.Write
30 import qualified Hcompta.Amount.Style as Amount.Style
31 import qualified Hcompta.Balance as Balance
32 import qualified Hcompta.Date as Date
33 import qualified Hcompta.Date.Read as Date.Read
34 import qualified Hcompta.Date.Write as Date.Write
35 import qualified Hcompta.Filter as Filter
36 import qualified Hcompta.Filter.Read as Filter.Read
37 import qualified Hcompta.Format.Ledger as Format.Ledger
38 import qualified Hcompta.Format.Ledger.Read as Format.Ledger.Read
39 import qualified Hcompta.Format.Ledger.Write as Format.Ledger.Write
40 import qualified Hcompta.Lib.Foldable as Lib.Foldable
41 import qualified Hcompta.Lib.Parsec as P
42 import qualified Hcompta.Lib.TreeMap as Lib.TreeMap
45 main = defaultMain $ hUnitTestToTests test_Hcompta
47 (~?) :: String -> Bool -> Test
48 (~?) s b = s ~: (b ~?= True)
54 [ "TreeMap" ~: TestList
55 [ "insert" ~: TestList
57 (Lib.TreeMap.insert const ((0::Int):|[]) () Lib.TreeMap.empty)
59 (Lib.TreeMap.TreeMap $
61 [ ((0::Int), Lib.TreeMap.leaf ())
64 (Lib.TreeMap.insert const ((0::Int):|1:[]) () Lib.TreeMap.empty)
66 (Lib.TreeMap.TreeMap $
68 [ ((0::Int), Lib.TreeMap.Node
69 { Lib.TreeMap.node_value = Nothing
70 , Lib.TreeMap.node_size = 1
71 , Lib.TreeMap.node_descendants =
72 Lib.TreeMap.singleton ((1::Int):|[]) ()
79 , "map_by_depth_first" ~: TestList
82 , "flatten" ~: TestList
83 [ "[0, 0/1, 0/1/2]" ~:
84 (Lib.TreeMap.flatten id $
85 Lib.TreeMap.from_List const
86 [ (((0::Integer):|[]), ())
97 , "[1, 1/2, 1/22, 1/2/3, 1/2/33, 11, 11/2, 11/2/3, 11/2/33]" ~:
98 (Lib.TreeMap.flatten id $
99 Lib.TreeMap.from_List const
108 , ((11:|2:33:[]), ())
113 [ (((1::Integer):|[]), ())
121 , ((11:|2:33:[]), ())
125 , "Foldable" ~: TestList
126 [ "accumLeftsAndFoldrRights" ~: TestList
128 (Lib.Foldable.accumLeftsAndFoldrRights (++) [""] $
131 (([(0::Integer)], [(""::String)]))
133 ((take 1 *** take 0) $
134 Lib.Foldable.accumLeftsAndFoldrRights (++) [""] $
135 ( repeat (Left [0]) ))
137 ([(0::Integer)], ([]::[String]))
138 , "Right:Left:Right:Left" ~:
139 (Lib.Foldable.accumLeftsAndFoldrRights (++) ["0"] $
140 ( Right ["2"]:Left [1]:Right ["1"]:Left [0]:[] ))
142 (([1, 0]::[Integer]), (["2", "1", "0"]::[String]))
143 , "Right:Left:Right:repeat Left" ~:
144 ((take 1 *** take 2) $
145 Lib.Foldable.accumLeftsAndFoldrRights (++) ["0"] $
146 ( Right ["2"]:Left [1]:Right ["1"]:repeat (Left [0]) ))
148 (([1]::[Integer]), (["2", "1"]::[String]))
152 , "Account" ~: TestList
153 [ "foldr" ~: TestList
155 (reverse $ Account.foldr ("A":|[]) (:) []) ~?= ["A":|[]]
157 (reverse $ Account.foldr ("A":|["B"]) (:) []) ~?= ["A":|[], "A":|["B"]]
159 (reverse $ Account.foldr ("A":|["B", "C"]) (:) []) ~?= ["A":|[], "A":|["B"], "A":|["B", "C"]]
161 , "ascending" ~: TestList
163 Account.ascending ("A":|[]) ~?= Nothing
165 Account.ascending ("A":|["B"]) ~?= Just ("A":|[])
167 Account.ascending ("A":|["B", "C"]) ~?= Just ("A":|["B"])
170 , "Amount" ~: TestList
175 { Amount.quantity = Decimal 0 1
176 , Amount.style = Amount.Style.nil
177 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
182 { Amount.quantity = Decimal 0 1
183 , Amount.style = Amount.Style.nil
184 { Amount.Style.unit_side = Just $ Amount.Style.Side_Right
190 { Amount.quantity = Decimal 0 2
191 , Amount.style = Amount.Style.nil
192 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
197 , "from_List" ~: TestList
198 [ "from_List [$1, 1$] = $2" ~:
201 { Amount.quantity = Decimal 0 1
202 , Amount.style = Amount.Style.nil
203 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
208 { Amount.quantity = Decimal 0 1
209 , Amount.style = Amount.Style.nil
210 { Amount.Style.unit_side = Just $ Amount.Style.Side_Right
218 { Amount.quantity = Decimal 0 2
219 , Amount.style = Amount.Style.nil
220 { Amount.Style.unit_side = Just $ Amount.Style.Side_Left
227 [ "amount" ~: TestList
229 (Data.Either.rights $
231 (Amount.Read.amount <* P.eof)
235 , "\"0\" = Right 0" ~:
236 (Data.Either.rights $
238 (Amount.Read.amount <* P.eof)
242 { Amount.quantity = Decimal 0 0
244 , "\"00\" = Right 0" ~:
245 (Data.Either.rights $
247 (Amount.Read.amount <* P.eof)
251 { Amount.quantity = Decimal 0 0
253 , "\"0.\" = Right 0." ~:
254 (Data.Either.rights $
256 (Amount.Read.amount <* P.eof)
260 { Amount.quantity = Decimal 0 0
263 { Amount.Style.fractioning = Just '.'
266 , "\".0\" = Right 0.0" ~:
267 (Data.Either.rights $
269 (Amount.Read.amount <* P.eof)
273 { Amount.quantity = Decimal 0 0
276 { Amount.Style.fractioning = Just '.'
277 , Amount.Style.precision = 1
280 , "\"0,\" = Right 0," ~:
281 (Data.Either.rights $
283 (Amount.Read.amount <* P.eof)
287 { Amount.quantity = Decimal 0 0
290 { Amount.Style.fractioning = Just ','
293 , "\",0\" = Right 0,0" ~:
294 (Data.Either.rights $
296 (Amount.Read.amount <* P.eof)
300 { Amount.quantity = Decimal 0 0
303 { Amount.Style.fractioning = Just ','
304 , Amount.Style.precision = 1
308 (Data.Either.rights $
310 (Amount.Read.amount <* P.eof)
315 (Data.Either.rights $
317 (Amount.Read.amount <* P.eof)
321 , "\"0.0\" = Right 0.0" ~:
322 (Data.Either.rights $
324 (Amount.Read.amount <* P.eof)
325 () "" ("0.0"::Text)])
328 { Amount.quantity = Decimal 0 0
331 { Amount.Style.fractioning = Just '.'
332 , Amount.Style.precision = 1
335 , "\"00.00\" = Right 0.00" ~:
336 (Data.Either.rights $
338 (Amount.Read.amount <* P.eof)
339 () "" ("00.00"::Text)])
342 { Amount.quantity = Decimal 0 0
345 { Amount.Style.fractioning = Just '.'
346 , Amount.Style.precision = 2
349 , "\"0,0\" = Right 0,0" ~:
350 (Data.Either.rights $
352 (Amount.Read.amount <* P.eof)
353 () "" ("0,0"::Text)])
356 { Amount.quantity = Decimal 0 0
359 { Amount.Style.fractioning = Just ','
360 , Amount.Style.precision = 1
363 , "\"00,00\" = Right 0,00" ~:
364 (Data.Either.rights $
366 (Amount.Read.amount <* P.eof)
367 () "" ("00,00"::Text)])
370 { Amount.quantity = Decimal 0 0
373 { Amount.Style.fractioning = Just ','
374 , Amount.Style.precision = 2
377 , "\"0_0\" = Right 0" ~:
378 (Data.Either.rights $
380 (Amount.Read.amount <* P.eof)
381 () "" ("0_0"::Text)])
384 { Amount.quantity = Decimal 0 0
387 { Amount.Style.fractioning = Nothing
388 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [1]
389 , Amount.Style.precision = 0
392 , "\"00_00\" = Right 0" ~:
393 (Data.Either.rights $
395 (Amount.Read.amount <* P.eof)
396 () "" ("00_00"::Text)])
399 { Amount.quantity = Decimal 0 0
402 { Amount.Style.fractioning = Nothing
403 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [2]
404 , Amount.Style.precision = 0
407 , "\"0,000.00\" = Right 0,000.00" ~:
408 (Data.Either.rights $
410 (Amount.Read.amount <* P.eof)
411 () "" ("0,000.00"::Text)])
414 { Amount.quantity = Decimal 0 0
417 { Amount.Style.fractioning = Just '.'
418 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
419 , Amount.Style.precision = 2
422 , "\"0.000,00\" = Right 0.000,00" ~:
423 (Data.Either.rights $
426 () "" ("0.000,00"::Text)])
429 { Amount.quantity = Decimal 0 0
432 { Amount.Style.fractioning = Just ','
433 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
434 , Amount.Style.precision = 2
437 , "\"1,000.00\" = Right 1,000.00" ~:
438 (Data.Either.rights $
440 (Amount.Read.amount <* P.eof)
441 () "" ("1,000.00"::Text)])
444 { Amount.quantity = Decimal 0 1000
447 { Amount.Style.fractioning = Just '.'
448 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
449 , Amount.Style.precision = 2
452 , "\"1.000,00\" = Right 1.000,00" ~:
453 (Data.Either.rights $
456 () "" ("1.000,00"::Text)])
459 { Amount.quantity = Decimal 0 1000
462 { Amount.Style.fractioning = Just ','
463 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
464 , Amount.Style.precision = 2
467 , "\"1,000.00.\" = Left" ~:
468 (Data.Either.rights $
471 () "" ("1,000.00."::Text)])
474 , "\"1.000,00,\" = Left" ~:
475 (Data.Either.rights $
478 () "" ("1.000,00,"::Text)])
481 , "\"1,000.00_\" = Left" ~:
482 (Data.Either.rights $
485 () "" ("1,000.00_"::Text)])
488 , "\"12\" = Right 12" ~:
489 (Data.Either.rights $
491 (Amount.Read.amount <* P.eof)
492 () "" ("123"::Text)])
495 { Amount.quantity = Decimal 0 123
497 , "\"1.2\" = Right 1.2" ~:
498 (Data.Either.rights $
500 (Amount.Read.amount <* P.eof)
501 () "" ("1.2"::Text)])
504 { Amount.quantity = Decimal 1 12
507 { Amount.Style.fractioning = Just '.'
508 , Amount.Style.precision = 1
511 , "\"1,2\" = Right 1,2" ~:
512 (Data.Either.rights $
514 (Amount.Read.amount <* P.eof)
515 () "" ("1,2"::Text)])
518 { Amount.quantity = Decimal 1 12
521 { Amount.Style.fractioning = Just ','
522 , Amount.Style.precision = 1
525 , "\"12.23\" = Right 12.23" ~:
526 (Data.Either.rights $
528 (Amount.Read.amount <* P.eof)
529 () "" ("12.34"::Text)])
532 { Amount.quantity = Decimal 2 1234
535 { Amount.Style.fractioning = Just '.'
536 , Amount.Style.precision = 2
539 , "\"12,23\" = Right 12,23" ~:
540 (Data.Either.rights $
542 (Amount.Read.amount <* P.eof)
543 () "" ("12,34"::Text)])
546 { Amount.quantity = Decimal 2 1234
549 { Amount.Style.fractioning = Just ','
550 , Amount.Style.precision = 2
553 , "\"1_2\" = Right 1_2" ~:
554 (Data.Either.rights $
556 (Amount.Read.amount <* P.eof)
557 () "" ("1_2"::Text)])
560 { Amount.quantity = Decimal 0 12
563 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [1]
564 , Amount.Style.precision = 0
567 , "\"1_23\" = Right 1_23" ~:
568 (Data.Either.rights $
570 (Amount.Read.amount <* P.eof)
571 () "" ("1_23"::Text)])
574 { Amount.quantity = Decimal 0 123
577 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [2]
578 , Amount.Style.precision = 0
581 , "\"1_23_456\" = Right 1_23_456" ~:
582 (Data.Either.rights $
584 (Amount.Read.amount <* P.eof)
585 () "" ("1_23_456"::Text)])
588 { Amount.quantity = Decimal 0 123456
591 { Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [3, 2]
592 , Amount.Style.precision = 0
595 , "\"1_23_456.7890_12345_678901\" = Right 1_23_456.7890_12345_678901" ~:
596 (Data.Either.rights $
598 (Amount.Read.amount <* P.eof)
599 () "" ("1_23_456.7890_12345_678901"::Text)])
602 { Amount.quantity = Decimal 15 123456789012345678901
605 { Amount.Style.fractioning = Just '.'
606 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [3, 2]
607 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping '_' [4, 5, 6]
608 , Amount.Style.precision = 15
611 , "\"123456_78901_2345.678_90_1\" = Right 123456_78901_2345.678_90_1" ~:
612 (Data.Either.rights $
614 (Amount.Read.amount <* P.eof)
615 () "" ("123456_78901_2345.678_90_1"::Text)])
618 { Amount.quantity = Decimal 6 123456789012345678901
621 { Amount.Style.fractioning = Just '.'
622 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '_' [4, 5, 6]
623 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping '_' [3, 2]
624 , Amount.Style.precision = 6
627 , "\"$1\" = Right $1" ~:
628 (Data.Either.rights $
630 (Amount.Read.amount <* P.eof)
634 { Amount.quantity = Decimal 0 1
637 { Amount.Style.fractioning = Nothing
638 , Amount.Style.grouping_integral = Nothing
639 , Amount.Style.grouping_fractional = Nothing
640 , Amount.Style.precision = 0
641 , Amount.Style.unit_side = Just Amount.Style.Side_Left
642 , Amount.Style.unit_spaced = Just False
646 , "\"1$\" = Right 1$" ~:
647 (Data.Either.rights $
649 (Amount.Read.amount <* P.eof)
653 { Amount.quantity = Decimal 0 1
656 { Amount.Style.fractioning = Nothing
657 , Amount.Style.grouping_integral = Nothing
658 , Amount.Style.grouping_fractional = Nothing
659 , Amount.Style.precision = 0
660 , Amount.Style.unit_side = Just Amount.Style.Side_Right
661 , Amount.Style.unit_spaced = Just False
665 , "\"$ 1\" = Right $ 1" ~:
666 (Data.Either.rights $
668 (Amount.Read.amount <* P.eof)
669 () "" ("$ 1"::Text)])
672 { Amount.quantity = Decimal 0 1
675 { Amount.Style.fractioning = Nothing
676 , Amount.Style.grouping_integral = Nothing
677 , Amount.Style.grouping_fractional = Nothing
678 , Amount.Style.precision = 0
679 , Amount.Style.unit_side = Just Amount.Style.Side_Left
680 , Amount.Style.unit_spaced = Just True
684 , "\"1 $\" = Right 1 $" ~:
685 (Data.Either.rights $
687 (Amount.Read.amount <* P.eof)
688 () "" ("1 $"::Text)])
691 { Amount.quantity = Decimal 0 1
694 { Amount.Style.fractioning = Nothing
695 , Amount.Style.grouping_integral = Nothing
696 , Amount.Style.grouping_fractional = Nothing
697 , Amount.Style.precision = 0
698 , Amount.Style.unit_side = Just Amount.Style.Side_Right
699 , Amount.Style.unit_spaced = Just True
703 , "\"-$1\" = Right $-1" ~:
704 (Data.Either.rights $
706 (Amount.Read.amount <* P.eof)
707 () "" ("-$1"::Text)])
710 { Amount.quantity = Decimal 0 (-1)
713 { Amount.Style.fractioning = Nothing
714 , Amount.Style.grouping_integral = Nothing
715 , Amount.Style.grouping_fractional = Nothing
716 , Amount.Style.precision = 0
717 , Amount.Style.unit_side = Just Amount.Style.Side_Left
718 , Amount.Style.unit_spaced = Just False
722 , "\"\\\"4 2\\\"1\" = Right \\\"4 2\\\"1" ~:
723 (Data.Either.rights $
725 (Amount.Read.amount <* P.eof)
726 () "" ("\"4 2\"1"::Text)])
729 { Amount.quantity = Decimal 0 1
732 { Amount.Style.fractioning = Nothing
733 , Amount.Style.grouping_integral = Nothing
734 , Amount.Style.grouping_fractional = Nothing
735 , Amount.Style.precision = 0
736 , Amount.Style.unit_side = Just Amount.Style.Side_Left
737 , Amount.Style.unit_spaced = Just False
739 , Amount.unit = "4 2"
741 , "\"1\\\"4 2\\\"\" = Right 1\\\"4 2\\\"" ~:
742 (Data.Either.rights $
744 (Amount.Read.amount <* P.eof)
745 () "" ("1\"4 2\""::Text)])
748 { Amount.quantity = Decimal 0 1
751 { Amount.Style.fractioning = Nothing
752 , Amount.Style.grouping_integral = Nothing
753 , Amount.Style.grouping_fractional = Nothing
754 , Amount.Style.precision = 0
755 , Amount.Style.unit_side = Just Amount.Style.Side_Right
756 , Amount.Style.unit_spaced = Just False
758 , Amount.unit = "4 2"
760 , "\"$1.000,00\" = Right $1.000,00" ~:
761 (Data.Either.rights $
763 (Amount.Read.amount <* P.eof)
764 () "" ("$1.000,00"::Text)])
767 { Amount.quantity = Decimal 0 1000
770 { Amount.Style.fractioning = Just ','
771 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
772 , Amount.Style.grouping_fractional = Nothing
773 , Amount.Style.precision = 2
774 , Amount.Style.unit_side = Just Amount.Style.Side_Left
775 , Amount.Style.unit_spaced = Just False
779 , "\"1.000,00$\" = Right 1.000,00$" ~:
780 (Data.Either.rights $
782 (Amount.Read.amount <* P.eof)
783 () "" ("1.000,00$"::Text)])
786 { Amount.quantity = Decimal 0 1000
789 { Amount.Style.fractioning = Just ','
790 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping '.' [3]
791 , Amount.Style.grouping_fractional = Nothing
792 , Amount.Style.precision = 2
793 , Amount.Style.unit_side = Just Amount.Style.Side_Right
794 , Amount.Style.unit_spaced = Just False
800 , "Write" ~: TestList
801 [ "amount" ~: TestList
803 ((Format.Ledger.Write.show
804 Format.Ledger.Write.Style
805 { Format.Ledger.Write.style_color=False
806 , Format.Ledger.Write.style_align=True
813 ((Format.Ledger.Write.show
814 Format.Ledger.Write.Style
815 { Format.Ledger.Write.style_color=False
816 , Format.Ledger.Write.style_align=True
820 { Amount.style = Amount.Style.nil
821 { Amount.Style.precision = 2 }
826 ((Format.Ledger.Write.show
827 Format.Ledger.Write.Style
828 { Format.Ledger.Write.style_color=False
829 , Format.Ledger.Write.style_align=True
833 { Amount.quantity = Decimal 0 123
838 ((Format.Ledger.Write.show
839 Format.Ledger.Write.Style
840 { Format.Ledger.Write.style_color=False
841 , Format.Ledger.Write.style_align=True
845 { Amount.quantity = Decimal 0 (- 123)
850 ((Format.Ledger.Write.show
851 Format.Ledger.Write.Style
852 { Format.Ledger.Write.style_color=False
853 , Format.Ledger.Write.style_align=True
857 { Amount.quantity = Decimal 1 123
858 , Amount.style = Amount.Style.nil
859 { Amount.Style.fractioning = Just '.'
865 ((Format.Ledger.Write.show
866 Format.Ledger.Write.Style
867 { Format.Ledger.Write.style_color=False
868 , Format.Ledger.Write.style_align=True
872 { Amount.quantity = Decimal 1 125
873 , Amount.style = Amount.Style.nil
874 { Amount.Style.fractioning = Just '.'
880 ((Format.Ledger.Write.show
881 Format.Ledger.Write.Style
882 { Format.Ledger.Write.style_color=False
883 , Format.Ledger.Write.style_align=True
887 { Amount.quantity = Decimal 1 123
888 , Amount.style = Amount.Style.nil
889 { Amount.Style.fractioning = Just '.'
890 , Amount.Style.precision = 1
895 , "1,234.56 @ prec=2" ~:
896 ((Format.Ledger.Write.show
897 Format.Ledger.Write.Style
898 { Format.Ledger.Write.style_color=False
899 , Format.Ledger.Write.style_align=True
903 { Amount.quantity = Decimal 2 123456
904 , Amount.style = Amount.Style.nil
905 { Amount.Style.fractioning = Just '.'
906 , Amount.Style.precision = 2
907 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
912 , "123,456,789,01,2.3456789 @ prec=7" ~:
913 ((Format.Ledger.Write.show
914 Format.Ledger.Write.Style
915 { Format.Ledger.Write.style_color=False
916 , Format.Ledger.Write.style_align=True
920 { Amount.quantity = Decimal 7 1234567890123456789
921 , Amount.style = Amount.Style.nil
922 { Amount.Style.fractioning = Just '.'
923 , Amount.Style.precision = 7
924 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [1, 2, 3]
928 "123,456,789,01,2.3456789")
929 , "1234567.8,90,123,456,789 @ prec=12" ~:
930 ((Format.Ledger.Write.show
931 Format.Ledger.Write.Style
932 { Format.Ledger.Write.style_color=False
933 , Format.Ledger.Write.style_align=True
937 { Amount.quantity = Decimal 12 1234567890123456789
938 , Amount.style = Amount.Style.nil
939 { Amount.Style.fractioning = Just '.'
940 , Amount.Style.precision = 12
941 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [1, 2, 3]
945 "1234567.8,90,123,456,789")
946 , "1,2,3,4,5,6,7,89,012.3456789 @ prec=7" ~:
947 ((Format.Ledger.Write.show
948 Format.Ledger.Write.Style
949 { Format.Ledger.Write.style_color=False
950 , Format.Ledger.Write.style_align=True
954 { Amount.quantity = Decimal 7 1234567890123456789
955 , Amount.style = Amount.Style.nil
956 { Amount.Style.fractioning = Just '.'
957 , Amount.Style.precision = 7
958 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3, 2, 1]
962 "1,2,3,4,5,6,7,89,012.3456789")
963 , "1234567.890,12,3,4,5,6,7,8,9 @ prec=12" ~:
964 ((Format.Ledger.Write.show
965 Format.Ledger.Write.Style
966 { Format.Ledger.Write.style_color=False
967 , Format.Ledger.Write.style_align=True
971 { Amount.quantity = Decimal 12 1234567890123456789
972 , Amount.style = Amount.Style.nil
973 { Amount.Style.fractioning = Just '.'
974 , Amount.Style.precision = 12
975 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [3, 2, 1]
979 "1234567.890,12,3,4,5,6,7,8,9")
981 , "amount_length" ~: TestList
983 ((Amount.Write.amount_length
988 ((Amount.Write.amount_length
990 { Amount.style = Amount.Style.nil
991 { Amount.Style.precision = 2 }
996 ((Amount.Write.amount_length
998 { Amount.quantity = Decimal 0 123
1003 ((Amount.Write.amount_length
1005 { Amount.quantity = Decimal 0 (- 123)
1009 , "12.3 @ prec=0" ~:
1010 ((Amount.Write.amount_length
1012 { Amount.quantity = Decimal 1 123
1013 , Amount.style = Amount.Style.nil
1014 { Amount.Style.fractioning = Just '.'
1019 , "12.5 @ prec=0" ~:
1020 ((Amount.Write.amount_length
1022 { Amount.quantity = Decimal 1 125
1023 , Amount.style = Amount.Style.nil
1024 { Amount.Style.fractioning = Just '.'
1029 , "12.3 @ prec=1" ~:
1030 ((Amount.Write.amount_length
1032 { Amount.quantity = Decimal 1 123
1033 , Amount.style = Amount.Style.nil
1034 { Amount.Style.fractioning = Just '.'
1035 , Amount.Style.precision = 1
1040 , "1,234.56 @ prec=2" ~:
1041 ((Amount.Write.amount_length
1043 { Amount.quantity = Decimal 2 123456
1044 , Amount.style = Amount.Style.nil
1045 { Amount.Style.fractioning = Just '.'
1046 , Amount.Style.precision = 2
1047 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3]
1052 , "123,456,789,01,2.3456789 @ prec=7" ~:
1053 ((Amount.Write.amount_length
1055 { Amount.quantity = Decimal 7 1234567890123456789
1056 , Amount.style = Amount.Style.nil
1057 { Amount.Style.fractioning = Just '.'
1058 , Amount.Style.precision = 7
1059 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [1, 2, 3]
1064 , "1234567.8,90,123,456,789 @ prec=12" ~:
1065 ((Amount.Write.amount_length
1067 { Amount.quantity = Decimal 12 1234567890123456789
1068 , Amount.style = Amount.Style.nil
1069 { Amount.Style.fractioning = Just '.'
1070 , Amount.Style.precision = 12
1071 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [1, 2, 3]
1076 , "1,2,3,4,5,6,7,89,012.3456789 @ prec=7" ~:
1077 ((Amount.Write.amount_length
1079 { Amount.quantity = Decimal 7 1234567890123456789
1080 , Amount.style = Amount.Style.nil
1081 { Amount.Style.fractioning = Just '.'
1082 , Amount.Style.precision = 7
1083 , Amount.Style.grouping_integral = Just $ Amount.Style.Grouping ',' [3, 2, 1]
1088 , "1234567.890,12,3,4,5,6,7,8,9 @ prec=12" ~:
1089 ((Amount.Write.amount_length
1091 { Amount.quantity = Decimal 12 1234567890123456789
1092 , Amount.style = Amount.Style.nil
1093 { Amount.Style.fractioning = Just '.'
1094 , Amount.Style.precision = 12
1095 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [3, 2, 1]
1100 , "1000000.000,00,0,0,0,0,0,0,0 @ prec=12" ~:
1101 ((Amount.Write.amount_length
1103 { Amount.quantity = Decimal 12 1000000000000000000
1104 , Amount.style = Amount.Style.nil
1105 { Amount.Style.fractioning = Just '.'
1106 , Amount.Style.precision = 12
1107 , Amount.Style.grouping_fractional = Just $ Amount.Style.Grouping ',' [3, 2, 1]
1113 ((Amount.Write.amount_length $
1115 { Amount.quantity = Decimal 0 999
1116 , Amount.style = Amount.Style.nil
1117 { Amount.Style.precision = 0
1122 , "1000 @ prec=0" ~:
1123 ((Amount.Write.amount_length $
1125 { Amount.quantity = Decimal 0 1000
1126 , Amount.style = Amount.Style.nil
1127 { Amount.Style.precision = 0
1132 , "10,00€ @ prec=2" ~:
1133 ((Amount.Write.amount_length $ Amount.eur 10)
1139 , "Date" ~: TestList
1140 [ "Read" ~: TestList
1141 [ "date" ~: TestList
1143 (Data.Either.rights $
1144 [P.runParser_with_Error
1145 (Date.Read.date id Nothing <* P.eof)
1146 () "" ("2000/01/01"::Text)])
1148 [ Time.zonedTimeToUTC $
1151 (Time.fromGregorian 2000 01 01)
1152 (Time.TimeOfDay 0 0 0))
1154 , "2000/01/01 some text" ~:
1155 (Data.Either.rights $
1156 [P.runParser_with_Error
1157 (Date.Read.date id Nothing)
1158 () "" ("2000/01/01 some text"::Text)])
1160 [ Time.zonedTimeToUTC $
1163 (Time.fromGregorian 2000 01 01)
1164 (Time.TimeOfDay 0 0 0))
1166 , "2000/01/01 12:34" ~:
1167 (Data.Either.rights $
1168 [P.runParser_with_Error
1169 (Date.Read.date id Nothing <* P.eof)
1170 () "" ("2000/01/01 12:34"::Text)])
1172 [ Time.zonedTimeToUTC $
1175 (Time.fromGregorian 2000 01 01)
1176 (Time.TimeOfDay 12 34 0))
1178 , "2000/01/01 12:34:56" ~:
1179 (Data.Either.rights $
1180 [P.runParser_with_Error
1181 (Date.Read.date id Nothing <* P.eof)
1182 () "" ("2000/01/01 12:34:56"::Text)])
1184 [ Time.zonedTimeToUTC $
1187 (Time.fromGregorian 2000 01 01)
1188 (Time.TimeOfDay 12 34 56))
1190 , "2000/01/01 12:34 CET" ~:
1191 (Data.Either.rights $
1192 [P.runParser_with_Error
1193 (Date.Read.date id Nothing <* P.eof)
1194 () "" ("2000/01/01 12:34 CET"::Text)])
1196 [ Time.zonedTimeToUTC $
1199 (Time.fromGregorian 2000 01 01)
1200 (Time.TimeOfDay 12 34 0))
1201 (Time.TimeZone 60 True "CET")]
1202 , "2000/01/01 12:34 +0130" ~:
1203 (Data.Either.rights $
1204 [P.runParser_with_Error
1205 (Date.Read.date id Nothing <* P.eof)
1206 () "" ("2000/01/01 12:34 +0130"::Text)])
1208 [ Time.zonedTimeToUTC $
1211 (Time.fromGregorian 2000 01 01)
1212 (Time.TimeOfDay 12 34 0))
1213 (Time.TimeZone 90 False "+0130")]
1214 , "2000/01/01 12:34:56 CET" ~:
1215 (Data.Either.rights $
1216 [P.runParser_with_Error
1217 (Date.Read.date id Nothing <* P.eof)
1218 () "" ("2000/01/01 12:34:56 CET"::Text)])
1220 [ Time.zonedTimeToUTC $
1223 (Time.fromGregorian 2000 01 01)
1224 (Time.TimeOfDay 12 34 56))
1225 (Time.TimeZone 60 True "CET")]
1227 (Data.Either.rights $
1228 [P.runParser_with_Error
1229 (Date.Read.date id Nothing <* P.eof)
1230 () "" ("2001/02/29"::Text)])
1234 (Data.Either.rights $
1235 [P.runParser_with_Error
1236 (Date.Read.date id (Just 2000) <* P.eof)
1237 () "" ("01/01"::Text)])
1239 [ Time.zonedTimeToUTC $
1242 (Time.fromGregorian 2000 01 01)
1243 (Time.TimeOfDay 0 0 0))
1247 , "Write" ~: TestList
1248 [ "date" ~: TestList
1250 ((Format.Ledger.Write.show
1251 Format.Ledger.Write.Style
1252 { Format.Ledger.Write.style_color=False
1253 , Format.Ledger.Write.style_align=True
1259 , "2000/01/01 12:34:51 CET" ~:
1260 (Format.Ledger.Write.show
1261 Format.Ledger.Write.Style
1262 { Format.Ledger.Write.style_color=False
1263 , Format.Ledger.Write.style_align=True
1266 Time.zonedTimeToUTC $
1269 (Time.fromGregorian 2000 01 01)
1270 (Time.TimeOfDay 12 34 51))
1271 (Time.TimeZone 60 False "CET"))
1273 "2000/01/01 11:34:51"
1274 , "2000/01/01 12:34:51 +0100" ~:
1275 (Format.Ledger.Write.show
1276 Format.Ledger.Write.Style
1277 { Format.Ledger.Write.style_color=False
1278 , Format.Ledger.Write.style_align=True
1281 Time.zonedTimeToUTC $
1284 (Time.fromGregorian 2000 01 01)
1285 (Time.TimeOfDay 12 34 51))
1286 (Time.TimeZone 60 False ""))
1288 "2000/01/01 11:34:51"
1289 , "2000/01/01 01:02:03" ~:
1290 (Format.Ledger.Write.show
1291 Format.Ledger.Write.Style
1292 { Format.Ledger.Write.style_color=False
1293 , Format.Ledger.Write.style_align=True
1296 Time.zonedTimeToUTC $
1299 (Time.fromGregorian 2000 01 01)
1300 (Time.TimeOfDay 1 2 3))
1303 "2000/01/01 01:02:03"
1305 (Format.Ledger.Write.show
1306 Format.Ledger.Write.Style
1307 { Format.Ledger.Write.style_color=False
1308 , Format.Ledger.Write.style_align=True
1311 Time.zonedTimeToUTC $
1314 (Time.fromGregorian 0 01 01)
1315 (Time.TimeOfDay 1 2 0))
1320 (Format.Ledger.Write.show
1321 Format.Ledger.Write.Style
1322 { Format.Ledger.Write.style_color=False
1323 , Format.Ledger.Write.style_align=True
1326 Time.zonedTimeToUTC $
1329 (Time.fromGregorian 0 01 01)
1330 (Time.TimeOfDay 1 0 0))
1335 (Format.Ledger.Write.show
1336 Format.Ledger.Write.Style
1337 { Format.Ledger.Write.style_color=False
1338 , Format.Ledger.Write.style_align=True
1341 Time.zonedTimeToUTC $
1344 (Time.fromGregorian 0 01 01)
1345 (Time.TimeOfDay 0 1 0))
1350 (Format.Ledger.Write.show
1351 Format.Ledger.Write.Style
1352 { Format.Ledger.Write.style_color=False
1353 , Format.Ledger.Write.style_align=True
1356 Time.zonedTimeToUTC $
1359 (Time.fromGregorian 0 01 01)
1360 (Time.TimeOfDay 0 0 0))
1367 , "Filter" ~: TestList
1368 [ "test" ~: TestList
1369 [ "Test_Account" ~: TestList
1372 [ Filter.Test_Account_Section_Text
1373 (Filter.Test_Text_Exact "A")
1375 (("A":|[]::Account))
1378 [ Filter.Test_Account_Section_Any
1380 (("A":|[]::Account))
1383 [ Filter.Test_Account_Section_Many
1385 (("A":|[]::Account))
1388 [ Filter.Test_Account_Section_Many
1389 , Filter.Test_Account_Section_Text
1390 (Filter.Test_Text_Exact "A")
1392 (("A":|[]::Account))
1395 [ Filter.Test_Account_Section_Text
1396 (Filter.Test_Text_Exact "A")
1397 , Filter.Test_Account_Section_Many
1399 (("A":|[]::Account))
1402 [ Filter.Test_Account_Section_Text
1403 (Filter.Test_Text_Exact "A")
1404 , Filter.Test_Account_Section_Many
1406 (("A":|"B":[]::Account))
1409 [ Filter.Test_Account_Section_Text
1410 (Filter.Test_Text_Exact "A")
1411 , Filter.Test_Account_Section_Text
1412 (Filter.Test_Text_Exact "B")
1414 (("A":|"B":[]::Account))
1417 [ Filter.Test_Account_Section_Text
1418 (Filter.Test_Text_Exact "A")
1419 , Filter.Test_Account_Section_Many
1420 , Filter.Test_Account_Section_Text
1421 (Filter.Test_Text_Exact "B")
1423 (("A":|"B":[]::Account))
1426 [ Filter.Test_Account_Section_Many
1427 , Filter.Test_Account_Section_Text
1428 (Filter.Test_Text_Exact "B")
1429 , Filter.Test_Account_Section_Many
1431 (("A":|"B":"C":[]::Account))
1434 [ Filter.Test_Account_Section_Many
1435 , Filter.Test_Account_Section_Text
1436 (Filter.Test_Text_Exact "C")
1438 (("A":|"B":"C":[]::Account))
1440 , "Test_Bool" ~: TestList
1443 (Filter.Any::Filter.Test_Bool Filter.Test_Account)
1444 (("A":|[]::Account))
1447 , "Read" ~: TestList
1448 [ "test_account_section" ~: TestList
1450 (Data.Either.rights $
1452 (Filter.Read.test_account <* P.eof)
1455 [ [Filter.Test_Account_Section_Any]
1458 (Data.Either.rights $
1460 (Filter.Read.test_account <* P.eof)
1463 [ [Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")]
1466 (Data.Either.rights $
1468 (Filter.Read.test_account <* P.eof)
1469 () "" ("AA"::Text)])
1471 [ [Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "AA")]
1474 (Data.Either.rights $
1476 (Filter.Read.test_account <* P.eof)
1477 () "" ("::A"::Text)])
1479 [ [ Filter.Test_Account_Section_Many
1480 , Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")
1484 (Data.Either.rights $
1486 (Filter.Read.test_account <* P.eof)
1487 () "" (":A"::Text)])
1489 [ [ Filter.Test_Account_Section_Many
1490 , Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")
1494 (Data.Either.rights $
1496 (Filter.Read.test_account <* P.eof)
1497 () "" ("A:"::Text)])
1499 [ [ Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")
1500 , Filter.Test_Account_Section_Many
1504 (Data.Either.rights $
1506 (Filter.Read.test_account <* P.eof)
1507 () "" ("A::"::Text)])
1509 [ [ Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")
1510 , Filter.Test_Account_Section_Many
1514 (Data.Either.rights $
1516 (Filter.Read.test_account <* P.eof)
1517 () "" ("A:B"::Text)])
1519 [ [ Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")
1520 , Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "B") ]
1523 (Data.Either.rights $
1525 (Filter.Read.test_account <* P.eof)
1526 () "" ("A::B"::Text)])
1528 [ [ Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")
1529 , Filter.Test_Account_Section_Many
1530 , Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "B")
1534 (Data.Either.rights $
1536 (Filter.Read.test_account <* P.eof)
1537 () "" ("A:::B"::Text)])
1539 [ [ Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")
1540 , Filter.Test_Account_Section_Many
1541 , Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "B")
1545 (Data.Either.rights $
1547 (Filter.Read.test_account <* P.char ' ' <* P.eof)
1548 () "" ("A: "::Text)])
1550 [ [ Filter.Test_Account_Section_Text (Filter.Test_Text_Exact "A")
1551 , Filter.Test_Account_Section_Many
1555 , "test_bool" ~: TestList
1557 (Data.Either.rights $
1559 (Filter.Read.test_bool
1560 [ P.char 'E' >> return (return True) ]
1562 () "" ("( E )"::Text)])
1564 [ Filter.And (Filter.Bool True) Filter.Any
1567 (Data.Either.rights $
1569 (Filter.Read.test_bool
1570 [ P.char 'E' >> return (return True) ]
1572 () "" ("( ( E ) )"::Text)])
1574 [ Filter.And (Filter.And (Filter.Bool True) Filter.Any) Filter.Any
1576 , "( E ) & ( E )" ~:
1577 (Data.Either.rights $
1579 (Filter.Read.test_bool
1580 [ P.char 'E' >> return (return True) ]
1582 () "" ("( E ) & ( E )"::Text)])
1585 (Filter.And (Filter.Bool True) Filter.Any)
1586 (Filter.And (Filter.Bool True) Filter.Any)
1588 , "( E ) + ( E )" ~:
1589 (Data.Either.rights $
1591 (Filter.Read.test_bool
1592 [ P.char 'E' >> return (return True) ]
1594 () "" ("( E ) + ( E )"::Text)])
1597 (Filter.And (Filter.Bool True) Filter.Any)
1598 (Filter.And (Filter.Bool True) Filter.Any)
1600 , "( E ) - ( E )" ~:
1601 (Data.Either.rights $
1603 (Filter.Read.test_bool
1604 [ P.char 'E' >> return (return True) ]
1606 () "" ("( E ) - ( E )"::Text)])
1609 (Filter.And (Filter.Bool True) Filter.Any)
1610 (Filter.Not (Filter.And (Filter.Bool True) Filter.Any))
1613 (Data.Either.rights $
1615 (Filter.Read.test_bool
1616 [ P.char 'E' >> return (return True) ]
1618 () "" ("(- E )"::Text)])
1620 [ Filter.And (Filter.Not (Filter.Bool True)) Filter.Any
1625 , "Balance" ~: TestList
1626 [ "balance" ~: TestList
1627 [ "[A+$1] = A+$1 & $+1" ~:
1629 (Format.Ledger.posting ("A":|[]))
1630 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ]
1635 { Balance.balance_by_account =
1636 Lib.TreeMap.from_List const $
1637 Data.List.map (id *** Data.Map.map Amount.sum) $
1638 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
1639 , Balance.balance_by_unit =
1641 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1643 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
1644 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1649 , "[A+$1, A-$1] = {A+$0, $+0}" ~:
1651 (flip Balance.balance)
1653 [ (Format.Ledger.posting ("A":|[]))
1654 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ]
1656 , (Format.Ledger.posting ("A":|[]))
1657 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ -1 ]
1662 { Balance.balance_by_account =
1663 Lib.TreeMap.from_List const $
1665 , Data.Map.fromListWith const $
1666 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance s, s))
1672 , Balance.balance_by_unit =
1674 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1676 { Balance.unit_sum_amount = Amount.Sum_Both
1679 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1684 , "[A+$1, A-€1] = {A+$1-€1, $+1 €-1}" ~:
1686 (flip Balance.balance)
1688 [ (Format.Ledger.posting ("A":|[]))
1689 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ]
1691 , (Format.Ledger.posting ("A":|[]))
1692 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.eur $ -1 ]
1697 { Balance.balance_by_account =
1698 Lib.TreeMap.from_List const $
1699 Data.List.map (id *** Data.Map.map Amount.sum) $
1700 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ -1 ]) ]
1701 , Balance.balance_by_unit =
1703 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1705 { Balance.unit_sum_amount = Amount.Sum_Positive (Amount.usd $ 1)
1706 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1710 { Balance.unit_sum_amount = Amount.Sum_Negative (Amount.eur $ -1)
1711 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1716 , "[A+$1, B-$1] = {A+$1 B-$1, $+0}" ~:
1718 (flip Balance.balance)
1720 [ (Format.Ledger.posting ("A":|[]))
1721 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ]
1723 , (Format.Ledger.posting ("B":|[]))
1724 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ -1 ]
1729 { Balance.balance_by_account =
1730 Lib.TreeMap.from_List const $
1731 Data.List.map (id *** Data.Map.map Amount.sum) $
1732 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
1733 , ("B":|[], Amount.from_List [ Amount.usd $ -1 ])
1735 , Balance.balance_by_unit =
1737 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1739 { Balance.unit_sum_amount = Amount.Sum_Both
1742 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1749 (flip Balance.balance)
1751 [ (Format.Ledger.posting ("A":|[]))
1752 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ]
1754 , (Format.Ledger.posting ("B":|[]))
1755 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ]
1760 { Balance.balance_by_account =
1761 Lib.TreeMap.from_List const $
1762 Data.List.map (id *** Data.Map.map Amount.sum) $
1763 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
1764 , ("B":|[], Amount.from_List [ Amount.usd $ 1 ])
1766 , Balance.balance_by_unit =
1768 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1770 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 2
1771 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1776 , "[A+$1+€2, A-$1-€2] = {A+$0+€0, $+0 €+0}" ~:
1778 (flip Balance.balance)
1780 [ (Format.Ledger.posting ("A":|[]))
1781 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2 ]
1783 , (Format.Ledger.posting ("A":|[]))
1784 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2 ]
1789 { Balance.balance_by_account =
1790 Lib.TreeMap.from_List const $
1792 , Data.Map.fromListWith const $
1793 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance s, s))
1794 [ Amount.Sum_Both (Amount.usd $ -1) (Amount.usd $ 1)
1795 , Amount.Sum_Both (Amount.eur $ -2) (Amount.eur $ 2)
1799 , Balance.balance_by_unit =
1801 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1803 { Balance.unit_sum_amount = Amount.Sum_Both (Amount.usd $ -1) (Amount.usd $ 1)
1804 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1808 { Balance.unit_sum_amount = Amount.Sum_Both (Amount.eur $ -2) (Amount.eur $ 2)
1809 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1814 , "[A+$1+€2+£3, B-$1-2€-£3] = {A+$1+€2+£3 B-$1-€2-£3, $+0 €+0 £+0}" ~:
1816 (flip Balance.balance)
1818 [ (Format.Ledger.posting ("A":|[]))
1819 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ]
1821 , (Format.Ledger.posting ("B":|[]))
1822 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ]
1827 { Balance.balance_by_account =
1828 Lib.TreeMap.from_List const $
1829 Data.List.map (id *** Data.Map.map Amount.sum) $
1830 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ])
1831 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ])
1833 , Balance.balance_by_unit =
1835 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1837 { Balance.unit_sum_amount = Amount.Sum_Both (Amount.usd $ -1) (Amount.usd $ 1)
1838 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1842 { Balance.unit_sum_amount = Amount.Sum_Both (Amount.eur $ -2) (Amount.eur $ 2)
1843 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1847 { Balance.unit_sum_amount = Amount.Sum_Both (Amount.gbp $ -3) (Amount.gbp $ 3)
1848 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1854 , "union" ~: TestList
1855 [ "nil nil = nil" ~:
1856 Balance.union Balance.nil Balance.nil
1858 (Balance.nil::Balance.Balance Amount)
1859 , "{A+$1, $+1} {A+$1, $+1} = {A+$2, $+2}" ~:
1862 { Balance.balance_by_account =
1863 Lib.TreeMap.from_List const $
1864 Data.List.map (id *** Data.Map.map Amount.sum) $
1865 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
1866 , Balance.balance_by_unit =
1868 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1870 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
1871 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1877 { Balance.balance_by_account =
1878 Lib.TreeMap.from_List const $
1879 Data.List.map (id *** Data.Map.map Amount.sum) $
1880 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
1881 , Balance.balance_by_unit =
1883 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1885 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
1886 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1893 { Balance.balance_by_account =
1894 Lib.TreeMap.from_List const $
1895 Data.List.map (id *** Data.Map.map Amount.sum) $
1896 [ ("A":|[], Amount.from_List [ Amount.usd $ 2 ]) ]
1897 , Balance.balance_by_unit =
1899 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1901 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 2
1902 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1907 , "{A+$1, $+1} {B+$1, $+1} = {A+$1 B+$1, $+2}" ~:
1910 { Balance.balance_by_account =
1911 Lib.TreeMap.from_List const $
1912 Data.List.map (id *** Data.Map.map Amount.sum) $
1913 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
1914 , Balance.balance_by_unit =
1916 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1918 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
1919 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1925 { Balance.balance_by_account =
1926 Lib.TreeMap.from_List const $
1927 Data.List.map (id *** Data.Map.map Amount.sum) $
1928 [ ("B":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
1929 , Balance.balance_by_unit =
1931 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1933 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
1934 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1941 { Balance.balance_by_account =
1942 Lib.TreeMap.from_List const $
1943 Data.List.map (id *** Data.Map.map Amount.sum) $
1944 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
1945 , ("B":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
1946 , Balance.balance_by_unit =
1948 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1950 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 2
1951 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1956 , "{A+$1, $+1} {B+€1, €+1} = {A+$1 B+€1, $+1 €+1}" ~:
1959 { Balance.balance_by_account =
1960 Lib.TreeMap.from_List const $
1961 Data.List.map (id *** Data.Map.map Amount.sum) $
1962 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ]
1963 , Balance.balance_by_unit =
1965 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1967 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
1968 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1974 { Balance.balance_by_account =
1975 Lib.TreeMap.from_List const $
1976 Data.List.map (id *** Data.Map.map Amount.sum) $
1977 [ ("B":|[], Amount.from_List [ Amount.eur $ 1 ]) ]
1978 , Balance.balance_by_unit =
1980 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1982 { Balance.unit_sum_amount = Amount.sum $ Amount.eur $ 1
1983 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
1990 { Balance.balance_by_account =
1991 Lib.TreeMap.from_List const $
1992 Data.List.map (id *** Data.Map.map Amount.sum) $
1993 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
1994 , ("B":|[], Amount.from_List [ Amount.eur $ 1 ]) ]
1995 , Balance.balance_by_unit =
1997 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
1999 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
2000 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2004 { Balance.unit_sum_amount = Amount.sum $ Amount.eur $ 1
2005 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2011 , "expanded" ~: TestList
2012 [ "nil_By_Account" ~:
2016 (Lib.TreeMap.empty::Balance.Expanded Amount)
2019 (Lib.TreeMap.from_List const $
2020 Data.List.map (id *** Data.Map.map Amount.sum) $
2021 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ]) ])
2023 (Lib.TreeMap.from_List const $
2024 [ ("A":|[], Balance.Account_Sum_Expanded
2025 { Balance.inclusive =
2026 Data.Map.map Amount.sum $
2027 Amount.from_List [ Amount.usd $ 1 ]
2028 , Balance.exclusive =
2029 Data.Map.map Amount.sum $
2030 Amount.from_List [ Amount.usd $ 1 ]
2033 , "A/A+$1 = A+$1 A/A+$1" ~:
2035 (Lib.TreeMap.from_List const $
2036 Data.List.map (id *** Data.Map.map Amount.sum) $
2037 [ ("A":|["A"], Amount.from_List [ Amount.usd $ 1 ]) ])
2039 (Lib.TreeMap.from_List const
2040 [ ("A":|[], Balance.Account_Sum_Expanded
2041 { Balance.inclusive =
2042 Data.Map.map Amount.sum $
2043 Amount.from_List [ Amount.usd $ 1 ]
2044 , Balance.exclusive =
2045 Data.Map.map Amount.sum $
2048 , ("A":|["A"], Balance.Account_Sum_Expanded
2049 { Balance.inclusive =
2050 Data.Map.map Amount.sum $
2051 Amount.from_List [ Amount.usd $ 1 ]
2052 , Balance.exclusive =
2053 Data.Map.map Amount.sum $
2054 Amount.from_List [ Amount.usd $ 1 ]
2057 , "A/B+$1 = A+$1 A/B+$1" ~:
2059 (Lib.TreeMap.from_List const $
2060 Data.List.map (id *** Data.Map.map Amount.sum) $
2061 [ ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ]) ])
2063 (Lib.TreeMap.from_List const
2064 [ ("A":|[], Balance.Account_Sum_Expanded
2065 { Balance.inclusive =
2066 Data.Map.map Amount.sum $
2067 Amount.from_List [ Amount.usd $ 1 ]
2068 , Balance.exclusive =
2069 Data.Map.map Amount.sum $
2072 , ("A":|["B"], Balance.Account_Sum_Expanded
2073 { Balance.inclusive =
2074 Data.Map.map Amount.sum $
2075 Amount.from_List [ Amount.usd $ 1 ]
2076 , Balance.exclusive =
2077 Data.Map.map Amount.sum $
2078 Amount.from_List [ Amount.usd $ 1 ]
2081 , "A/B/C+$1 = A+$1 A/B+$1 A/B/C+$1" ~:
2083 (Lib.TreeMap.from_List const $
2084 Data.List.map (id *** Data.Map.map Amount.sum) $
2085 [ ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ]) ])
2087 (Lib.TreeMap.from_List const $
2088 [ ("A":|[], Balance.Account_Sum_Expanded
2089 { Balance.inclusive =
2090 Data.Map.map Amount.sum $
2091 Amount.from_List [ Amount.usd $ 1 ]
2092 , Balance.exclusive =
2093 Data.Map.map Amount.sum $
2096 , ("A":|["B"], Balance.Account_Sum_Expanded
2097 { Balance.inclusive =
2098 Data.Map.map Amount.sum $
2099 Amount.from_List [ Amount.usd $ 1 ]
2100 , Balance.exclusive =
2101 Data.Map.map Amount.sum $
2104 , ("A":|["B", "C"], Balance.Account_Sum_Expanded
2105 { Balance.inclusive =
2106 Data.Map.map Amount.sum $
2107 Amount.from_List [ Amount.usd $ 1 ]
2108 , Balance.exclusive =
2109 Data.Map.map Amount.sum $
2110 Amount.from_List [ Amount.usd $ 1 ]
2113 , "A+$1 A/B+$1 = A+$2 A/B+$1" ~:
2115 (Lib.TreeMap.from_List const $
2116 Data.List.map (id *** Data.Map.map Amount.sum) $
2117 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2118 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
2121 (Lib.TreeMap.from_List const
2122 [ ("A":|[], Balance.Account_Sum_Expanded
2123 { Balance.inclusive =
2124 Data.Map.map Amount.sum $
2125 Amount.from_List [ Amount.usd $ 2 ]
2126 , Balance.exclusive =
2127 Data.Map.map Amount.sum $
2128 Amount.from_List [ Amount.usd $ 1 ]
2130 , ("A":|["B"], Balance.Account_Sum_Expanded
2131 { Balance.inclusive =
2132 Data.Map.map Amount.sum $
2133 Amount.from_List [ Amount.usd $ 1 ]
2134 , Balance.exclusive =
2135 Data.Map.map Amount.sum $
2136 Amount.from_List [ Amount.usd $ 1 ]
2139 , "A+$1 A/B+$1 A/B/C+$1 = A+$3 A/B+$2 A/B/C+$1" ~:
2141 (Lib.TreeMap.from_List const $
2142 Data.List.map (id *** Data.Map.map Amount.sum) $
2143 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2144 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
2145 , ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ])
2148 (Lib.TreeMap.from_List const
2149 [ ("A":|[], Balance.Account_Sum_Expanded
2150 { Balance.inclusive =
2151 Data.Map.map Amount.sum $
2152 Amount.from_List [ Amount.usd $ 3 ]
2153 , Balance.exclusive =
2154 Data.Map.map Amount.sum $
2155 Amount.from_List [ Amount.usd $ 1 ]
2157 , ("A":|["B"], Balance.Account_Sum_Expanded
2158 { Balance.inclusive =
2159 Data.Map.map Amount.sum $
2160 Amount.from_List [ Amount.usd $ 2 ]
2161 , Balance.exclusive =
2162 Data.Map.map Amount.sum $
2163 Amount.from_List [ Amount.usd $ 1 ]
2165 , ("A":|["B", "C"], Balance.Account_Sum_Expanded
2166 { Balance.inclusive =
2167 Data.Map.map Amount.sum $
2168 Amount.from_List [ Amount.usd $ 1 ]
2169 , Balance.exclusive =
2170 Data.Map.map Amount.sum $
2171 Amount.from_List [ Amount.usd $ 1 ]
2174 , "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" ~:
2176 (Lib.TreeMap.from_List const $
2177 Data.List.map (id *** Data.Map.map Amount.sum) $
2178 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2179 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
2180 , ("A":|["B", "C"], Amount.from_List [ Amount.usd $ 1 ])
2181 , ("A":|["B", "C", "D"], Amount.from_List [ Amount.usd $ 1 ])
2184 (Lib.TreeMap.from_List const
2185 [ ("A":|[], Balance.Account_Sum_Expanded
2186 { Balance.inclusive =
2187 Data.Map.map Amount.sum $
2188 Amount.from_List [ Amount.usd $ 4 ]
2189 , Balance.exclusive =
2190 Data.Map.map Amount.sum $
2191 Amount.from_List [ Amount.usd $ 1 ]
2193 , ("A":|["B"], Balance.Account_Sum_Expanded
2194 { Balance.inclusive =
2195 Data.Map.map Amount.sum $
2196 Amount.from_List [ Amount.usd $ 3 ]
2197 , Balance.exclusive =
2198 Data.Map.map Amount.sum $
2199 Amount.from_List [ Amount.usd $ 1 ]
2201 , ("A":|["B", "C"], Balance.Account_Sum_Expanded
2202 { Balance.inclusive =
2203 Data.Map.map Amount.sum $
2204 Amount.from_List [ Amount.usd $ 2 ]
2205 , Balance.exclusive =
2206 Data.Map.map Amount.sum $
2207 Amount.from_List [ Amount.usd $ 1 ]
2209 , ("A":|["B", "C", "D"], Balance.Account_Sum_Expanded
2210 { Balance.inclusive =
2211 Data.Map.map Amount.sum $
2212 Amount.from_List [ Amount.usd $ 1 ]
2213 , Balance.exclusive =
2214 Data.Map.map Amount.sum $
2215 Amount.from_List [ Amount.usd $ 1 ]
2218 , "A+$1 A/B+$1 A/BB+$1 AA/B+$1 = A+$3 A/B+$1 A/BB+$1 AA+$1 AA/B+$1" ~:
2220 (Lib.TreeMap.from_List const $
2221 Data.List.map (id *** Data.Map.map Amount.sum) $
2222 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2223 , ("A":|["B"], Amount.from_List [ Amount.usd $ 1 ])
2224 , ("A":|["BB"], Amount.from_List [ Amount.usd $ 1 ])
2225 , ("AA":|["B"], Amount.from_List [ Amount.usd $ 1 ])
2228 (Lib.TreeMap.from_List const
2229 [ ("A":|[], Balance.Account_Sum_Expanded
2230 { Balance.inclusive =
2231 Data.Map.map Amount.sum $
2232 Amount.from_List [ Amount.usd $ 3 ]
2233 , Balance.exclusive =
2234 Data.Map.map Amount.sum $
2235 Amount.from_List [ Amount.usd $ 1 ]
2237 , ("A":|["B"], Balance.Account_Sum_Expanded
2238 { Balance.inclusive =
2239 Data.Map.map Amount.sum $
2240 Amount.from_List [ Amount.usd $ 1 ]
2241 , Balance.exclusive =
2242 Data.Map.map Amount.sum $
2243 Amount.from_List [ Amount.usd $ 1 ]
2245 , ("A":|["BB"], Balance.Account_Sum_Expanded
2246 { Balance.inclusive =
2247 Data.Map.map Amount.sum $
2248 Amount.from_List [ Amount.usd $ 1 ]
2249 , Balance.exclusive =
2250 Data.Map.map Amount.sum $
2251 Amount.from_List [ Amount.usd $ 1 ]
2253 , ("AA":|[], Balance.Account_Sum_Expanded
2254 { Balance.inclusive =
2255 Data.Map.map Amount.sum $
2256 Amount.from_List [ Amount.usd $ 1 ]
2257 , Balance.exclusive =
2258 Data.Map.map Amount.sum $
2261 , ("AA":|["B"], Balance.Account_Sum_Expanded
2262 { Balance.inclusive =
2263 Data.Map.map Amount.sum $
2264 Amount.from_List [ Amount.usd $ 1 ]
2265 , Balance.exclusive =
2266 Data.Map.map Amount.sum $
2267 Amount.from_List [ Amount.usd $ 1 ]
2271 , "deviation" ~: TestList
2273 (Balance.deviation $
2275 { Balance.balance_by_account =
2276 Lib.TreeMap.from_List const $
2277 Data.List.map (id *** Data.Map.map Amount.sum) $
2278 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2279 , ("B":|[], Amount.from_List [])
2281 , Balance.balance_by_unit =
2283 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2285 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
2286 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2292 (Balance.Deviation $
2294 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2296 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
2297 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2301 , "{A+$1 B+$1, $2}" ~:
2302 (Balance.deviation $
2304 { Balance.balance_by_account =
2305 Lib.TreeMap.from_List const $
2306 Data.List.map (id *** Data.Map.map Amount.sum) $
2307 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2308 , ("B":|[], Amount.from_List [ Amount.usd $ 1 ])
2310 , Balance.balance_by_unit =
2312 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2314 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 2
2315 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2323 (Balance.Deviation $
2325 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2327 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 2
2328 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2334 , "is_equilibrium_inferrable" ~: TestList
2335 [ "nil" ~: TestCase $
2337 Balance.is_equilibrium_inferrable $
2339 (Balance.nil::Balance.Balance Amount.Amount)
2340 , "{A+$0, $+0}" ~: TestCase $
2342 Balance.is_equilibrium_inferrable $
2345 { Balance.balance_by_account =
2346 Lib.TreeMap.from_List const $
2347 Data.List.map (id *** Data.Map.map Amount.sum) $
2348 [ ("A":|[], Amount.from_List [ Amount.usd $ 0 ])
2350 , Balance.balance_by_unit =
2352 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2354 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 0
2355 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2360 , "{A+$1, $+1}" ~: TestCase $
2362 Balance.is_equilibrium_inferrable $
2365 { Balance.balance_by_account =
2366 Lib.TreeMap.from_List const $
2367 Data.List.map (id *** Data.Map.map Amount.sum) $
2368 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2370 , Balance.balance_by_unit =
2372 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2374 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
2375 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2380 , "{A+$0+€0, $0 €+0}" ~: TestCase $
2382 Balance.is_equilibrium_inferrable $
2385 { Balance.balance_by_account =
2386 Lib.TreeMap.from_List const $
2387 Data.List.map (id *** Data.Map.map Amount.sum) $
2388 [ ("A":|[], Amount.from_List [ Amount.usd $ 0, Amount.eur $ 0 ])
2390 , Balance.balance_by_unit =
2392 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2394 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 0
2395 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2399 { Balance.unit_sum_amount = Amount.sum $ Amount.eur $ 0
2400 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2405 , "{A+$1, B-$1, $+0}" ~: TestCase $
2407 Balance.is_equilibrium_inferrable $
2410 { Balance.balance_by_account =
2411 Lib.TreeMap.from_List const $
2412 Data.List.map (id *** Data.Map.map Amount.sum) $
2413 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2414 , ("B":|[], Amount.from_List [ Amount.usd $ -1 ])
2416 , Balance.balance_by_unit =
2418 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2420 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 0
2421 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2426 , "{A+$1 B, $+1}" ~: TestCase $
2428 Balance.is_equilibrium_inferrable $
2431 { Balance.balance_by_account =
2432 Lib.TreeMap.from_List const $
2433 Data.List.map (id *** Data.Map.map Amount.sum) $
2434 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2435 , ("B":|[], Amount.from_List [])
2437 , Balance.balance_by_unit =
2439 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2441 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
2442 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2447 , "{A+$1 B+€1, $+1 €+1}" ~: TestCase $
2449 Balance.is_equilibrium_inferrable $
2452 { Balance.balance_by_account =
2453 Lib.TreeMap.from_List const $
2454 Data.List.map (id *** Data.Map.map Amount.sum) $
2455 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2456 , ("B":|[], Amount.from_List [ Amount.eur $ 1 ])
2458 , Balance.balance_by_unit =
2460 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2462 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 1
2463 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2467 { Balance.unit_sum_amount = Amount.sum $ Amount.eur $ 1
2468 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2473 , "{A+$1 B-$1+€1, $+0 €+1}" ~: TestCase $
2475 Balance.is_equilibrium_inferrable $
2478 { Balance.balance_by_account =
2479 Lib.TreeMap.from_List const $
2480 Data.List.map (id *** Data.Map.map Amount.sum) $
2481 [ ("A":|[], Amount.from_List [ Amount.usd $ 1 ])
2482 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ 1 ])
2484 , Balance.balance_by_unit =
2486 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2488 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 0
2489 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2493 { Balance.unit_sum_amount = Amount.sum $ Amount.eur $ 1
2494 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2499 , "{A+$1+€2+£3 B-$1-€2-£3, $+0 €+0 £+0}" ~: TestCase $
2501 Balance.is_equilibrium_inferrable $
2504 { Balance.balance_by_account =
2505 Lib.TreeMap.from_List const $
2506 Data.List.map (id *** Data.Map.map Amount.sum) $
2507 [ ("A":|[], Amount.from_List [ Amount.usd $ 1, Amount.eur $ 2, Amount.gbp $ 3 ])
2508 , ("B":|[], Amount.from_List [ Amount.usd $ -1, Amount.eur $ -2, Amount.gbp $ -3 ])
2510 , Balance.balance_by_unit =
2512 Data.List.map (\s -> (Amount.unit $ Amount.sum_balance $ Balance.unit_sum_amount s, s))
2514 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 0
2515 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2519 { Balance.unit_sum_amount = Amount.sum $ Amount.eur $ 0
2520 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2524 { Balance.unit_sum_amount = Amount.sum $ Amount.gbp $ 0
2525 , Balance.unit_sum_accounts = Data.Map.fromList $ Data.List.map (,())
2531 , "infer_equilibrium" ~: TestList
2533 (snd $ Balance.infer_equilibrium $
2534 Format.Ledger.posting_by_Account
2535 [ (Format.Ledger.posting ("A":|[]))
2536 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ] }
2537 , (Format.Ledger.posting ("B":|[]))
2538 { Format.Ledger.posting_amounts=Amount.from_List [] }
2542 Format.Ledger.posting_by_Account
2543 [ (Format.Ledger.posting ("A":|[]))
2544 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ] }
2545 , (Format.Ledger.posting ("B":|[]))
2546 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ -1 ] }
2549 (snd $ Balance.infer_equilibrium $
2550 Format.Ledger.posting_by_Account
2551 [ (Format.Ledger.posting ("A":|[]))
2552 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ] }
2553 , (Format.Ledger.posting ("B":|[]))
2554 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.eur $ -1 ] }
2558 Format.Ledger.posting_by_Account
2559 [ (Format.Ledger.posting ("A":|[]))
2560 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1, Amount.eur $ 1] }
2561 , (Format.Ledger.posting ("B":|[]))
2562 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.eur $ -1, Amount.usd $ -1 ] }
2565 (snd $ Balance.infer_equilibrium $
2566 Format.Ledger.posting_by_Account
2567 [ (Format.Ledger.posting ("A":|[]))
2568 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ] }
2569 , (Format.Ledger.posting ("B":|[]))
2570 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ] }
2575 { Balance.unit_sum_amount = Amount.sum $ Amount.usd $ 2
2576 , Balance.unit_sum_accounts = Data.Map.fromList []}
2578 , "{A+$1 B-$1 B-1€}" ~:
2579 (snd $ Balance.infer_equilibrium $
2580 Format.Ledger.posting_by_Account
2581 [ (Format.Ledger.posting ("A":|[]))
2582 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1 ] }
2583 , (Format.Ledger.posting ("B":|[]))
2584 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ -1, Amount.eur $ -1 ] }
2588 Format.Ledger.posting_by_Account
2589 [ (Format.Ledger.posting ("A":|[]))
2590 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ 1, Amount.eur $ 1 ] }
2591 , (Format.Ledger.posting ("B":|[]))
2592 { Format.Ledger.posting_amounts=Amount.from_List [ Amount.usd $ -1, Amount.eur $ -1 ] }
2596 , "Format" ~: TestList
2597 [ "Ledger" ~: TestList
2598 [ "Read" ~: TestList
2599 [ "account_name" ~: TestList
2601 (Data.Either.rights $
2603 (Format.Ledger.Read.account_name <* P.eof)
2608 (Data.Either.rights $
2610 (Format.Ledger.Read.account_name <* P.eof)
2615 (Data.Either.rights $
2617 (Format.Ledger.Read.account_name <* P.eof)
2618 () "" ("AA"::Text)])
2622 (Data.Either.rights $
2624 (Format.Ledger.Read.account_name <* P.eof)
2629 (Data.Either.rights $
2631 (Format.Ledger.Read.account_name <* P.eof)
2636 (Data.Either.rights $
2638 (Format.Ledger.Read.account_name <* P.eof)
2639 () "" ("A:"::Text)])
2643 (Data.Either.rights $
2645 (Format.Ledger.Read.account_name <* P.eof)
2646 () "" (":A"::Text)])
2650 (Data.Either.rights $
2652 (Format.Ledger.Read.account_name <* P.eof)
2653 () "" ("A "::Text)])
2657 (Data.Either.rights $
2659 (Format.Ledger.Read.account_name)
2660 () "" ("A "::Text)])
2664 (Data.Either.rights $
2666 (Format.Ledger.Read.account_name <* P.eof)
2667 () "" ("A A"::Text)])
2671 (Data.Either.rights $
2673 (Format.Ledger.Read.account_name <* P.eof)
2674 () "" ("A "::Text)])
2678 (Data.Either.rights $
2680 (Format.Ledger.Read.account_name <* P.eof)
2681 () "" ("A \n"::Text)])
2685 (Data.Either.rights $
2687 (Format.Ledger.Read.account_name <* P.eof)
2688 () "" ("(A)A"::Text)])
2692 (Data.Either.rights $
2694 (Format.Ledger.Read.account_name <* P.eof)
2695 () "" ("( )A"::Text)])
2699 (Data.Either.rights $
2701 (Format.Ledger.Read.account_name <* P.eof)
2702 () "" ("(A) A"::Text)])
2706 (Data.Either.rights $
2708 (Format.Ledger.Read.account_name <* P.eof)
2709 () "" ("[ ]A"::Text)])
2713 (Data.Either.rights $
2715 (Format.Ledger.Read.account_name <* P.eof)
2716 () "" ("(A) "::Text)])
2720 (Data.Either.rights $
2722 (Format.Ledger.Read.account_name <* P.eof)
2723 () "" ("(A)"::Text)])
2727 (Data.Either.rights $
2729 (Format.Ledger.Read.account_name <* P.eof)
2730 () "" ("A(A)"::Text)])
2734 (Data.Either.rights $
2736 (Format.Ledger.Read.account_name <* P.eof)
2737 () "" ("[A]A"::Text)])
2741 (Data.Either.rights $
2743 (Format.Ledger.Read.account_name <* P.eof)
2744 () "" ("[A] A"::Text)])
2748 (Data.Either.rights $
2750 (Format.Ledger.Read.account_name <* P.eof)
2751 () "" ("[A] "::Text)])
2755 (Data.Either.rights $
2757 (Format.Ledger.Read.account_name <* P.eof)
2758 () "" ("[A]"::Text)])
2762 , "account" ~: TestList
2764 (Data.Either.rights $
2766 (Format.Ledger.Read.account <* P.eof)
2771 (Data.Either.rights $
2773 (Format.Ledger.Read.account <* P.eof)
2778 (Data.Either.rights $
2780 (Format.Ledger.Read.account <* P.eof)
2781 () "" ("A:"::Text)])
2785 (Data.Either.rights $
2787 (Format.Ledger.Read.account <* P.eof)
2788 () "" (":A"::Text)])
2792 (Data.Either.rights $
2794 (Format.Ledger.Read.account <* P.eof)
2795 () "" ("A "::Text)])
2799 (Data.Either.rights $
2801 (Format.Ledger.Read.account <* P.eof)
2802 () "" (" A"::Text)])
2806 (Data.Either.rights $
2808 (Format.Ledger.Read.account <* P.eof)
2809 () "" ("A:B"::Text)])
2813 (Data.Either.rights $
2815 (Format.Ledger.Read.account <* P.eof)
2816 () "" ("A:B:C"::Text)])
2819 , "\"Aa:Bbb:Cccc\"" ~:
2820 (Data.Either.rights $
2822 (Format.Ledger.Read.account <* P.eof)
2823 () "" ("Aa:Bbb:Cccc"::Text)])
2825 ["Aa":|["Bbb", "Cccc"]]
2826 , "\"A a : B b b : C c c c\"" ~:
2827 (Data.Either.rights $
2829 (Format.Ledger.Read.account <* P.eof)
2830 () "" ("A a : B b b : C c c c"::Text)])
2832 ["A a ":|[" B b b ", " C c c c"]]
2834 (Data.Either.rights $
2836 (Format.Ledger.Read.account <* P.eof)
2837 () "" ("A: :C"::Text)])
2841 (Data.Either.rights $
2843 (Format.Ledger.Read.account <* P.eof)
2844 () "" ("A::C"::Text)])
2848 (Data.Either.rights $
2850 (Format.Ledger.Read.account <* P.eof)
2851 () "" ("A:B:(C)"::Text)])
2855 , "posting_type" ~: TestList
2857 Format.Ledger.Read.posting_type
2860 (Format.Ledger.Posting_Type_Regular, "A":|[])
2862 Format.Ledger.Read.posting_type
2865 (Format.Ledger.Posting_Type_Regular, "(":|[])
2867 Format.Ledger.Read.posting_type
2870 (Format.Ledger.Posting_Type_Regular, ")":|[])
2872 Format.Ledger.Read.posting_type
2875 (Format.Ledger.Posting_Type_Regular, "()":|[])
2877 Format.Ledger.Read.posting_type
2880 (Format.Ledger.Posting_Type_Regular, "( )":|[])
2882 Format.Ledger.Read.posting_type
2885 (Format.Ledger.Posting_Type_Virtual, "A":|[])
2887 Format.Ledger.Read.posting_type
2890 (Format.Ledger.Posting_Type_Virtual, "A":|["B", "C"])
2892 Format.Ledger.Read.posting_type
2895 (Format.Ledger.Posting_Type_Regular, "A":|["B", "C"])
2897 Format.Ledger.Read.posting_type
2900 (Format.Ledger.Posting_Type_Regular, "(A)":|["B", "C"])
2902 Format.Ledger.Read.posting_type
2905 (Format.Ledger.Posting_Type_Regular, "A":|["(B)", "C"])
2907 Format.Ledger.Read.posting_type
2910 (Format.Ledger.Posting_Type_Regular, "A":|["B", "(C)"])
2912 Format.Ledger.Read.posting_type
2915 (Format.Ledger.Posting_Type_Regular, "[":|[])
2917 Format.Ledger.Read.posting_type
2920 (Format.Ledger.Posting_Type_Regular, "]":|[])
2922 Format.Ledger.Read.posting_type
2925 (Format.Ledger.Posting_Type_Regular, "[]":|[])
2927 Format.Ledger.Read.posting_type
2930 (Format.Ledger.Posting_Type_Regular, "[ ]":|[])
2932 Format.Ledger.Read.posting_type
2935 (Format.Ledger.Posting_Type_Virtual_Balanced, "A":|[])
2937 Format.Ledger.Read.posting_type
2940 (Format.Ledger.Posting_Type_Virtual_Balanced, "A":|["B", "C"])
2942 Format.Ledger.Read.posting_type
2945 (Format.Ledger.Posting_Type_Regular, "A":|["B", "C"])
2947 Format.Ledger.Read.posting_type
2950 (Format.Ledger.Posting_Type_Regular, "[A]":|["B", "C"])
2952 Format.Ledger.Read.posting_type
2955 (Format.Ledger.Posting_Type_Regular, "A":|["[B]", "C"])
2957 Format.Ledger.Read.posting_type
2960 (Format.Ledger.Posting_Type_Regular, "A":|["B", "[C]"])
2962 , "comment" ~: TestList
2963 [ "; some comment = Right \" some comment\"" ~:
2964 (Data.Either.rights $
2966 (Format.Ledger.Read.comment <* P.eof)
2967 () "" ("; some comment"::Text)])
2970 , "; some comment \\n = Right \" some comment \"" ~:
2971 (Data.Either.rights $
2973 (Format.Ledger.Read.comment <* P.newline <* P.eof)
2974 () "" ("; some comment \n"::Text)])
2976 [ " some comment " ]
2977 , "; some comment \\r\\n = Right \" some comment \"" ~:
2978 (Data.Either.rights $
2980 (Format.Ledger.Read.comment <* P.string "\r\n" <* P.eof)
2981 () "" ("; some comment \r\n"::Text)])
2983 [ " some comment " ]
2985 , "comments" ~: TestList
2986 [ "; some comment\\n ; some other comment = Right [\" some comment\", \" some other comment\"]" ~:
2987 (Data.Either.rights $
2989 (Format.Ledger.Read.comments <* P.eof)
2990 () "" ("; some comment\n ; some other comment"::Text)])
2992 [ [" some comment", " some other comment"] ]
2993 , "; some comment \\n = Right \" some comment \"" ~:
2994 (Data.Either.rights $
2996 (Format.Ledger.Read.comments <* P.string "\n" <* P.eof)
2997 () "" ("; some comment \n"::Text)])
2999 [ [" some comment "] ]
3001 , "tag_value" ~: TestList
3003 (Data.Either.rights $
3005 (Format.Ledger.Read.tag_value <* P.eof)
3010 (Data.Either.rights $
3012 (Format.Ledger.Read.tag_value <* P.char '\n' <* P.eof)
3013 () "" (",\n"::Text)])
3017 (Data.Either.rights $
3019 (Format.Ledger.Read.tag_value <* P.eof)
3020 () "" (",x"::Text)])
3024 (Data.Either.rights $
3026 (Format.Ledger.Read.tag_value <* P.string ",x:" <* P.eof)
3027 () "" (",x:"::Text)])
3031 (Data.Either.rights $
3033 (Format.Ledger.Read.tag_value <* P.string ", n:" <* P.eof)
3034 () "" ("v, v, n:"::Text)])
3040 (Data.Either.rights $
3042 (Format.Ledger.Read.tag <* P.eof)
3043 () "" ("Name:"::Text)])
3047 (Data.Either.rights $
3049 (Format.Ledger.Read.tag <* P.eof)
3050 () "" ("Name:Value"::Text)])
3053 , "Name:Value\\n" ~:
3054 (Data.Either.rights $
3056 (Format.Ledger.Read.tag <* P.string "\n" <* P.eof)
3057 () "" ("Name:Value\n"::Text)])
3061 (Data.Either.rights $
3063 (Format.Ledger.Read.tag <* P.eof)
3064 () "" ("Name:Val ue"::Text)])
3066 [("Name", "Val ue")]
3068 (Data.Either.rights $
3070 (Format.Ledger.Read.tag <* P.eof)
3071 () "" ("Name:,"::Text)])
3075 (Data.Either.rights $
3077 (Format.Ledger.Read.tag <* P.eof)
3078 () "" ("Name:Val,ue"::Text)])
3080 [("Name", "Val,ue")]
3082 (Data.Either.rights $
3084 (Format.Ledger.Read.tag <* P.string ",ue:" <* P.eof)
3085 () "" ("Name:Val,ue:"::Text)])
3089 , "tags" ~: TestList
3091 (Data.Either.rights $
3093 (Format.Ledger.Read.tags <* P.eof)
3094 () "" ("Name:"::Text)])
3101 (Data.Either.rights $
3103 (Format.Ledger.Read.tags <* P.eof)
3104 () "" ("Name:,"::Text)])
3111 (Data.Either.rights $
3113 (Format.Ledger.Read.tags <* P.eof)
3114 () "" ("Name:,Name:"::Text)])
3117 [ ("Name", ["", ""])
3121 (Data.Either.rights $
3123 (Format.Ledger.Read.tags <* P.eof)
3124 () "" ("Name:,Name2:"::Text)])
3131 , "Name: , Name2:" ~:
3132 (Data.Either.rights $
3134 (Format.Ledger.Read.tags <* P.eof)
3135 () "" ("Name: , Name2:"::Text)])
3142 , "Name:,Name2:,Name3:" ~:
3143 (Data.Either.rights $
3145 (Format.Ledger.Read.tags <* P.eof)
3146 () "" ("Name:,Name2:,Name3:"::Text)])
3154 , "Name:Val ue,Name2:V a l u e,Name3:V al ue" ~:
3155 (Data.Either.rights $
3157 (Format.Ledger.Read.tags <* P.eof)
3158 () "" ("Name:Val ue,Name2:V a l u e,Name3:V al ue"::Text)])
3161 [ ("Name", ["Val ue"])
3162 , ("Name2", ["V a l u e"])
3163 , ("Name3", ["V al ue"])
3167 , "posting" ~: TestList
3168 [ " A:B:C = Right A:B:C" ~:
3169 (Data.Either.rights $
3170 [P.runParser_with_Error
3171 (Format.Ledger.Read.posting <* P.eof)
3172 Format.Ledger.Read.nil_Context "" (" A:B:C"::Text)])
3174 [ ( (Format.Ledger.posting ("A":|["B", "C"]))
3175 { Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3177 , Format.Ledger.Posting_Type_Regular
3180 , " !A:B:C = Right !A:B:C" ~:
3181 (Data.List.map fst $
3182 Data.Either.rights $
3183 [P.runParser_with_Error
3184 (Format.Ledger.Read.posting <* P.eof)
3185 Format.Ledger.Read.nil_Context "" (" !A:B:C"::Text)])
3187 [ (Format.Ledger.posting ("A":|["B", "C"]))
3188 { Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3189 , Format.Ledger.posting_status = True
3192 , " *A:B:C = Right *A:B:C" ~:
3193 (Data.List.map fst $
3194 Data.Either.rights $
3195 [P.runParser_with_Error
3196 (Format.Ledger.Read.posting <* P.eof)
3197 Format.Ledger.Read.nil_Context "" (" *A:B:C"::Text)])
3199 [ (Format.Ledger.posting ("A":|["B", "C"]))
3200 { Format.Ledger.posting_amounts = Data.Map.fromList []
3201 , Format.Ledger.posting_comments = []
3202 , Format.Ledger.posting_dates = []
3203 , Format.Ledger.posting_status = True
3204 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3205 , Format.Ledger.posting_tags = Data.Map.fromList []
3208 , " A:B:C $1 = Right A:B:C $1" ~:
3209 (Data.List.map fst $
3210 Data.Either.rights $
3211 [P.runParser_with_Error
3212 (Format.Ledger.Read.posting <* P.eof)
3213 Format.Ledger.Read.nil_Context "" (" A:B:C $1"::Text)])
3215 [ (Format.Ledger.posting ("A":|["B","C $1"]))
3216 { Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3219 , " A:B:C $1 = Right A:B:C $1" ~:
3220 (Data.List.map fst $
3221 Data.Either.rights $
3222 [P.runParser_with_Error
3223 (Format.Ledger.Read.posting <* P.eof)
3224 Format.Ledger.Read.nil_Context "" (" A:B:C $1"::Text)])
3226 [ (Format.Ledger.posting ("A":|["B", "C"]))
3227 { Format.Ledger.posting_amounts = Data.Map.fromList
3229 { Amount.quantity = 1
3230 , Amount.style = Amount.Style.nil
3231 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3232 , Amount.Style.unit_spaced = Just False
3237 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3240 , " A:B:C $1 + 1€ = Right A:B:C $1 + 1€" ~:
3241 (Data.List.map fst $
3242 Data.Either.rights $
3243 [P.runParser_with_Error
3244 (Format.Ledger.Read.posting <* P.eof)
3245 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1€"::Text)])
3247 [ (Format.Ledger.posting ("A":|["B", "C"]))
3248 { Format.Ledger.posting_amounts = Data.Map.fromList
3250 { Amount.quantity = 1
3251 , Amount.style = Amount.Style.nil
3252 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3253 , Amount.Style.unit_spaced = Just False
3258 { Amount.quantity = 1
3259 , Amount.style = Amount.Style.nil
3260 { Amount.Style.unit_side = Just Amount.Style.Side_Right
3261 , Amount.Style.unit_spaced = Just False
3266 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3269 , " A:B:C $1 + 1$ = Right A:B:C $2" ~:
3270 (Data.List.map fst $
3271 Data.Either.rights $
3272 [P.runParser_with_Error
3273 (Format.Ledger.Read.posting <* P.eof)
3274 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1$"::Text)])
3276 [ (Format.Ledger.posting ("A":|["B", "C"]))
3277 { Format.Ledger.posting_amounts = Data.Map.fromList
3279 { Amount.quantity = 2
3280 , Amount.style = Amount.Style.nil
3281 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3282 , Amount.Style.unit_spaced = Just False
3287 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3290 , " A:B:C $1 + 1$ + 1$ = Right A:B:C $3" ~:
3291 (Data.List.map fst $
3292 Data.Either.rights $
3293 [P.runParser_with_Error
3294 (Format.Ledger.Read.posting <* P.eof)
3295 Format.Ledger.Read.nil_Context "" (" A:B:C $1 + 1$ + 1$"::Text)])
3297 [ (Format.Ledger.posting ("A":|["B", "C"]))
3298 { Format.Ledger.posting_amounts = Data.Map.fromList
3300 { Amount.quantity = 3
3301 , Amount.style = Amount.Style.nil
3302 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3303 , Amount.Style.unit_spaced = Just False
3308 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3311 , " A:B:C ; some comment = Right A:B:C ; some comment" ~:
3312 (Data.List.map fst $
3313 Data.Either.rights $
3314 [P.runParser_with_Error
3315 (Format.Ledger.Read.posting <* P.eof)
3316 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment"::Text)])
3318 [ (Format.Ledger.posting ("A":|["B", "C"]))
3319 { Format.Ledger.posting_amounts = Data.Map.fromList []
3320 , Format.Ledger.posting_comments = [" some comment"]
3321 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3324 , " A:B:C ; some comment\\n ; some other comment = Right A:B:C ; some comment\\n ; some other comment" ~:
3325 (Data.List.map fst $
3326 Data.Either.rights $
3327 [P.runParser_with_Error
3328 (Format.Ledger.Read.posting <* P.eof)
3329 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment\n ; some other comment"::Text)])
3331 [ (Format.Ledger.posting ("A":|["B", "C"]))
3332 { Format.Ledger.posting_amounts = Data.Map.fromList []
3333 , Format.Ledger.posting_comments = [" some comment", " some other comment"]
3334 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3337 , " A:B:C $1 ; some comment = Right A:B:C $1 ; some comment" ~:
3338 (Data.List.map fst $
3339 Data.Either.rights $
3340 [P.runParser_with_Error
3341 (Format.Ledger.Read.posting)
3342 Format.Ledger.Read.nil_Context "" (" A:B:C $1 ; some comment"::Text)])
3344 [ (Format.Ledger.posting ("A":|["B", "C"]))
3345 { Format.Ledger.posting_amounts = Data.Map.fromList
3347 { Amount.quantity = 1
3348 , Amount.style = Amount.Style.nil
3349 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3350 , Amount.Style.unit_spaced = Just False
3355 , Format.Ledger.posting_comments = [" some comment"]
3356 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3359 , " A:B:C ; N:V = Right A:B:C ; N:V" ~:
3360 (Data.List.map fst $
3361 Data.Either.rights $
3362 [P.runParser_with_Error
3363 (Format.Ledger.Read.posting <* P.eof)
3364 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V"::Text)])
3366 [ (Format.Ledger.posting ("A":|["B", "C"]))
3367 { Format.Ledger.posting_comments = [" N:V"]
3368 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3369 , Format.Ledger.posting_tags = Data.Map.fromList
3374 , " A:B:C ; some comment N:V = Right A:B:C ; some comment N:V" ~:
3375 (Data.List.map fst $
3376 Data.Either.rights $
3377 [P.runParser_with_Error
3378 (Format.Ledger.Read.posting <* P.eof)
3379 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment N:V"::Text)])
3381 [ (Format.Ledger.posting ("A":|["B", "C"]))
3382 { Format.Ledger.posting_comments = [" some comment N:V"]
3383 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3384 , Format.Ledger.posting_tags = Data.Map.fromList
3389 , " A:B:C ; some comment N:V v, N2:V2 v2 = Right A:B:C ; some comment N:V v, N2:V2 v2" ~:
3390 (Data.List.map fst $
3391 Data.Either.rights $
3392 [P.runParser_with_Error
3393 (Format.Ledger.Read.posting )
3394 Format.Ledger.Read.nil_Context "" (" A:B:C ; some comment N:V v, N2:V2 v2"::Text)])
3396 [ (Format.Ledger.posting ("A":|["B", "C"]))
3397 { Format.Ledger.posting_comments = [" some comment N:V v, N2:V2 v2"]
3398 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3399 , Format.Ledger.posting_tags = Data.Map.fromList
3405 , " A:B:C ; N:V\\n ; N:V2 = Right A:B:C ; N:V\\n ; N:V2" ~:
3406 (Data.List.map fst $
3407 Data.Either.rights $
3408 [P.runParser_with_Error
3409 (Format.Ledger.Read.posting <* P.eof)
3410 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V\n ; N:V2"::Text)])
3412 [ (Format.Ledger.posting ("A":|["B", "C"]))
3413 { Format.Ledger.posting_comments = [" N:V", " N:V2"]
3414 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3415 , Format.Ledger.posting_tags = Data.Map.fromList
3416 [ ("N", ["V", "V2"])
3420 , " A:B:C ; N:V\\n ; N2:V = Right A:B:C ; N:V\\n ; N2:V" ~:
3421 (Data.List.map fst $
3422 Data.Either.rights $
3423 [P.runParser_with_Error
3424 (Format.Ledger.Read.posting <* P.eof)
3425 Format.Ledger.Read.nil_Context "" (" A:B:C ; N:V\n ; N2:V"::Text)])
3427 [ (Format.Ledger.posting ("A":|["B", "C"]))
3428 { Format.Ledger.posting_comments = [" N:V", " N2:V"]
3429 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3430 , Format.Ledger.posting_tags = Data.Map.fromList
3436 , " A:B:C ; date:2001/01/01 = Right A:B:C ; date:2001/01/01" ~:
3437 (Data.List.map fst $
3438 Data.Either.rights $
3439 [P.runParser_with_Error
3440 (Format.Ledger.Read.posting <* P.eof)
3441 Format.Ledger.Read.nil_Context "" (" A:B:C ; date:2001/01/01"::Text)])
3443 [ (Format.Ledger.posting ("A":|["B", "C"]))
3444 { Format.Ledger.posting_comments = [" date:2001/01/01"]
3445 , Format.Ledger.posting_dates =
3446 [ Time.zonedTimeToUTC $
3449 (Time.fromGregorian 2001 01 01)
3450 (Time.TimeOfDay 0 0 0))
3453 , Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3454 , Format.Ledger.posting_tags = Data.Map.fromList
3455 [ ("date", ["2001/01/01"])
3459 , " (A:B:C) = Right (A:B:C)" ~:
3460 (Data.Either.rights $
3461 [P.runParser_with_Error
3462 (Format.Ledger.Read.posting <* P.eof)
3463 Format.Ledger.Read.nil_Context "" (" (A:B:C)"::Text)])
3465 [ ( (Format.Ledger.posting ("A":|["B", "C"]))
3466 { Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3468 , Format.Ledger.Posting_Type_Virtual
3471 , " [A:B:C] = Right [A:B:C]" ~:
3472 (Data.Either.rights $
3473 [P.runParser_with_Error
3474 (Format.Ledger.Read.posting <* P.eof)
3475 Format.Ledger.Read.nil_Context "" (" [A:B:C]"::Text)])
3477 [ ( (Format.Ledger.posting ("A":|["B", "C"]))
3478 { Format.Ledger.posting_sourcepos = P.newPos "" 1 1
3480 , Format.Ledger.Posting_Type_Virtual_Balanced
3484 , "transaction" ~: TestList
3485 [ "2000/01/01 some description\\n A:B:C $1\\n a:b:c" ~:
3486 (Data.Either.rights $
3487 [P.runParser_with_Error
3488 (Format.Ledger.Read.transaction <* P.eof)
3489 Format.Ledger.Read.nil_Context "" ("2000/01/01 some description\n A:B:C $1\n a:b:c"::Text)])
3491 [ Format.Ledger.transaction
3492 { Format.Ledger.transaction_dates=
3493 ( Time.zonedTimeToUTC $
3496 (Time.fromGregorian 2000 01 01)
3497 (Time.TimeOfDay 0 0 0))
3500 , Format.Ledger.transaction_description="some description"
3501 , Format.Ledger.transaction_postings = Format.Ledger.posting_by_Account
3502 [ (Format.Ledger.posting ("A":|["B", "C"]))
3503 { Format.Ledger.posting_amounts = Data.Map.fromList
3505 { Amount.quantity = 1
3506 , Amount.style = Amount.Style.nil
3507 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3508 , Amount.Style.unit_spaced = Just False
3513 , Format.Ledger.posting_sourcepos = P.newPos "" 2 1
3515 , (Format.Ledger.posting ("a":|["b", "c"]))
3516 { Format.Ledger.posting_amounts = Data.Map.fromList
3518 { Amount.quantity = -1
3519 , Amount.style = Amount.Style.nil
3520 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3521 , Amount.Style.unit_spaced = Just False
3526 , Format.Ledger.posting_sourcepos = P.newPos "" 3 1
3529 , Format.Ledger.transaction_sourcepos = P.newPos "" 1 1
3532 , "2000/01/01 some description\\n A:B:C $1\\n a:b:c\\n" ~:
3533 (Data.Either.rights $
3534 [P.runParser_with_Error
3535 (Format.Ledger.Read.transaction <* P.newline <* P.eof)
3536 Format.Ledger.Read.nil_Context "" ("2000/01/01 some description\n A:B:C $1\n a:b:c\n"::Text)])
3538 [ Format.Ledger.transaction
3539 { Format.Ledger.transaction_dates=
3540 ( Time.zonedTimeToUTC $
3543 (Time.fromGregorian 2000 01 01)
3544 (Time.TimeOfDay 0 0 0))
3547 , Format.Ledger.transaction_description="some description"
3548 , Format.Ledger.transaction_postings = Format.Ledger.posting_by_Account
3549 [ (Format.Ledger.posting ("A":|["B", "C"]))
3550 { Format.Ledger.posting_amounts = Data.Map.fromList
3552 { Amount.quantity = 1
3553 , Amount.style = Amount.Style.nil
3554 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3555 , Amount.Style.unit_spaced = Just False
3560 , Format.Ledger.posting_sourcepos = P.newPos "" 2 1
3562 , (Format.Ledger.posting ("a":|["b", "c"]))
3563 { Format.Ledger.posting_amounts = Data.Map.fromList
3565 { Amount.quantity = -1
3566 , Amount.style = Amount.Style.nil
3567 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3568 , Amount.Style.unit_spaced = Just False
3573 , Format.Ledger.posting_sourcepos = P.newPos "" 3 1
3576 , Format.Ledger.transaction_sourcepos = P.newPos "" 1 1
3579 , "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" ~:
3580 (Data.Either.rights $
3581 [P.runParser_with_Error
3582 (Format.Ledger.Read.transaction <* P.eof)
3583 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)])
3585 [ Format.Ledger.transaction
3586 { Format.Ledger.transaction_comments_after =
3588 , " some other;comment"
3590 , " some last comment"
3592 , Format.Ledger.transaction_dates=
3593 ( Time.zonedTimeToUTC $
3596 (Time.fromGregorian 2000 01 01)
3597 (Time.TimeOfDay 0 0 0))
3600 , Format.Ledger.transaction_description="some description"
3601 , Format.Ledger.transaction_postings = Format.Ledger.posting_by_Account
3602 [ (Format.Ledger.posting ("A":|["B", "C"]))
3603 { Format.Ledger.posting_amounts = Data.Map.fromList
3605 { Amount.quantity = 1
3606 , Amount.style = Amount.Style.nil
3607 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3608 , Amount.Style.unit_spaced = Just False
3613 , Format.Ledger.posting_sourcepos = P.newPos "" 5 1
3615 , (Format.Ledger.posting ("a":|["b", "c"]))
3616 { Format.Ledger.posting_amounts = Data.Map.fromList
3618 { Amount.quantity = -1
3619 , Amount.style = Amount.Style.nil
3620 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3621 , Amount.Style.unit_spaced = Just False
3626 , Format.Ledger.posting_sourcepos = P.newPos "" 6 1
3629 , Format.Ledger.transaction_tags = Data.Map.fromList
3632 , Format.Ledger.transaction_sourcepos = P.newPos "" 1 1
3636 , "journal" ~: TestList
3637 [ "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
3639 P.runParserT_with_Error
3640 (Format.Ledger.Read.journal "" {-<* P.eof-})
3641 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)
3643 (\j -> j{Format.Ledger.journal_last_read_time=
3644 Format.Ledger.journal_last_read_time Format.Ledger.journal}) $
3645 Data.Either.rights [jnl])
3647 [ Format.Ledger.journal
3648 { Format.Ledger.journal_transactions =
3649 Format.Ledger.transaction_by_Date
3650 [ Format.Ledger.transaction
3651 { Format.Ledger.transaction_dates=
3652 ( Time.zonedTimeToUTC $
3655 (Time.fromGregorian 2000 01 01)
3656 (Time.TimeOfDay 0 0 0))
3659 , Format.Ledger.transaction_description="1° description"
3660 , Format.Ledger.transaction_postings = Format.Ledger.posting_by_Account
3661 [ (Format.Ledger.posting ("A":|["B", "C"]))
3662 { Format.Ledger.posting_amounts = Data.Map.fromList
3664 { Amount.quantity = 1
3665 , Amount.style = Amount.Style.nil
3666 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3667 , Amount.Style.unit_spaced = Just False
3672 , Format.Ledger.posting_sourcepos = P.newPos "" 2 1
3674 , (Format.Ledger.posting ("a":|["b", "c"]))
3675 { Format.Ledger.posting_amounts = Data.Map.fromList
3677 { Amount.quantity = -1
3678 , Amount.style = Amount.Style.nil
3679 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3680 , Amount.Style.unit_spaced = Just False
3685 , Format.Ledger.posting_sourcepos = P.newPos "" 3 1
3688 , Format.Ledger.transaction_sourcepos = P.newPos "" 1 1
3690 , Format.Ledger.transaction
3691 { Format.Ledger.transaction_dates=
3692 ( Time.zonedTimeToUTC $
3695 (Time.fromGregorian 2000 01 02)
3696 (Time.TimeOfDay 0 0 0))
3699 , Format.Ledger.transaction_description="2° description"
3700 , Format.Ledger.transaction_postings = Format.Ledger.posting_by_Account
3701 [ (Format.Ledger.posting ("A":|["B", "C"]))
3702 { Format.Ledger.posting_amounts = Data.Map.fromList
3704 { Amount.quantity = 1
3705 , Amount.style = Amount.Style.nil
3706 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3707 , Amount.Style.unit_spaced = Just False
3712 , Format.Ledger.posting_sourcepos = P.newPos "" 5 1
3714 , (Format.Ledger.posting ("x":|["y", "z"]))
3715 { Format.Ledger.posting_amounts = Data.Map.fromList
3717 { Amount.quantity = -1
3718 , Amount.style = Amount.Style.nil
3719 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3720 , Amount.Style.unit_spaced = Just False
3725 , Format.Ledger.posting_sourcepos = P.newPos "" 6 1
3728 , Format.Ledger.transaction_sourcepos = P.newPos "" 4 1
3735 , "Write" ~: TestList
3736 [ "account" ~: TestList
3738 ((Format.Ledger.Write.show
3739 Format.Ledger.Write.Style
3740 { Format.Ledger.Write.style_color=False
3741 , Format.Ledger.Write.style_align=True
3743 Format.Ledger.Write.account Format.Ledger.Posting_Type_Regular $
3748 ((Format.Ledger.Write.show
3749 Format.Ledger.Write.Style
3750 { Format.Ledger.Write.style_color=False
3751 , Format.Ledger.Write.style_align=True
3753 Format.Ledger.Write.account Format.Ledger.Posting_Type_Regular $
3758 ((Format.Ledger.Write.show
3759 Format.Ledger.Write.Style
3760 { Format.Ledger.Write.style_color=False
3761 , Format.Ledger.Write.style_align=True
3763 Format.Ledger.Write.account Format.Ledger.Posting_Type_Virtual $
3768 ((Format.Ledger.Write.show
3769 Format.Ledger.Write.Style
3770 { Format.Ledger.Write.style_color=False
3771 , Format.Ledger.Write.style_align=True
3773 Format.Ledger.Write.account Format.Ledger.Posting_Type_Virtual_Balanced $
3778 , "transaction" ~: TestList
3780 ((Format.Ledger.Write.show
3781 Format.Ledger.Write.Style
3782 { Format.Ledger.Write.style_color=False
3783 , Format.Ledger.Write.style_align=True
3785 Format.Ledger.Write.transaction
3786 Format.Ledger.transaction)
3789 , "2000/01/01 some description\\n\\ta:b:c\\n\\t ; first comment\\n\\t ; second comment\\n\\t ; third comment\\n\\tA:B:C $1" ~:
3790 ((Format.Ledger.Write.show
3791 Format.Ledger.Write.Style
3792 { Format.Ledger.Write.style_color=False
3793 , Format.Ledger.Write.style_align=True
3795 Format.Ledger.Write.transaction $
3796 Format.Ledger.transaction
3797 { Format.Ledger.transaction_dates=
3798 ( Time.zonedTimeToUTC $
3801 (Time.fromGregorian 2000 01 01)
3802 (Time.TimeOfDay 0 0 0))
3805 , Format.Ledger.transaction_description="some description"
3806 , Format.Ledger.transaction_postings = Format.Ledger.posting_by_Account
3807 [ (Format.Ledger.posting ("A":|["B", "C"]))
3808 { Format.Ledger.posting_amounts = Data.Map.fromList
3810 { Amount.quantity = 1
3811 , Amount.style = Amount.Style.nil
3812 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3813 , Amount.Style.unit_spaced = Just False
3819 , (Format.Ledger.posting ("a":|["b", "c"]))
3820 { Format.Ledger.posting_comments = ["first comment","second comment","third comment"]
3825 "2000/01/01 some description\n\ta:b:c\n\t ; first comment\n\t ; second comment\n\t ; third comment\n\tA:B:C $1")
3826 , "2000/01/01 some description\\n\\tA:B:C $1\\n\\tAA:BB:CC $123" ~:
3827 ((Format.Ledger.Write.show
3828 Format.Ledger.Write.Style
3829 { Format.Ledger.Write.style_color=False
3830 , Format.Ledger.Write.style_align=True
3832 Format.Ledger.Write.transaction $
3833 Format.Ledger.transaction
3834 { Format.Ledger.transaction_dates=
3835 ( Time.zonedTimeToUTC $
3838 (Time.fromGregorian 2000 01 01)
3839 (Time.TimeOfDay 0 0 0))
3842 , Format.Ledger.transaction_description="some description"
3843 , Format.Ledger.transaction_postings = Format.Ledger.posting_by_Account
3844 [ (Format.Ledger.posting ("A":|["B", "C"]))
3845 { Format.Ledger.posting_amounts = Data.Map.fromList
3847 { Amount.quantity = 1
3848 , Amount.style = Amount.Style.nil
3849 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3850 , Amount.Style.unit_spaced = Just False
3856 , (Format.Ledger.posting ("AA":|["BB", "CC"]))
3857 { Format.Ledger.posting_amounts = Data.Map.fromList
3859 { Amount.quantity = 123
3860 , Amount.style = Amount.Style.nil
3861 { Amount.Style.unit_side = Just Amount.Style.Side_Left
3862 , Amount.Style.unit_spaced = Just False
3871 "2000/01/01 some description\n\tA:B:C $1\n\tAA:BB:CC $123")