module Main where import Control.Applicative import Control.Monad import Control.Monad.IO.Class import Data.IORef import Data.List import System.FilePath (replaceDirectory, splitPath, takeDirectory) import System.FilePath.Glob (glob) import Test.Framework (defaultMain) import Test.Framework.Providers.HUnit (hUnitTestToTests) import Test.HUnit import Language.Egison import Language.Egison.Core import Language.Egison.CmdOptions import qualified Language.Egison.Parser as Parser import qualified Language.Egison.ParserNonS as ParserNonS import Language.Egison.Pretty import Language.Egison.Primitives import Language.Egison.Types main :: IO () main = do let unitTests = map runUnitTestCase unitTestCases unitNonSTests = map runUnitTestCaseNonS unitNonSTestCases sampleTests = map runSampleTestCase sampleTestCases in defaultMain . hUnitTestToTests . test $ unitNonSTests ++ unitTests ++ sampleTests unitTestCases :: [FilePath] unitTestCases = [ "test/syntax.egi" , "test/primitive.egi" , "test/lib/math/analysis.egi" , "test/lib/math/tensor.egi" , "test/lib/math/arithmetic.egi" , "test/lib/math/algebra.egi" , "test/lib/core/string.egi" , "test/lib/core/base.egi" , "test/lib/core/collection.egi" , "test/lib/core/order.egi" , "test/lib/core/number.egi" , "sample/mahjong.egi" , "sample/poker-hands-with-joker.egi" , "sample/poker-hands.egi" , "sample/primes.egi" ] unitNonSTestCases :: [FilePath] unitNonSTestCases = [ "nons-test/test/syntax.egi" , "nons-test/test/primitive.egi" , "nons-test/test/lib/core/base.egi" , "nons-test/test/lib/core/order.egi" ] sampleTestCases :: [FilePath] sampleTestCases = [ "test/answer/sample/math/geometry/riemann-curvature-tensor-of-S2.egi" , "test/answer/sample/math/number/17th-root-of-unity.egi" ] runUnitTestCase :: FilePath -> Test runUnitTestCase file = TestLabel file . TestCase $ do env <- initialEnv defaultOption assertEgisonM $ do exprs <- Parser.loadFile file let (bindings, tests) = foldr collectDefsAndTests ([], []) exprs env' <- recursiveBind env bindings forM_ tests $ evalExprDeep env' where assertEgisonM :: EgisonM a -> Assertion assertEgisonM m = fromEgisonM m >>= assertString . either show (const "") runUnitTestCaseNonS :: FilePath -> Test runUnitTestCaseNonS file = TestLabel file . TestCase $ do env <- initialEnv (defaultOption { optSExpr = False }) assertEgisonM $ do exprs <- ParserNonS.loadFile file let (bindings, tests) = foldr collectDefsAndTests ([], []) exprs env' <- recursiveBind env bindings forM_ tests $ evalExprDeep env' where assertEgisonM :: EgisonM a -> Assertion assertEgisonM m = fromEgisonM m >>= assertString . either show (const "") runSampleTestCase :: FilePath -> Test runSampleTestCase file = TestLabel file . TestCase $ do env <- initialEnv defaultOption let directory_path = takeDirectory file answers <- readFile file assertEgisonM (lines answers) $ do exprs <- Parser.loadFile (replaceDirectory file $ concat $ drop 2 $ splitPath directory_path) let (bindings, tests) = foldr collectDefsAndTests ([], []) exprs env' <- recursiveBind env bindings vals <- forM tests (evalExprDeep env') return $ zip tests vals where assertEgisonM :: [String] -> EgisonM [(EgisonExpr, EgisonValue)] -> Assertion assertEgisonM answers m = fromEgisonM m >>= assertString . either show (f answers) f :: [String] -> [(EgisonExpr, EgisonValue)] -> String f answers ls = g answers ls 0 g x y i = let (e, v) = unzip y in if (x !! i) == prettyS (v !! i) then (if i < (length y - 1) then g x y (i + 1) else "") else "failed " ++ show (e !! i) ++ "\n expected: " ++ (x !! i) ++ "\n but found: " ++ prettyS (v !! i) collectDefsAndTests :: EgisonTopExpr -> ([(Var, EgisonExpr)], [EgisonExpr]) -> ([(Var, EgisonExpr)], [EgisonExpr]) collectDefsAndTests (Define name expr) (bindings, tests) = ((name, expr) : bindings, tests) collectDefsAndTests (Test expr) (bindings, tests) = (bindings, expr : tests) collectDefsAndTests _ r = r