packages feed

mulang-4.4.0: src/Language/Mulang/Interpreter/Runner.hs

{-# LANGUAGE DeriveGeneric #-}

module Language.Mulang.Interpreter.Runner (
  runTests,
  runTestsForDir,
  TestResult(..),
  TestStatus(..)) where

import GHC.Generics

import           Control.Monad (forM)
import           Control.Monad.State.Strict
import           Data.Maybe (fromMaybe, fromJust)
import           Data.List (intercalate)

import qualified Language.Mulang.Ast as Mu
import Language.Mulang.Interpreter
import Language.Mulang.Parsers (MaybeParser)

data TestResult
  = TestResult { description :: [String], status :: TestStatus } deriving (Generic, Show, Eq)

data TestStatus
  = Success
  | Failure String
  deriving (Generic, Show, Eq)

data MuTest = MuTest [String] Mu.Expression deriving (Show)

runTestsForDir :: String -> String -> MaybeParser -> IO ()
runTestsForDir solutionPath testPath parse = do
  solution <- fromJust . parse <$> readFile solutionPath
  tests <- fromJust . parse <$> readFile testPath
  results <- runTests solution tests
  forM_ results $ \result -> case result of
    (TestResult desc Success) -> do
      putStrLn $ "PASS : " ++ intercalate " > " desc
    (TestResult desc (Failure reason)) -> do
      putStrLn $ "FAIL : " ++ intercalate " > " desc
      putStrLn $ "       " ++ show reason

runTests :: Mu.Expression -> Mu.Expression -> IO [TestResult]
runTests code = runTests' code . getTests

runTests' :: Mu.Expression -> [MuTest] -> IO [TestResult]
runTests' expr tests = do
  (_ref, context) <- eval defaultContext expr
  forM tests $ \(MuTest desc testExpr) -> do
    (exceptionRef, testContext) <- eval' context $ do
      (_, lastException) <- evalRaising context testExpr
      return $ fromMaybe nullRef lastException
    let exception = dereference' (globalObjects testContext) exceptionRef
    case exception of
      MuNull -> return $ TestResult desc Success
      v -> return $ TestResult desc (Failure $ show v)

getTests :: Mu.Expression -> [MuTest]
getTests expr = getAllTestsFromExpr [] expr

getAllTestsFromExpr :: [String] -> Mu.Expression -> [MuTest]
getAllTestsFromExpr _ Mu.None                             = []
getAllTestsFromExpr s (Mu.Test (Mu.MuString desc) f)      = [MuTest (s ++ [desc]) f]
getAllTestsFromExpr s (Mu.TestGroup (Mu.MuString desc) f) = getAllTestsFromExpr (s ++ [desc]) f
getAllTestsFromExpr s (Mu.Sequence expressions)           = concatMap (getAllTestsFromExpr s) expressions
getAllTestsFromExpr s e                                   = error $ "Unknown expression: " ++ show e ++ "\nIn " ++ intercalate " > " s