cln: Reduce duplication in test utilities.
This commit is contained in:
		
							parent
							
								
									8968733630
								
							
						
					
					
						commit
						1aff74f702
					
				| @ -20,7 +20,7 @@ module Hledger.Utils.Test ( | ||||
| ) | ||||
| where | ||||
| 
 | ||||
| import Control.Monad.Except (ExceptT, runExceptT) | ||||
| import Control.Monad.Except (ExceptT(..), liftEither, runExceptT, withExceptT, unless) | ||||
| import Control.Monad.State.Strict (StateT, evalStateT, execStateT) | ||||
| import Data.Default (Default(..)) | ||||
| import Data.List (isInfixOf) | ||||
| @ -54,16 +54,28 @@ assertRight :: (HasCallStack, Eq a, Show a) => Either a b -> Assertion | ||||
| assertRight (Right _) = return () | ||||
| assertRight (Left a)  = assertFailure $ "expected Right, got (Left " ++ show a ++ ")" | ||||
| 
 | ||||
| -- | Run a parser on the given text and display a helpful error. | ||||
| parseHelper :: (HasCallStack, Default st, Monad m) => | ||||
|   StateT st (ParsecT CustomErr T.Text m) a -> T.Text -> ExceptT String m a | ||||
| parseHelper parser input = | ||||
|   withExceptT (\e -> "\nparse error at " ++ customErrorBundlePretty e ++ "\n") . ExceptT | ||||
|   $ runParserT (evalStateT (parser <* eof) def) "" input | ||||
| 
 | ||||
| -- | Run a stateful parser in IO and process either a failure or success to | ||||
| -- produce an 'Assertion'. Suitable for hledger's JournalParser parsers. | ||||
| assertParseHelper :: (HasCallStack, Default st) => | ||||
|   (String -> Assertion) -> (a -> Assertion) | ||||
|   -> StateT st (ParsecT CustomErr T.Text IO) a -> T.Text | ||||
|   -> Assertion | ||||
| assertParseHelper onFailure onSuccess parser input = | ||||
|   either onFailure onSuccess =<< runExceptT (parseHelper parser input) | ||||
| 
 | ||||
| -- | Assert that this stateful parser runnable in IO successfully parses | ||||
| -- all of the given input text, showing the parse error if it fails. | ||||
| -- Suitable for hledger's JournalParser parsers. | ||||
| assertParse :: (HasCallStack, Eq a, Show a, Default st) => | ||||
| assertParse :: (HasCallStack, Default st) => | ||||
|   StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> Assertion | ||||
| assertParse parser input = do | ||||
|   ep <- runParserT (evalStateT (parser <* eof) def) "" input | ||||
|   either (assertFailure.(++"\n").("\nparse error at "++).customErrorBundlePretty) | ||||
|          (const $ return ()) | ||||
|          ep | ||||
| assertParse = assertParseHelper assertFailure (const $ return ()) | ||||
| 
 | ||||
| -- | Assert a parser produces an expected value. | ||||
| assertParseEq :: (HasCallStack, Eq a, Show a, Default st) => | ||||
| @ -74,35 +86,23 @@ assertParseEq parser input = assertParseEqOn parser input id | ||||
| -- before comparing it. | ||||
| assertParseEqOn :: (HasCallStack, Eq b, Show b, Default st) => | ||||
|   StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> (a -> b) -> b -> Assertion | ||||
| assertParseEqOn parser input f expected = do | ||||
|   ep <- runParserT (evalStateT (parser <* eof) def) "" input | ||||
|   either (assertFailure . (++"\n") . ("\nparse error at "++) . customErrorBundlePretty) | ||||
|          (assertEqual "" expected . f) | ||||
|          ep | ||||
| assertParseEqOn parser input f expected = | ||||
|   assertParseHelper assertFailure (assertEqual "" expected . f) parser input | ||||
| 
 | ||||
| -- | Assert that this stateful parser runnable in IO fails to parse | ||||
| -- the given input text, with a parse error containing the given string. | ||||
| assertParseError :: (HasCallStack, Eq a, Show a, Default st) => | ||||
|   StateT st (ParsecT CustomErr T.Text IO) a -> String -> String -> Assertion | ||||
| assertParseError parser input errstr = do | ||||
|   ep <- runParserT (evalStateT parser def) "" (T.pack input) | ||||
|   case ep of | ||||
|     Right v -> assertFailure $ "\nparse succeeded unexpectedly, producing:\n" ++ pshow v ++ "\n" | ||||
|     Left e  -> do | ||||
|       let e' = customErrorBundlePretty e | ||||
|       if errstr `isInfixOf` e' | ||||
|       then return () | ||||
|       else assertFailure $ "\nparse error is not as expected:\n" ++ e' ++ "\n" | ||||
|   StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> String -> Assertion | ||||
| assertParseError parser input errstr = assertParseHelper | ||||
|   (\e -> unless (errstr `isInfixOf` e) $ assertFailure $ "\nparse error is not as expected:" ++ e) | ||||
|   (\v -> assertFailure $ "\nparse succeeded unexpectedly, producing:\n" ++ pshow v ++ "\n") | ||||
|   parser input | ||||
| 
 | ||||
