LslPlus-0.3.0: src/Language/Lsl/UnitTest.hs
module Language.Lsl.UnitTest(
LSLUnitTest(..),
FuncCallExpectations(..),
ExpectationMode(..),
EntryPoint(..),
Binding,
expectedReturns,
removeExpectation) where
import Control.Monad(liftM2)
import Data.List(maximumBy)
import Language.Lsl.Internal.Type(LSLValue(..))
import Language.Lsl.Internal.Exec(Binding(..))
import Language.Lsl.Internal.Util(removeLookup)
data FuncCallExpectations a = FuncCallExpectations {
expectationMode :: ExpectationMode,
callList :: [((String, [Maybe (LSLValue a)]),LSLValue a)] } deriving (Show)
data ExpectationMode = Nice | Normal | Exhaust | Strict deriving (Show,Eq)
data EntryPoint = ModuleFunc String String | ScriptFunc String String | ScriptHandler String String String
deriving (Show)
data LSLUnitTest = LSLUnitTest {
unitTestName :: String,
entryPoint :: EntryPoint,
initialGlobs :: [Binding Float],
arguments :: [LSLValue Float],
expectedCalls :: FuncCallExpectations Float,
expectedReturn :: Maybe (LSLValue Float),
expectedGlobalVals :: [Binding Float],
expectedNewState :: Maybe String
} deriving (Show)
argMatch (Just x) y | lslValuesMatch x y = Just 1
| otherwise = Nothing
argMatch Nothing _ = Just 0
argsMatch expectArgs args = foldl (liftM2 (+)) (Just 0) $ zipWith argMatch expectArgs args
lslValuesMatch (FVal a) (FVal b) = a == b ||
if a == 0.0 then b < 0.000001
else if b == 0.0 then a < 0.000001
else abs ((b - a) / a) < 0.000001
lslValuesMatch x y = x == y
matchFail :: Monad m => m a
matchFail = fail "no matching call"
expectedReturns :: (RealFloat a,Monad m) => String -> [LSLValue a] -> FuncCallExpectations a -> m ((String,[Maybe (LSLValue a)]),LSLValue a)
expectedReturns name args (FuncCallExpectations Strict (match@((name',expectArgs),returns):_)) =
if name /= name' || argsMatch expectArgs args == Nothing then matchFail
else return match
expectedReturns name args (FuncCallExpectations Strict _) = matchFail
expectedReturns n a (FuncCallExpectations mode callList) =
let rightNames = filter ((n==) . fst . fst) callList
argMatch (Just x) y | x == y = Just 1
| otherwise = Nothing
argMatch Nothing _ = Just 0
argsMatch args expectArgs = foldl (liftM2 (+)) (Just 0) $ zipWith argMatch expectArgs args
ranked = zip (map (argsMatch a) (map (snd . fst) rightNames)) rightNames
orderMatch (Nothing,_) (Nothing,_) = EQ
orderMatch _ (Nothing,_) = GT
orderMatch (Nothing,_) _ = LT
orderMatch ((Just a),_) ((Just b),_) = compare a b
in case ranked of
[] -> fail matchFail
_ -> case maximumBy orderMatch ranked of
(Nothing,_) -> matchFail
(_,e) -> return e
removeExpectation :: (RealFloat a) => (String,[Maybe (LSLValue a)]) -> FuncCallExpectations a -> FuncCallExpectations a
removeExpectation m fce = fce { callList = removeLookup m (callList fce) }