elsa-0.2.2.0: tests/Test.hs
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main where
import System.Directory
import System.Exit
import System.FilePath
import System.Environment
import System.IO
import System.IO.Error
import Control.Monad (when)
import Test.Tasty
import Test.Tasty.HUnit
import Text.Printf
import Language.Elsa
main :: IO ()
main = defaultMain =<< group "Tests" [unitTests]
unitTests = group "Unit"
[ testGroup "ok" <$> dirTests "tests/ok" TestOk
, testGroup "further" <$> dirTests "tests/further" TestPartial
, testGroup "invalid" <$> dirTests "tests/invalid" TestInvalid
, testGroup "dupdefn" <$> dirTests "tests/dupdefn" TestDupDefn
, testGroup "dupeval" <$> dirTests "tests/dupeval" TestDupEval
]
data Outcome
= TestOk
| TestPartial
| TestInvalid
| TestMixed
| TestDupDefn
| TestDupEval
deriving (Eq, Ord, Show)
--------------------------------------------------------------------------------
dirTests :: FilePath -> Outcome -> IO [TestTree]
--------------------------------------------------------------------------------
dirTests root code
= do files <- walkDirectory root
let tests = [ root </> rel | f <- files, isTest f, let rel = makeRelative root f ]
return $ mkTest code <$> tests
isTest :: FilePath -> Bool
isTest f = takeExtension f `elem` [".lc"]
--------------------------------------------------------------------------------
mkTest :: Outcome -> FilePath -> TestTree
--------------------------------------------------------------------------------
mkTest code file
= testCase file $ do
res <- doTest file
when (res /= code) (assertFailure "Wrong Result")
doTest :: FilePath -> IO Outcome
doTest f = resultOutcome . elsa <$> parseFile f
resultOutcome :: [Result a] -> Outcome
resultOutcome rs = case (oks, invs, parts, ddefn, deval) of
(True, False, False, False, False) -> TestOk
(False, True, False, False, False) -> TestInvalid
(False, False, True, False, False) -> TestPartial
(False, False, False, True, False) -> TestDupDefn
(False, False, False, False, True) -> TestDupEval
_ -> TestMixed
where
oks = notNull [ r | r@(OK {}) <- rs ]
invs = notNull [ r | r@(Invalid {}) <- rs ]
parts = notNull [ r | r@(Partial {}) <- rs ]
ddefn = notNull [ r | r@(DupDefn {}) <- rs ]
deval = notNull [ r | r@(DupEval {}) <- rs ]
notNull = not . null
----------------------------------------------------------------------------------------
-- Generic Helpers
----------------------------------------------------------------------------------------
group n xs = testGroup n <$> sequence xs
----------------------------------------------------------------------------------------
walkDirectory :: FilePath -> IO [FilePath]
----------------------------------------------------------------------------------------
walkDirectory root
= do (ds,fs) <- partitionM doesDirectoryExist . candidates =<< (getDirectoryContents root `catchIOError` const (return []))
(fs++) <$> concatMapM walkDirectory ds
where
candidates fs = [root </> f | f <- fs, not (isExtSeparator (head f))]
partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a],[a])
partitionM f = go [] []
where
go ls rs [] = return (ls,rs)
go ls rs (x:xs) = do b <- f x
if b then go (x:ls) rs xs
else go ls (x:rs) xs
-- isDirectory :: FilePath -> IO Bool
-- isDirectory = fmap Posix.isDirectory . Posix.getFileStatus
concatMapM :: Applicative m => (a -> m [b]) -> [a] -> m [b]
concatMapM _ [] = pure []
concatMapM f (x:xs) = (++) <$> f x <*> concatMapM f xs