From dd9e78a67a861600268c8ab41ebd0cbd5dc1243f Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Mon, 27 Dec 2010 20:26:22 +0000 Subject: [PATCH] reorganize tests --- hledger-lib/Hledger/Data.hs | 24 +- hledger-lib/Hledger/Data/Account.hs | 3 + hledger-lib/Hledger/Data/AccountName.hs | 26 + hledger-lib/Hledger/Data/Amount.hs | 57 +- hledger-lib/Hledger/Data/Commodity.hs | 4 + hledger-lib/Hledger/Data/Dates.hs | 54 +- hledger-lib/Hledger/Data/Journal.hs | 4 + hledger-lib/Hledger/Data/Ledger.hs | 5 + hledger-lib/Hledger/Data/Posting.hs | 3 + hledger-lib/Hledger/Data/TimeLog.hs | 2 +- hledger-lib/Hledger/Data/Transaction.hs | 65 +- hledger-lib/Hledger/Read.hs | 4 +- hledger-lib/Hledger/Read/JournalReader.hs | 16 +- hledger-lib/Hledger/Read/TimelogReader.hs | 4 +- hledger/Hledger/Cli.hs | 909 +++++++++++++++++ hledger/Hledger/Cli/Balance.hs | 4 + hledger/Hledger/Cli/Commands.hs | 40 - hledger/Hledger/Cli/Convert.hs | 2 +- hledger/Hledger/Cli/Options.hs | 25 + hledger/Hledger/Cli/Register.hs | 48 +- hledger/Hledger/Cli/Tests.hs | 1071 +-------------------- hledger/Hledger/Cli/Utils.hs | 1 + 22 files changed, 1215 insertions(+), 1156 deletions(-) create mode 100644 hledger/Hledger/Cli.hs delete mode 100644 hledger/Hledger/Cli/Commands.hs diff --git a/hledger-lib/Hledger/Data.hs b/hledger-lib/Hledger/Data.hs index 5d1b87654..54e8cbf3d 100644 --- a/hledger-lib/Hledger/Data.hs +++ b/hledger-lib/Hledger/Data.hs @@ -37,16 +37,16 @@ import Hledger.Data.Utils tests_Hledger_Data = TestList [ - -- Hledger.Data.Account.tests_Account - -- ,Hledger.Data.AccountName.tests_AccountName - Hledger.Data.Amount.tests_Amount - -- ,Hledger.Data.Commodity.tests_Commodity - ,Hledger.Data.Dates.tests_Dates - ,Hledger.Data.Transaction.tests_Transaction - -- ,Hledger.Data.Hledger.Data.tests_Hledger.Data - -- ,Hledger.Data.Journal.tests_Journal - -- ,Hledger.Data.Posting.tests_Posting - ,Hledger.Data.TimeLog.tests_TimeLog - -- ,Hledger.Data.Types.tests_Types - -- ,Hledger.Data.Utils.tests_Utils + tests_Hledger_Data_Account + ,tests_Hledger_Data_AccountName + ,tests_Hledger_Data_Amount + ,tests_Hledger_Data_Commodity + ,tests_Hledger_Data_Dates + ,tests_Hledger_Data_Journal + ,tests_Hledger_Data_Ledger + ,tests_Hledger_Data_Posting + ,tests_Hledger_Data_TimeLog + ,tests_Hledger_Data_Transaction + -- ,tests_Hledger_Data_Types + -- ,tests_Hledger_Data_Utils ] diff --git a/hledger-lib/Hledger/Data/Account.hs b/hledger-lib/Hledger/Data/Account.hs index 375c241d1..95a90086f 100644 --- a/hledger-lib/Hledger/Data/Account.hs +++ b/hledger-lib/Hledger/Data/Account.hs @@ -25,3 +25,6 @@ instance Eq Account where nullacct = Account "" [] nullmixedamt +tests_Hledger_Data_Account = TestList [ + ] + diff --git a/hledger-lib/Hledger/Data/AccountName.hs b/hledger-lib/Hledger/Data/AccountName.hs index 08fbed7d2..27422b5b9 100644 --- a/hledger-lib/Hledger/Data/AccountName.hs +++ b/hledger-lib/Hledger/Data/AccountName.hs @@ -173,3 +173,29 @@ elideAccountName width s = clipAccountName :: Int -> AccountName -> AccountName clipAccountName n = accountNameFromComponents . take n . accountNameComponents +tests_Hledger_Data_AccountName = TestList + [ + "accountNameTreeFrom" ~: do + accountNameTreeFrom ["a"] `is` Node "top" [Node "a" []] + accountNameTreeFrom ["a","b"] `is` Node "top" [Node "a" [], Node "b" []] + accountNameTreeFrom ["a","a:b"] `is` Node "top" [Node "a" [Node "a:b" []]] + accountNameTreeFrom ["a:b:c"] `is` Node "top" [Node "a" [Node "a:b" [Node "a:b:c" []]]] + + ,"expandAccountNames" ~: + expandAccountNames ["assets:cash","assets:checking","expenses:vacation"] `is` + ["assets","assets:cash","assets:checking","expenses","expenses:vacation"] + + ,"isAccountNamePrefixOf" ~: do + "assets" `isAccountNamePrefixOf` "assets" `is` False + "assets" `isAccountNamePrefixOf` "assets:bank" `is` True + "assets" `isAccountNamePrefixOf` "assets:bank:checking" `is` True + "my assets" `isAccountNamePrefixOf` "assets:bank" `is` False + + ,"isSubAccountNameOf" ~: do + "assets" `isSubAccountNameOf` "assets" `is` False + "assets:bank" `isSubAccountNameOf` "assets" `is` True + "assets:bank:checking" `isSubAccountNameOf` "assets" `is` False + "assets:bank" `isSubAccountNameOf` "my assets" `is` False + + ] + diff --git a/hledger-lib/Hledger/Data/Amount.hs b/hledger-lib/Hledger/Data/Amount.hs index 67568f351..6a6c5e617 100644 --- a/hledger-lib/Hledger/Data/Amount.hs +++ b/hledger-lib/Hledger/Data/Amount.hs @@ -38,7 +38,32 @@ price-discarding arithmetic which ignores and discards prices. -} -module Hledger.Data.Amount +module Hledger.Data.Amount ( + amounts, + canonicaliseAmount, + canonicaliseMixedAmount, + convertMixedAmountTo, + costOfAmount, + costOfMixedAmount, + isNegativeMixedAmount, + isReallyZeroMixedAmountCost, + isZeroMixedAmount, + maxprecision, + missingamt, + normaliseMixedAmount, + nullamt, + nullmixedamt, + punctuatethousands, + showMixedAmount, + showMixedAmountDebug, + showMixedAmountOrZero, + showMixedAmountOrZeroWithoutPrice, + showMixedAmountWithoutPrice, + showMixedAmountWithPrecision, + sumMixedAmountsPreservingHighestPrecision, + tests_Hledger_Data_Amount + -- Hledger.Data.Amount.tests_Hledger_Data_Amount + ) where import qualified Data.Map as Map import Data.Map (findWithDefault) @@ -216,14 +241,14 @@ isNegativeMixedAmount m = case as of [a] -> Just $ isNegativeAmount a isReallyZeroMixedAmountCost :: MixedAmount -> Bool isReallyZeroMixedAmountCost = isReallyZeroMixedAmount . costOfMixedAmount --- | MixedAmount derives Eq in Types.hs, but that doesn't know that we --- want $0 = EUR0 = 0. Yet we don't want to drag all this code in there. --- When zero equality is important, use this, for now; should be used --- everywhere. -mixedAmountEquals :: MixedAmount -> MixedAmount -> Bool -mixedAmountEquals a b = amounts a' == amounts b' || (isZeroMixedAmount a' && isZeroMixedAmount b') - where a' = normaliseMixedAmount a - b' = normaliseMixedAmount b +-- -- | MixedAmount derives Eq in Types.hs, but that doesn't know that we +-- -- want $0 = EUR0 = 0. Yet we don't want to drag all this code in there. +-- -- When zero equality is important, use this, for now; should be used +-- -- everywhere. +-- mixedAmountEquals :: MixedAmount -> MixedAmount -> Bool +-- mixedAmountEquals a b = amounts a' == amounts b' || (isZeroMixedAmount a' && isZeroMixedAmount b') +-- where a' = normaliseMixedAmount a +-- b' = normaliseMixedAmount b -- | Get the string representation of a mixed amount, showing each of -- its component amounts. NB a mixed amount can have an empty amounts @@ -231,8 +256,8 @@ mixedAmountEquals a b = amounts a' == amounts b' || (isZeroMixedAmount a' && isZ showMixedAmount :: MixedAmount -> String showMixedAmount m = vConcatRightAligned $ map show $ amounts $ normaliseMixedAmount m -setMixedAmountPrecision :: Int -> MixedAmount -> MixedAmount -setMixedAmountPrecision p (Mixed as) = Mixed $ map (setAmountPrecision p) as +-- setMixedAmountPrecision :: Int -> MixedAmount -> MixedAmount +-- setMixedAmountPrecision p (Mixed as) = Mixed $ map (setAmountPrecision p) as -- | Get the string representation of a mixed amount, showing each of its -- component amounts with the specified precision, ignoring their @@ -382,7 +407,7 @@ missingamt :: MixedAmount missingamt = Mixed [Amount Commodity {symbol="AUTO",side=L,spaced=False,comma=False,precision=0} 0 Nothing] -tests_Amount = TestList [ +tests_Hledger_Data_Amount = TestList [ "showMixedAmount" ~: do showMixedAmount (Mixed [Amount dollar 0 Nothing]) `is` "$0.00" @@ -417,5 +442,13 @@ tests_Amount = TestList [ Amount dollar (-0.25) Nothing]) `is` Mixed [Amount dollar 0 Nothing] + ,"normaliseMixedAmount" ~: do + normaliseMixedAmount (Mixed []) ~?= Mixed [nullamt] + + ,"punctuatethousands 1" ~: punctuatethousands "" `is` "" + + ,"punctuatethousands 2" ~: punctuatethousands "1234567.8901" `is` "1,234,567.8901" + + ,"punctuatethousands 3" ~: punctuatethousands "-100" `is` "-100" ] diff --git a/hledger-lib/Hledger/Data/Commodity.hs b/hledger-lib/Hledger/Data/Commodity.hs index 4b200646b..e58876722 100644 --- a/hledger-lib/Hledger/Data/Commodity.hs +++ b/hledger-lib/Hledger/Data/Commodity.hs @@ -57,3 +57,7 @@ canonicaliseCommodities cs = commoditymap = Map.fromList [(s, commoditieswithsymbol s) | s <- symbols] commoditieswithsymbol s = filter ((s==) . symbol) cs symbols = nub $ map symbol cs + +tests_Hledger_Data_Commodity = TestList [ + ] + diff --git a/hledger-lib/Hledger/Data/Dates.hs b/hledger-lib/Hledger/Data/Dates.hs index 1b0c57ce4..87a71be7c 100644 --- a/hledger-lib/Hledger/Data/Dates.hs +++ b/hledger-lib/Hledger/Data/Dates.hs @@ -470,7 +470,8 @@ nulldatespan = DateSpan Nothing Nothing nulldate = parsedate "1900/01/01" -tests_Dates = TestList [ +tests_Hledger_Data_Dates = TestList + [ "splitSpan" ~: do let gives (interval, span) = (splitSpan interval span `is`) @@ -489,4 +490,53 @@ tests_Dates = TestList [ (Quarterly,mkdatespan "2008/01/01" "2008/01/01") `gives` [mkdatespan "2008/01/01" "2008/01/01"] - ] + ,"parsedate" ~: do + let date1 = parsedate "2008/11/26" + parsedate "2008/02/03" `is` parsetimewith "%Y/%m/%d" "2008/02/03" date1 + parsedate "2008-02-03" `is` parsetimewith "%Y/%m/%d" "2008/02/03" date1 + + ,"period expressions" ~: do + let todaysdate = parsedate "2008/11/26" + let str `gives` result = show (parsewith (periodexpr todaysdate) str) `is` ("Right " ++ result) + "from aug to oct" `gives` "(NoInterval,DateSpan (Just 2008-08-01) (Just 2008-10-01))" + "aug to oct" `gives` "(NoInterval,DateSpan (Just 2008-08-01) (Just 2008-10-01))" + "every day from aug to oct" `gives` "(Daily,DateSpan (Just 2008-08-01) (Just 2008-10-01))" + "daily from aug" `gives` "(Daily,DateSpan (Just 2008-08-01) Nothing)" + "every week to 2009" `gives` "(Weekly,DateSpan Nothing (Just 2009-01-01))" + + ,"fixSmartDateStr" ~: do + let gives = is . fixSmartDateStr (parsedate "2008/11/26") + "1999-12-02" `gives` "1999/12/02" + "1999.12.02" `gives` "1999/12/02" + "1999/3/2" `gives` "1999/03/02" + "19990302" `gives` "1999/03/02" + "2008/2" `gives` "2008/02/01" + "0020/2" `gives` "0020/02/01" + "1000" `gives` "1000/01/01" + "4/2" `gives` "2008/04/02" + "2" `gives` "2008/11/02" + "January" `gives` "2008/01/01" + "feb" `gives` "2008/02/01" + "today" `gives` "2008/11/26" + "yesterday" `gives` "2008/11/25" + "tomorrow" `gives` "2008/11/27" + "this day" `gives` "2008/11/26" + "last day" `gives` "2008/11/25" + "next day" `gives` "2008/11/27" + "this week" `gives` "2008/11/24" -- last monday + "last week" `gives` "2008/11/17" -- previous monday + "next week" `gives` "2008/12/01" -- next monday + "this month" `gives` "2008/11/01" + "last month" `gives` "2008/10/01" + "next month" `gives` "2008/12/01" + "this quarter" `gives` "2008/10/01" + "last quarter" `gives` "2008/07/01" + "next quarter" `gives` "2009/01/01" + "this year" `gives` "2008/01/01" + "last year" `gives` "2007/01/01" + "next year" `gives` "2009/01/01" +-- "last wed" `gives` "2008/11/19" +-- "next friday" `gives` "2008/11/28" +-- "next january" `gives` "2009/01/01" + + ] diff --git a/hledger-lib/Hledger/Data/Journal.hs b/hledger-lib/Hledger/Data/Journal.hs index f4ec830fe..da9a249c4 100644 --- a/hledger-lib/Hledger/Data/Journal.hs +++ b/hledger-lib/Hledger/Data/Journal.hs @@ -389,3 +389,7 @@ postingsByAccount ps = m' sortedps = sortBy (comparing paccount) ps groupedps = groupBy (\p1 p2 -> paccount p1 == paccount p2) sortedps m' = Map.fromList [(paccount $ head g, g) | g <- groupedps] + +tests_Hledger_Data_Journal = TestList [ + ] + diff --git a/hledger-lib/Hledger/Data/Ledger.hs b/hledger-lib/Hledger/Data/Ledger.hs index 5ee5547ac..eff48386d 100644 --- a/hledger-lib/Hledger/Data/Ledger.hs +++ b/hledger-lib/Hledger/Data/Ledger.hs @@ -122,3 +122,8 @@ rawdatespan = journalDateSpan . journal ledgeramounts :: Ledger -> [MixedAmount] ledgeramounts = journalAmounts . journal + +tests_Hledger_Data_Ledger = TestList + [ + ] + diff --git a/hledger-lib/Hledger/Data/Posting.hs b/hledger-lib/Hledger/Data/Posting.hs index 50a196a0c..0044d9cb4 100644 --- a/hledger-lib/Hledger/Data/Posting.hs +++ b/hledger-lib/Hledger/Data/Posting.hs @@ -91,3 +91,6 @@ postingsDateSpan [] = DateSpan Nothing Nothing postingsDateSpan ps = DateSpan (Just $ postingDate $ head ps') (Just $ addDays 1 $ postingDate $ last ps') where ps' = sortBy (comparing postingDate) ps +tests_Hledger_Data_Posting = TestList [ + ] + diff --git a/hledger-lib/Hledger/Data/TimeLog.hs b/hledger-lib/Hledger/Data/TimeLog.hs index 2aa173474..b2db5f007 100644 --- a/hledger-lib/Hledger/Data/TimeLog.hs +++ b/hledger-lib/Hledger/Data/TimeLog.hs @@ -90,7 +90,7 @@ entryFromTimeLogInOut i o ps = [Posting{pstatus=False,paccount=acctname,pamount=amount, pcomment="",ptype=VirtualPosting,pmetadata=[],ptransaction=Just t}] -tests_TimeLog = TestList [ +tests_Hledger_Data_TimeLog = TestList [ "timeLogEntriesToTransactions" ~: do today <- getCurrentDay diff --git a/hledger-lib/Hledger/Data/Transaction.hs b/hledger-lib/Hledger/Data/Transaction.hs index ba92daa1b..392639e9d 100644 --- a/hledger-lib/Hledger/Data/Transaction.hs +++ b/hledger-lib/Hledger/Data/Transaction.hs @@ -182,7 +182,7 @@ txnTieKnot t@Transaction{tpostings=ps} = t{tpostings=map (settxn t) ps} settxn :: Transaction -> Posting -> Posting settxn t p = p{ptransaction=Just t} -tests_Transaction = TestList [ +tests_Hledger_Data_Transaction = TestList [ "showTransaction" ~: do assertEqual "show a balanced transaction, eliding last amount" (unlines @@ -264,4 +264,67 @@ tests_Transaction = TestList [ ,Posting False "b" missingamt "" RegularPosting [] Nothing ] "")) + ,"balanceTransaction" ~: do + assertBool "detect unbalanced entry, sign error" + (isLeft $ balanceTransaction Nothing + (Transaction (parsedate "2007/01/28") Nothing False "" "test" "" [] + [Posting False "a" (Mixed [dollars 1]) "" RegularPosting [] Nothing, + Posting False "b" (Mixed [dollars 1]) "" RegularPosting [] Nothing + ] "")) + assertBool "detect unbalanced entry, multiple missing amounts" + (isLeft $ balanceTransaction Nothing + (Transaction (parsedate "2007/01/28") Nothing False "" "test" "" [] + [Posting False "a" missingamt "" RegularPosting [] Nothing, + Posting False "b" missingamt "" RegularPosting [] Nothing + ] "")) + let e = balanceTransaction Nothing (Transaction (parsedate "2007/01/28") Nothing False "" "test" "" [] + [Posting False "a" (Mixed [dollars 1]) "" RegularPosting [] Nothing, + Posting False "b" missingamt "" RegularPosting [] Nothing + ] "") + assertBool "one missing amount should be ok" (isRight e) + assertEqual "balancing amount is added" + (Mixed [dollars (-1)]) + (case e of + Right e' -> (pamount $ last $ tpostings e') + Left _ -> error' "should not happen") + + ,"isTransactionBalanced" ~: do + let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] + [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) + ,Posting False "c" (Mixed [dollars (-1.00)]) "" RegularPosting [] (Just t) + ] "" + assertBool "detect balanced" (isTransactionBalanced Nothing t) + let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] + [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) + ,Posting False "c" (Mixed [dollars (-1.01)]) "" RegularPosting [] (Just t) + ] "" + assertBool "detect unbalanced" (not $ isTransactionBalanced Nothing t) + let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] + [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) + ] "" + assertBool "detect unbalanced, one posting" (not $ isTransactionBalanced Nothing t) + let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] + [Posting False "b" (Mixed [dollars 0]) "" RegularPosting [] (Just t) + ] "" + assertBool "one zero posting is considered balanced for now" (isTransactionBalanced Nothing t) + let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] + [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) + ,Posting False "c" (Mixed [dollars (-1.00)]) "" RegularPosting [] (Just t) + ,Posting False "d" (Mixed [dollars 100]) "" VirtualPosting [] (Just t) + ] "" + assertBool "virtual postings don't need to balance" (isTransactionBalanced Nothing t) + let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] + [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) + ,Posting False "c" (Mixed [dollars (-1.00)]) "" RegularPosting [] (Just t) + ,Posting False "d" (Mixed [dollars 100]) "" BalancedVirtualPosting [] (Just t) + ] "" + assertBool "balanced virtual postings need to balance among themselves" (not $ isTransactionBalanced Nothing t) + let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] + [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) + ,Posting False "c" (Mixed [dollars (-1.00)]) "" RegularPosting [] (Just t) + ,Posting False "d" (Mixed [dollars 100]) "" BalancedVirtualPosting [] (Just t) + ,Posting False "e" (Mixed [dollars (-100)]) "" BalancedVirtualPosting [] (Just t) + ] "" + assertBool "balanced virtual postings need to balance among themselves (2)" (isTransactionBalanced Nothing t) + ] diff --git a/hledger-lib/Hledger/Read.hs b/hledger-lib/Hledger/Read.hs index 5604cbfd5..2ba716bdc 100644 --- a/hledger-lib/Hledger/Read.hs +++ b/hledger-lib/Hledger/Read.hs @@ -137,12 +137,12 @@ myTimelog = myTimelogPath >>= readJournalFile Nothing >>= either error' return tests_Hledger_Read = TestList [ + tests_Hledger_Read_JournalReader, + tests_Hledger_Read_TimelogReader, "journalFile" ~: do assertBool "journalFile should parse an empty file" (isRight $ parseWithCtx nullctx JournalReader.journalFile "") jE <- readJournal Nothing "" -- don't know how to get it from journalFile either error' (assertBool "journalFile parsing an empty file should give an empty journal" . null . jtxns) jE - ,JournalReader.tests_JournalReader - ,TimelogReader.tests_TimelogReader ] diff --git a/hledger-lib/Hledger/Read/JournalReader.hs b/hledger-lib/Hledger/Read/JournalReader.hs index 1cd36e8ed..328b19a3b 100644 --- a/hledger-lib/Hledger/Read/JournalReader.hs +++ b/hledger-lib/Hledger/Read/JournalReader.hs @@ -104,17 +104,17 @@ i, o, b, h -} module Hledger.Read.JournalReader ( - tests_JournalReader, - reader, - journalFile, + emptyLine, journalAddFile, - someamount, + journalFile, ledgeraccountname, + ledgerdatetime, + ledgerDefaultYear, ledgerExclamationDirective, ledgerHistoricalPrice, - ledgerDefaultYear, - emptyLine, - ledgerdatetime, + reader, + someamount, + tests_Hledger_Read_JournalReader ) where import Control.Monad.Error (ErrorT(..), throwError, catchError) @@ -590,7 +590,7 @@ numberpartsstartingwithpoint = do return ("",frac) -tests_JournalReader = TestList [ +tests_Hledger_Read_JournalReader = TestList [ "ledgerTransaction" ~: do assertParseEqual (parseWithCtx nullctx ledgerTransaction entry1_str) entry1 diff --git a/hledger-lib/Hledger/Read/TimelogReader.hs b/hledger-lib/Hledger/Read/TimelogReader.hs index 4883044c1..e1f21b565 100644 --- a/hledger-lib/Hledger/Read/TimelogReader.hs +++ b/hledger-lib/Hledger/Read/TimelogReader.hs @@ -43,8 +43,8 @@ o 2007/03/10 17:26:02 -} module Hledger.Read.TimelogReader ( - tests_TimelogReader, reader, + tests_Hledger_Read_TimelogReader ) where import Control.Monad.Error (ErrorT(..)) @@ -96,6 +96,6 @@ timelogentry = do comment <- optionMaybe (many1 spacenonewline >> liftM2 (++) getParentAccount restofline) return $ TimeLogEntry (read [code]) datetime (maybe "" rstrip comment) -tests_TimelogReader = TestList [ +tests_Hledger_Read_TimelogReader = TestList [ ] diff --git a/hledger/Hledger/Cli.hs b/hledger/Hledger/Cli.hs new file mode 100644 index 000000000..f27cb3f9d --- /dev/null +++ b/hledger/Hledger/Cli.hs @@ -0,0 +1,909 @@ +{-| +Hledger.Cli re-exports the options, utilities and commands provided by the +hledger command-line program. +-} + +module Hledger.Cli ( + module Hledger.Cli.Add, + module Hledger.Cli.Balance, + module Hledger.Cli.Convert, + module Hledger.Cli.Histogram, + module Hledger.Cli.Print, + module Hledger.Cli.Register, + module Hledger.Cli.Stats, + module Hledger.Cli.Options, + module Hledger.Cli.Utils, + tests_Hledger_Cli + ) +where +import Hledger.Cli.Add +import Hledger.Cli.Balance +import Hledger.Cli.Convert +import Hledger.Cli.Histogram +import Hledger.Cli.Print +import Hledger.Cli.Register +import Hledger.Cli.Stats +import Hledger.Cli.Options +import Hledger.Cli.Utils + + +import qualified Data.Map as Map +import System.Time (ClockTime(TOD)) + +import Hledger.Data -- including testing utils in Hledger.Data.Utils +import Hledger.Read +import Hledger.Read.JournalReader (someamount) + + +-- | hledger and hledger-lib's unit tests aggregated from all modules +-- plus some more which are easier to define here for now. +-- tests_Hledger_Cli1 :: Test +tests_Hledger_Cli = TestList + [ + tests_Hledger_Data + ,tests_Hledger_Read + -- ,tests_Hledger_Cli_Add + -- ,tests_Hledger_Cli_Balance + ,tests_Hledger_Cli_Convert + -- ,tests_Hledger_Cli_Histogram + ,tests_Hledger_Cli_Options + -- ,tests_Hledger_Cli_Print + ,tests_Hledger_Cli_Register + -- ,tests_Hledger_Cli_Stats + + + ,"account directive" ~: + let sameParse str1 str2 = do j1 <- readJournal Nothing str1 >>= either error' return + j2 <- readJournal Nothing str2 >>= either error' return + j1 `is` j2{filereadtime=filereadtime j1, files=files j1, jContext=jContext j1} + in TestList + [ + "account directive 1" ~: sameParse + "2008/12/07 One\n test:from $-1\n test:to $1\n" + "!account test\n2008/12/07 One\n from $-1\n to $1\n" + + ,"account directive 2" ~: sameParse + "2008/12/07 One\n test:foo:from $-1\n test:foo:to $1\n" + "!account test\n!account foo\n2008/12/07 One\n from $-1\n to $1\n" + + ,"account directive 3" ~: sameParse + "2008/12/07 One\n test:from $-1\n test:to $1\n" + "!account test\n!account foo\n!end\n2008/12/07 One\n from $-1\n to $1\n" + + ,"account directive 4" ~: sameParse + ("2008/12/07 One\n alpha $-1\n beta $1\n" ++ + "!account outer\n2008/12/07 Two\n aigh $-2\n bee $2\n" ++ + "!account inner\n2008/12/07 Three\n gamma $-3\n delta $3\n" ++ + "!end\n2008/12/07 Four\n why $-4\n zed $4\n" ++ + "!end\n2008/12/07 Five\n foo $-5\n bar $5\n" + ) + ("2008/12/07 One\n alpha $-1\n beta $1\n" ++ + "2008/12/07 Two\n outer:aigh $-2\n outer:bee $2\n" ++ + "2008/12/07 Three\n outer:inner:gamma $-3\n outer:inner:delta $3\n" ++ + "2008/12/07 Four\n outer:why $-4\n outer:zed $4\n" ++ + "2008/12/07 Five\n foo $-5\n bar $5\n" + ) + ] + + ,"ledgerAccountNames" ~: + ledgerAccountNames ledger7 `is` + ["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances", + "expenses","expenses:food","expenses:food:dining","expenses:phone","expenses:vacation", + "liabilities","liabilities:credit cards","liabilities:credit cards:discover"] + + ,"balance report tests" ~: + let (opts,args) `gives` es = do + l <- samplejournalwithopts opts args + t <- getCurrentLocalTime + balanceReportAsText opts (balanceReport opts (optsToFilterSpec opts args t) l) `is` unlines es + in TestList + [ + + "balance report with no args" ~: + ([], []) `gives` + [" $-1 assets" + ," $1 bank:saving" + ," $-2 cash" + ," $2 expenses" + ," $1 food" + ," $1 supplies" + ," $-2 income" + ," $-1 gifts" + ," $-1 salary" + ," $1 liabilities:debts" + ,"--------------------" + ," $0" + ] + + ,"balance report can be limited with --depth" ~: + ([Depth "1"], []) `gives` + [" $-1 assets" + ," $2 expenses" + ," $-2 income" + ," $1 liabilities" + ,"--------------------" + ," $0" + ] + + ,"balance report with account pattern o" ~: + ([SubTotal], ["o"]) `gives` + [" $1 expenses:food" + ," $-2 income" + ," $-1 gifts" + ," $-1 salary" + ,"--------------------" + ," $-1" + ] + + ,"balance report with account pattern o and --depth 1" ~: + ([Depth "1"], ["o"]) `gives` + [" $1 expenses" + ," $-2 income" + ,"--------------------" + ," $-1" + ] + + ,"balance report with account pattern a" ~: + ([], ["a"]) `gives` + [" $-1 assets" + ," $1 bank:saving" + ," $-2 cash" + ," $-1 income:salary" + ," $1 liabilities:debts" + ,"--------------------" + ," $-1" + ] + + ,"balance report with account pattern e" ~: + ([], ["e"]) `gives` + [" $-1 assets" + ," $1 bank:saving" + ," $-2 cash" + ," $2 expenses" + ," $1 food" + ," $1 supplies" + ," $-2 income" + ," $-1 gifts" + ," $-1 salary" + ," $1 liabilities:debts" + ,"--------------------" + ," $0" + ] + + ,"balance report with unmatched parent of two matched subaccounts" ~: + ([], ["cash","saving"]) `gives` + [" $-1 assets" + ," $1 bank:saving" + ," $-2 cash" + ,"--------------------" + ," $-1" + ] + + ,"balance report with multi-part account name" ~: + ([], ["expenses:food"]) `gives` + [" $1 expenses:food" + ,"--------------------" + ," $1" + ] + + ,"balance report with negative account pattern" ~: + ([], ["not:assets"]) `gives` + [" $2 expenses" + ," $1 food" + ," $1 supplies" + ," $-2 income" + ," $-1 gifts" + ," $-1 salary" + ," $1 liabilities:debts" + ,"--------------------" + ," $1" + ] + + ,"balance report negative account pattern always matches full name" ~: + ([], ["not:e"]) `gives` + ["--------------------" + ," 0" + ] + + ,"balance report negative patterns affect totals" ~: + ([], ["expenses","not:food"]) `gives` + [" $1 expenses:supplies" + ,"--------------------" + ," $1" + ] + + ,"balance report with -E shows zero-balance accounts" ~: + ([SubTotal,Empty], ["assets"]) `gives` + [" $-1 assets" + ," $1 bank" + ," $0 checking" + ," $1 saving" + ," $-2 cash" + ,"--------------------" + ," $-1" + ] + + ,"balance report with cost basis" ~: do + j <- (readJournal Nothing $ unlines + ["" + ,"2008/1/1 test " + ," a:b 10h @ $50" + ," c:d " + ]) >>= either error' return + let j' = journalCanonicaliseAmounts $ journalConvertAmountsToCost j -- enable cost basis adjustment + balanceReportAsText [] (balanceReport [] nullfilterspec j') `is` + unlines + [" $500 a:b" + ," $-500 c:d" + ,"--------------------" + ," $0" + ] + + ,"balance report elides zero-balance root account(s)" ~: do + l <- readJournalWithOpts [] + (unlines + ["2008/1/1 one" + ," test:a 1" + ," test:b" + ]) + balanceReportAsText [] (balanceReport [] nullfilterspec l) `is` + unlines + [" 1 test:a" + ," -1 test:b" + ,"--------------------" + ," 0" + ] + + ] + + ,"journalCanonicaliseAmounts" ~: + "use the greatest precision" ~: + (map precision $ journalAmountAndPriceCommodities $ journalCanonicaliseAmounts $ journalWithAmounts ["1","2.00"]) `is` [2,2] + + ,"commodities" ~: + Map.elems (commodities ledger7) `is` [Commodity {symbol="$", side=L, spaced=False, comma=False, precision=2}] + + -- don't know what this should do + -- ,"elideAccountName" ~: do + -- (elideAccountName 50 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa" + -- `is` "aa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa") + -- (elideAccountName 20 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa" + -- `is` "aa:aa:aaaaaaaaaaaaaa") + + ,"default year" ~: do + rl <- readJournal Nothing defaultyear_journal_str >>= either error' return + tdate (head $ jtxns rl) `is` fromGregorian 2009 1 1 + return () + + ,"print report tests" ~: TestList + [ + + "print expenses" ~: + do + let args = ["expenses"] + l <- samplejournalwithopts [] args + t <- getCurrentLocalTime + showTransactions (optsToFilterSpec [] args t) l `is` unlines + ["2008/06/03 * eat & shop" + ," expenses:food $1" + ," expenses:supplies $1" + ," assets:cash $-2" + ,"" + ] + + , "print report with depth arg" ~: + do + l <- samplejournal + t <- getCurrentLocalTime + showTransactions (optsToFilterSpec [Depth "2"] [] t) l `is` unlines + ["2008/01/01 income" + ," income:salary $-1" + ,"" + ,"2008/06/01 gift" + ," income:gifts $-1" + ,"" + ,"2008/06/03 * eat & shop" + ," expenses:food $1" + ," expenses:supplies $1" + ," assets:cash $-2" + ,"" + ,"2008/12/31 * pay off" + ," liabilities:debts $1" + ,"" + ] + + ] + + ,"register report tests" ~: + let registerdates = filter (not . null) . map (strip . take 10) . lines + in + TestList + [ + + "register report with no args" ~: + do + l <- samplejournal + (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] [] t1) l) `is` unlines + ["2008/01/01 income assets:bank:checking $1 $1" + ," income:salary $-1 0" + ,"2008/06/01 gift assets:bank:checking $1 $1" + ," income:gifts $-1 0" + ,"2008/06/02 save assets:bank:saving $1 $1" + ," assets:bank:checking $-1 0" + ,"2008/06/03 eat & shop expenses:food $1 $1" + ," expenses:supplies $1 $2" + ," assets:cash $-2 0" + ,"2008/12/31 pay off liabilities:debts $1 $1" + ," assets:bank:checking $-1 0" + ] + + ,"register report with cleared option" ~: + do + let opts = [Cleared] + l <- readJournalWithOpts opts sample_journal_str + (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` unlines + ["2008/06/03 eat & shop expenses:food $1 $1" + ," expenses:supplies $1 $2" + ," assets:cash $-2 0" + ,"2008/12/31 pay off liabilities:debts $1 $1" + ," assets:bank:checking $-1 0" + ] + + ,"register report with uncleared option" ~: + do + let opts = [UnCleared] + l <- readJournalWithOpts opts sample_journal_str + (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` unlines + ["2008/01/01 income assets:bank:checking $1 $1" + ," income:salary $-1 0" + ,"2008/06/01 gift assets:bank:checking $1 $1" + ," income:gifts $-1 0" + ,"2008/06/02 save assets:bank:saving $1 $1" + ," assets:bank:checking $-1 0" + ] + + ,"register report sorts by date" ~: + do + l <- readJournalWithOpts [] $ unlines + ["2008/02/02 a" + ," b 1" + ," c" + ,"" + ,"2008/01/01 d" + ," e 1" + ," f" + ] + registerdates (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] [] t1) l) `is` ["2008/01/01","2008/02/02"] + + ,"register report with account pattern" ~: + do + l <- samplejournal + (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] ["cash"] t1) l) `is` unlines + ["2008/06/03 eat & shop assets:cash $-2 $-2" + ] + + ,"register report with account pattern, case insensitive" ~: + do + l <- samplejournal + (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] ["cAsH"] t1) l) `is` unlines + ["2008/06/03 eat & shop assets:cash $-2 $-2" + ] + + ,"register report with display expression" ~: + do + l <- samplejournal + let gives displayexpr = + (registerdates (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is`) + where opts = [Display displayexpr] + "d<[2008/6/2]" `gives` ["2008/01/01","2008/06/01"] + "d<=[2008/6/2]" `gives` ["2008/01/01","2008/06/01","2008/06/02"] + "d=[2008/6/2]" `gives` ["2008/06/02"] + "d>=[2008/6/2]" `gives` ["2008/06/02","2008/06/03","2008/12/31"] + "d>[2008/6/2]" `gives` ["2008/06/03","2008/12/31"] + + ,"register report with period expression" ~: + do + l <- samplejournal + let periodexpr `gives` dates = do + l' <- samplejournalwithopts opts [] + registerdates (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l') `is` dates + where opts = [Period periodexpr] + "" `gives` ["2008/01/01","2008/06/01","2008/06/02","2008/06/03","2008/12/31"] + "2008" `gives` ["2008/01/01","2008/06/01","2008/06/02","2008/06/03","2008/12/31"] + "2007" `gives` [] + "june" `gives` ["2008/06/01","2008/06/02","2008/06/03"] + "monthly" `gives` ["2008/01/01","2008/06/01","2008/12/01"] + "quarterly" `gives` ["2008/01/01","2008/04/01","2008/10/01"] + let opts = [Period "yearly"] + (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` unlines + ["2008/01/01 - 2008/12/31 assets:bank:saving $1 $1" + ," assets:cash $-2 $-1" + ," expenses:food $1 0" + ," expenses:supplies $1 $1" + ," income:gifts $-1 0" + ," income:salary $-1 $-1" + ," liabilities:debts $1 0" + ] + let opts = [Period "quarterly"] + registerdates (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` ["2008/01/01","2008/04/01","2008/10/01"] + let opts = [Period "quarterly",Empty] + registerdates (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` ["2008/01/01","2008/04/01","2008/07/01","2008/10/01"] + + ] + + , "register report with depth arg" ~: + do + l <- samplejournal + let opts = [Depth "2"] + (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` unlines + ["2008/01/01 income assets:bank $1 $1" + ," income:salary $-1 0" + ,"2008/06/01 gift assets:bank $1 $1" + ," income:gifts $-1 0" + ,"2008/06/02 save assets:bank $1 $1" + ," assets:bank $-1 0" + ,"2008/06/03 eat & shop expenses:food $1 $1" + ," expenses:supplies $1 $2" + ," assets:cash $-2 0" + ,"2008/12/31 pay off liabilities:debts $1 $1" + ," assets:bank $-1 0" + ] + + ,"show dollars" ~: show (dollars 1) ~?= "$1.00" + + ,"show hours" ~: show (hours 1) ~?= "1.0h" + + ,"unicode in balance layout" ~: do + l <- readJournalWithOpts [] + "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n" + balanceReportAsText [] (balanceReport [] (optsToFilterSpec [] [] t1) l) `is` unlines + [" -100 актив:наличные" + ," 100 расходы:покупки" + ,"--------------------" + ," 0" + ] + + ,"unicode in register layout" ~: do + l <- readJournalWithOpts [] + "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n" + (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] [] t1) l) `is` unlines + ["2009/01/01 медвежья шкура расходы:покупки 100 100" + ," актив:наличные -100 0"] + + ,"subAccounts" ~: do + l <- liftM (journalToLedger nullfilterspec) samplejournal + let a = ledgerAccount l "assets" + map aname (ledgerSubAccounts l a) `is` ["assets:bank","assets:cash"] + + ] + + +-- fixtures/test data + +t1 = LocalTime date1 midday where date1 = parsedate "2008/11/26" + +samplejournal = readJournalWithOpts [] sample_journal_str +samplejournalwithopts opts _ = readJournalWithOpts opts sample_journal_str + +sample_journal_str = unlines + ["; A sample journal file." + ,";" + ,"; Sets up this account tree:" + ,"; assets" + ,"; bank" + ,"; checking" + ,"; saving" + ,"; cash" + ,"; expenses" + ,"; food" + ,"; supplies" + ,"; income" + ,"; gifts" + ,"; salary" + ,"; liabilities" + ,"; debts" + ,"" + ,"2008/01/01 income" + ," assets:bank:checking $1" + ," income:salary" + ,"" + ,"2008/06/01 gift" + ," assets:bank:checking $1" + ," income:gifts" + ,"" + ,"2008/06/02 save" + ," assets:bank:saving $1" + ," assets:bank:checking" + ,"" + ,"2008/06/03 * eat & shop" + ," expenses:food $1" + ," expenses:supplies $1" + ," assets:cash" + ,"" + ,"2008/12/31 * pay off" + ," liabilities:debts $1" + ," assets:bank:checking" + ,"" + ,"" + ,";final comment" + ] + +defaultyear_journal_str = unlines + ["Y2009" + ,"" + ,"01/01 A" + ," a $1" + ," b" + ] + +-- write_sample_journal = writeFile "sample.journal" sample_journal_str + +-- entry2_str = unlines +-- ["2007/01/27 * joes diner" +-- ," expenses:food:dining $10.00" +-- ," expenses:gifts $10.00" +-- ," assets:checking $-20.00" +-- ,"" +-- ] + +-- entry3_str = unlines +-- ["2007/01/01 * opening balance" +-- ," assets:cash $4.82" +-- ," equity:opening balances" +-- ,"" +-- ,"2007/01/01 * opening balance" +-- ," assets:cash $4.82" +-- ," equity:opening balances" +-- ,"" +-- ,"2007/01/28 coopportunity" +-- ," expenses:food:groceries $47.18" +-- ," assets:checking" +-- ,"" +-- ] + +-- periodic_entry1_str = unlines +-- ["~ monthly from 2007/2/2" +-- ," assets:saving $200.00" +-- ," assets:checking" +-- ,"" +-- ] + +-- periodic_entry2_str = unlines +-- ["~ monthly from 2007/2/2" +-- ," assets:saving $200.00 ;auto savings" +-- ," assets:checking" +-- ,"" +-- ] + +-- periodic_entry3_str = unlines +-- ["~ monthly from 2007/01/01" +-- ," assets:cash $4.82" +-- ," equity:opening balances" +-- ,"" +-- ,"~ monthly from 2007/01/01" +-- ," assets:cash $4.82" +-- ," equity:opening balances" +-- ,"" +-- ] + +-- journal1_str = unlines +-- ["" +-- ,"2007/01/27 * joes diner" +-- ," expenses:food:dining $10.00" +-- ," expenses:gifts $10.00" +-- ," assets:checking $-20.00" +-- ,"" +-- ,"" +-- ,"2007/01/28 coopportunity" +-- ," expenses:food:groceries $47.18" +-- ," assets:checking $-47.18" +-- ,"" +-- ,"" +-- ] + +-- journal2_str = unlines +-- [";comment" +-- ,"2007/01/27 * joes diner" +-- ," expenses:food:dining $10.00" +-- ," assets:checking $-47.18" +-- ,"" +-- ] + +-- journal3_str = unlines +-- ["2007/01/27 * joes diner" +-- ," expenses:food:dining $10.00" +-- ,";intra-entry comment" +-- ," assets:checking $-47.18" +-- ,"" +-- ] + +-- journal4_str = unlines +-- ["!include \"somefile\"" +-- ,"2007/01/27 * joes diner" +-- ," expenses:food:dining $10.00" +-- ," assets:checking $-47.18" +-- ,"" +-- ] + +-- journal5_str = "" + +-- journal6_str = unlines +-- ["~ monthly from 2007/1/21" +-- ," expenses:entertainment $16.23 ;netflix" +-- ," assets:checking" +-- ,"" +-- ,"; 2007/01/01 * opening balance" +-- ,"; assets:saving $200.04" +-- ,"; equity:opening balances " +-- ,"" +-- ] + +-- journal7_str = unlines +-- ["2007/01/01 * opening balance" +-- ," assets:cash $4.82" +-- ," equity:opening balances " +-- ,"" +-- ,"2007/01/01 * opening balance" +-- ," income:interest $-4.82" +-- ," equity:opening balances " +-- ,"" +-- ,"2007/01/02 * ayres suites" +-- ," expenses:vacation $179.92" +-- ," assets:checking " +-- ,"" +-- ,"2007/01/02 * auto transfer to savings" +-- ," assets:saving $200.00" +-- ," assets:checking " +-- ,"" +-- ,"2007/01/03 * poquito mas" +-- ," expenses:food:dining $4.82" +-- ," assets:cash " +-- ,"" +-- ,"2007/01/03 * verizon" +-- ," expenses:phone $95.11" +-- ," assets:checking " +-- ,"" +-- ,"2007/01/03 * discover" +-- ," liabilities:credit cards:discover $80.00" +-- ," assets:checking " +-- ,"" +-- ,"2007/01/04 * blue cross" +-- ," expenses:health:insurance $90.00" +-- ," assets:checking " +-- ,"" +-- ,"2007/01/05 * village market liquor" +-- ," expenses:food:dining $6.48" +-- ," assets:checking " +-- ,"" +-- ] + +journal7 = Journal + [] + [] + [ + txnTieKnot $ Transaction { + tdate=parsedate "2007/01/01", + teffectivedate=Nothing, + tstatus=False, + tcode="*", + tdescription="opening balance", + tcomment="", + tmetadata=[], + tpostings=[ + Posting { + pstatus=False, + paccount="assets:cash", + pamount=(Mixed [dollars 4.82]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + }, + Posting { + pstatus=False, + paccount="equity:opening balances", + pamount=(Mixed [dollars (-4.82)]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + } + ], + tpreceding_comment_lines="" + } + , + txnTieKnot $ Transaction { + tdate=parsedate "2007/02/01", + teffectivedate=Nothing, + tstatus=False, + tcode="*", + tdescription="ayres suites", + tcomment="", + tmetadata=[], + tpostings=[ + Posting { + pstatus=False, + paccount="expenses:vacation", + pamount=(Mixed [dollars 179.92]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + }, + Posting { + pstatus=False, + paccount="assets:checking", + pamount=(Mixed [dollars (-179.92)]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + } + ], + tpreceding_comment_lines="" + } + , + txnTieKnot $ Transaction { + tdate=parsedate "2007/01/02", + teffectivedate=Nothing, + tstatus=False, + tcode="*", + tdescription="auto transfer to savings", + tcomment="", + tmetadata=[], + tpostings=[ + Posting { + pstatus=False, + paccount="assets:saving", + pamount=(Mixed [dollars 200]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + }, + Posting { + pstatus=False, + paccount="assets:checking", + pamount=(Mixed [dollars (-200)]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + } + ], + tpreceding_comment_lines="" + } + , + txnTieKnot $ Transaction { + tdate=parsedate "2007/01/03", + teffectivedate=Nothing, + tstatus=False, + tcode="*", + tdescription="poquito mas", + tcomment="", + tmetadata=[], + tpostings=[ + Posting { + pstatus=False, + paccount="expenses:food:dining", + pamount=(Mixed [dollars 4.82]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + }, + Posting { + pstatus=False, + paccount="assets:cash", + pamount=(Mixed [dollars (-4.82)]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + } + ], + tpreceding_comment_lines="" + } + , + txnTieKnot $ Transaction { + tdate=parsedate "2007/01/03", + teffectivedate=Nothing, + tstatus=False, + tcode="*", + tdescription="verizon", + tcomment="", + tmetadata=[], + tpostings=[ + Posting { + pstatus=False, + paccount="expenses:phone", + pamount=(Mixed [dollars 95.11]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + }, + Posting { + pstatus=False, + paccount="assets:checking", + pamount=(Mixed [dollars (-95.11)]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + } + ], + tpreceding_comment_lines="" + } + , + txnTieKnot $ Transaction { + tdate=parsedate "2007/01/03", + teffectivedate=Nothing, + tstatus=False, + tcode="*", + tdescription="discover", + tcomment="", + tmetadata=[], + tpostings=[ + Posting { + pstatus=False, + paccount="liabilities:credit cards:discover", + pamount=(Mixed [dollars 80]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + }, + Posting { + pstatus=False, + paccount="assets:checking", + pamount=(Mixed [dollars (-80)]), + pcomment="", + ptype=RegularPosting, + pmetadata=[], + ptransaction=Nothing + } + ], + tpreceding_comment_lines="" + } + ] + [] + [] + "" + nullctx + [] + (TOD 0 0) + +ledger7 = journalToLedger nullfilterspec journal7 + +-- journal8_str = unlines +-- ["2008/1/1 test " +-- ," a:b 10h @ $40" +-- ," c:d " +-- ,"" +-- ] + +-- timelogentry1_str = "i 2007/03/11 16:19:00 hledger\n" +-- timelogentry1 = TimeLogEntry In (parsedatetime "2007/03/11 16:19:00") "hledger" + +-- timelogentry2_str = "o 2007/03/11 16:30:00\n" +-- timelogentry2 = TimeLogEntry Out (parsedatetime "2007/03/11 16:30:00") "" + +-- a1 = Mixed [(hours 1){price=Just $ Mixed [Amount (comm "$") 10 Nothing]}] +-- a2 = Mixed [(hours 2){price=Just $ Mixed [Amount (comm "EUR") 10 Nothing]}] +-- a3 = Mixed $ amounts a1 ++ amounts a2 + +journalWithAmounts :: [String] -> Journal +journalWithAmounts as = + Journal + [] + [] + [t | a <- as, let t = nulltransaction{tdescription=a,tpostings=[nullposting{pamount=parse a,ptransaction=Just t}]}] + [] + [] + "" + nullctx + [] + (TOD 0 0) + where parse = fromparse . parseWithCtx nullctx someamount + diff --git a/hledger/Hledger/Cli/Balance.hs b/hledger/Hledger/Cli/Balance.hs index 328c4b47d..194ae9676 100644 --- a/hledger/Hledger/Cli/Balance.hs +++ b/hledger/Hledger/Cli/Balance.hs @@ -101,6 +101,7 @@ module Hledger.Cli.Balance ( ,balance ,balanceReport ,balanceReportAsText + ,tests_Hledger_Cli_Balance -- ,tests_Balance ) where import Hledger.Data.Utils @@ -211,3 +212,6 @@ isInterestingIndented opts l a isInterestingTree = treeany (isInteresting opts l . aname) subtrees = map (fromJust . ledgerAccountTreeAt l) $ ledgerSubAccounts l $ ledgerAccount l a +tests_Hledger_Cli_Balance = TestList + [ + ] diff --git a/hledger/Hledger/Cli/Commands.hs b/hledger/Hledger/Cli/Commands.hs deleted file mode 100644 index f6209a990..000000000 --- a/hledger/Hledger/Cli/Commands.hs +++ /dev/null @@ -1,40 +0,0 @@ -{-# LANGUAGE CPP #-} -{-| - -The Commands package defines all the commands offered by the hledger -application, like \"register\" and \"balance\". This module exports all -the commands; you can also import individual modules if you prefer. - --} - -module Hledger.Cli.Commands ( - module Hledger.Cli.Add, - module Hledger.Cli.Balance, - module Hledger.Cli.Convert, - module Hledger.Cli.Histogram, - module Hledger.Cli.Print, - module Hledger.Cli.Register, - module Hledger.Cli.Stats, - tests_Hledger_Commands - ) -where -import Hledger.Cli.Add -import Hledger.Cli.Balance -import Hledger.Cli.Convert -import Hledger.Cli.Histogram -import Hledger.Cli.Print -import Hledger.Cli.Register -import Hledger.Cli.Stats -import Test.HUnit (Test(TestList)) - - -tests_Hledger_Commands = TestList - [ --- Hledger.Cli.Add.tests_Add --- ,Hledger.Cli.Balance.tests_Balance - Hledger.Cli.Convert.tests_Convert --- ,Hledger.Cli.Histogram.tests_Histogram --- ,Hledger.Cli.Print.tests_Print - ,Hledger.Cli.Register.tests_Register --- ,Hledger.Cli.Stats.tests_Stats - ] diff --git a/hledger/Hledger/Cli/Convert.hs b/hledger/Hledger/Cli/Convert.hs index cd4c08bed..810a5f825 100644 --- a/hledger/Hledger/Cli/Convert.hs +++ b/hledger/Hledger/Cli/Convert.hs @@ -350,7 +350,7 @@ identify rules defacct desc | null matchingrules = (defacct,desc) caseinsensitive = ("(?i)"++) -tests_Convert = TestList [ +tests_Hledger_Cli_Convert = TestList [ "convert rules parsing: empty file" ~: do -- let assertMixedAmountParse parseresult mixedamount = diff --git a/hledger/Hledger/Cli/Options.hs b/hledger/Hledger/Cli/Options.hs index bfcf3f6db..720d55f54 100644 --- a/hledger/Hledger/Cli/Options.hs +++ b/hledger/Hledger/Cli/Options.hs @@ -295,3 +295,28 @@ optsToFilterSpec opts args t = FilterSpec { -- where -- listtomaybe [] = Nothing -- listtomaybe vs = Just $ last vs + +tests_Hledger_Cli_Options = TestList + [ + "dateSpanFromOpts" ~: do + let todaysdate = parsedate "2008/11/26" + let gives = is . show . dateSpanFromOpts todaysdate + [] `gives` "DateSpan Nothing Nothing" + [Begin "2008", End "2009"] `gives` "DateSpan (Just 2008-01-01) (Just 2009-01-01)" + [Period "in 2008"] `gives` "DateSpan (Just 2008-01-01) (Just 2009-01-01)" + [Begin "2005", End "2007",Period "in 2008"] `gives` "DateSpan (Just 2008-01-01) (Just 2009-01-01)" + + ,"intervalFromOpts" ~: do + let gives = is . intervalFromOpts + [] `gives` NoInterval + [DailyOpt] `gives` Daily + [WeeklyOpt] `gives` Weekly + [MonthlyOpt] `gives` Monthly + [QuarterlyOpt] `gives` Quarterly + [YearlyOpt] `gives` Yearly + [Period "weekly"] `gives` Weekly + [Period "monthly"] `gives` Monthly + [Period "quarterly"] `gives` Quarterly + [WeeklyOpt, Period "yearly"] `gives` Yearly + + ] \ No newline at end of file diff --git a/hledger/Hledger/Cli/Register.hs b/hledger/Hledger/Cli/Register.hs index db2b09cd7..c3f232b78 100644 --- a/hledger/Hledger/Cli/Register.hs +++ b/hledger/Hledger/Cli/Register.hs @@ -12,7 +12,7 @@ module Hledger.Cli.Register ( ,registerReport ,registerReportAsText ,showPostingWithBalanceForVty - ,tests_Register + ,tests_Hledger_Cli_Register ) where import Safe (headMay, lastMay) @@ -198,10 +198,46 @@ depthClipPosting Nothing p = p depthClipPosting (Just d) p@Posting{paccount=a} = p{paccount=clipAccountName d a} -tests_Register :: Test -tests_Register = TestList [ +tests_Hledger_Cli_Register :: Test +tests_Hledger_Cli_Register = TestList + [ - "summarisePostingsByInterval" ~: do - summarisePostingsByInterval Quarterly Nothing False (DateSpan Nothing Nothing) [] ~?= [] + "summarisePostingsByInterval" ~: do + summarisePostingsByInterval Quarterly Nothing False (DateSpan Nothing Nothing) [] ~?= [] - ] + -- ,"summarisePostingsInDateSpan" ~: do + -- let gives (b,e,depth,showempty,ps) = + -- (summarisePostingsInDateSpan (mkdatespan b e) depth showempty ps `is`) + -- let ps = + -- [ + -- nullposting{lpdescription="desc",lpaccount="expenses:food:groceries",lpamount=Mixed [dollars 1]} + -- ,nullposting{lpdescription="desc",lpaccount="expenses:food:dining", lpamount=Mixed [dollars 2]} + -- ,nullposting{lpdescription="desc",lpaccount="expenses:food", lpamount=Mixed [dollars 4]} + -- ,nullposting{lpdescription="desc",lpaccount="expenses:food:dining", lpamount=Mixed [dollars 8]} + -- ] + -- ("2008/01/01","2009/01/01",0,9999,False,[]) `gives` + -- [] + -- ("2008/01/01","2009/01/01",0,9999,True,[]) `gives` + -- [ + -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31"} + -- ] + -- ("2008/01/01","2009/01/01",0,9999,False,ts) `gives` + -- [ + -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses:food", lpamount=Mixed [dollars 4]} + -- ,nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses:food:dining", lpamount=Mixed [dollars 10]} + -- ,nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses:food:groceries",lpamount=Mixed [dollars 1]} + -- ] + -- ("2008/01/01","2009/01/01",0,2,False,ts) `gives` + -- [ + -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses:food",lpamount=Mixed [dollars 15]} + -- ] + -- ("2008/01/01","2009/01/01",0,1,False,ts) `gives` + -- [ + -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses",lpamount=Mixed [dollars 15]} + -- ] + -- ("2008/01/01","2009/01/01",0,0,False,ts) `gives` + -- [ + -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="",lpamount=Mixed [dollars 15]} + -- ] + + ] diff --git a/hledger/Hledger/Cli/Tests.hs b/hledger/Hledger/Cli/Tests.hs index 98dfc0373..dd64c1e19 100644 --- a/hledger/Hledger/Cli/Tests.hs +++ b/hledger/Hledger/Cli/Tests.hs @@ -28,16 +28,10 @@ $ bin/hledger -f data/sample.journal balance o module Hledger.Cli.Tests where -import qualified Data.Map as Map import System.Exit (exitFailure, exitWith, ExitCode(ExitSuccess)) -- base 3 compatible -import System.Time (ClockTime(TOD)) import Hledger.Data -- including testing utils in Hledger.Data.Utils -import Hledger.Read (readJournal) -import Hledger.Read.JournalReader (someamount) -import Hledger.Cli.Commands -import Hledger.Cli.Options -import Hledger.Cli.Utils +import Hledger.Cli -- | Run unit tests. @@ -48,1068 +42,7 @@ runtests _ args = do then exitFailure else exitWith ExitSuccess where - ts = TestList $ filter matchname $ tflatten tests -- show flat test names + ts = TestList $ filter matchname $ tflatten tests_Hledger_Cli -- show flat test names -- ts = tfilter matchname $ TestList tests -- show hierarchical test names matchname = matchpats args . tname --- | unit tests, augmenting the ones defined in each module. Where that is --- inconvenient due to import cycles or whatever, we define them here. -tests :: Test -tests = TestList [ - tests_Hledger_Data, - tests_Hledger_Commands, - - "account directive" ~: - let sameParse str1 str2 = do j1 <- readJournal Nothing str1 >>= either error' return - j2 <- readJournal Nothing str2 >>= either error' return - j1 `is` j2{filereadtime=filereadtime j1, files=files j1, jContext=jContext j1} - in TestList - [ - "account directive 1" ~: sameParse - "2008/12/07 One\n test:from $-1\n test:to $1\n" - "!account test\n2008/12/07 One\n from $-1\n to $1\n" - - ,"account directive 2" ~: sameParse - "2008/12/07 One\n test:foo:from $-1\n test:foo:to $1\n" - "!account test\n!account foo\n2008/12/07 One\n from $-1\n to $1\n" - - ,"account directive 3" ~: sameParse - "2008/12/07 One\n test:from $-1\n test:to $1\n" - "!account test\n!account foo\n!end\n2008/12/07 One\n from $-1\n to $1\n" - - ,"account directive 4" ~: sameParse - ("2008/12/07 One\n alpha $-1\n beta $1\n" ++ - "!account outer\n2008/12/07 Two\n aigh $-2\n bee $2\n" ++ - "!account inner\n2008/12/07 Three\n gamma $-3\n delta $3\n" ++ - "!end\n2008/12/07 Four\n why $-4\n zed $4\n" ++ - "!end\n2008/12/07 Five\n foo $-5\n bar $5\n" - ) - ("2008/12/07 One\n alpha $-1\n beta $1\n" ++ - "2008/12/07 Two\n outer:aigh $-2\n outer:bee $2\n" ++ - "2008/12/07 Three\n outer:inner:gamma $-3\n outer:inner:delta $3\n" ++ - "2008/12/07 Four\n outer:why $-4\n outer:zed $4\n" ++ - "2008/12/07 Five\n foo $-5\n bar $5\n" - ) - ] - - ,"accountnames" ~: - accountnames ledger7 `is` - ["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances", - "expenses","expenses:food","expenses:food:dining","expenses:phone","expenses:vacation", - "liabilities","liabilities:credit cards","liabilities:credit cards:discover"] - - ,"accountNameTreeFrom" ~: do - accountNameTreeFrom ["a"] `is` Node "top" [Node "a" []] - accountNameTreeFrom ["a","b"] `is` Node "top" [Node "a" [], Node "b" []] - accountNameTreeFrom ["a","a:b"] `is` Node "top" [Node "a" [Node "a:b" []]] - accountNameTreeFrom ["a:b:c"] `is` Node "top" [Node "a" [Node "a:b" [Node "a:b:c" []]]] - - ,"balance report tests" ~: - let (opts,args) `gives` es = do - l <- samplejournalwithopts opts args - t <- getCurrentLocalTime - balanceReportAsText opts (balanceReport opts (optsToFilterSpec opts args t) l) `is` unlines es - in TestList - [ - - "balance report with no args" ~: - ([], []) `gives` - [" $-1 assets" - ," $1 bank:saving" - ," $-2 cash" - ," $2 expenses" - ," $1 food" - ," $1 supplies" - ," $-2 income" - ," $-1 gifts" - ," $-1 salary" - ," $1 liabilities:debts" - ,"--------------------" - ," $0" - ] - - ,"balance report can be limited with --depth" ~: - ([Depth "1"], []) `gives` - [" $-1 assets" - ," $2 expenses" - ," $-2 income" - ," $1 liabilities" - ,"--------------------" - ," $0" - ] - - ,"balance report with account pattern o" ~: - ([SubTotal], ["o"]) `gives` - [" $1 expenses:food" - ," $-2 income" - ," $-1 gifts" - ," $-1 salary" - ,"--------------------" - ," $-1" - ] - - ,"balance report with account pattern o and --depth 1" ~: - ([Depth "1"], ["o"]) `gives` - [" $1 expenses" - ," $-2 income" - ,"--------------------" - ," $-1" - ] - - ,"balance report with account pattern a" ~: - ([], ["a"]) `gives` - [" $-1 assets" - ," $1 bank:saving" - ," $-2 cash" - ," $-1 income:salary" - ," $1 liabilities:debts" - ,"--------------------" - ," $-1" - ] - - ,"balance report with account pattern e" ~: - ([], ["e"]) `gives` - [" $-1 assets" - ," $1 bank:saving" - ," $-2 cash" - ," $2 expenses" - ," $1 food" - ," $1 supplies" - ," $-2 income" - ," $-1 gifts" - ," $-1 salary" - ," $1 liabilities:debts" - ,"--------------------" - ," $0" - ] - - ,"balance report with unmatched parent of two matched subaccounts" ~: - ([], ["cash","saving"]) `gives` - [" $-1 assets" - ," $1 bank:saving" - ," $-2 cash" - ,"--------------------" - ," $-1" - ] - - ,"balance report with multi-part account name" ~: - ([], ["expenses:food"]) `gives` - [" $1 expenses:food" - ,"--------------------" - ," $1" - ] - - ,"balance report with negative account pattern" ~: - ([], ["not:assets"]) `gives` - [" $2 expenses" - ," $1 food" - ," $1 supplies" - ," $-2 income" - ," $-1 gifts" - ," $-1 salary" - ," $1 liabilities:debts" - ,"--------------------" - ," $1" - ] - - ,"balance report negative account pattern always matches full name" ~: - ([], ["not:e"]) `gives` - ["--------------------" - ," 0" - ] - - ,"balance report negative patterns affect totals" ~: - ([], ["expenses","not:food"]) `gives` - [" $1 expenses:supplies" - ,"--------------------" - ," $1" - ] - - ,"balance report with -E shows zero-balance accounts" ~: - ([SubTotal,Empty], ["assets"]) `gives` - [" $-1 assets" - ," $1 bank" - ," $0 checking" - ," $1 saving" - ," $-2 cash" - ,"--------------------" - ," $-1" - ] - - ,"balance report with cost basis" ~: do - j <- (readJournal Nothing $ unlines - ["" - ,"2008/1/1 test " - ," a:b 10h @ $50" - ," c:d " - ]) >>= either error' return - let j' = journalCanonicaliseAmounts $ journalConvertAmountsToCost j -- enable cost basis adjustment - balanceReportAsText [] (balanceReport [] nullfilterspec j') `is` - unlines - [" $500 a:b" - ," $-500 c:d" - ,"--------------------" - ," $0" - ] - - ,"balance report elides zero-balance root account(s)" ~: do - l <- readJournalWithOpts [] - (unlines - ["2008/1/1 one" - ," test:a 1" - ," test:b" - ]) - balanceReportAsText [] (balanceReport [] nullfilterspec l) `is` - unlines - [" 1 test:a" - ," -1 test:b" - ,"--------------------" - ," 0" - ] - - ] - - ,"balanceTransaction" ~: do - assertBool "detect unbalanced entry, sign error" - (isLeft $ balanceTransaction Nothing - (Transaction (parsedate "2007/01/28") Nothing False "" "test" "" [] - [Posting False "a" (Mixed [dollars 1]) "" RegularPosting [] Nothing, - Posting False "b" (Mixed [dollars 1]) "" RegularPosting [] Nothing - ] "")) - assertBool "detect unbalanced entry, multiple missing amounts" - (isLeft $ balanceTransaction Nothing - (Transaction (parsedate "2007/01/28") Nothing False "" "test" "" [] - [Posting False "a" missingamt "" RegularPosting [] Nothing, - Posting False "b" missingamt "" RegularPosting [] Nothing - ] "")) - let e = balanceTransaction Nothing (Transaction (parsedate "2007/01/28") Nothing False "" "test" "" [] - [Posting False "a" (Mixed [dollars 1]) "" RegularPosting [] Nothing, - Posting False "b" missingamt "" RegularPosting [] Nothing - ] "") - assertBool "one missing amount should be ok" (isRight e) - assertEqual "balancing amount is added" - (Mixed [dollars (-1)]) - (case e of - Right e' -> (pamount $ last $ tpostings e') - Left _ -> error' "should not happen") - - ,"journalCanonicaliseAmounts" ~: - "use the greatest precision" ~: - (map precision $ journalAmountAndPriceCommodities $ journalCanonicaliseAmounts $ journalWithAmounts ["1","2.00"]) `is` [2,2] - - ,"commodities" ~: - Map.elems (commodities ledger7) `is` [Commodity {symbol="$", side=L, spaced=False, comma=False, precision=2}] - - ,"dateSpanFromOpts" ~: do - let todaysdate = parsedate "2008/11/26" - let gives = is . show . dateSpanFromOpts todaysdate - [] `gives` "DateSpan Nothing Nothing" - [Begin "2008", End "2009"] `gives` "DateSpan (Just 2008-01-01) (Just 2009-01-01)" - [Period "in 2008"] `gives` "DateSpan (Just 2008-01-01) (Just 2009-01-01)" - [Begin "2005", End "2007",Period "in 2008"] `gives` "DateSpan (Just 2008-01-01) (Just 2009-01-01)" - - -- don't know what this should do - -- ,"elideAccountName" ~: do - -- (elideAccountName 50 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa" - -- `is` "aa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa") - -- (elideAccountName 20 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa" - -- `is` "aa:aa:aaaaaaaaaaaaaa") - - ,"expandAccountNames" ~: - expandAccountNames ["assets:cash","assets:checking","expenses:vacation"] `is` - ["assets","assets:cash","assets:checking","expenses","expenses:vacation"] - - ,"intervalFromOpts" ~: do - let gives = is . intervalFromOpts - [] `gives` NoInterval - [DailyOpt] `gives` Daily - [WeeklyOpt] `gives` Weekly - [MonthlyOpt] `gives` Monthly - [QuarterlyOpt] `gives` Quarterly - [YearlyOpt] `gives` Yearly - [Period "weekly"] `gives` Weekly - [Period "monthly"] `gives` Monthly - [Period "quarterly"] `gives` Quarterly - [WeeklyOpt, Period "yearly"] `gives` Yearly - - ,"isAccountNamePrefixOf" ~: do - "assets" `isAccountNamePrefixOf` "assets" `is` False - "assets" `isAccountNamePrefixOf` "assets:bank" `is` True - "assets" `isAccountNamePrefixOf` "assets:bank:checking" `is` True - "my assets" `isAccountNamePrefixOf` "assets:bank" `is` False - - ,"isTransactionBalanced" ~: do - let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] - [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) - ,Posting False "c" (Mixed [dollars (-1.00)]) "" RegularPosting [] (Just t) - ] "" - assertBool "detect balanced" (isTransactionBalanced Nothing t) - let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] - [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) - ,Posting False "c" (Mixed [dollars (-1.01)]) "" RegularPosting [] (Just t) - ] "" - assertBool "detect unbalanced" (not $ isTransactionBalanced Nothing t) - let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] - [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) - ] "" - assertBool "detect unbalanced, one posting" (not $ isTransactionBalanced Nothing t) - let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] - [Posting False "b" (Mixed [dollars 0]) "" RegularPosting [] (Just t) - ] "" - assertBool "one zero posting is considered balanced for now" (isTransactionBalanced Nothing t) - let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] - [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) - ,Posting False "c" (Mixed [dollars (-1.00)]) "" RegularPosting [] (Just t) - ,Posting False "d" (Mixed [dollars 100]) "" VirtualPosting [] (Just t) - ] "" - assertBool "virtual postings don't need to balance" (isTransactionBalanced Nothing t) - let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] - [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) - ,Posting False "c" (Mixed [dollars (-1.00)]) "" RegularPosting [] (Just t) - ,Posting False "d" (Mixed [dollars 100]) "" BalancedVirtualPosting [] (Just t) - ] "" - assertBool "balanced virtual postings need to balance among themselves" (not $ isTransactionBalanced Nothing t) - let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" [] - [Posting False "b" (Mixed [dollars 1.00]) "" RegularPosting [] (Just t) - ,Posting False "c" (Mixed [dollars (-1.00)]) "" RegularPosting [] (Just t) - ,Posting False "d" (Mixed [dollars 100]) "" BalancedVirtualPosting [] (Just t) - ,Posting False "e" (Mixed [dollars (-100)]) "" BalancedVirtualPosting [] (Just t) - ] "" - assertBool "balanced virtual postings need to balance among themselves (2)" (isTransactionBalanced Nothing t) - - ,"isSubAccountNameOf" ~: do - "assets" `isSubAccountNameOf` "assets" `is` False - "assets:bank" `isSubAccountNameOf` "assets" `is` True - "assets:bank:checking" `isSubAccountNameOf` "assets" `is` False - "assets:bank" `isSubAccountNameOf` "my assets" `is` False - - ,"default year" ~: do - rl <- readJournal Nothing defaultyear_journal_str >>= either error' return - tdate (head $ jtxns rl) `is` fromGregorian 2009 1 1 - return () - - ,"normaliseMixedAmount" ~: do - normaliseMixedAmount (Mixed []) ~?= Mixed [nullamt] - - ,"parsedate" ~: do - parsedate "2008/02/03" `is` parsetimewith "%Y/%m/%d" "2008/02/03" date1 - parsedate "2008-02-03" `is` parsetimewith "%Y/%m/%d" "2008/02/03" date1 - - ,"period expressions" ~: do - let todaysdate = parsedate "2008/11/26" - let str `gives` result = show (parsewith (periodexpr todaysdate) str) `is` ("Right " ++ result) - "from aug to oct" `gives` "(NoInterval,DateSpan (Just 2008-08-01) (Just 2008-10-01))" - "aug to oct" `gives` "(NoInterval,DateSpan (Just 2008-08-01) (Just 2008-10-01))" - "every day from aug to oct" `gives` "(Daily,DateSpan (Just 2008-08-01) (Just 2008-10-01))" - "daily from aug" `gives` "(Daily,DateSpan (Just 2008-08-01) Nothing)" - "every week to 2009" `gives` "(Weekly,DateSpan Nothing (Just 2009-01-01))" - - ,"print report tests" ~: TestList - [ - - "print expenses" ~: - do - let args = ["expenses"] - l <- samplejournalwithopts [] args - t <- getCurrentLocalTime - showTransactions (optsToFilterSpec [] args t) l `is` unlines - ["2008/06/03 * eat & shop" - ," expenses:food $1" - ," expenses:supplies $1" - ," assets:cash $-2" - ,"" - ] - - , "print report with depth arg" ~: - do - l <- samplejournal - t <- getCurrentLocalTime - showTransactions (optsToFilterSpec [Depth "2"] [] t) l `is` unlines - ["2008/01/01 income" - ," income:salary $-1" - ,"" - ,"2008/06/01 gift" - ," income:gifts $-1" - ,"" - ,"2008/06/03 * eat & shop" - ," expenses:food $1" - ," expenses:supplies $1" - ," assets:cash $-2" - ,"" - ,"2008/12/31 * pay off" - ," liabilities:debts $1" - ,"" - ] - - ] - - ,"punctuatethousands 1" ~: punctuatethousands "" `is` "" - - ,"punctuatethousands 2" ~: punctuatethousands "1234567.8901" `is` "1,234,567.8901" - - ,"punctuatethousands 3" ~: punctuatethousands "-100" `is` "-100" - - ,"register report tests" ~: - let registerdates = filter (not . null) . map (strip . take 10) . lines - in - TestList - [ - - "register report with no args" ~: - do - l <- samplejournal - (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] [] t1) l) `is` unlines - ["2008/01/01 income assets:bank:checking $1 $1" - ," income:salary $-1 0" - ,"2008/06/01 gift assets:bank:checking $1 $1" - ," income:gifts $-1 0" - ,"2008/06/02 save assets:bank:saving $1 $1" - ," assets:bank:checking $-1 0" - ,"2008/06/03 eat & shop expenses:food $1 $1" - ," expenses:supplies $1 $2" - ," assets:cash $-2 0" - ,"2008/12/31 pay off liabilities:debts $1 $1" - ," assets:bank:checking $-1 0" - ] - - ,"register report with cleared option" ~: - do - let opts = [Cleared] - l <- readJournalWithOpts opts sample_journal_str - (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` unlines - ["2008/06/03 eat & shop expenses:food $1 $1" - ," expenses:supplies $1 $2" - ," assets:cash $-2 0" - ,"2008/12/31 pay off liabilities:debts $1 $1" - ," assets:bank:checking $-1 0" - ] - - ,"register report with uncleared option" ~: - do - let opts = [UnCleared] - l <- readJournalWithOpts opts sample_journal_str - (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` unlines - ["2008/01/01 income assets:bank:checking $1 $1" - ," income:salary $-1 0" - ,"2008/06/01 gift assets:bank:checking $1 $1" - ," income:gifts $-1 0" - ,"2008/06/02 save assets:bank:saving $1 $1" - ," assets:bank:checking $-1 0" - ] - - ,"register report sorts by date" ~: - do - l <- readJournalWithOpts [] $ unlines - ["2008/02/02 a" - ," b 1" - ," c" - ,"" - ,"2008/01/01 d" - ," e 1" - ," f" - ] - registerdates (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] [] t1) l) `is` ["2008/01/01","2008/02/02"] - - ,"register report with account pattern" ~: - do - l <- samplejournal - (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] ["cash"] t1) l) `is` unlines - ["2008/06/03 eat & shop assets:cash $-2 $-2" - ] - - ,"register report with account pattern, case insensitive" ~: - do - l <- samplejournal - (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] ["cAsH"] t1) l) `is` unlines - ["2008/06/03 eat & shop assets:cash $-2 $-2" - ] - - ,"register report with display expression" ~: - do - l <- samplejournal - let gives displayexpr = - (registerdates (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is`) - where opts = [Display displayexpr] - "d<[2008/6/2]" `gives` ["2008/01/01","2008/06/01"] - "d<=[2008/6/2]" `gives` ["2008/01/01","2008/06/01","2008/06/02"] - "d=[2008/6/2]" `gives` ["2008/06/02"] - "d>=[2008/6/2]" `gives` ["2008/06/02","2008/06/03","2008/12/31"] - "d>[2008/6/2]" `gives` ["2008/06/03","2008/12/31"] - - ,"register report with period expression" ~: - do - l <- samplejournal - let periodexpr `gives` dates = do - l' <- samplejournalwithopts opts [] - registerdates (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l') `is` dates - where opts = [Period periodexpr] - "" `gives` ["2008/01/01","2008/06/01","2008/06/02","2008/06/03","2008/12/31"] - "2008" `gives` ["2008/01/01","2008/06/01","2008/06/02","2008/06/03","2008/12/31"] - "2007" `gives` [] - "june" `gives` ["2008/06/01","2008/06/02","2008/06/03"] - "monthly" `gives` ["2008/01/01","2008/06/01","2008/12/01"] - "quarterly" `gives` ["2008/01/01","2008/04/01","2008/10/01"] - let opts = [Period "yearly"] - (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` unlines - ["2008/01/01 - 2008/12/31 assets:bank:saving $1 $1" - ," assets:cash $-2 $-1" - ," expenses:food $1 0" - ," expenses:supplies $1 $1" - ," income:gifts $-1 0" - ," income:salary $-1 $-1" - ," liabilities:debts $1 0" - ] - let opts = [Period "quarterly"] - registerdates (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` ["2008/01/01","2008/04/01","2008/10/01"] - let opts = [Period "quarterly",Empty] - registerdates (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` ["2008/01/01","2008/04/01","2008/07/01","2008/10/01"] - - ] - - , "register report with depth arg" ~: - do - l <- samplejournal - let opts = [Depth "2"] - (registerReportAsText opts $ registerReport opts (optsToFilterSpec opts [] t1) l) `is` unlines - ["2008/01/01 income assets:bank $1 $1" - ," income:salary $-1 0" - ,"2008/06/01 gift assets:bank $1 $1" - ," income:gifts $-1 0" - ,"2008/06/02 save assets:bank $1 $1" - ," assets:bank $-1 0" - ,"2008/06/03 eat & shop expenses:food $1 $1" - ," expenses:supplies $1 $2" - ," assets:cash $-2 0" - ,"2008/12/31 pay off liabilities:debts $1 $1" - ," assets:bank $-1 0" - ] - - ,"show dollars" ~: show (dollars 1) ~?= "$1.00" - - ,"show hours" ~: show (hours 1) ~?= "1.0h" - - ,"unicode in balance layout" ~: do - l <- readJournalWithOpts [] - "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n" - balanceReportAsText [] (balanceReport [] (optsToFilterSpec [] [] t1) l) `is` unlines - [" -100 актив:наличные" - ," 100 расходы:покупки" - ,"--------------------" - ," 0" - ] - - ,"unicode in register layout" ~: do - l <- readJournalWithOpts [] - "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n" - (registerReportAsText [] $ registerReport [] (optsToFilterSpec [] [] t1) l) `is` unlines - ["2009/01/01 медвежья шкура расходы:покупки 100 100" - ," актив:наличные -100 0"] - - ,"fixSmartDateStr" ~: do - let gives = is . fixSmartDateStr (parsedate "2008/11/26") - "1999-12-02" `gives` "1999/12/02" - "1999.12.02" `gives` "1999/12/02" - "1999/3/2" `gives` "1999/03/02" - "19990302" `gives` "1999/03/02" - "2008/2" `gives` "2008/02/01" - "0020/2" `gives` "0020/02/01" - "1000" `gives` "1000/01/01" - "4/2" `gives` "2008/04/02" - "2" `gives` "2008/11/02" - "January" `gives` "2008/01/01" - "feb" `gives` "2008/02/01" - "today" `gives` "2008/11/26" - "yesterday" `gives` "2008/11/25" - "tomorrow" `gives` "2008/11/27" - "this day" `gives` "2008/11/26" - "last day" `gives` "2008/11/25" - "next day" `gives` "2008/11/27" - "this week" `gives` "2008/11/24" -- last monday - "last week" `gives` "2008/11/17" -- previous monday - "next week" `gives` "2008/12/01" -- next monday - "this month" `gives` "2008/11/01" - "last month" `gives` "2008/10/01" - "next month" `gives` "2008/12/01" - "this quarter" `gives` "2008/10/01" - "last quarter" `gives` "2008/07/01" - "next quarter" `gives` "2009/01/01" - "this year" `gives` "2008/01/01" - "last year" `gives` "2007/01/01" - "next year" `gives` "2009/01/01" --- "last wed" `gives` "2008/11/19" --- "next friday" `gives` "2008/11/28" --- "next january" `gives` "2009/01/01" - - ,"subAccounts" ~: do - l <- liftM (journalToLedger nullfilterspec) samplejournal - let a = ledgerAccount l "assets" - map aname (ledgerSubAccounts l a) `is` ["assets:bank","assets:cash"] - - -- ,"summarisePostingsInDateSpan" ~: do - -- let gives (b,e,depth,showempty,ps) = - -- (summarisePostingsInDateSpan (mkdatespan b e) depth showempty ps `is`) - -- let ps = - -- [ - -- nullposting{lpdescription="desc",lpaccount="expenses:food:groceries",lpamount=Mixed [dollars 1]} - -- ,nullposting{lpdescription="desc",lpaccount="expenses:food:dining", lpamount=Mixed [dollars 2]} - -- ,nullposting{lpdescription="desc",lpaccount="expenses:food", lpamount=Mixed [dollars 4]} - -- ,nullposting{lpdescription="desc",lpaccount="expenses:food:dining", lpamount=Mixed [dollars 8]} - -- ] - -- ("2008/01/01","2009/01/01",0,9999,False,[]) `gives` - -- [] - -- ("2008/01/01","2009/01/01",0,9999,True,[]) `gives` - -- [ - -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31"} - -- ] - -- ("2008/01/01","2009/01/01",0,9999,False,ts) `gives` - -- [ - -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses:food", lpamount=Mixed [dollars 4]} - -- ,nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses:food:dining", lpamount=Mixed [dollars 10]} - -- ,nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses:food:groceries",lpamount=Mixed [dollars 1]} - -- ] - -- ("2008/01/01","2009/01/01",0,2,False,ts) `gives` - -- [ - -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses:food",lpamount=Mixed [dollars 15]} - -- ] - -- ("2008/01/01","2009/01/01",0,1,False,ts) `gives` - -- [ - -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="expenses",lpamount=Mixed [dollars 15]} - -- ] - -- ("2008/01/01","2009/01/01",0,0,False,ts) `gives` - -- [ - -- nullposting{lpdate=parsedate "2008/01/01",lpdescription="- 2008/12/31",lpaccount="",lpamount=Mixed [dollars 15]} - -- ] - - ] - - --- fixtures/test data - -date1 = parsedate "2008/11/26" -t1 = LocalTime date1 midday - -samplejournal = readJournalWithOpts [] sample_journal_str -samplejournalwithopts opts _ = readJournalWithOpts opts sample_journal_str - -sample_journal_str = unlines - ["; A sample journal file." - ,";" - ,"; Sets up this account tree:" - ,"; assets" - ,"; bank" - ,"; checking" - ,"; saving" - ,"; cash" - ,"; expenses" - ,"; food" - ,"; supplies" - ,"; income" - ,"; gifts" - ,"; salary" - ,"; liabilities" - ,"; debts" - ,"" - ,"2008/01/01 income" - ," assets:bank:checking $1" - ," income:salary" - ,"" - ,"2008/06/01 gift" - ," assets:bank:checking $1" - ," income:gifts" - ,"" - ,"2008/06/02 save" - ," assets:bank:saving $1" - ," assets:bank:checking" - ,"" - ,"2008/06/03 * eat & shop" - ," expenses:food $1" - ," expenses:supplies $1" - ," assets:cash" - ,"" - ,"2008/12/31 * pay off" - ," liabilities:debts $1" - ," assets:bank:checking" - ,"" - ,"" - ,";final comment" - ] - -defaultyear_journal_str = unlines - ["Y2009" - ,"" - ,"01/01 A" - ," a $1" - ," b" - ] - -write_sample_journal = writeFile "sample.journal" sample_journal_str - -entry2_str = unlines - ["2007/01/27 * joes diner" - ," expenses:food:dining $10.00" - ," expenses:gifts $10.00" - ," assets:checking $-20.00" - ,"" - ] - -entry3_str = unlines - ["2007/01/01 * opening balance" - ," assets:cash $4.82" - ," equity:opening balances" - ,"" - ,"2007/01/01 * opening balance" - ," assets:cash $4.82" - ," equity:opening balances" - ,"" - ,"2007/01/28 coopportunity" - ," expenses:food:groceries $47.18" - ," assets:checking" - ,"" - ] - -periodic_entry1_str = unlines - ["~ monthly from 2007/2/2" - ," assets:saving $200.00" - ," assets:checking" - ,"" - ] - -periodic_entry2_str = unlines - ["~ monthly from 2007/2/2" - ," assets:saving $200.00 ;auto savings" - ," assets:checking" - ,"" - ] - -periodic_entry3_str = unlines - ["~ monthly from 2007/01/01" - ," assets:cash $4.82" - ," equity:opening balances" - ,"" - ,"~ monthly from 2007/01/01" - ," assets:cash $4.82" - ," equity:opening balances" - ,"" - ] - -journal1_str = unlines - ["" - ,"2007/01/27 * joes diner" - ," expenses:food:dining $10.00" - ," expenses:gifts $10.00" - ," assets:checking $-20.00" - ,"" - ,"" - ,"2007/01/28 coopportunity" - ," expenses:food:groceries $47.18" - ," assets:checking $-47.18" - ,"" - ,"" - ] - -journal2_str = unlines - [";comment" - ,"2007/01/27 * joes diner" - ," expenses:food:dining $10.00" - ," assets:checking $-47.18" - ,"" - ] - -journal3_str = unlines - ["2007/01/27 * joes diner" - ," expenses:food:dining $10.00" - ,";intra-entry comment" - ," assets:checking $-47.18" - ,"" - ] - -journal4_str = unlines - ["!include \"somefile\"" - ,"2007/01/27 * joes diner" - ," expenses:food:dining $10.00" - ," assets:checking $-47.18" - ,"" - ] - -journal5_str = "" - -journal6_str = unlines - ["~ monthly from 2007/1/21" - ," expenses:entertainment $16.23 ;netflix" - ," assets:checking" - ,"" - ,"; 2007/01/01 * opening balance" - ,"; assets:saving $200.04" - ,"; equity:opening balances " - ,"" - ] - -journal7_str = unlines - ["2007/01/01 * opening balance" - ," assets:cash $4.82" - ," equity:opening balances " - ,"" - ,"2007/01/01 * opening balance" - ," income:interest $-4.82" - ," equity:opening balances " - ,"" - ,"2007/01/02 * ayres suites" - ," expenses:vacation $179.92" - ," assets:checking " - ,"" - ,"2007/01/02 * auto transfer to savings" - ," assets:saving $200.00" - ," assets:checking " - ,"" - ,"2007/01/03 * poquito mas" - ," expenses:food:dining $4.82" - ," assets:cash " - ,"" - ,"2007/01/03 * verizon" - ," expenses:phone $95.11" - ," assets:checking " - ,"" - ,"2007/01/03 * discover" - ," liabilities:credit cards:discover $80.00" - ," assets:checking " - ,"" - ,"2007/01/04 * blue cross" - ," expenses:health:insurance $90.00" - ," assets:checking " - ,"" - ,"2007/01/05 * village market liquor" - ," expenses:food:dining $6.48" - ," assets:checking " - ,"" - ] - -journal7 = Journal - [] - [] - [ - txnTieKnot $ Transaction { - tdate=parsedate "2007/01/01", - teffectivedate=Nothing, - tstatus=False, - tcode="*", - tdescription="opening balance", - tcomment="", - tmetadata=[], - tpostings=[ - Posting { - pstatus=False, - paccount="assets:cash", - pamount=(Mixed [dollars 4.82]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - }, - Posting { - pstatus=False, - paccount="equity:opening balances", - pamount=(Mixed [dollars (-4.82)]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - } - ], - tpreceding_comment_lines="" - } - , - txnTieKnot $ Transaction { - tdate=parsedate "2007/02/01", - teffectivedate=Nothing, - tstatus=False, - tcode="*", - tdescription="ayres suites", - tcomment="", - tmetadata=[], - tpostings=[ - Posting { - pstatus=False, - paccount="expenses:vacation", - pamount=(Mixed [dollars 179.92]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - }, - Posting { - pstatus=False, - paccount="assets:checking", - pamount=(Mixed [dollars (-179.92)]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - } - ], - tpreceding_comment_lines="" - } - , - txnTieKnot $ Transaction { - tdate=parsedate "2007/01/02", - teffectivedate=Nothing, - tstatus=False, - tcode="*", - tdescription="auto transfer to savings", - tcomment="", - tmetadata=[], - tpostings=[ - Posting { - pstatus=False, - paccount="assets:saving", - pamount=(Mixed [dollars 200]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - }, - Posting { - pstatus=False, - paccount="assets:checking", - pamount=(Mixed [dollars (-200)]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - } - ], - tpreceding_comment_lines="" - } - , - txnTieKnot $ Transaction { - tdate=parsedate "2007/01/03", - teffectivedate=Nothing, - tstatus=False, - tcode="*", - tdescription="poquito mas", - tcomment="", - tmetadata=[], - tpostings=[ - Posting { - pstatus=False, - paccount="expenses:food:dining", - pamount=(Mixed [dollars 4.82]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - }, - Posting { - pstatus=False, - paccount="assets:cash", - pamount=(Mixed [dollars (-4.82)]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - } - ], - tpreceding_comment_lines="" - } - , - txnTieKnot $ Transaction { - tdate=parsedate "2007/01/03", - teffectivedate=Nothing, - tstatus=False, - tcode="*", - tdescription="verizon", - tcomment="", - tmetadata=[], - tpostings=[ - Posting { - pstatus=False, - paccount="expenses:phone", - pamount=(Mixed [dollars 95.11]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - }, - Posting { - pstatus=False, - paccount="assets:checking", - pamount=(Mixed [dollars (-95.11)]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - } - ], - tpreceding_comment_lines="" - } - , - txnTieKnot $ Transaction { - tdate=parsedate "2007/01/03", - teffectivedate=Nothing, - tstatus=False, - tcode="*", - tdescription="discover", - tcomment="", - tmetadata=[], - tpostings=[ - Posting { - pstatus=False, - paccount="liabilities:credit cards:discover", - pamount=(Mixed [dollars 80]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - }, - Posting { - pstatus=False, - paccount="assets:checking", - pamount=(Mixed [dollars (-80)]), - pcomment="", - ptype=RegularPosting, - pmetadata=[], - ptransaction=Nothing - } - ], - tpreceding_comment_lines="" - } - ] - [] - [] - "" - nullctx - [] - (TOD 0 0) - -ledger7 = journalToLedger nullfilterspec journal7 - -journal8_str = unlines - ["2008/1/1 test " - ," a:b 10h @ $40" - ," c:d " - ,"" - ] - -timelogentry1_str = "i 2007/03/11 16:19:00 hledger\n" -timelogentry1 = TimeLogEntry In (parsedatetime "2007/03/11 16:19:00") "hledger" - -timelogentry2_str = "o 2007/03/11 16:30:00\n" -timelogentry2 = TimeLogEntry Out (parsedatetime "2007/03/11 16:30:00") "" - -a1 = Mixed [(hours 1){price=Just $ Mixed [Amount (comm "$") 10 Nothing]}] -a2 = Mixed [(hours 2){price=Just $ Mixed [Amount (comm "EUR") 10 Nothing]}] -a3 = Mixed $ amounts a1 ++ amounts a2 - -journalWithAmounts :: [String] -> Journal -journalWithAmounts as = - Journal - [] - [] - [t | a <- as, let t = nulltransaction{tdescription=a,tpostings=[nullposting{pamount=parse a,ptransaction=Just t}]}] - [] - [] - "" - nullctx - [] - (TOD 0 0) - where parse = fromparse . parseWithCtx nullctx someamount - diff --git a/hledger/Hledger/Cli/Utils.hs b/hledger/Hledger/Cli/Utils.hs index b449a0c05..9985c1df5 100644 --- a/hledger/Hledger/Cli/Utils.hs +++ b/hledger/Hledger/Cli/Utils.hs @@ -19,6 +19,7 @@ module Hledger.Cli.Utils writeFileWithBackup, writeFileWithBackupIfChanged, readFileStrictly, + Test(TestList), ) where import Hledger.Data