— How to use: runghc testFoo.hs
import System.Environment (getArgs)
import System.Exit (exitFailure)
import Test.HUnit
import Text.Read (readMaybe)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import TrycatDef
import Trycat (interp)
testBind =
[ “bind 1” ~:
unTC (MkTC (\s -> (Map.delete “x” s, Right 17))
>>= \a -> MkTC (\s -> (Map.insert “y” a s, Right (even a))))
(Map.fromList [(“x”,7), (“z”,3)])
~?= (Map.fromList [(“y”,17), (“z”,3)], Right False)
, “bind 2” ~:
unTC (MkTC (\s -> (Map.delete “x” s, Left DivByZero))
>>= \a -> MkTC (\s -> (Map.insert “y” a s, Left VarUninit)))
(Map.fromList [(“x”,7), (“z”,3)])
~?= (Map.fromList [(“z”,3)], Left DivByZero :: Either Exception ())
]
testPutVar =
[ “putVar init” ~:
unTC (putVar “x” 5) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“x”,5), (“z”,3)], Right ())
, “putVar update” ~:
unTC (putVar “z” 5) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“z”,5)], Right ())
]
testGetVar =
[ “getVar exists” ~:
unTC (getVar “z”) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“z”,3)], Right 3)
, “getVar uninit” ~:
unTC (getVar “x”) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“z”,3)], Left VarUninit)
]
testRaise =
[ “raise” ~:
[ “divbyzero” ~:
unTC (raise DivByZero) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“z”,3)], Left DivByZero :: Either Exception ())
, “varuninit” ~:
unTC (raise VarUninit) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“z”,3)], Left VarUninit :: Either Exception ())
]
]
testTryCatch =
[ “try (throw divbyzero) catch (divbyzero)” ~:
unTC (tryCatch
(MkTC (\s -> (Map.insert “x” 11 s, Left DivByZero)))
DivByZero
(MkTC (\s -> (Map.insert “z” 4 s, Right 14))))
(Map.fromList [(“z”,3)])
~?= (Map.fromList [(“x”,11), (“z”,4)], Right 14)
, “try (throw varuninit) catch (divbyzero)” ~:
unTC (tryCatch
(MkTC (\s -> (Map.insert “x” 11 s, Left VarUninit)))
DivByZero
(MkTC (\s -> (Map.insert “z” 4 s, Right 14))))
(Map.fromList [(“z”,3)])
~?= (Map.fromList [(“x”,11), (“z”,3)], Left VarUninit)
]
run :: Stmt -> (Map String Integer, Either Exception ())
run stmt = runWith stmt Map.empty
runWith :: Stmt -> Map String Integer -> (Map String Integer, Either Exception ())
runWith stmt s0 = unTC (interp stmt) s0
testAssign =
[ “assign x:=5” ~:
runWith (Assign “x” (Lit 5)) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“x”,5), (“z”,3)], Right ())
, “assign divbyzero” ~:
runWith (Assign “x” (Div (Lit 5) (Lit 0))) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“z”,3)], Left DivByZero)
, “assign varuninit” ~:
runWith (Assign “x” (Var “y”)) (Map.fromList [(“z”,3)])
~?= (Map.fromList [(“z”,3)], Left VarUninit)
]
testCompound =
[ “compound assigns” ~:
runWith (Compound [ Assign “x” (Lit 5)
, Assign “y” (Lit 17)
, Assign “z” (Var “y”)
])
(Map.fromList [(“z”, 3)])
~?= (Map.fromList [(“x”,5), (“y”,17), (“z”,17)], Right ())
, “compound exception in the middle” ~:
runWith (Compound [ Assign “x” (Lit 5)
, Assign “y” (Var “n”)
, Assign “z” (Lit 100)
])
(Map.fromList [(“z”, 3)])
~?= (Map.fromList [(“x”,5), (“z”,3)], Left VarUninit)
]
testTry =
[ “try caught” ~:
runWith (Try [ Assign “x” (Lit 5)
, Assign “y” (Var “n”)
, Assign “z” (Lit 100)
]
VarUninit
[ Assign “k” (Lit 10) ])
(Map.fromList [(“z”, 3)])
~?= (Map.fromList [(“x”,5), (“k”,10), (“z”,3)], Right ())
, “try not caught” ~:
runWith (Try [ Assign “x” (Lit 5)
, Assign “y” (Div (Lit 1) (Lit 0))
, Assign “z” (Lit 100)
]
VarUninit
[ Assign “k” (Lit 10) ])
(Map.fromList [(“z”, 3)])
~?= (Map.fromList [(“x”,5), (“z”,3)], Left DivByZero)
]
tests = testBind ++ testPutVar ++ testGetVar ++ testRaise ++ testTryCatch
++ testAssign ++ testCompound ++ testTry
— More tests when marking.
main = do
args <- getArgs
case args of
a:_ | Just n <- readMaybe a, 0 <= n, n < length tests ->
do c@Counts{errors=e, failures=f} <- runTestTT (tests !! n)
if e == 0 && f == 0
then return c
else exitFailure
| otherwise -> error “No such test number.”
_ -> runTestTT (TestList tests)