| -- | Run a stateful parser in IO like assertParse, then assert that the | ||||
| -- final state (the wrapped state, not megaparsec's internal state), | ||||
| -- transformed by the given function, matches the given expected value. | ||||
| assertParseStateOn :: (HasCallStack, Eq b, Show b, Default st) => | ||||
|      StateT st (ParsecT CustomErr T.Text IO) a | ||||
|   -> T.Text | ||||
|   -> (st -> b) | ||||
|   -> b | ||||
|   -> Assertion | ||||
|      StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> (st -> b) -> b -> Assertion | ||||
| assertParseStateOn parser input f expected = do | ||||
|   es <- runParserT (execStateT (parser <* eof) def) "" input | ||||
|   case es of | ||||
| @ -110,70 +110,40 @@ assertParseStateOn parser input f expected = do | ||||
|     Right s  -> assertEqual "" expected $ f s | ||||
| 
 | ||||
| -- | These "E" variants of the above are suitable for hledger's ErroringJournalParser parsers. | ||||
| parseHelperE :: (HasCallStack, Default st, Monad m) => | ||||
|   StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError m)) a -> T.Text -> ExceptT String m a | ||||
| parseHelperE parser input = do | ||||
|   withExceptT (\e -> "\nparse error at " ++ customErrorBundlePretty e ++ "\n") . liftEither | ||||
|   =<< withExceptT (\e -> "parse error at " ++ finalErrorBundlePretty (attachSource "" input e)) | ||||
|         (runParserT (evalStateT (parser <* eof) def) "" input) | ||||
| 
 | ||||
| assertParseHelperE :: (HasCallStack, Default st) => | ||||
|   (String -> Assertion) -> (a -> Assertion) | ||||
|   -> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a -> T.Text | ||||
|   -> Assertion | ||||
| assertParseHelperE onFailure onSuccess parser input = | ||||
|   either onFailure onSuccess =<< runExceptT (parseHelperE parser input) | ||||
| 
 | ||||
| assertParseE | ||||
|   :: (HasCallStack, Eq a, Show a, Default st) | ||||
|   => StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a | ||||
|   -> T.Text | ||||
|   -> Assertion | ||||
| assertParseE parser input = do | ||||
|   let filepath = "" | ||||
|   eep <- runExceptT $ | ||||
|            runParserT (evalStateT (parser <* eof) def) filepath input | ||||
|   case eep of | ||||
|     Left finalErr -> | ||||
|       let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr | ||||
|       in  assertFailure $ "parse error at " <> prettyErr | ||||
|     Right ep -> | ||||
|       either (assertFailure.(++"\n").("\nparse error at "++).customErrorBundlePretty) | ||||
|              (const $ return ()) | ||||
|              ep | ||||
|   => StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a -> T.Text -> Assertion | ||||
| assertParseE = assertParseHelperE assertFailure (const $ return ()) | ||||
| 
 | ||||
| assertParseEqE | ||||
|   :: (Default st, Eq a, Show a, HasCallStack) | ||||
|   => StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a | ||||
|   -> T.Text | ||||
|   -> a | ||||
|   -> Assertion | ||||
|   => StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a -> T.Text -> a -> Assertion | ||||
| assertParseEqE parser input = assertParseEqOnE parser input id | ||||
| 
 | ||||
| assertParseEqOnE | ||||
|   :: (HasCallStack, Eq b, Show b, Default st) | ||||
|   => StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a | ||||
|   -> T.Text | ||||
|   -> (a -> b) | ||||
|   -> b | ||||
|   -> Assertion | ||||
| assertParseEqOnE parser input f expected = do | ||||
|   let filepath = "" | ||||
|   eep <- runExceptT $ runParserT (evalStateT (parser <* eof) def) filepath input | ||||
|   case eep of | ||||
|     Left finalErr -> | ||||
|       let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr | ||||
|       in  assertFailure $ "parse error at " <> prettyErr | ||||
|     Right ep -> | ||||
|       either (assertFailure . (++"\n") . ("\nparse error at "++) . customErrorBundlePretty) | ||||
|              (assertEqual "" expected . f) | ||||
|              ep | ||||
|   => StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a -> T.Text -> (a -> b) -> b -> Assertion | ||||
| assertParseEqOnE parser input f expected = | ||||
|   assertParseHelperE assertFailure (assertEqual "" expected . f) parser input | ||||
| 
 | ||||
| assertParseErrorE | ||||
|   :: (Default st, Eq a, Show a, HasCallStack) | ||||
|   => StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a | ||||
|   -> T.Text | ||||
|   -> String | ||||
|   -> Assertion | ||||
| assertParseErrorE parser input errstr = do | ||||
|   let filepath = "" | ||||
|   eep <- runExceptT $ runParserT (evalStateT parser def) filepath input | ||||
|   case eep of | ||||
|     Left finalErr -> do | ||||
|       let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr | ||||
|       if errstr `isInfixOf` prettyErr | ||||
|       then return () | ||||
|       else assertFailure $ "\nparse error is not as expected:\n" ++ prettyErr ++ "\n" | ||||
|     Right ep -> case ep of | ||||
|       Right v -> assertFailure $ "\nparse succeeded unexpectedly, producing:\n" ++ pshow v ++ "\n" | ||||
|       Left e  -> do | ||||
|         let e' = customErrorBundlePretty e | ||||
|         if errstr `isInfixOf` e' | ||||
|         then return () | ||||
|         else assertFailure $ "\nparse error is not as expected:\n" ++ e' ++ "\n" | ||||
|   => StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a -> T.Text -> String -> Assertion | ||||
| assertParseErrorE parser input errstr = assertParseHelperE | ||||
|   (\e -> unless (errstr `isInfixOf` e) $ assertFailure $ "\nparse error is not as expected:" ++ e) | ||||
|   (\v -> assertFailure $ "\nparse succeeded unexpectedly, producing:\n" ++ pshow v ++ "\n") | ||||
|   parser input | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user