{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} import Prelude import Test.HUnit hiding ((~?), test) import Test.Framework.Providers.HUnit (hUnitTestToTests) import Test.Framework.Runners.Console (defaultMain) -- import Control.Applicative (Const(..)) import Control.Arrow ((***)) import Data.Data () -- import qualified Data.Either import Data.Function (on) -- import Data.Functor.Compose (Compose(..)) import qualified Data.List as List import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.Map.Strict as Map import Data.Maybe (fromJust) import qualified Data.Strict.Maybe as Strict import Data.Text (Text) -- import qualified Text.Parsec as P hiding (char, space, spaces, string) import qualified Hcompta.Account as Account import qualified Hcompta.Balance as Balance -- import qualified Hcompta.Filter as Filter -- import qualified Hcompta.Filter.Read as Filter.Read import qualified Hcompta.Lib.Foldable as Lib.Foldable import qualified Hcompta.Lib.Interval as Lib.Interval import qualified Hcompta.Lib.Interval.Sieve as Lib.Interval.Sieve -- import qualified Hcompta.Lib.Parsec as P import qualified Hcompta.Lib.TreeMap as TreeMap import qualified Hcompta.Polarize as Polarize import qualified Hcompta.Quantity as Quantity -- import qualified Hcompta.Tag as Tag -- (~?) :: String -> Bool -> Test -- (~?) s b = s ~: (b ~?= True) amounts :: (Quantity.Addable q, Ord u) => [(u, q)] -> Map.Map u q amounts = Map.fromListWith Quantity.quantity_add amount_usd = (("$"::Text),) amount_eur = (("€"::Text),) amount_gbp = (("£"::Text),) main :: IO () main = defaultMain $ hUnitTestToTests test type instance test :: Test test = TestList [ ] {- [ "Lib" ~: TestList [ "TreeMap" ~: TestList [ "insert" ~: TestList [ "[] 0" ~: (TreeMap.insert const ((0::Int):|[]) () TreeMap.empty) ~?= (TreeMap.TreeMap $ Map.fromList [ ((0::Int), TreeMap.leaf ()) ]) , "[] 0/1" ~: (TreeMap.insert const ((0::Int):|1:[]) () TreeMap.empty) ~?= (TreeMap.TreeMap $ Map.fromList [ ((0::Int), TreeMap.Node { TreeMap.node_value = Strict.Nothing , TreeMap.node_size = 1 , TreeMap.node_descendants = TreeMap.singleton ((1::Int):|[]) () }) ]) ] , "union" ~: TestList [ ] , "map_by_depth_first" ~: TestList [ "[0, 0/1, 0/1/2, 1, 1/2/3]" ~: (TreeMap.map_by_depth_first (\descendants value -> Map.foldl' (\acc v -> (++) acc $ Strict.fromMaybe undefined $ TreeMap.node_value v ) (Strict.fromMaybe [] value) (TreeMap.nodes descendants) ) $ TreeMap.from_List const [ (((0::Integer):|[]), [0]) , ((0:|1:[]), [0,1]) , ((0:|1:2:[]), [0,1,2]) , ((1:|[]), [1]) , ((1:|2:3:[]), [1,2,3]) ] ) ~?= (TreeMap.from_List const [ ((0:|[]), [0,0,1,0,1,2]) , ((0:|1:[]), [0,1,0,1,2]) , ((0:|1:2:[]), [0,1,2]) , ((1:|[]), [1,1,2,3]) , ((1:|2:[]), [1,2,3]) , ((1:|2:3:[]), [1,2,3]) ]) , "[0/0]" ~: (TreeMap.map_by_depth_first (\descendants value -> Map.foldl' (\acc v -> (++) acc $ Strict.fromMaybe undefined $ TreeMap.node_value v ) (Strict.fromMaybe [] value) (TreeMap.nodes descendants) ) $ TreeMap.from_List const [ (((0::Integer):|0:[]), [0,0]) ] ) ~?= (TreeMap.from_List const [ ((0:|[]), [0,0]) , ((0:|0:[]), [0,0]) ]) ] , "flatten" ~: TestList [ "[0, 0/1, 0/1/2]" ~: (TreeMap.flatten id $ TreeMap.from_List const [ (((0::Integer):|[]), ()) , ((0:|1:[]), ()) , ((0:|1:2:[]), ()) ] ) ~?= (Map.fromList [ ((0:|[]), ()) , ((0:|1:[]), ()) , ((0:|1:2:[]), ()) ]) , "[1, 1/2, 1/22, 1/2/3, 1/2/33, 11, 11/2, 11/2/3, 11/2/33]" ~: (TreeMap.flatten id $ TreeMap.from_List const [ ((1:|[]), ()) , ((1:|2:[]), ()) , ((1:|22:[]), ()) , ((1:|2:3:[]), ()) , ((1:|2:33:[]), ()) , ((11:|[]), ()) , ((11:|2:[]), ()) , ((11:|2:3:[]), ()) , ((11:|2:33:[]), ()) ] ) ~?= (Map.fromList [ (((1::Integer):|[]), ()) , ((1:|2:[]), ()) , ((1:|22:[]), ()) , ((1:|2:3:[]), ()) , ((1:|2:33:[]), ()) , ((11:|[]), ()) , ((11:|2:[]), ()) , ((11:|2:3:[]), ()) , ((11:|2:33:[]), ()) ]) ] , "find_along" ~: TestList [ "0/1/2/3 [0, 0/1, 0/1/2, 0/1/2/3]" ~: (TreeMap.find_along (0:|[1,2,3]) $ TreeMap.from_List const [ (((0::Integer):|[]), [0]) , ((0:|1:[]), [0,1]) , ((0:|1:2:[]), [0,1,2]) , ((0:|1:2:3:[]), [0,1,2,3]) ] ) ~?= [ [0] , [0,1] , [0,1,2] , [0,1,2,3] ] , "0/1/2/3 [0, 0/1]" ~: (TreeMap.find_along (0:|[1,2,3]) $ TreeMap.from_List const [ (((0::Integer):|[]), [0]) , ((0:|1:[]), [0,1]) ] ) ~?= [ [0] , [0,1] ] ] ] , "Foldable" ~: TestList [ "accumLeftsAndFoldrRights" ~: TestList [ "Left" ~: (Lib.Foldable.accumLeftsAndFoldrRights (++) [""] $ [Left [0]]) ~?= (([(0::Integer)], [(""::String)])) , "repeat Left" ~: ((take 1 *** take 0) $ Lib.Foldable.accumLeftsAndFoldrRights (++) [""] $ ( repeat (Left [0]) )) ~?= ([(0::Integer)], ([]::[String])) , "Right:Left:Right:Left" ~: (Lib.Foldable.accumLeftsAndFoldrRights (++) ["0"] $ ( Right ["2"]:Left [1]:Right ["1"]:Left [0]:[] )) ~?= (([1, 0]::[Integer]), (["2", "1", "0"]::[String])) , "Right:Left:Right:repeat Left" ~: ((take 1 *** take 2) $ Lib.Foldable.accumLeftsAndFoldrRights (++) ["0"] $ ( Right ["2"]:Left [1]:Right ["1"]:repeat (Left [0]) )) ~?= (([1]::[Integer]), (["2", "1"]::[String])) ] ] , "Interval" ~: TestList [ "position" ~: TestList $ concatMap (\(mi, mj, p) -> let i = fromJust mi in let j = fromJust mj in let (le, ge) = case p of Lib.Interval.Equal -> (EQ, EQ) _ -> (LT, GT) in [ ((show . Lib.Interval.Pretty) i ++ " " ++ (show . Lib.Interval.Pretty) j) ~: Lib.Interval.position i j ~?= (p, le) , ((show . Lib.Interval.Pretty) j ++ " " ++ (show . Lib.Interval.Pretty) i) ~: Lib.Interval.position j i ~?= (p, ge) ] ) [ ( (Lib.Interval.<..<) 0 (4::Integer) , (Lib.Interval.<..<) 5 9 , Lib.Interval.Away ) , ( (Lib.Interval.<..<) 0 4 , (Lib.Interval.<=..<) 4 9 , Lib.Interval.Adjacent ) , ( (Lib.Interval.<..<) 0 5 , (Lib.Interval.<..<) 4 9 , Lib.Interval.Overlap ) , ( (Lib.Interval.<..<) 0 5 , (Lib.Interval.<..<) 0 9 , Lib.Interval.Prefix ) , ( (Lib.Interval.<..<) 0 9 , (Lib.Interval.<..<) 1 8 , Lib.Interval.Include ) , ( (Lib.Interval.<..<) 0 9 , (Lib.Interval.<..<) 5 9 , Lib.Interval.Suffixed ) , ( (Lib.Interval.<..<) 0 9 , (Lib.Interval.<..<) 0 9 , Lib.Interval.Equal ) , ( (Lib.Interval.<..<) 0 9 , (Lib.Interval.<..<=) 0 9 , Lib.Interval.Prefix ) , ( (Lib.Interval.<=..<) 0 9 , (Lib.Interval.<..<) 0 9 , Lib.Interval.Suffixed ) , ( (Lib.Interval.<=..<=) 0 9 , (Lib.Interval.<..<) 0 9 , Lib.Interval.Include ) ] , "intersection" ~: TestList $ concatMap (\(mi, mj, e) -> let i = fromJust mi in let j = fromJust mj in [ ((show . Lib.Interval.Pretty) i ++ " " ++ (show . Lib.Interval.Pretty) j) ~: Lib.Interval.intersection i j ~?= e , ((show . Lib.Interval.Pretty) j ++ " " ++ (show . Lib.Interval.Pretty) i) ~: Lib.Interval.intersection j i ~?= e ] ) [ ( (Lib.Interval.<..<) 0 (4::Integer) , (Lib.Interval.<..<) 5 9 , Nothing ) , ( (Lib.Interval.<..<=) 0 5 , (Lib.Interval.<=..<) 5 9 , (Lib.Interval.<=..<=) 5 5 ) , ( (Lib.Interval.<..<) 0 6 , (Lib.Interval.<..<) 4 9 , (Lib.Interval.<..<) 4 6 ) , ( (Lib.Interval.<..<=) 0 6 , (Lib.Interval.<=..<) 4 9 , (Lib.Interval.<=..<=) 4 6 ) , ( (Lib.Interval.<..<) 0 6 , (Lib.Interval.<=..<) 4 9 , (Lib.Interval.<=..<) 4 6 ) , ( (Lib.Interval.<..<=) 0 6 , (Lib.Interval.<..<) 4 9 , (Lib.Interval.<..<=) 4 6 ) , ( (Lib.Interval.<..<) 0 9 , (Lib.Interval.<..<) 0 9 , (Lib.Interval.<..<) 0 9 ) , ( (Lib.Interval.<=..<) 0 9 , (Lib.Interval.<..<=) 0 9 , (Lib.Interval.<..<) 0 9 ) , ( (Lib.Interval.<..<=) 0 9 , (Lib.Interval.<=..<) 0 9 , (Lib.Interval.<..<) 0 9 ) , ( (Lib.Interval.<=..<=) 0 9 , (Lib.Interval.<=..<=) 0 9 , (Lib.Interval.<=..<=) 0 9 ) ] , "union" ~: TestList $ concatMap (\(mi, mj, e) -> let i = fromJust mi in let j = fromJust mj in [ ((show . Lib.Interval.Pretty) i ++ " " ++ (show . Lib.Interval.Pretty) j) ~: Lib.Interval.union i j ~?= e , ((show . Lib.Interval.Pretty) j ++ " " ++ (show . Lib.Interval.Pretty) i) ~: Lib.Interval.union j i ~?= e ] ) [ ( (Lib.Interval.<..<) 0 (4::Integer) , (Lib.Interval.<..<) 5 9 , Nothing ) , ( (Lib.Interval.<..<=) 0 5 , (Lib.Interval.<..<) 5 9 , (Lib.Interval.<..<) 0 9 ) , ( (Lib.Interval.<..<) 0 5 , (Lib.Interval.<=..<) 5 9 , (Lib.Interval.<..<) 0 9 ) , ( (Lib.Interval.<..<=) 0 5 , (Lib.Interval.<=..<) 5 9 , (Lib.Interval.<..<) 0 9 ) , ( (Lib.Interval.<..<) 0 6 , (Lib.Interval.<..<) 4 9 , (Lib.Interval.<..<) 0 9 ) , ( (Lib.Interval.<..<) 0 9 , (Lib.Interval.<..<) 0 9 , (Lib.Interval.<..<) 0 9 ) , ( (Lib.Interval.<=..<) 0 9 , (Lib.Interval.<..<=) 0 9 , (Lib.Interval.<=..<=) 0 9 ) , ( (Lib.Interval.<..<=) 0 9 , (Lib.Interval.<=..<) 0 9 , (Lib.Interval.<=..<=) 0 9 ) , ( (Lib.Interval.<=..<=) 0 9 , (Lib.Interval.<=..<=) 0 9 , (Lib.Interval.<=..<=) 0 9 ) ] , "Sieve" ~: TestList $ [ "union" ~: TestList $ List.concatMap (\(mis, me) -> let is = map (fromJust) mis in let e = map (fromJust) me in let sil = foldl (flip (Lib.Interval.Sieve.union . Lib.Interval.Sieve.singleton)) Lib.Interval.Sieve.empty is in let sir = foldr (Lib.Interval.Sieve.union . Lib.Interval.Sieve.singleton) Lib.Interval.Sieve.empty is in [ (List.intercalate " " $ map (show . Lib.Interval.Pretty) is) ~: Lib.Interval.Sieve.intervals sil ~?= e , (List.intercalate " " $ map (show . Lib.Interval.Pretty) $ reverse is) ~: Lib.Interval.Sieve.intervals sir ~?= e ] ) [ ( [ (Lib.Interval.<=..<) 0 (5::Integer) , (Lib.Interval.<=..<=) 5 9 ] , [ (Lib.Interval.<=..<=) 0 9 ] ) , ( [ (Lib.Interval.<=..<=) 0 5 , (Lib.Interval.<=..<=) 0 9 ] , [ (Lib.Interval.<=..<=) 0 9 ] ) , ( [ (Lib.Interval.<=..<=) 0 4 , (Lib.Interval.<=..<=) 5 9 , (Lib.Interval.<=..<=) 3 6 ] , [ (Lib.Interval.<=..<=) 0 9 ] ) , ( [ (Lib.Interval.<=..<=) 1 4 , (Lib.Interval.<=..<=) 5 8 ] , [ (Lib.Interval.<=..<=) 1 4 , (Lib.Interval.<=..<=) 5 8 ] ) , ( [ (Lib.Interval.<=..<=) 1 8 , (Lib.Interval.<=..<=) 0 9 ] , [ (Lib.Interval.<=..<=) 0 9 ] ) , ( [ (Lib.Interval.<=..<=) 1 4 , (Lib.Interval.<=..<=) 5 8 , (Lib.Interval.<=..<=) 0 9 ] , [ (Lib.Interval.<=..<=) 0 9 ] ) ] ++ List.concatMap (\(mis, mjs, me) -> let is = map fromJust mis in let js = map fromJust mjs in let e = map fromJust me in let iu = foldl (flip (Lib.Interval.Sieve.union . Lib.Interval.Sieve.singleton)) Lib.Interval.Sieve.empty is in let ju = foldl (flip (Lib.Interval.Sieve.union . Lib.Interval.Sieve.singleton)) Lib.Interval.Sieve.empty js in [ ((List.intercalate " " $ map (show . Lib.Interval.Pretty) is) ++ " u " ++ (List.intercalate " " $ map (show . Lib.Interval.Pretty) js)) ~: Lib.Interval.Sieve.intervals (Lib.Interval.Sieve.union iu ju) ~?= e , ((List.intercalate " " $ map (show . Lib.Interval.Pretty) $ js) ++ " u " ++ (List.intercalate " " $ map (show . Lib.Interval.Pretty) $ is)) ~: Lib.Interval.Sieve.intervals (Lib.Interval.Sieve.union ju iu) ~?= e ] ) [ ( [ (Lib.Interval.<=..<=) 0 (1::Integer) , (Lib.Interval.<=..<=) 2 4 ] , [ (Lib.Interval.<=..<=) 0 3 ] , [ (Lib.Interval.<=..<=) 0 4 ] ) , ( [ (Lib.Interval.<=..<=) 0 1 , (Lib.Interval.<=..<=) 2 3 , (Lib.Interval.<=..<=) 4 5 , (Lib.Interval.<=..<=) 6 7 ] , [ (Lib.Interval.<=..<=) 1 2 , (Lib.Interval.<=..<=) 3 4 , (Lib.Interval.<=..<=) 5 6 ] , [ (Lib.Interval.<=..<=) 0 7 ] ) , ( [ (Lib.Interval.<=..<=) 0 1 , (Lib.Interval.<=..<=) 2 3 ] , [ (Lib.Interval.<=..<=) 4 5 ] , [ (Lib.Interval.<=..<=) 0 1 , (Lib.Interval.<=..<=) 2 3 , (Lib.Interval.<=..<=) 4 5 ] ) , ( [ (Lib.Interval.<=..<=) 0 1 , (Lib.Interval.<=..<=) 4 5 ] , [ (Lib.Interval.<=..<=) 2 3 ] , [ (Lib.Interval.<=..<=) 0 1 , (Lib.Interval.<=..<=) 2 3 , (Lib.Interval.<=..<=) 4 5 ] ) ] , "intersection" ~: TestList $ List.concatMap (\(mis, mjs, me) -> let is = map (fromJust) mis in let js = map (fromJust) mjs in let e = map (fromJust) me in let iu = foldl (flip (Lib.Interval.Sieve.union . Lib.Interval.Sieve.singleton)) Lib.Interval.Sieve.empty is in let ju = foldl (flip (Lib.Interval.Sieve.union . Lib.Interval.Sieve.singleton)) Lib.Interval.Sieve.empty js in [ ((List.intercalate " " $ map (show . Lib.Interval.Pretty) is) ++ " n " ++ (List.intercalate " " $ map (show . Lib.Interval.Pretty) js)) ~: Lib.Interval.Sieve.intervals (Lib.Interval.Sieve.intersection iu ju) ~?= e , ((List.intercalate " " $ map (show . Lib.Interval.Pretty) $ js) ++ " n " ++ (List.intercalate " " $ map (show . Lib.Interval.Pretty) $ is)) ~: Lib.Interval.Sieve.intervals (Lib.Interval.Sieve.intersection ju iu) ~?= e ] ) [ ( [ (Lib.Interval.<=..<) 0 (5::Integer) ] , [ (Lib.Interval.<=..<=) 5 9 ] , [ ] ) , ( [ (Lib.Interval.<=..<=) 0 5 ] , [ (Lib.Interval.<=..<=) 5 9 ] , [ (Lib.Interval.<=..<=) 5 5 ] ) , ( [ (Lib.Interval.<=..<=) 0 5 ] , [ (Lib.Interval.<=..<=) 0 9 ] , [ (Lib.Interval.<=..<=) 0 5 ] ) , ( [ (Lib.Interval.<=..<=) 0 4 , (Lib.Interval.<=..<=) 5 9 ] , [ (Lib.Interval.<=..<=) 3 6 ] , [ (Lib.Interval.<=..<=) 3 4 , (Lib.Interval.<=..<=) 5 6 ] ) , ( [ (Lib.Interval.<=..<=) 1 4 , (Lib.Interval.<=..<=) 6 8 ] , [ (Lib.Interval.<=..<=) 2 3 , (Lib.Interval.<=..<=) 5 7 ] , [ (Lib.Interval.<=..<=) 2 3 , (Lib.Interval.<=..<=) 6 7 ] ) ] , "complement" ~: TestList $ List.concatMap (\(mis, me) -> let is = map fromJust mis in let e = map fromJust me in let iu = foldl (flip (Lib.Interval.Sieve.union . Lib.Interval.Sieve.singleton)) Lib.Interval.Sieve.empty is in [ show (Lib.Interval.Pretty $ Lib.Interval.Sieve.fmap_interval (Lib.Interval.fmap_unsafe $ Lib.Interval.Pretty) iu) ~: Lib.Interval.Sieve.intervals (Lib.Interval.Sieve.complement iu) ~?= e ] ) [ ( [ ((Lib.Interval.<=..<) `on` Lib.Interval.Limited) 0 (5::Integer) , ((Lib.Interval.<=..<=) `on` Lib.Interval.Limited) 5 9 ] , [ Just $ (Lib.Interval...<) 0 , Just $ (Lib.Interval.<..) 9 ] ) , ( [ Just $ Lib.Interval.unlimited ] , [ ] ) , ( [ ] , [ Just $ Lib.Interval.unlimited ] ) , ( [ Just $ (Lib.Interval...<) 0 , Just $ (Lib.Interval.<..) 0 ] , [ Just $ Lib.Interval.point $ Lib.Interval.Limited 0 ] ) , ( [ ((Lib.Interval.<=..<) `on` Lib.Interval.Limited) 0 1 , ((Lib.Interval.<=..<) `on` Lib.Interval.Limited) 2 3 , ((Lib.Interval.<..<=) `on` Lib.Interval.Limited) 3 4 ] , [ Just $ (Lib.Interval...<) 0 , ((Lib.Interval.<=..<) `on` Lib.Interval.Limited) 1 2 , Just $ Lib.Interval.point $ Lib.Interval.Limited 3 , Just $ (Lib.Interval.<..) 4 ] ) ] , "complement_with" ~: TestList $ List.concatMap (\(mib, mis, me) -> let ib = fromJust mib in let is = map fromJust mis in let e = map fromJust me in let iu = foldl (flip (Lib.Interval.Sieve.union . Lib.Interval.Sieve.singleton)) Lib.Interval.Sieve.empty is in [ show (Lib.Interval.Pretty iu) ~: Lib.Interval.Sieve.intervals (Lib.Interval.Sieve.complement_with ib iu) ~?= e ] ) [ ( (Lib.Interval.<=..<=) (-10) (10::Integer) , [ (Lib.Interval.<=..<) 0 5 , (Lib.Interval.<=..<=) 5 9 ] , [ (Lib.Interval.<=..<) (-10) 0 , (Lib.Interval.<..<=) 9 10 ] ) , ( (Lib.Interval.<=..<=) (-10) 10 , [ (Lib.Interval.<=..<=) (-10) 10 ] , [ ] ) , ( (Lib.Interval.<=..<=) (-10) 10 , [ ] , [ (Lib.Interval.<=..<=) (-10) 10 ] ) , ( (Lib.Interval.<=..<=) (-10) 10 , [ (Lib.Interval.<=..<) (-10) 0 , (Lib.Interval.<..<=) 0 10 ] , [ Just $ Lib.Interval.point 0 ] ) , ( (Lib.Interval.<=..<=) (-10) 10 , [ Just $ Lib.Interval.point 0 ] , [ (Lib.Interval.<=..<) (-10) 0 , (Lib.Interval.<..<=) 0 10 ] ) , ( (Lib.Interval.<=..<=) 0 10 , [ (Lib.Interval.<..<=) 0 10 ] , [ Just $ Lib.Interval.point 0 ] ) , ( (Lib.Interval.<=..<=) 0 10 , [ (Lib.Interval.<=..<) 0 10 ] , [ Just $ Lib.Interval.point 10 ] ) , ( Just $ Lib.Interval.point 0 , [ ] , [ Just $ Lib.Interval.point 0 ] ) , ( Just $ Lib.Interval.point 0 , [ Just $ Lib.Interval.point 0 ] , [ ] ) ] ] ] ] , "Account" ~: TestList [ "foldr" ~: TestList [ "[A]" ~: (reverse $ Account.foldr ("A":|[]) (:) []) ~?= ["A":|[]] , "[A, B]" ~: (reverse $ Account.foldr ("A":|["B"]) (:) []) ~?= ["A":|[], "A":|["B"]] , "[A, B, C]" ~: (reverse $ Account.foldr ("A":|["B", "C"]) (:) []) ~?= ["A":|[], "A":|["B"], "A":|["B", "C"]] ] , "ascending" ~: TestList [ "[A]" ~: Account.ascending ("A":|[]) ~?= Nothing , "[A, B]" ~: Account.ascending ("A":|["B"]) ~?= Just ("A":|[]) , "[A, B, C]" ~: Account.ascending ("A":|["B", "C"]) ~?= Just ("A":|["B"]) ] ] , "Filter" ~: TestList [ "test" ~: TestList [ "Filter_Path" ~: TestList [ "A A" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") ]) ((("A"::Text):|[])) , "* A" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Any ]) ((("A"::Text):|[])) , ": A" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Many ]) ((("A"::Text):|[])) , ":A A" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") ]) ((("A"::Text):|[])) , "A: A" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Many ]) ((("A"::Text):|[])) , "A: A:B" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Many ]) ((("A"::Text):|"B":[])) , "A:B A:B" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") ]) ((("A"::Text):|"B":[])) , "A::B A:B" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") ]) ((("A"::Text):|"B":[])) , ":B: A:B:C" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") , Filter.Filter_Path_Section_Many ]) ((("A"::Text):|"B":"C":[])) , ":C A:B:C" ~? Filter.test (Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "C") ]) ((("A"::Text):|"B":"C":[])) , "A:B:C::D A:B:C:CC:CCC:D:E" ~? Filter.test (Filter.Filter_Path Filter.Gt [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "C") , Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "D") ]) ((("A"::Text):|"B":"C":"CC":"CCC":"D":"E":[])) ] , "Filter_Bool" ~: TestList [ "Any A" ~? Filter.test (Filter.Any::Filter.Filter_Bool (Filter.Filter_Account (Tag.Tags, NonEmpty Text))) (mempty, ("A":|[])) ] , "Filter_Ord" ~: TestList [ "0 < (1, 2)" ~? Filter.test (Filter.With_Interval $ Filter.Filter_Ord Filter.Gt (0::Integer)) (fromJust $ (Lib.Interval.<=..<=) 1 2) , "(-2, -1) < 0" ~? Filter.test (Filter.With_Interval $ Filter.Filter_Ord Filter.Lt (0::Integer)) (fromJust $ (Lib.Interval.<=..<=) (-2) (-1)) , "not (1 < (0, 2))" ~? (not $ Filter.test (Filter.With_Interval $ Filter.Filter_Ord Filter.Gt (1::Integer)) (fromJust $ (Lib.Interval.<=..<=) 0 2)) ] ] , "Read" ~: TestList [ "filter_account" ~: TestList [ "*" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("*"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Any ] ] , "A" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("A"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") ] ] , "AA" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("AA"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "AA") ] ] , "::A" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("::A"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") ] ] , ":A" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" (":A"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") ] ] , "A:" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("A:"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Many ] ] , "A::" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("A::"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Many ] ] , "A:B" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("A:B"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") ] ] , "A::B" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("A::B"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") ] ] , "A:::B" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("A:::B"::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Many , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") ] ] , "A: " ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.char ' ' <* P.eof) () "" ("A: "::Text)]) ~?= [ Filter.Filter_Path Filter.Eq [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Many ] ] , "<=A:B" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" ("<=A:B"::Text)]) ~?= [ Filter.Filter_Path Filter.Le [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") ] ] , ">=A:B" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" (">=A:B"::Text)]) ~?= [ Filter.Filter_Path Filter.Ge [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") ] ] , "A:B" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_account_path <* P.eof) () "" (">A:B"::Text)]) ~?= [ Filter.Filter_Path Filter.Gt [ Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "A") , Filter.Filter_Path_Section_Text (Filter.Filter_Text_Exact "B") ] ] ] , "filter_bool" ~: TestList [ "( E )" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_bool [ P.char 'E' >> return (return $ Filter.Bool True) ] <* P.eof) () "" ("( E )"::Text)]) ~?= [ Filter.And (Filter.Bool True) Filter.Any ] , "( ( E ) )" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_bool [ P.char 'E' >> return (return $ Filter.Bool True) ] <* P.eof) () "" ("( ( E ) )"::Text)]) ~?= [ Filter.And (Filter.And (Filter.Bool True) Filter.Any) Filter.Any ] , "( E ) & ( E )" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_bool [ P.char 'E' >> return (return $ Filter.Bool True) ] <* P.eof) () "" ("( E ) & ( E )"::Text)]) ~?= [ Filter.And (Filter.And (Filter.Bool True) Filter.Any) (Filter.And (Filter.Bool True) Filter.Any) ] , "( E ) + ( E )" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_bool [ P.char 'E' >> return (return $ Filter.Bool True) ] <* P.eof) () "" ("( E ) + ( E )"::Text)]) ~?= [ Filter.Or (Filter.And (Filter.Bool True) Filter.Any) (Filter.And (Filter.Bool True) Filter.Any) ] , "( E ) - ( E )" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_bool [ P.char 'E' >> return (return $ Filter.Bool True) ] <* P.eof) () "" ("( E ) - ( E )"::Text)]) ~?= [ Filter.And (Filter.And (Filter.Bool True) Filter.Any) (Filter.Not (Filter.And (Filter.Bool True) Filter.Any)) ] , "(- E )" ~: (Data.Either.rights $ [P.runParser (Filter.Read.filter_bool [ P.char 'E' >> return (return $ Filter.Bool True) ] <* P.eof) () "" ("(- E )"::Text)]) ~?= [ Filter.And (Filter.Not (Filter.Bool True)) Filter.Any ] ] ] ] , "Balance" ~: TestList [ "balance" ~: TestList [ "[A+$1] = A+$1 & $+1" ~: (Balance.cons ( (("A"::Text):|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ (1::Integer) ] ) Balance.empty) ~?= (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ List.map (id *** Balance.Account_Sum . Map.map Polarize.polarize) $ [ ("A":|[], amounts [ amount_usd $ 1 ]) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize $ 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] } ) , "[A+$1, A-$1] = {A+$0, $+0}" ~: (List.foldl (flip Balance.cons) Balance.empty [ ( (("A"::Text):|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ (1::Integer) ] ) , ( ("A":|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ -1 ] ) ]) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( "A":|[] , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.Polarized_Both (-1) ( 1) ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Both (-1) ( 1) , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] } , "[A+$1, A-€1] = {A+$1-€1, $+1 €-1}" ~: (List.foldl (flip Balance.cons) Balance.empty [ ( (("A"::Text):|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ (1::Integer) ] ) , ( ("A":|[]) , Map.map Polarize.polarize $ amounts [ amount_eur $ -1 ] ) ]) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ List.map (id *** Balance.Account_Sum . Map.map Polarize.polarize) $ [ ("A":|[], amounts [ amount_usd $ 1, amount_eur $ -1 ]) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Positive 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } , amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Negative (-1) , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] } , "[A+$1, B-$1] = {A+$1 B-$1, $+0}" ~: (List.foldl (flip Balance.cons) Balance.empty [ ( (("A"::Text):|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ (1::Integer) ] ) , ( ("B":|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ -1 ] ) ]) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ List.map (id *** Balance.Account_Sum . Map.map Polarize.polarize) $ [ ("A":|[], amounts [ amount_usd $ 1 ]) , ("B":|[], amounts [ amount_usd $ -1 ]) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Both (-1) 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } ] } , "[A+$1, B+$1]" ~: (List.foldl (flip Balance.cons) Balance.empty [ ( (("A"::Text):|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ (1::Integer) ] ) , ( ("B":|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] ) ]) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ List.map (id *** Balance.Account_Sum . Map.map Polarize.polarize) $ [ ("A":|[], amounts [ amount_usd $ 1 ]) , ("B":|[], amounts [ amount_usd $ 1 ]) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 2 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } ] } , "[A+$1+€2, A-$1-€2] = {A+$0+€0, $+0 €+0}" ~: (List.foldl (flip Balance.cons) Balance.empty [ ( (("A"::Text):|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ 1, amount_eur $ (2::Integer) ] ) , ( ("A":|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ -1, amount_eur $ -2 ] ) ]) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ("A":|[] , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.Polarized_Both (-1) 1 , amount_eur $ Polarize.Polarized_Both (-2) 2 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Both (-1) 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } , amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Both (-2) 2 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] } , "[A+$1+€2+£3, B-$1-2€-£3] = {A+$1+€2+£3 B-$1-€2-£3, $+0 €+0 £+0}" ~: (List.foldl (flip Balance.cons) Balance.empty [ ( (("A"::Text):|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ (1::Integer), amount_eur $ 2, amount_gbp $ 3 ] ) , ( ("B":|[]) , Map.map Polarize.polarize $ amounts [ amount_usd $ -1, amount_eur $ -2, amount_gbp $ -3 ] ) ]) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ List.map (id *** Balance.Account_Sum . Map.map Polarize.polarize) $ [ ("A":|[], amounts [ amount_usd $ 1, amount_eur $ 2, amount_gbp $ 3 ]) , ("B":|[], amounts [ amount_usd $ -1, amount_eur $ -2, amount_gbp $ -3 ]) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Both (-1) 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } , amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Both (-2) 2 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } , amount_gbp $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.Polarized_Both (-3) 3 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } ] } ] , "union" ~: TestList [ "{A+$1, $+1} {A+$1, $+1} = {A+$2, $+2}" ~: Balance.union (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( "A":|[] , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( "A":|[] , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 2 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 2 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] } , "{A+$1, $+1} {B+$1, $+1} = {A+$1 B+$1, $+2}" ~: Balance.union (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["B":|[]] } ] }) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 2 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } ] } , "{A+$1, $+1} {B+€1, €+1} = {A+$1 B+€1, $+1 €+1}" ~: Balance.union (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_eur $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["B":|[]] } ] }) ~?= Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_eur $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } , amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["B":|[]] } ] } ] , "expanded" ~: TestList [ "mempty" ~: Balance.expanded TreeMap.empty ~?= (TreeMap.empty::Balance.Expanded (NonEmpty Text) Text Integer) , "A+$1 = A+$1" ~: Balance.expanded (TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ]::Balance.Balance_by_Account Text Text (Polarize.Polarized Integer)) ~?= (TreeMap.from_List const $ [ ("A":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) ]) , "A/A+$1 = A+$1 A/A+$1" ~: Balance.expanded (TreeMap.from_List const $ [ ( ("A":|["A"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ]::Balance.Balance_by_Account Text Text (Polarize.Polarized Integer)) ~?= (TreeMap.from_List const [ ("A":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [] }) , ("A":|["A"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) ]) , "A/B+$1 = A+$1 A/B+$1" ~: Balance.expanded (TreeMap.from_List const $ [ ( ("A":|["B"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ]::Balance.Balance_by_Account Text Text (Polarize.Polarized Integer)) ~?= (TreeMap.from_List const [ ("A":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [] }) , ("A":|["B"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) ]) , "A/B/C+$1 = A+$1 A/B+$1 A/B/C+$1" ~: Balance.expanded (TreeMap.from_List const $ [ ( ("A":|["B", "C"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ]::Balance.Balance_by_Account Text Text (Polarize.Polarized Integer)) ~?= (TreeMap.from_List const $ [ ("A":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [] }) , ("A":|["B"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [] }) , ("A":|["B", "C"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) ]) , "A+$1 A/B+$1 = A+$2 A/B+$1" ~: Balance.expanded (TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("A":|["B"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ]::Balance.Balance_by_Account Text Text (Polarize.Polarized Integer)) ~?= (TreeMap.from_List const [ ("A":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 2 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("A":|["B"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) ]) , "A+$1 A/B+$1 A/B/C+$1 = A+$3 A/B+$2 A/B/C+$1" ~: Balance.expanded (TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("A":|["B"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("A":|["B", "C"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ]::Balance.Balance_by_Account Text Text (Polarize.Polarized Integer)) ~?= (TreeMap.from_List const [ ("A":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 3 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("A":|["B"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 2 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("A":|["B", "C"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) ]) , "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" ~: Balance.expanded (TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("A":|["B"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("A":|["B", "C"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("A":|["B", "C", "D"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ]::Balance.Balance_by_Account Text Text (Polarize.Polarized Integer)) ~?= (TreeMap.from_List const [ ("A":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 4 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("A":|["B"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 3 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("A":|["B", "C"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 2 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("A":|["B", "C", "D"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) ]) , "A+$1 A/B+$1 A/BB+$1 AA/B+$1 = A+$3 A/B+$1 A/BB+$1 AA+$1 AA/B+$1" ~: Balance.expanded (TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("A":|["B"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("A":|["BB"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("AA":|["B"]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ]::Balance.Balance_by_Account Text Text (Polarize.Polarized Integer)) ~?= (TreeMap.from_List const [ ("A":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 3 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("A":|["B"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("A":|["BB"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) , ("AA":|[], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [] }) , ("AA":|["B"], Balance.Account_Sum_Expanded { Balance.inclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] , Balance.exclusive = Balance.Account_Sum $ Map.map Polarize.polarize $ amounts [ amount_usd $ 1 ] }) ]) ] , "deviation" ~: TestList [ "{A+$1, $1}" ~: (Balance.deviation $ Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }::Balance.Deviation (NonEmpty Text) Text (Polarize.Polarized Integer)) ~?= (Balance.Deviation $ Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["B":|[]] } ]) , "{A+$1 B+$1, $2}" ~: (Balance.deviation $ Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 2 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) [ "A":|[] , "B":|[] ] } ] }::Balance.Deviation (NonEmpty Text) Text (Polarize.Polarized Integer)) ~?= (Balance.Deviation $ Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 2 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) [ ] } ]) ] , "is_equilibrium_inferrable" ~: TestList [ "empty" ~: TestCase $ (@=?) True $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.empty::Balance.Balance (NonEmpty Text) Text Integer) , "{A+$0, $+0}" ~: TestCase $ (@=?) True $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 0 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 0 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) , "{A+$1, $+1}" ~: TestCase $ (@=?) False $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) , "{A+$0+€0, $0 €+0}" ~: TestCase $ (@=?) True $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 0 , amount_eur $ Polarize.polarize 0 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 0 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } , amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 0 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) , "{A+$1, B-$1, $+0}" ~: TestCase $ (@=?) True $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize (-1) ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 0 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) , "{A+$1 B, $+1}" ~: TestCase $ (@=?) True $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) , "{A+$1 B+€1, $+1 €+1}" ~: TestCase $ (@=?) True $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_eur $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[]] } , amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["B":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) , "{A+$1 B-$1+€1, $+0 €+1}" ~: TestCase $ (@=?) True $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize (-1) , amount_eur $ Polarize.polarize 1 ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 0 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } , amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 1 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["B":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) , "{A+$1+€2+£3 B-$1-€2-£3, $+0 €+0 £+0}" ~: TestCase $ (@=?) True $ Balance.is_equilibrium_inferrable $ Balance.deviation $ (Balance.Balance { Balance.balance_by_account = TreeMap.from_List const $ [ ( ("A":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize 1 , amount_eur $ Polarize.polarize 2 , amount_gbp $ Polarize.polarize 3 ] ) , ( ("B":|[]) , Balance.Account_Sum $ Map.fromListWith const $ [ amount_usd $ Polarize.polarize (-1) , amount_eur $ Polarize.polarize (-2) , amount_gbp $ Polarize.polarize (-3) ] ) ] , Balance.balance_by_unit = Balance.Balance_by_Unit $ Map.fromList $ [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 0 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } , amount_eur $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 0 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } , amount_gbp $ Balance.Unit_Sum { Balance.unit_sum_quantity = Polarize.polarize 0 , Balance.unit_sum_accounts = Map.fromList $ List.map (,()) ["A":|[], "B":|[]] } ] }::Balance.Balance (NonEmpty Text) Text (Polarize.Polarized Integer)) ] , "infer_equilibrium" ~: TestList [ "{A+$1 B}" ~: (snd $ Balance.infer_equilibrium $ Map.fromList $ List.map (\(acct, amts) -> (acct, [(acct, amts)])) $ [ ( ("A"::Text):|[] , amounts [ amount_usd $ (1::Integer) ] ) , ( "B":|[] , amounts [] ) ]) ~?= (Right $ Map.fromList $ List.map (\(acct, amts) -> (acct, [(acct, amts)])) $ [ ( "A":|[] , amounts [ amount_usd $ 1 ] ) , ( "B":|[] , amounts [ amount_usd $ -1 ] ) ]) , "{A+$1 B-1€}" ~: (snd $ Balance.infer_equilibrium $ Map.fromList $ List.map (\(acct, amts) -> (acct, [(acct, amts)])) $ [ ( ("A"::Text):|[] , amounts [ amount_usd $ (1::Integer) ] ) , ( "B":|[] , amounts [ amount_eur $ -1 ] ) ]) ~?= (Right $ Map.fromList $ List.map (\(acct, amts) -> (acct, [(acct, amts)])) $ [ ( ("A"::Text):|[] , amounts [ amount_usd $ 1, amount_eur $ (1::Integer)] ) , ( "B":|[] , amounts [ amount_eur $ -1, amount_usd $ -1 ] ) ]) , "{A+$1 B+$1}" ~: (snd $ Balance.infer_equilibrium $ Map.fromList $ List.map (\(acct, amts) -> (acct, [(acct, amts)])) $ [ ( ("A"::Text):|[] , amounts [ amount_usd $ (1::Integer) ] ) , ( "B":|[] , amounts [ amount_usd $ 1 ] ) ]) ~?= (Left [ amount_usd $ Balance.Unit_Sum { Balance.unit_sum_quantity = 2 , Balance.unit_sum_accounts = Map.fromList []} ]) , "{A+$1 B-$1 B-1€}" ~: (snd $ Balance.infer_equilibrium $ Map.fromList $ List.map (\(acct, amts) -> (acct, [(acct, amts)])) $ [ ( ("A"::Text):|[] , amounts [ amount_usd $ (1::Integer) ] ) , ( "B":|[] , amounts [ amount_usd $ -1, amount_eur $ -1 ] ) ]) ~?= (Right $ Map.fromList $ List.map (\(acct, amts) -> (acct, [(acct, amts)])) $ [ ( "A":|[] , amounts [ amount_usd $ 1, amount_eur $ 1 ] ) , ( "B":|[] , amounts [ amount_usd $ -1, amount_eur $ -1 ] ) ]) ] ] ] -}