2016-04-21 04:05:08 +03:00
|
|
|
{-# LANGUAGE CPP #-}
|
2015-09-13 08:00:16 +03:00
|
|
|
module Main where
|
|
|
|
|
2017-01-28 17:35:22 +03:00
|
|
|
#if !MIN_VERSION_base(4,8,0)
|
2017-03-14 21:42:03 +03:00
|
|
|
import Control.Applicative
|
2016-04-21 04:05:08 +03:00
|
|
|
#endif
|
|
|
|
|
2017-03-14 21:42:03 +03:00
|
|
|
import Control.Monad.Freer
|
2015-09-13 08:00:16 +03:00
|
|
|
|
2017-03-14 21:42:03 +03:00
|
|
|
import Test.Tasty
|
|
|
|
import Test.Tasty.HUnit
|
|
|
|
import Test.Tasty.QuickCheck
|
2015-09-13 08:00:16 +03:00
|
|
|
|
2017-03-14 21:42:03 +03:00
|
|
|
import Tests.Coroutine
|
|
|
|
import Tests.Exception
|
|
|
|
import Tests.Fresh
|
|
|
|
import Tests.Loop
|
|
|
|
import Tests.NonDet
|
|
|
|
import Tests.Reader
|
|
|
|
import Tests.State
|
|
|
|
import Tests.StateRW
|
2015-09-13 08:00:16 +03:00
|
|
|
|
2016-03-03 18:10:56 +03:00
|
|
|
import qualified Data.List
|
|
|
|
|
2015-09-13 08:00:16 +03:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Pure Tests --
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
addInEff :: Int -> Int -> Int
|
|
|
|
addInEff x y = run ((+) <$> pure x <*> pure y)
|
|
|
|
|
|
|
|
pureTests :: TestTree
|
|
|
|
pureTests = testGroup "Pure Eff tests"
|
2015-09-13 08:17:28 +03:00
|
|
|
[ testProperty "Pure run just works: (+)"
|
2015-09-13 08:00:16 +03:00
|
|
|
(\x y -> addInEff x y == x + y)
|
|
|
|
]
|
|
|
|
|
2016-03-02 15:38:05 +03:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Coroutine Tests --
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- | Counts number of consecutive pairs of odd elements at beginning of a list.
|
|
|
|
countOddDuoPrefix :: [Int] -> Int
|
|
|
|
countOddDuoPrefix list = count list 0
|
|
|
|
where
|
|
|
|
count (i1:i2:is) n = if even i1 && even i2 then n else count is (n+1)
|
2017-03-14 21:42:03 +03:00
|
|
|
count _ n = n
|
2016-03-02 15:38:05 +03:00
|
|
|
|
|
|
|
coroutineTests :: TestTree
|
|
|
|
coroutineTests = testGroup "Coroutine Eff tests"
|
|
|
|
[ testProperty "Counting consecutive pairs of odds"
|
|
|
|
(\list -> runTestCoroutine list == countOddDuoPrefix list)
|
|
|
|
]
|
|
|
|
|
2015-09-13 08:00:16 +03:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Exception Tests --
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
exceptionTests :: TestTree
|
|
|
|
exceptionTests = testGroup "Exception Eff tests"
|
|
|
|
[ testProperty "Exc takes precedence" (\x y -> testExceptionTakesPriority x y == Left y)
|
|
|
|
, testCase "uncaught: runState (runError t)" $
|
|
|
|
ter1 @?= (Left "exc", 2)
|
|
|
|
, testCase "uncaught: runError (runState t)" $
|
|
|
|
ter2 @?= Left "exc"
|
|
|
|
, testCase "caught: runState (runError t)" $
|
|
|
|
ter3 @?= (Right "exc", 2)
|
|
|
|
, testCase "caught: runError (runState t)" $
|
|
|
|
ter4 @?= Right ("exc", 2)
|
|
|
|
, testCase "success: runReader (runErrBig t)" (ex2rr @?= Right 5)
|
|
|
|
, testCase "uncaught: runReader (runErrBig t)" $
|
|
|
|
ex2rr1 @?= Left (TooBig 7)
|
|
|
|
, testCase "uncaught: runErrBig (runReader t)" $
|
|
|
|
ex2rr2 @?= Left (TooBig 7)
|
|
|
|
]
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Fresh Effect Tests --
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
freshTests :: TestTree
|
|
|
|
freshTests = testGroup "Fresh tests"
|
|
|
|
[ testCase "Start at 0, refresh twice, yields 1" (testFresh 10 @?= 9)
|
|
|
|
, testProperty "Freshening n times yields (n-1)" (\n -> n > 0 ==> testFresh n == (n-1))
|
|
|
|
]
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Nondeterministic Effect Tests --
|
|
|
|
--------------------------------------------------------------------------------
|
2016-03-03 18:10:56 +03:00
|
|
|
-- https://wiki.haskell.org/Prime_numbers
|
|
|
|
primesTo :: Int -> [Int]
|
|
|
|
primesTo m = sieve [2..m] {- (\\) is set-difference for unordered lists -}
|
|
|
|
where
|
|
|
|
sieve (x:xs) = x : sieve (xs Data.List.\\ [x,x+x..m])
|
2017-03-14 21:42:03 +03:00
|
|
|
sieve [] = []
|
2016-03-03 18:10:56 +03:00
|
|
|
|
2017-02-16 16:24:44 +03:00
|
|
|
nonDetTests :: TestTree
|
|
|
|
nonDetTests = testGroup "NonDet tests"
|
2016-03-03 18:10:56 +03:00
|
|
|
[ testProperty "Primes in 2..n generated by ifte"
|
|
|
|
(\n' -> let n = abs n' in testIfte [2..n] == primesTo n)
|
2015-09-13 08:00:16 +03:00
|
|
|
]
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Reader Effect Tests --
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
readerTests :: TestTree
|
|
|
|
readerTests = testGroup "Reader tests"
|
|
|
|
[ testProperty "Reader passes along environment: n + x"
|
|
|
|
(\n x -> testReader n x == n + x)
|
|
|
|
, testProperty "Multiple readers work"
|
2017-01-28 14:57:31 +03:00
|
|
|
(\i n -> testMultiReader i n == ((i + 2) + fromIntegral (n + 1)))
|
2015-09-13 08:00:16 +03:00
|
|
|
, testProperty "Local injects into env"
|
|
|
|
(\env inc -> testLocal env inc == 2*(env+1) + inc)
|
|
|
|
]
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- State[RW] Effect Tests --
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
stateTests :: TestTree
|
|
|
|
stateTests = testGroup "State tests"
|
|
|
|
[ testProperty "get after put n yields (n,n)" (\n -> testPutGet n 0 == (n,n))
|
|
|
|
, testProperty "Final put determines stored state" $
|
|
|
|
\p1 p2 start -> testPutGetPutGetPlus p1 p2 start == (p1+p2, p2)
|
|
|
|
, testProperty "If only getting, start state determines outcome" $
|
|
|
|
\start -> testGetStart start == (start,start)
|
|
|
|
, testProperty "testPutGet: State == StateRW" $
|
|
|
|
\n -> testPutGet n 0 == testPutGetRW n 0
|
|
|
|
, testProperty "testPutGetPutGetPlus: State == StateRW" $
|
|
|
|
\p1 p2 start -> testPutGetPutGetPlus p1 p2 start == testPutGetPutGetPlusRW p1 p2 start
|
|
|
|
, testProperty "testGetStart: State == StateRW" $
|
|
|
|
\n -> testGetStart n == testGetStartRW n
|
2017-01-21 19:36:50 +03:00
|
|
|
, testProperty "testEvalState: evalState discards final state" $
|
|
|
|
\n -> testEvalState n == n
|
|
|
|
, testProperty "testExecState: execState returns final state" $
|
|
|
|
\n -> testExecState n == n
|
2015-09-13 08:00:16 +03:00
|
|
|
]
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Runner --
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
main :: IO ()
|
2017-03-14 21:42:03 +03:00
|
|
|
main = do
|
|
|
|
runForeverLoop
|
|
|
|
defaultMain $ testGroup "Tests"
|
|
|
|
[ pureTests
|
|
|
|
, coroutineTests
|
|
|
|
, exceptionTests
|
|
|
|
, freshTests
|
|
|
|
, nonDetTests
|
|
|
|
, readerTests
|
|
|
|
, stateTests
|
|
|
|
]
|