lib: make 'includedirectivep' an 'ErroringJournalParser'
- Update tests as well, requiring test utilities in Utils/Test.hs analogous to the those for 'JournalParser' but instead for 'ErroringJournalParser'
This commit is contained in:
parent
855a8f1985
commit
3e54fc77a4
@ -106,7 +106,7 @@ reader = Reader
|
|||||||
-- | Parse and post-process a "Journal" from hledger's journal file
|
-- | Parse and post-process a "Journal" from hledger's journal file
|
||||||
-- format, or give an error.
|
-- format, or give an error.
|
||||||
parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal
|
parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal
|
||||||
parse iopts = parseAndFinaliseJournal' journalp' iopts
|
parse iopts = parseAndFinaliseJournal journalp' iopts
|
||||||
where
|
where
|
||||||
journalp' = do
|
journalp' = do
|
||||||
-- reverse parsed aliases to ensure that they are applied in order given on commandline
|
-- reverse parsed aliases to ensure that they are applied in order given on commandline
|
||||||
@ -124,10 +124,10 @@ aliasesFromOpts = map (\a -> fromparse $ runParser accountaliasp ("--alias "++qu
|
|||||||
-- | A journal parser. Accumulates and returns a "ParsedJournal",
|
-- | A journal parser. Accumulates and returns a "ParsedJournal",
|
||||||
-- which should be finalised/validated before use.
|
-- which should be finalised/validated before use.
|
||||||
--
|
--
|
||||||
-- >>> rjp (journalp <* eof) "2015/1/1\n a 0\n"
|
-- >>> rejp (journalp <* eof) "2015/1/1\n a 0\n"
|
||||||
-- Right Journal with 1 transactions, 1 accounts
|
-- Right (Right Journal with 1 transactions, 1 accounts)
|
||||||
--
|
--
|
||||||
journalp :: MonadIO m => JournalParser m ParsedJournal
|
journalp :: MonadIO m => ErroringJournalParser m ParsedJournal
|
||||||
journalp = do
|
journalp = do
|
||||||
many addJournalItemP
|
many addJournalItemP
|
||||||
eof
|
eof
|
||||||
@ -135,7 +135,7 @@ journalp = do
|
|||||||
|
|
||||||
-- | A side-effecting parser; parses any kind of journal item
|
-- | A side-effecting parser; parses any kind of journal item
|
||||||
-- and updates the parse state accordingly.
|
-- and updates the parse state accordingly.
|
||||||
addJournalItemP :: MonadIO m => JournalParser m ()
|
addJournalItemP :: MonadIO m => ErroringJournalParser m ()
|
||||||
addJournalItemP =
|
addJournalItemP =
|
||||||
-- all journal line types can be distinguished by the first
|
-- all journal line types can be distinguished by the first
|
||||||
-- character, can use choice without backtracking
|
-- character, can use choice without backtracking
|
||||||
@ -154,7 +154,7 @@ addJournalItemP =
|
|||||||
-- | Parse any journal directive and update the parse state accordingly.
|
-- | Parse any journal directive and update the parse state accordingly.
|
||||||
-- Cf http://hledger.org/manual.html#directives,
|
-- Cf http://hledger.org/manual.html#directives,
|
||||||
-- http://ledger-cli.org/3.0/doc/ledger3.html#Command-Directives
|
-- http://ledger-cli.org/3.0/doc/ledger3.html#Command-Directives
|
||||||
directivep :: MonadIO m => JournalParser m ()
|
directivep :: MonadIO m => ErroringJournalParser m ()
|
||||||
directivep = (do
|
directivep = (do
|
||||||
optional $ char '!'
|
optional $ char '!'
|
||||||
choice [
|
choice [
|
||||||
@ -174,7 +174,7 @@ directivep = (do
|
|||||||
]
|
]
|
||||||
) <?> "directive"
|
) <?> "directive"
|
||||||
|
|
||||||
includedirectivep :: MonadIO m => JournalParser m ()
|
includedirectivep :: MonadIO m => ErroringJournalParser m ()
|
||||||
includedirectivep = do
|
includedirectivep = do
|
||||||
string "include"
|
string "include"
|
||||||
lift (skipSome spacenonewline)
|
lift (skipSome spacenonewline)
|
||||||
@ -784,8 +784,8 @@ tests_JournalReader = tests "JournalReader" [
|
|||||||
|
|
||||||
,tests "directivep" [
|
,tests "directivep" [
|
||||||
test "supports !" $ do
|
test "supports !" $ do
|
||||||
expectParse directivep "!account a\n"
|
expectParseE directivep "!account a\n"
|
||||||
expectParse directivep "!D 1.0\n"
|
expectParseE directivep "!D 1.0\n"
|
||||||
]
|
]
|
||||||
|
|
||||||
,test "accountdirectivep" $ do
|
,test "accountdirectivep" $ do
|
||||||
@ -808,8 +808,8 @@ tests_JournalReader = tests "JournalReader" [
|
|||||||
expectParse ignoredpricecommoditydirectivep "N $\n"
|
expectParse ignoredpricecommoditydirectivep "N $\n"
|
||||||
|
|
||||||
,test "includedirectivep" $ do
|
,test "includedirectivep" $ do
|
||||||
test "include" $ expectParseError includedirectivep "include nosuchfile\n" "No existing files match pattern: nosuchfile"
|
test "include" $ expectParseErrorE includedirectivep "include nosuchfile\n" "No existing files match pattern: nosuchfile"
|
||||||
test "glob" $ expectParseError includedirectivep "include nosuchfile*\n" "No existing files match pattern: nosuchfile*"
|
test "glob" $ expectParseErrorE includedirectivep "include nosuchfile*\n" "No existing files match pattern: nosuchfile*"
|
||||||
|
|
||||||
,test "marketpricedirectivep" $ expectParseEq marketpricedirectivep
|
,test "marketpricedirectivep" $ expectParseEq marketpricedirectivep
|
||||||
"P 2017/01/30 BTC $922.83\n"
|
"P 2017/01/30 BTC $922.83\n"
|
||||||
@ -828,7 +828,7 @@ tests_JournalReader = tests "JournalReader" [
|
|||||||
|
|
||||||
|
|
||||||
,tests "journalp" [
|
,tests "journalp" [
|
||||||
test "empty file" $ expectParseEq journalp "" nulljournal
|
test "empty file" $ expectParseEqE journalp "" nulljournal
|
||||||
]
|
]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|||||||
@ -16,13 +16,18 @@ module Hledger.Utils.Test (
|
|||||||
,is
|
,is
|
||||||
,expectEqPP
|
,expectEqPP
|
||||||
,expectParse
|
,expectParse
|
||||||
|
,expectParseE
|
||||||
,expectParseError
|
,expectParseError
|
||||||
|
,expectParseErrorE
|
||||||
,expectParseEq
|
,expectParseEq
|
||||||
|
,expectParseEqE
|
||||||
,expectParseEqOn
|
,expectParseEqOn
|
||||||
|
,expectParseEqOnE
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Exception
|
import Control.Exception
|
||||||
|
import Control.Monad.Except (ExceptT, runExceptT)
|
||||||
import Control.Monad.State.Strict (StateT, evalStateT)
|
import Control.Monad.State.Strict (StateT, evalStateT)
|
||||||
#if !(MIN_VERSION_base(4,11,0))
|
#if !(MIN_VERSION_base(4,11,0))
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
@ -101,6 +106,7 @@ is = flip expectEqPP
|
|||||||
|
|
||||||
-- | Test that this stateful parser runnable in IO successfully parses
|
-- | Test that this stateful parser runnable in IO successfully parses
|
||||||
-- all of the given input text, showing the parse error if it fails.
|
-- all of the given input text, showing the parse error if it fails.
|
||||||
|
|
||||||
-- Suitable for hledger's JournalParser parsers.
|
-- Suitable for hledger's JournalParser parsers.
|
||||||
expectParse :: (Monoid st, Eq a, Show a, HasCallStack) =>
|
expectParse :: (Monoid st, Eq a, Show a, HasCallStack) =>
|
||||||
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> E.Test ()
|
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> E.Test ()
|
||||||
@ -108,6 +114,24 @@ expectParse parser input = do
|
|||||||
ep <- E.io (runParserT (evalStateT (parser <* eof) mempty) "" input)
|
ep <- E.io (runParserT (evalStateT (parser <* eof) mempty) "" input)
|
||||||
either (fail.(++"\n").("\nparse error at "++).parseErrorPretty) (const ok) ep
|
either (fail.(++"\n").("\nparse error at "++).parseErrorPretty) (const ok) ep
|
||||||
|
|
||||||
|
-- Suitable for hledger's ErroringJournalParser parsers.
|
||||||
|
expectParseE
|
||||||
|
:: (Monoid st, Eq a, Show a, HasCallStack)
|
||||||
|
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
||||||
|
-> T.Text
|
||||||
|
-> E.Test ()
|
||||||
|
expectParseE parser input = do
|
||||||
|
let filepath = ""
|
||||||
|
eep <- E.io $ runExceptT $
|
||||||
|
runParserT (evalStateT (parser <* eof) mempty) filepath input
|
||||||
|
case eep of
|
||||||
|
Left finalErr ->
|
||||||
|
let prettyErr = finalParseErrorPretty $ attachSource filepath input finalErr
|
||||||
|
in fail $ "parse error at " <> prettyErr
|
||||||
|
Right ep -> either (fail.(++"\n").("\nparse error at "++).parseErrorPretty)
|
||||||
|
(const ok)
|
||||||
|
ep
|
||||||
|
|
||||||
-- | Test that this stateful parser runnable in IO fails to parse
|
-- | Test that this stateful parser runnable in IO fails to parse
|
||||||
-- the given input text, with a parse error containing the given string.
|
-- the given input text, with a parse error containing the given string.
|
||||||
expectParseError :: (Monoid st, Eq a, Show a, HasCallStack) =>
|
expectParseError :: (Monoid st, Eq a, Show a, HasCallStack) =>
|
||||||
@ -122,12 +146,43 @@ expectParseError parser input errstr = do
|
|||||||
then ok
|
then ok
|
||||||
else fail $ "\nparse error is not as expected:\n" ++ e' ++ "\n"
|
else fail $ "\nparse error is not as expected:\n" ++ e' ++ "\n"
|
||||||
|
|
||||||
|
expectParseErrorE
|
||||||
|
:: (Monoid st, Eq a, Show a, HasCallStack)
|
||||||
|
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
||||||
|
-> T.Text
|
||||||
|
-> String
|
||||||
|
-> E.Test ()
|
||||||
|
expectParseErrorE parser input errstr = do
|
||||||
|
let filepath = ""
|
||||||
|
eep <- E.io $ runExceptT $ runParserT (evalStateT parser mempty) filepath input
|
||||||
|
case eep of
|
||||||
|
Left finalErr -> do
|
||||||
|
let prettyErr = finalParseErrorPretty $ attachSource filepath input finalErr
|
||||||
|
if errstr `isInfixOf` prettyErr
|
||||||
|
then ok
|
||||||
|
else fail $ "\nparse error is not as expected:\n" ++ prettyErr ++ "\n"
|
||||||
|
Right ep -> case ep of
|
||||||
|
Right v -> fail $ "\nparse succeeded unexpectedly, producing:\n" ++ pshow v ++ "\n"
|
||||||
|
Left e -> do
|
||||||
|
let e' = parseErrorPretty e
|
||||||
|
if errstr `isInfixOf` e'
|
||||||
|
then ok
|
||||||
|
else fail $ "\nparse error is not as expected:\n" ++ e' ++ "\n"
|
||||||
|
|
||||||
-- | Like expectParse, but also test the parse result is an expected value,
|
-- | Like expectParse, but also test the parse result is an expected value,
|
||||||
-- pretty-printing both if it fails.
|
-- pretty-printing both if it fails.
|
||||||
expectParseEq :: (Monoid st, Eq a, Show a, HasCallStack) =>
|
expectParseEq :: (Monoid st, Eq a, Show a, HasCallStack) =>
|
||||||
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> a -> E.Test ()
|
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> a -> E.Test ()
|
||||||
expectParseEq parser input expected = expectParseEqOn parser input id expected
|
expectParseEq parser input expected = expectParseEqOn parser input id expected
|
||||||
|
|
||||||
|
expectParseEqE
|
||||||
|
:: (Monoid st, Eq a, Show a, HasCallStack)
|
||||||
|
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
||||||
|
-> T.Text
|
||||||
|
-> a
|
||||||
|
-> E.Test ()
|
||||||
|
expectParseEqE parser input expected = expectParseEqOnE parser input id expected
|
||||||
|
|
||||||
-- | Like expectParseEq, but transform the parse result with the given function
|
-- | Like expectParseEq, but transform the parse result with the given function
|
||||||
-- before comparing it.
|
-- before comparing it.
|
||||||
expectParseEqOn :: (Monoid st, Eq b, Show b, HasCallStack) =>
|
expectParseEqOn :: (Monoid st, Eq b, Show b, HasCallStack) =>
|
||||||
@ -136,3 +191,23 @@ expectParseEqOn parser input f expected = do
|
|||||||
ep <- E.io $ runParserT (evalStateT (parser <* eof) mempty) "" input
|
ep <- E.io $ runParserT (evalStateT (parser <* eof) mempty) "" input
|
||||||
either (fail . (++"\n") . ("\nparse error at "++) . parseErrorPretty) (expectEqPP expected . f) ep
|
either (fail . (++"\n") . ("\nparse error at "++) . parseErrorPretty) (expectEqPP expected . f) ep
|
||||||
|
|
||||||
|
expectParseEqOnE
|
||||||
|
:: (Monoid st, Eq b, Show b, HasCallStack)
|
||||||
|
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
||||||
|
-> T.Text
|
||||||
|
-> (a -> b)
|
||||||
|
-> b
|
||||||
|
-> E.Test ()
|
||||||
|
expectParseEqOnE parser input f expected = do
|
||||||
|
let filepath = ""
|
||||||
|
eep <- E.io $ runExceptT $
|
||||||
|
runParserT (evalStateT (parser <* eof) mempty) filepath input
|
||||||
|
case eep of
|
||||||
|
Left finalErr ->
|
||||||
|
let prettyErr = finalParseErrorPretty $ attachSource filepath input finalErr
|
||||||
|
in fail $ "parse error at " <> prettyErr
|
||||||
|
Right ep ->
|
||||||
|
either (fail . (++"\n") . ("\nparse error at "++) . parseErrorPretty)
|
||||||
|
(expectEqPP expected . f)
|
||||||
|
ep
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user