Yampa-0.12: tests/AFRPTestsCommon.hs
{-# OPTIONS_GHC -fno-warn-tabs #-}
{-
******************************************************************************
* A F R P *
* *
* Module: AFRPTestsCommon *
* Purpose: Common definitions for the regression test modules. *
* Authors: Antony Courtney and Henrik Nilsson *
* *
* Copyright (c) Yale University, 2003 *
* *
******************************************************************************
-}
module AFRPTestsCommon where
import System.IO.Unsafe (unsafePerformIO)
import Data.IORef (newIORef, writeIORef, readIORef)
import FRP.Yampa
------------------------------------------------------------------------------
-- Rough equality with instances
------------------------------------------------------------------------------
-- Rough equality. Only intended to be good enough for test cases in this
-- module.
class REq a where
(~=) :: a -> a -> Bool
epsilon :: Fractional a => a
epsilon = 0.0001
instance REq Float where
x ~= y = abs (x - y) < epsilon -- A relative measure should be used.
instance REq Double where
x ~= y = abs (x - y) < epsilon -- A relative measure should be used.
instance REq Int where
(~=) = (==)
instance REq Integer where
(~=) = (==)
instance REq Bool where
(~=) = (==)
instance REq Char where
(~=) = (==)
instance REq () where
() ~= () = True
instance (REq a, REq b) => REq (a,b) where
(x1,x2) ~= (y1,y2) = x1 ~= y1 && x2 ~= y2
instance (REq a, REq b, REq c) => REq (a,b,c) where
(x1,x2,x3) ~= (y1,y2,y3) = x1 ~= y1 && x2 ~= y2 && x3 ~= y3
instance (REq a, REq b, REq c, REq d) => REq (a,b,c,d) where
(x1,x2,x3,x4) ~= (y1,y2,y3,y4) = x1 ~= y1
&& x2 ~= y2
&& x3 ~= y3
&& x4 ~= y4
instance (REq a, REq b, REq c, REq d, REq e) => REq (a,b,c,d,e) where
(x1,x2,x3,x4,x5) ~= (y1,y2,y3,y4,y5) = x1 ~= y1
&& x2 ~= y2
&& x3 ~= y3
&& x4 ~= y4
&& x5 ~= y5
instance REq a => REq (Maybe a) where
Nothing ~= Nothing = True
(Just x) ~= (Just y) = x ~= y
_ ~= _ = False
instance REq a => REq (Event a) where
NoEvent ~= NoEvent = True
(Event x) ~= (Event y) = x ~= y
_ ~= _ = False
instance (REq a, REq b) => REq (Either a b) where
(Left x) ~= (Left y) = x ~= y
(Right x) ~= (Right y) = x ~= y
_ ~= _ = False
instance REq a => REq [a] where
[] ~= [] = True
(x:xs) ~= (y:ys) = x ~= y && xs ~= ys
_ ~= _ = False
------------------------------------------------------------------------------
-- Testing utilities
------------------------------------------------------------------------------
testSF1 :: SF Double a -> [a]
testSF1 sf = take 25 (embed sf (deltaEncodeBy (~=) 0.25 [0.0..]))
testSF2 :: SF Double a -> [a]
testSF2 sf = take 25 (embed sf (deltaEncodeBy (~=) 0.25 input))
where
-- The initial 0.0 is just for result compatibility with an older
-- version.
input = 0.0 : [ fromIntegral (b `div` freq) | b <- [1..] :: [Int] ]
freq = 5
------------------------------------------------------------------------------
-- Test harness for space behaviour
------------------------------------------------------------------------------
{-
-- Test for space leaks.
-- Carefully defined in an attempt to defeat fully lazy lambda lifting.
-- Seems to work, but may be unsafe if the compiler decides to optimize
-- aggressively.
testSFSpaceLeak :: Int -> SF Double a -> a
testSFSpaceLeak n sf = embed sf (deltaEncodeBy (~=) 0.25 [(seq n 0.0)..]) !! n
-}
-- Using embed/deltaEncode seems to be a bad idea since fully lazy
-- lambda lifting often results in lifting a big input list to the top
-- level in the form of a CAF. Using reactimate and avoiding constructing
-- input/output lists should be more robust.
testSFSpaceLeak :: Int -> SF Double a -> a
testSFSpaceLeak n sf = unsafePerformIO $ do
countr <- newIORef 0
inputr <- newIORef undefined
outputr <- newIORef undefined
let init = do
let input0 = 0.0
writeIORef inputr input0
count <- readIORef countr
writeIORef countr (count + 1)
return input0
sense _ = do
input <- readIORef inputr
let input' = input + 0.5
writeIORef inputr input'
count <- readIORef countr
writeIORef countr (count + 1)
return (0.25, Just input')
actuate _ output = do
writeIORef outputr output
_input <- readIORef inputr
count <- readIORef countr
return (count >= n)
reactimate init sense actuate sf
-- return output
readIORef outputr
------------------------------------------------------------------------------
-- Some utilities used for testing laws
------------------------------------------------------------------------------
fun_prod f g = \(x,y) -> (f x, g y)
assoc :: ((a,b),c) -> (a,(b,c))
assoc ((a,b),c) = (a,(b,c))
assocInv :: (a,(b,c)) -> ((a,b),c)
assocInv (a,(b,c)) = ((a,b),c)