refactor/fix balanced entry checking and test it properly

This commit is contained in:
Simon Michael 2009-04-01 08:55:46 +00:00
parent 0cacc2a7e4
commit 89abdfa456
5 changed files with 61 additions and 35 deletions

View File

@ -49,7 +49,13 @@ pcommentwidth = no limit -- 22
@
-}
showEntry :: Entry -> String
showEntry e =
showEntry = showEntry' True
showEntryUnelided :: Entry -> String
showEntryUnelided = showEntry' False
showEntry' :: Bool -> Entry -> String
showEntry' elide e =
unlines $ [{-precedingcomment ++ -}description] ++ (showtxns $ etransactions e) ++ [""]
where
precedingcomment = epreceding_comment_lines e
@ -59,8 +65,9 @@ showEntry e =
code = if (length $ ecode e) > 0 then (printf " (%s)" $ ecode e) else ""
desc = " " ++ edescription e
comment = if (length $ ecomment e) > 0 then " ; "++(ecomment e) else ""
showtxns (t1:t2:[]) = [showtxn t1, showtxnnoamt t2]
showtxns ts = map showtxn ts
showtxns ts
| elide && length ts == 2 = [showtxn (ts !! 0), showtxnnoamt (ts !! 1)]
| otherwise = map showtxn ts
showtxn t = showacct t ++ " " ++ (showamount $ tamount t) ++ (showcomment $ tcomment t)
showtxnnoamt t = showacct t ++ " " ++ (showcomment $ tcomment t)
showacct t = " " ++ (showaccountname $ taccount t)
@ -77,19 +84,19 @@ isEntryBalanced (Entry {etransactions=ts}) =
-- amount first. We can auto-fill if there is just one non-virtual
-- transaction without an amount. The auto-filled balance will be
-- converted to cost basis if possible. If the entry can not be balanced,
-- raise an error.
balanceEntry :: Entry -> Entry
balanceEntry e@Entry{etransactions=ts} = (e{etransactions=ts'})
-- return an error message instead.
balanceEntry :: Entry -> Either String Entry
balanceEntry e@Entry{etransactions=ts}
| length missingamounts > 1 = Left $ showerr "could not balance this entry, too many missing amounts"
| not $ isEntryBalanced e' = Left $ showerr "could not balance this entry, amounts do not balance"
| otherwise = Right e'
where
check e
| isEntryBalanced e = e
| otherwise = error $ "could not balance this entry:\n" ++ show e
(withamounts, missingamounts) = partition hasAmount $ filter isReal ts
ts' = case (length missingamounts) of
0 -> ts
1 -> map balance ts
otherwise -> error $ "could not balance this entry, too many missing amounts:\n" ++ show e
otherstotal = sum $ map tamount withamounts
balance t
| isReal t && not (hasAmount t) = t{tamount = costOfMixedAmount (-otherstotal)}
e' = e{etransactions=ts'}
ts' | length missingamounts == 1 = map balance ts
| otherwise = ts
where
balance t | isReal t && not (hasAmount t) = t{tamount = costOfMixedAmount (-otherstotal)}
| otherwise = t
where otherstotal = sum $ map tamount withamounts
showerr s = printf "%s:\n%s" s (showEntryUnelided e)

View File

@ -301,6 +301,8 @@ ledgerDefaultYear = do
setYear y'
return $ return id
-- | Try to parse a ledger entry. If we successfully parse an entry, ensure it is balanced,
-- and if we cannot, raise an error.
ledgerEntry :: GenParser Char LedgerFileCtx Entry
ledgerEntry = do
date <- ledgerdate <?> "entry"
@ -313,7 +315,10 @@ ledgerEntry = do
comment <- ledgercomment
restofline
transactions <- ledgertransactions
return $ balanceEntry $ Entry date status code description comment transactions ""
let e = Entry date status code description comment transactions ""
case balanceEntry e of
Right e' -> return e'
Left err -> error err
ledgerdate :: GenParser Char LedgerFileCtx Day
ledgerdate = try ledgerfulldate <|> ledgerpartialdate

View File

@ -239,3 +239,13 @@ spacenonewline = satisfy (\c -> c `elem` " \v\f\t")
restofline :: GenParser Char st String
restofline = anyChar `manyTill` newline
isLeft :: Either a b -> Bool
isLeft (Left _) = True
isLeft _ = False
isRight :: Either a b -> Bool
isRight = not . isLeft

16
NOTES
View File

@ -10,24 +10,8 @@ clever tricks like the plague." --Edsger Dijkstra
* to do
** errors
*** not catching some unbalanced entries, two ways:
**** 1
1/1 test1
a $-100
b -10h @ $10
; $ hledger -B reg -- test1
; 2009/01/01 test1 a $-100.00 $-100.00
**** 2
1/1 test2
a $-100
b $-100
; $ hledger -B reg -- test2
; 2009/01/01 test2 a $-100.00 $-100.00
; b $-100.00 $-200.00
*** --depth works with reg -W but not with reg
*** register report should sort by date
*** too many dependencies, hard to install esp. without cabal install
** features
*** more ledger features
**** rename entry -> transaction, transaction -> posting

View File

@ -259,7 +259,27 @@ tests = [
]
,"balanceEntry" ~: do
(tamount $ last $ etransactions $ balanceEntry entry1) `is` Mixed [dollars (-47.18)]
let fromeither (Left err) = error err
fromeither (Right e) = e
(tamount $ last $ etransactions $ fromeither $ balanceEntry entry1) `is` Mixed [dollars (-47.18)]
assertBool "detect unbalanced entry, sign error"
(isLeft $ balanceEntry
(Entry (parsedate "2007/01/28") False "" "test" ""
[RawTransaction False "a" (Mixed [dollars 1]) "" RegularTransaction,
RawTransaction False "b" (Mixed [dollars 1]) "" RegularTransaction
] ""))
assertBool "detect unbalanced entry, multiple missing amounts"
(isLeft $ balanceEntry
(Entry (parsedate "2007/01/28") False "" "test" ""
[RawTransaction False "a" missingamt "" RegularTransaction,
RawTransaction False "b" missingamt "" RegularTransaction
] ""))
assertBool "one missing amount should be ok"
(isRight $ balanceEntry
(Entry (parsedate "2007/01/28") False "" "test" ""
[RawTransaction False "a" (Mixed [dollars 1]) "" RegularTransaction,
RawTransaction False "b" missingamt "" RegularTransaction
] ""))
,"balancereportacctnames" ~:
let gives (opt,pats) e = do