-- A little testing framework module Test where import Data.List (intercalate) import System.Exit (exitFailure) import Test.QuickCheck hiding (Success, Failure, expectFailure) data Expect = ExpectSuccess | ExpectFailure deriving Eq data Test = Test String Expect Property data Tests = Leaf Test | Node String [Tests] testGroup :: String -> [Tests] -> Tests testGroup = Node expectSuccess :: Testable a => String -> a -> Tests expectSuccess name p = Leaf $ Test name ExpectSuccess (property p) expectFailure :: Testable a => String -> a -> Tests expectFailure name p = Leaf $ Test name ExpectFailure (property p) runTest :: [String] -> Test -> IO () runTest labels (Test name expect property) = do let label = intercalate "." (reverse (name : labels)) result <- quickCheckWithResult (stdArgs { chatty = False }) property case (expect, isSuccess result) of (ExpectSuccess, True) -> putStrLn $ "OK: " ++ label (ExpectFailure, False) -> putStrLn $ "OK (expected failure): " ++ label (ExpectSuccess, False) -> do putStrLn $ "\nTest failure:\n " ++ label ++ "\n" putStrLn $ output result exitFailure (ExpectFailure, True) -> do putStrLn $ "\nUnexpected test success:\n " ++ label ++ "\n" putStrLn $ output result exitFailure runTests :: Tests -> IO () runTests = go [] where go labels (Leaf test) = runTest labels test go labels (Node label tests) = mapM_ (go (label : labels)) tests