angle-0.8.1.0: tests/Test/Angle/Exec/Exec.hs
module Test.Angle.Exec.Exec
( tests
) where
import TestHelper
appending :: [a] -> [[a]] -> [a]
appending x = concatMap (++x)
setupAddF :: String
setupAddF = appending "\n" [defIsInt, defAddInts]
defIsInt :: String
defIsInt = defun "isInt" "x" "return (== x asType(0, x));"
defAddInts :: String
defAddInts = defun "addInts" "x:@isInt, y:@isInt" "(+ x y);"
defun :: String -> String -> String -> String
defun n a b = concat ["defun ", n, "(", a, ") ", b]
checkRes :: String -> (LangLit -> Bool) -> Property
checkRes s r = monadicIO $ runEx s >>= (assert . r)
checkFail :: String -> Property
checkFail s = expectFailure $ monadicIO $ runEx s
checkResEq :: String -> LangLit -> Property
checkResEq s x = checkRes s (==x)
testLess :: Int -> Int -> Property
testLess = binTest LitBool (<) "<"
testGreater :: Int -> Int -> Property
testGreater = binTest LitBool (>) ">"
testLessEq :: Int -> Int -> Property
testLessEq = binTest LitBool (<=) "<="
testGreaterEq :: Int -> Int -> Property
testGreaterEq = binTest LitBool (>=) ">="
testAdd :: NonEmptyList Int -> Property
testAdd (NonEmpty xs) = opTest LitInt sum "+" xs
testAnd :: NonEmptyList Bool -> Property
testAnd (NonEmpty xs) = opTest LitBool and "&" xs
testSub :: NonEmptyList Int -> Property
testSub (NonEmpty xs) = opTest LitInt (foldl1 (-)) "-" xs
testMult :: NonEmptyList Int -> Property
testMult (NonEmpty xs) = opTest LitInt product "*" xs
testNot :: Bool -> Property
testNot = opTestUnary LitBool not "^"
testOr :: NonEmptyList Bool -> Property
testOr (NonEmpty xs) = opTest LitBool or "|" xs
-- | Helper function for testing binary operators.
binTest ::
(Show a, Show b) =>
(b -> LangLit)
-> (a -> a -> b)
-> String -> a -> a
-> Property
binTest t f op x y = checkResEq st (t $ f x y)
where st = opElts op [show x, show y]
opElts :: String -> [String] -> String
opElts op xs = concat [ "("
, op, " "
, appending " " (init xs)
, last xs
, ");"]
opStr :: (a -> LangLit) -> String -> [a] -> String
opStr t op xs = concat [ "("
, op, " "
, appending " " (init xs')
, last xs'
, ");"]
where xs' = map (showSyn . t) xs
opTest ::
(Show a) =>
(a -> LangLit)
-> ([a] -> a)
-> String -> [a]
-> Property
opTest t f op xs = checkResEq st (t $ f xs)
where st = opStr t op xs
opTestUnary :: (a -> LangLit) -> (a -> a) -> String -> a -> Property
opTestUnary t f op x = checkResEq st (t $ f x)
where st = concat [op, showSyn $ t x, ";"]
callShow :: (Show a) => String -> [a] -> String
callShow f xs = concat [ f, "("
, concatMap ((++", ") . show) (init xs)
, show (last xs)
, ");"
]
callShowSyn :: (ShowSyn a) => String -> [a] -> String
callShowSyn f xs = concat [ f, "("
, concatMap ((++", ") . showSyn) (init xs)
, showSyn (last xs)
, ");"
]
testBuiltinLength :: TinyList LangLit -> Property
testBuiltinLength (TinyList xs) = checkResEq toRun $ LitInt (length xs)
where toRun = callShowSyn "length" [LitList xs]
testBuiltinLengthRange :: NonNegative Int -> NonNegative Int -> NonNegative Int -> Property
testBuiltinLengthRange (NonNegative x) (NonNegative y) (NonNegative z) =
y > x && z > x ==> checkResEq toRun $ LitInt (length [x,z..y])
where toRun = callShowSyn "length" [LitRange (LitInt x) (Just $ LitInt y) (Just $ LitInt z)]
testBuiltinIsNull :: LangLit -> Property
testBuiltinIsNull x = checkResEq toRun $ LitBool (x == LitNull)
where
toRun = callShowSyn "isNull" [x]
testBuiltinIndexBasic :: TinyList LangLit -> NonNegative Int -> Property
testBuiltinIndexBasic (TinyList xs) (NonNegative x) = x < length xs
==> checkResEq toRun $ xs !! x
where
toRun = callShowSyn "index" [LitInt x, LitList xs]
testBuiltinStr :: LangLit -> Property
testBuiltinStr x = checkResEq toRun $ case x of
LitStr _ -> x
LitChar c -> LitStr [c]
r@(LitRange{}) -> LitStr $ showSyn r
x' -> LitStr (showSyn x')
where
toRun = callShowSyn "str" [x]
testClassAdd :: LangLit -> LangLit -> Property
testClassAdd (LitInt x) (LitInt y) = checkResEq toRun $ LitInt (x + y)
where toRun = setupAddF ++ callShow "addInts" [x, y]
testClassAdd x y = checkFail toRun
where toRun = setupAddF ++ callShowSyn "addInts" [x, y]
testReturnSimple :: NonLambda -> Property
testReturnSimple (NonLambda x) = checkResEq toRun x
where toRun = setupReturnSimple ++ callShowSyn "returnSimple" [x]
setupReturnSimple = defun "returnSimple" "x" "return x;"
newtype NonLambda = NonLambda LangLit
deriving (Show)
instance Arbitrary NonLambda where
arbitrary = liftM NonLambda $ arbitrary `suchThat`
(\x -> case x of
LitLambda{} -> False
_ -> True)
testReturnIfEmbedded :: Bool -> NonLambda -> NonLambda -> Property
testReturnIfEmbedded p (NonLambda x) (NonLambda y) | p = checkResEq toRun x
| otherwise = checkResEq toRun y
where toRun = setupReturnIfEmbedded ++ callShowSyn "returnIfEmbedded" [LitBool p, x, y]
setupReturnIfEmbedded = defun "returnIfEmbedded" "p, x, y" "if p then return x; else return y;"
testForLoopSimple :: TinyList LangLit -> Property
testForLoopSimple (TinyList xs) = checkResEq toRun (LitList xs)
where toRun = for "i" (showSyn $ LitList xs) "i;"
testForLoopBreakSimple :: NonEmptyList LangLit -> Property
testForLoopBreakSimple (NonEmpty xs) = checkResEq toRun (head xs)
where
toRun = for "i" (showSyn $ LitList xs) (multiStmt ["i;", "break;"])
testForLoopBreakWithValue :: NonEmptyList LangLit -> LangLit -> Property
testForLoopBreakWithValue (NonEmpty xs) y = checkResEq toRun y
where
toRun = for "i" (showSyn $ LitList xs) (multiStmt ["i;", "break " ++ showSyn y ++ ";"])
multiStmt :: [String] -> String
multiStmt xs = concat ["{", concat xs, "}"]
for :: String -> String -> String -> String
for ident expr body = concat [ "for ", ident, " in "
, expr, " do ", body]
tests :: [TestTree]
tests = [ testGroup "filter tests"
[
]
, testGroup "basic operators"
[ testProperty "less" testLess
, testProperty "add" testAdd
, testProperty "mult" testMult
, testProperty "not" testNot
, testProperty "sub" testSub
, testProperty "and" testAnd
, testProperty "or" testOr
, testProperty "lessEq" testLessEq
, testProperty "greaterEq" testGreaterEq
, testProperty "greater" testGreater
]
, testGroup "classes"
[ testProperty "isAdd" testClassAdd
]
, testGroup "basic functions"
[ testProperty "returnSimple" testReturnSimple
, testProperty "returnIfEmbedded" testReturnIfEmbedded
]
, testGroup "structures"
[ testProperty "simple for-loop" testForLoopSimple
, testProperty "for loop break - simple" testForLoopBreakSimple
, testProperty "for loop break - value" testForLoopBreakWithValue
]
, testGroup "builtin functions"
[ testProperty "length" testBuiltinLength
, testProperty "length with range" testBuiltinLengthRange
, testProperty "isNull" testBuiltinIsNull
, testProperty "index - basic" testBuiltinIndexBasic
, testProperty "str" testBuiltinStr
]
]