-- | This module contains utility functions for tests that have to parse -- the intermediate representation. -- -- There is one general function that works with any AST node that has a -- 'Parseable' instance as well as a specialized function for each AST -- node with a 'Parseable' instance. The specialized functions are mainly -- to be used for documentation purposes and to avoid expression type -- signatures in places where Haskell cannot infer the type of the node -- to parse. -- -- There are two versions of the parsing functions. The functions with -- @parseTest@ prefix parse the input string and report errors to an -- arbitrary 'MonadReporter'. The functions with @expectParseTest@ prefix, -- on the other hand, set the expectation that parsing is successful. -- If there is a parse error, an assertion failure will cause the test -- to fail immediately. The latter kind of functions is supposed to be -- used for setup actions. The example below illustrates how to use -- these functions. -- -- > it "..." $ do -- > expr <- expectParseTestExpr "..." -- > foo expr `shouldReturn` something -- -- This pattern is especially important when testing for failures. In the -- following example, we cannot distinguish whether @foo@ failed or we have -- a typo in our test expression. -- -- > it "..." $ shouldFail $ do -- > expr <- parseTestExpr "..." -- > foo expr -- -- Thus, we should rewrite such tests as follows (if possible). -- -- > it "..." $ do -- > expr <- expectParseTestExpr "..." -- > shouldFail (foo expr) module FreeC.Test.Parser ( -- * Within Reporters parseTestIR , parseTestName , parseTestQName , parseTestType , parseTestTypeScheme , parseTestTypeDecl , parseTestTypeSig , parseTestExpr , parseTestFuncDecl , parseTestImportDecl , parseTestModule -- * Within Expectations , expectParseTestIR , expectParseTestName , expectParseTestQName , expectParseTestType , expectParseTestTypeScheme , expectParseTestTypeDecl , expectParseTestTypeSig , expectParseTestExpr , expectParseTestFuncDecl , expectParseTestImportDecl , expectParseTestModule -- * Parsing Dependency Components , parseTestComponent , expectParseTestComponent ) where import Control.Monad.Fail ( MonadFail ) import Control.Monad.IO.Class ( MonadIO(..) ) import Test.HUnit.Base ( assertFailure ) import FreeC.Frontend.IR.Parser import FreeC.IR.DependencyGraph import FreeC.IR.SrcSpan import qualified FreeC.IR.Syntax as IR import FreeC.Monad.Reporter import FreeC.Pretty ------------------------------------------------------------------------------- -- Within Reporters -- ------------------------------------------------------------------------------- -- | Parses an IR node of type @a@ for testing purposes. parseTestIR :: (MonadReporter r, Parseable a) => String -> r a parseTestIR = parseIR . mkSrcFile "<test-input>" -- | Parses an IR name for testing purposes. parseTestName :: MonadReporter r => String -> r IR.Name parseTestName = parseTestIR -- | Parses a qualifiable IR name for testing purposes. parseTestQName :: MonadReporter r => String -> r IR.QName parseTestQName = parseTestIR -- | Parses an IR type expression for testing purposes. parseTestType :: MonadReporter r => String -> r IR.Type parseTestType = parseTestIR -- | Parses an IR type scheme for testing purposes. parseTestTypeScheme :: MonadReporter r => String -> r IR.TypeScheme parseTestTypeScheme = parseTestIR -- | Parses an IR type declaration for testing purposes. parseTestTypeDecl :: MonadReporter r => String -> r IR.TypeDecl parseTestTypeDecl = parseTestIR -- | Parses an IR type declaration for testing purposes. parseTestTypeSig :: MonadReporter r => String -> r IR.TypeSig parseTestTypeSig = parseTestIR -- | Parses an IR expression for testing purposes. parseTestExpr :: MonadReporter r => String -> r IR.Expr parseTestExpr = parseTestIR -- | Parses an IR function declaration for testing purposes. parseTestFuncDecl :: MonadReporter r => String -> r IR.FuncDecl parseTestFuncDecl = parseTestIR -- | Parses an IR import declaration for testing purposes. parseTestImportDecl :: MonadReporter r => String -> r IR.ImportDecl parseTestImportDecl = parseTestIR -- | Parses an IR module for testing purposes. parseTestModule :: MonadReporter r => [String] -> r IR.Module parseTestModule = parseTestIR . unlines ------------------------------------------------------------------------------- -- Within Expectations -- ------------------------------------------------------------------------------- -- | Parses an IR node of type @a@ for testing purposes and sets the -- expectation that parsing is successful. -- -- The first argument is a textual description of the type of node to parse. expectParseTestIR :: (MonadIO m, Parseable a) => String -> String -> m a expectParseTestIR nodeType input = do let (mx, ms) = runReporter (parseTestIR input) case mx of Just x -> return x Nothing -> liftIO $ assertFailure $ "Could not parse test " ++ nodeType ++ ".\nThe following " ++ show (length ms) ++ " messages were reported:\n" ++ showPretty ms -- | Parses an IR name for testing purposes and sets the -- expectation that parsing is successful. expectParseTestName :: MonadIO m => String -> m IR.Name expectParseTestName = expectParseTestIR "name" -- | Parses a qualifiable IR name for testing purposes and sets the -- expectation that parsing is successful. expectParseTestQName :: MonadIO m => String -> m IR.QName expectParseTestQName = expectParseTestIR "qualifiable name" -- | Parses an IR type expression for testing purposes and sets the -- expectation that parsing is successful. expectParseTestType :: MonadIO m => String -> m IR.Type expectParseTestType = expectParseTestIR "type expression" -- | Parses an IR type scheme for testing purposes and sets the -- expectation that parsing is successful. expectParseTestTypeScheme :: MonadIO m => String -> m IR.TypeScheme expectParseTestTypeScheme = expectParseTestIR "type scheme" -- | Parses an IR type declaration for testing purposes and sets the -- expectation that parsing is successful. expectParseTestTypeDecl :: MonadIO m => String -> m IR.TypeDecl expectParseTestTypeDecl = expectParseTestIR "type declaration" -- | Parses an IR type declaration for testing purposes and sets the -- expectation that parsing is successful. expectParseTestTypeSig :: MonadIO m => String -> m IR.TypeSig expectParseTestTypeSig = expectParseTestIR "type signature" -- | Parses an IR expression for testing purposes and sets the -- expectation that parsing is successful. expectParseTestExpr :: MonadIO m => String -> m IR.Expr expectParseTestExpr = expectParseTestIR "expression" -- | Parses an IR function declaration for testing purposes and sets the -- expectation that parsing is successful. expectParseTestFuncDecl :: MonadIO m => String -> m IR.FuncDecl expectParseTestFuncDecl = expectParseTestIR "function declaration" -- | Parses an IR import declaration for testing purposes and sets the -- expectation that parsing is successful. expectParseTestImportDecl :: MonadIO m => String -> m IR.ImportDecl expectParseTestImportDecl = expectParseTestIR "import" -- | Parses an IR module for testing purposes and sets the -- expectation that parsing is successful. expectParseTestModule :: MonadIO m => [String] -> m IR.Module expectParseTestModule = expectParseTestIR "module" . unlines ------------------------------------------------------------------------------- -- Parsing Dependency Components -- ------------------------------------------------------------------------------- -- | Parses the declarations in the given dependency component. parseTestComponent :: (MonadFail r, MonadReporter r, Parseable decl) => DependencyComponent String -> r (DependencyComponent decl) parseTestComponent = mapComponentM (mapM parseTestIR) -- | Parses the declarations in the given dependency component and sets the -- expectation that parsing is successful. expectParseTestComponent :: (MonadFail m, MonadIO m, Parseable decl) => DependencyComponent String -> m (DependencyComponent decl) expectParseTestComponent = mapComponentM (mapM (expectParseTestIR "dependency component"))