fix a failing test, handle unicode better in errors
This commit is contained in:
parent
4cd85ec767
commit
d29b393ca2
@ -44,7 +44,7 @@ getOption opts opt def =
|
|||||||
parseSize :: String -> (Int,Int)
|
parseSize :: String -> (Int,Int)
|
||||||
parseSize str = (read w, read h)
|
parseSize str = (read w, read h)
|
||||||
where
|
where
|
||||||
x = fromMaybe (error "Size should be in WIDTHxHEIGHT format") $ findIndex (=='x') str
|
x = fromMaybe (error' "Size should be in WIDTHxHEIGHT format") $ findIndex (=='x') str
|
||||||
(w,_:h) = splitAt x str
|
(w,_:h) = splitAt x str
|
||||||
|
|
||||||
-- | Generate pie chart
|
-- | Generate pie chart
|
||||||
|
|||||||
@ -7,7 +7,7 @@ module Hledger.Cli.Commands.Convert where
|
|||||||
import Hledger.Cli.Options (Opt(Debug))
|
import Hledger.Cli.Options (Opt(Debug))
|
||||||
import Hledger.Cli.Version (versionstr)
|
import Hledger.Cli.Version (versionstr)
|
||||||
import Hledger.Data.Types (Journal,AccountName,Transaction(..),Posting(..),PostingType(..))
|
import Hledger.Data.Types (Journal,AccountName,Transaction(..),Posting(..),PostingType(..))
|
||||||
import Hledger.Data.Utils (strip, spacenonewline, restofline, parseWithCtx, assertParse, assertParseEqual)
|
import Hledger.Data.Utils (strip, spacenonewline, restofline, parseWithCtx, assertParse, assertParseEqual, error')
|
||||||
import Hledger.Read.Common (emptyCtx)
|
import Hledger.Read.Common (emptyCtx)
|
||||||
import Hledger.Read.Journal (someamount,ledgeraccountname)
|
import Hledger.Read.Journal (someamount,ledgeraccountname)
|
||||||
import Hledger.Data.Amount (nullmixedamt)
|
import Hledger.Data.Amount (nullmixedamt)
|
||||||
@ -71,11 +71,11 @@ type CsvRecord = [String]
|
|||||||
-- using/creating a .rules file.
|
-- using/creating a .rules file.
|
||||||
convert :: [Opt] -> [String] -> Journal -> IO ()
|
convert :: [Opt] -> [String] -> Journal -> IO ()
|
||||||
convert opts args _ = do
|
convert opts args _ = do
|
||||||
when (null args) $ error "please specify a csv data file."
|
when (null args) $ error' "please specify a csv data file."
|
||||||
let csvfile = head args
|
let csvfile = head args
|
||||||
csvparse <- parseCSVFromFile csvfile
|
csvparse <- parseCSVFromFile csvfile
|
||||||
let records = case csvparse of
|
let records = case csvparse of
|
||||||
Left e -> error $ show e
|
Left e -> error' $ show e
|
||||||
Right rs -> reverse $ filter (/= [""]) rs
|
Right rs -> reverse $ filter (/= [""]) rs
|
||||||
let debug = Debug `elem` opts
|
let debug = Debug `elem` opts
|
||||||
rulesfile = rulesFileFor csvfile
|
rulesfile = rulesFileFor csvfile
|
||||||
@ -85,7 +85,7 @@ convert opts args _ = do
|
|||||||
writeFile rulesfile initialRulesFileContent
|
writeFile rulesfile initialRulesFileContent
|
||||||
else
|
else
|
||||||
hPrintf stderr "using conversion rules file %s\n" rulesfile
|
hPrintf stderr "using conversion rules file %s\n" rulesfile
|
||||||
rules <- liftM (either (error.show) id) $ parseCsvRulesFile rulesfile
|
rules <- liftM (either (error'.show) id) $ parseCsvRulesFile rulesfile
|
||||||
when debug $ hPrintf stderr "rules: %s\n" (show rules)
|
when debug $ hPrintf stderr "rules: %s\n" (show rules)
|
||||||
let requiredfields = max 2 (maxFieldIndex rules + 1)
|
let requiredfields = max 2 (maxFieldIndex rules + 1)
|
||||||
badrecords = take 1 $ filter ((< requiredfields).length) records
|
badrecords = take 1 $ filter ((< requiredfields).length) records
|
||||||
|
|||||||
@ -117,13 +117,13 @@ scrollY = sy . loc
|
|||||||
posY a = scrollY a + cursorY a
|
posY a = scrollY a + cursorY a
|
||||||
|
|
||||||
setCursorY, setScrollY, setPosY :: Int -> AppState -> AppState
|
setCursorY, setScrollY, setPosY :: Int -> AppState -> AppState
|
||||||
setCursorY _ AppState{alocs=[]} = error "shouldn't happen" -- silence warnings
|
setCursorY _ AppState{alocs=[]} = error' "shouldn't happen" -- silence warnings
|
||||||
setCursorY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocCursorY y l
|
setCursorY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocCursorY y l
|
||||||
|
|
||||||
setScrollY _ AppState{alocs=[]} = error "shouldn't happen" -- silence warnings
|
setScrollY _ AppState{alocs=[]} = error' "shouldn't happen" -- silence warnings
|
||||||
setScrollY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocScrollY y l
|
setScrollY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocScrollY y l
|
||||||
|
|
||||||
setPosY _ AppState{alocs=[]} = error "shouldn't happen" -- silence warnings
|
setPosY _ AppState{alocs=[]} = error' "shouldn't happen" -- silence warnings
|
||||||
setPosY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)}
|
setPosY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)}
|
||||||
where
|
where
|
||||||
l' = setLocScrollY sy $ setLocCursorY cy l
|
l' = setLocScrollY sy $ setLocCursorY cy l
|
||||||
|
|||||||
@ -725,7 +725,7 @@ hdstringlist :: [String] -> HamletData HledgerWebAppRoute
|
|||||||
hdstringlist ss = HDList [ [([], hdstring s)] | s <- ss ]
|
hdstringlist ss = HDList [ [([], hdstring s)] | s <- ss ]
|
||||||
|
|
||||||
instance Failure HamletException Handler
|
instance Failure HamletException Handler
|
||||||
where failure = error . show
|
where failure = error' . show
|
||||||
|
|
||||||
renderHamletFile :: FilePath -> HamletMap HledgerWebAppRoute -> Handler Html
|
renderHamletFile :: FilePath -> HamletMap HledgerWebAppRoute -> Handler Html
|
||||||
renderHamletFile hfile hmap = do
|
renderHamletFile hfile hmap = do
|
||||||
|
|||||||
@ -179,7 +179,7 @@ parseArguments = do
|
|||||||
case (as,es) of
|
case (as,es) of
|
||||||
(cmd:args,[]) -> return (os'',cmd,args)
|
(cmd:args,[]) -> return (os'',cmd,args)
|
||||||
([],[]) -> return (os'',"",[])
|
([],[]) -> return (os'',"",[])
|
||||||
(_,errs) -> ioError (userError (concat errs ++ help1))
|
(_,errs) -> ioError (userError' (concat errs ++ help1))
|
||||||
|
|
||||||
-- | Convert any fuzzy dates within these option values to explicit ones,
|
-- | Convert any fuzzy dates within these option values to explicit ones,
|
||||||
-- based on today's date.
|
-- based on today's date.
|
||||||
|
|||||||
@ -61,8 +61,8 @@ tests = TestList [
|
|||||||
tests_Hledger_Commands,
|
tests_Hledger_Commands,
|
||||||
|
|
||||||
"account directive" ~:
|
"account directive" ~:
|
||||||
let sameParse str1 str2 = do j1 <- readJournal Nothing str1 >>= either error return
|
let sameParse str1 str2 = do j1 <- readJournal Nothing str1 >>= either error' return
|
||||||
j2 <- readJournal Nothing str2 >>= either error return
|
j2 <- readJournal Nothing str2 >>= either error' return
|
||||||
j1 `is` j2{filereadtime=filereadtime j1, jtext=jtext j1}
|
j1 `is` j2{filereadtime=filereadtime j1, jtext=jtext j1}
|
||||||
in TestList
|
in TestList
|
||||||
[
|
[
|
||||||
@ -243,7 +243,7 @@ tests = TestList [
|
|||||||
,"2008/1/1 test "
|
,"2008/1/1 test "
|
||||||
," a:b 10h @ $50"
|
," a:b 10h @ $50"
|
||||||
," c:d "
|
," c:d "
|
||||||
]) >>= either error return
|
]) >>= either error' return
|
||||||
let j' = journalCanonicaliseAmounts $ journalConvertAmountsToCost j -- enable cost basis adjustment
|
let j' = journalCanonicaliseAmounts $ journalConvertAmountsToCost j -- enable cost basis adjustment
|
||||||
balanceReportAsText [] (balanceReport [] nullfilterspec j') `is`
|
balanceReportAsText [] (balanceReport [] nullfilterspec j') `is`
|
||||||
unlines
|
unlines
|
||||||
@ -292,7 +292,7 @@ tests = TestList [
|
|||||||
(Mixed [dollars (-1)])
|
(Mixed [dollars (-1)])
|
||||||
(case e of
|
(case e of
|
||||||
Right e' -> (pamount $ last $ tpostings e')
|
Right e' -> (pamount $ last $ tpostings e')
|
||||||
Left _ -> error "should not happen")
|
Left _ -> error' "should not happen")
|
||||||
|
|
||||||
,"journalCanonicaliseAmounts" ~:
|
,"journalCanonicaliseAmounts" ~:
|
||||||
"use the greatest precision" ~:
|
"use the greatest precision" ~:
|
||||||
@ -385,7 +385,7 @@ tests = TestList [
|
|||||||
"assets:bank" `isSubAccountNameOf` "my assets" `is` False
|
"assets:bank" `isSubAccountNameOf` "my assets" `is` False
|
||||||
|
|
||||||
,"default year" ~: do
|
,"default year" ~: do
|
||||||
rl <- readJournal Nothing defaultyear_journal_str >>= either error return
|
rl <- readJournal Nothing defaultyear_journal_str >>= either error' return
|
||||||
tdate (head $ jtxns rl) `is` fromGregorian 2009 1 1
|
tdate (head $ jtxns rl) `is` fromGregorian 2009 1 1
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ withJournalDo opts args _ cmd = do
|
|||||||
-- We kludgily read the file before parsing to grab the full text, unless
|
-- We kludgily read the file before parsing to grab the full text, unless
|
||||||
-- it's stdin, or it doesn't exist and we are adding. We read it strictly
|
-- it's stdin, or it doesn't exist and we are adding. We read it strictly
|
||||||
-- to let the add command work.
|
-- to let the add command work.
|
||||||
journalFilePathFromOpts opts >>= readJournalFile Nothing >>= either error runcmd
|
journalFilePathFromOpts opts >>= readJournalFile Nothing >>= either (error'.trace "BBB") runcmd
|
||||||
where
|
where
|
||||||
costify = (if CostBasis `elem` opts then journalConvertAmountsToCost else id)
|
costify = (if CostBasis `elem` opts then journalConvertAmountsToCost else id)
|
||||||
runcmd = cmd opts args . costify
|
runcmd = cmd opts args . costify
|
||||||
@ -46,7 +46,7 @@ withJournalDo opts args _ cmd = do
|
|||||||
-- | Get a journal from the given string and options, or throw an error.
|
-- | Get a journal from the given string and options, or throw an error.
|
||||||
readJournalWithOpts :: [Opt] -> String -> IO Journal
|
readJournalWithOpts :: [Opt] -> String -> IO Journal
|
||||||
readJournalWithOpts opts s = do
|
readJournalWithOpts opts s = do
|
||||||
j <- readJournal Nothing s >>= either error return
|
j <- readJournal Nothing s >>= either error' return
|
||||||
return $ (if cost then journalConvertAmountsToCost else id) j
|
return $ (if cost then journalConvertAmountsToCost else id) j
|
||||||
where cost = CostBasis `elem` opts
|
where cost = CostBasis `elem` opts
|
||||||
|
|
||||||
|
|||||||
@ -41,8 +41,8 @@ binaryfilename = prettify $ splitAtElement '.' buildversion :: String
|
|||||||
prettify (major:minor:bugfix:[]) = prettify [major,minor,bugfix,"0"]
|
prettify (major:minor:bugfix:[]) = prettify [major,minor,bugfix,"0"]
|
||||||
prettify (major:minor:[]) = prettify [major,minor,"0","0"]
|
prettify (major:minor:[]) = prettify [major,minor,"0","0"]
|
||||||
prettify (major:[]) = prettify [major,"0","0","0"]
|
prettify (major:[]) = prettify [major,"0","0","0"]
|
||||||
prettify [] = error "VERSION is empty, please fix"
|
prettify [] = error' "VERSION is empty, please fix"
|
||||||
prettify _ = error "VERSION has too many components, please fix"
|
prettify _ = error' "VERSION has too many components, please fix"
|
||||||
|
|
||||||
versionstr = prettify $ splitAtElement '.' buildversion :: String
|
versionstr = prettify $ splitAtElement '.' buildversion :: String
|
||||||
where
|
where
|
||||||
|
|||||||
@ -64,9 +64,9 @@ instance Num MixedAmount where
|
|||||||
fromInteger i = Mixed [Amount (comm "") (fromInteger i) Nothing]
|
fromInteger i = Mixed [Amount (comm "") (fromInteger i) Nothing]
|
||||||
negate (Mixed as) = Mixed $ map negateAmountPreservingPrice as
|
negate (Mixed as) = Mixed $ map negateAmountPreservingPrice as
|
||||||
(+) (Mixed as) (Mixed bs) = normaliseMixedAmount $ Mixed $ as ++ bs
|
(+) (Mixed as) (Mixed bs) = normaliseMixedAmount $ Mixed $ as ++ bs
|
||||||
(*) = error "programming error, mixed amounts do not support multiplication"
|
(*) = error' "programming error, mixed amounts do not support multiplication"
|
||||||
abs = error "programming error, mixed amounts do not support abs"
|
abs = error' "programming error, mixed amounts do not support abs"
|
||||||
signum = error "programming error, mixed amounts do not support signum"
|
signum = error' "programming error, mixed amounts do not support signum"
|
||||||
|
|
||||||
instance Ord MixedAmount where
|
instance Ord MixedAmount where
|
||||||
compare (Mixed as) (Mixed bs) = compare as bs
|
compare (Mixed as) (Mixed bs) = compare as bs
|
||||||
|
|||||||
@ -37,7 +37,7 @@ defaultcommodities = [dollar, euro, pound, hour, unknown]
|
|||||||
-- | Look up one of the hard-coded default commodities. For use in tests.
|
-- | Look up one of the hard-coded default commodities. For use in tests.
|
||||||
comm :: String -> Commodity
|
comm :: String -> Commodity
|
||||||
comm sym = fromMaybe
|
comm sym = fromMaybe
|
||||||
(error "commodity lookup failed")
|
(error' "commodity lookup failed")
|
||||||
$ find (\(Commodity{symbol=s}) -> s==sym) defaultcommodities
|
$ find (\(Commodity{symbol=s}) -> s==sym) defaultcommodities
|
||||||
|
|
||||||
-- | Find the conversion rate between two commodities. Currently returns 1.
|
-- | Find the conversion rate between two commodities. Currently returns 1.
|
||||||
|
|||||||
@ -65,7 +65,7 @@ splitspan start next span@(DateSpan (Just b) (Just e))
|
|||||||
: splitspan' start next (DateSpan (Just n) (Just e))
|
: splitspan' start next (DateSpan (Just n) (Just e))
|
||||||
where s = start b
|
where s = start b
|
||||||
n = next s
|
n = next s
|
||||||
splitspan' _ _ _ = error "won't happen, avoids warnings"
|
splitspan' _ _ _ = error' "won't happen, avoids warnings"
|
||||||
|
|
||||||
-- | Count the days in a DateSpan, or if it is open-ended return Nothing.
|
-- | Count the days in a DateSpan, or if it is open-ended return Nothing.
|
||||||
daysInSpan :: DateSpan -> Maybe Integer
|
daysInSpan :: DateSpan -> Maybe Integer
|
||||||
@ -234,12 +234,12 @@ parsedateM s = firstJust [
|
|||||||
|
|
||||||
-- | Parse a date-time string to a time type, or raise an error.
|
-- | Parse a date-time string to a time type, or raise an error.
|
||||||
parsedatetime :: String -> LocalTime
|
parsedatetime :: String -> LocalTime
|
||||||
parsedatetime s = fromMaybe (error $ "could not parse timestamp \"" ++ s ++ "\"")
|
parsedatetime s = fromMaybe (error' $ "could not parse timestamp \"" ++ s ++ "\"")
|
||||||
(parsedatetimeM s)
|
(parsedatetimeM s)
|
||||||
|
|
||||||
-- | Parse a date string to a time type, or raise an error.
|
-- | Parse a date string to a time type, or raise an error.
|
||||||
parsedate :: String -> Day
|
parsedate :: String -> Day
|
||||||
parsedate s = fromMaybe (error $ "could not parse date \"" ++ s ++ "\"")
|
parsedate s = fromMaybe (error' $ "could not parse date \"" ++ s ++ "\"")
|
||||||
(parsedateM s)
|
(parsedateM s)
|
||||||
|
|
||||||
-- | Parse a time string to a time type using the provided pattern, or
|
-- | Parse a time string to a time type using the provided pattern, or
|
||||||
|
|||||||
@ -65,7 +65,7 @@ entryFromTimeLogInOut :: TimeLogEntry -> TimeLogEntry -> Transaction
|
|||||||
entryFromTimeLogInOut i o
|
entryFromTimeLogInOut i o
|
||||||
| otime >= itime = t
|
| otime >= itime = t
|
||||||
| otherwise =
|
| otherwise =
|
||||||
error $ "clock-out time less than clock-in time in:\n" ++ showTransaction t
|
error' $ "clock-out time less than clock-in time in:\n" ++ showTransaction t
|
||||||
where
|
where
|
||||||
t = Transaction {
|
t = Transaction {
|
||||||
tdate = idate,
|
tdate = idate,
|
||||||
|
|||||||
@ -175,6 +175,14 @@ toPlatformString = case os of
|
|||||||
"darwin" -> UTF8.encodeString
|
"darwin" -> UTF8.encodeString
|
||||||
_ -> id
|
_ -> id
|
||||||
|
|
||||||
|
-- | A version of error that's better at displaying unicode.
|
||||||
|
error' :: String -> a
|
||||||
|
error' = error . toPlatformString
|
||||||
|
|
||||||
|
-- | A version of userError that's better at displaying unicode.
|
||||||
|
userError' :: String -> IOError
|
||||||
|
userError' = userError . toPlatformString
|
||||||
|
|
||||||
-- math
|
-- math
|
||||||
|
|
||||||
difforzero :: (Num a, Ord a) => a -> a -> a
|
difforzero :: (Num a, Ord a) => a -> a -> a
|
||||||
@ -281,7 +289,7 @@ parseWithCtx ctx p = runParser p ctx ""
|
|||||||
fromparse :: Either ParseError a -> a
|
fromparse :: Either ParseError a -> a
|
||||||
fromparse = either parseerror id
|
fromparse = either parseerror id
|
||||||
|
|
||||||
parseerror e = error $ showParseError e
|
parseerror e = error' $ showParseError e
|
||||||
|
|
||||||
showParseError e = "parse error at " ++ show e
|
showParseError e = "parse error at " ++ show e
|
||||||
|
|
||||||
|
|||||||
@ -129,11 +129,11 @@ myTimelogPath =
|
|||||||
|
|
||||||
-- | Read the user's default journal file, or give an error.
|
-- | Read the user's default journal file, or give an error.
|
||||||
myJournal :: IO Journal
|
myJournal :: IO Journal
|
||||||
myJournal = myJournalPath >>= readJournalFile Nothing >>= either error return
|
myJournal = myJournalPath >>= readJournalFile Nothing >>= either error' return
|
||||||
|
|
||||||
-- | Read the user's default timelog file, or give an error.
|
-- | Read the user's default timelog file, or give an error.
|
||||||
myTimelog :: IO Journal
|
myTimelog :: IO Journal
|
||||||
myTimelog = myTimelogPath >>= readJournalFile Nothing >>= either error return
|
myTimelog = myTimelogPath >>= readJournalFile Nothing >>= either error' return
|
||||||
|
|
||||||
tests_Hledger_Read = TestList
|
tests_Hledger_Read = TestList
|
||||||
[
|
[
|
||||||
@ -141,7 +141,7 @@ tests_Hledger_Read = TestList
|
|||||||
"journalFile" ~: do
|
"journalFile" ~: do
|
||||||
assertBool "journalFile should parse an empty file" (isRight $ parseWithCtx emptyCtx Journal.journalFile "")
|
assertBool "journalFile should parse an empty file" (isRight $ parseWithCtx emptyCtx Journal.journalFile "")
|
||||||
jE <- readJournal Nothing "" -- don't know how to get it from 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
|
either error' (assertBool "journalFile parsing an empty file should give an empty journal" . null . jtxns) jE
|
||||||
|
|
||||||
,Journal.tests_Journal
|
,Journal.tests_Journal
|
||||||
,Timelog.tests_Timelog
|
,Timelog.tests_Timelog
|
||||||
|
|||||||
@ -36,7 +36,7 @@ parseJournalWith p f s = do
|
|||||||
tl <- liftIO getCurrentLocalTime
|
tl <- liftIO getCurrentLocalTime
|
||||||
case runParser p emptyCtx f s of
|
case runParser p emptyCtx f s of
|
||||||
Right updates -> liftM (journalFinalise tc tl f s) $ updates `ap` return nulljournal
|
Right updates -> liftM (journalFinalise tc tl f s) $ updates `ap` return nulljournal
|
||||||
Left err -> throwError $ show err -- XXX raises an uncaught exception if we have a parsec user error, eg from many ?
|
Left err -> throwError $ show err
|
||||||
|
|
||||||
-- | Some state kept while parsing a journal file.
|
-- | Some state kept while parsing a journal file.
|
||||||
data JournalContext = Ctx {
|
data JournalContext = Ctx {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user