egison-5.1.0: test/Test.hs
module Main where
import Control.Monad.IO.Class (liftIO)
import Data.List (sort, (\\))
import System.Environment (getArgs)
import System.FilePath.Glob (glob)
import System.IO (hFlush, stdout)
import Test.Framework (defaultMainWithArgs)
import Test.Framework.Providers.HUnit (hUnitTestToTests)
import Test.HUnit
import Language.Egison
main :: IO ()
main = do
args <- getArgs
libTests <- discoverLibTests
mapM_ (\(f, why) -> putStrLn ("Skipping " ++ f ++ " (" ++ why ++ ")"))
skippedLibTests
flip defaultMainWithArgs args . hUnitTestToTests . test $
map runTestCase (languageTests ++ libTests ++ sampleTests)
-- | Language-level tests: the surface syntax and the primitives.
languageTests :: [FilePath]
languageTests =
[ "test/syntax.egi"
, "test/primitive.egi"
]
-- | Library unit tests: every test/lib/**/*.egi is discovered, so a new
-- suite dropped there runs without editing this file. To exclude one,
-- add it to skippedLibTests with the reason.
discoverLibTests :: IO [FilePath]
discoverLibTests = do
files <- glob "test/lib/**/*.egi"
return (sort files \\ map fst skippedLibTests)
-- | Discovered files excluded from the run, with the reason recorded
-- (printed at startup so the exclusion stays visible in the log).
skippedLibTests :: [(FilePath, String)]
skippedLibTests =
[ ("test/lib/core/io.egi", "interactive IO demos; its helper functions no longer exist")
, ("test/lib/core/shell.egi", "loads lib/core/shell.egi, which was removed")
]
-- | Whole programs registered for the language features they exercise.
sampleTests :: [FilePath]
sampleTests =
[ "sample/primes.egi" -- pattern matching with infinitely many results
, "sample/sat/cdcl.egi" -- a practical pattern-matching program
, "sample/poker-hands.egi"
, "sample/poker-hands-with-joker.egi"
, "sample/math/geometry/riemann-curvature-tensor-of-S2.egi" -- tensor index notation
, "sample/math/geometry/riemann-curvature-tensor-of-T2.egi" -- tensor indices and math quote
, "sample/math/geometry/curvature-form.egi" -- differential forms
, "sample/math/number/17th-root-of-unity.egi" -- rewriting of mathematical expressions
, "sample/math/geometry/hodge-laplacian-polar.egi" -- "..." in tensor indices
]
runTestCase :: FilePath -> Test
runTestCase file = TestLabel file . TestCase . assertEvalM $ do
-- Print the test file name before starting
liftIO $ do
putStrLn $ "\n=== Testing: " ++ file ++ " ==="
hFlush stdout
env <- initialEnv
-- Load core libraries, the math normalization library, and the test
-- file in ONE batch, mirroring the interpreter's initial load (see
-- Interpreter/egison.hs: the test file is included in the initial
-- load). A separate batch would keep the library operators' closures
-- pointing at the library-time mathNormalize, so rules declared in
-- the test file (declare rule auto / declare ideal) would never fire.
let coreLibExprs = map Load coreLibraries
mathLibExpr = [Load "lib/math/normalize.egi"]
allLibExprs = coreLibExprs ++ mathLibExpr
exprs <- loadFile file
evalTopExprsNoPrint env (allLibExprs ++ exprs)
where
assertEvalM :: EvalM a -> Assertion
assertEvalM m = fromEvalM defaultOption m >>= assertString . either show (const "")