{-# OPTIONS_GHC -fplugin=Polysemy.Plugin #-}
module LawSpec where
import Polysemy
import Polysemy.Check
import Test.Hspec
import Test.QuickCheck
import Test.Hspec.QuickCheck
import Polysemy.State
import Data.IORef (newIORef, readIORef)
spec :: Spec
spec = do
describe "pure state" $ do
prop "put >> put = put" $ do
s <- arbitrary
pure $ putPutLaw $ runPureState s
prop "get >>= put = pure ()" $ do
s <- arbitrary
pure $ getPutLaw $ runPureState s
prop "put >> get = put >> pure" $ do
s <- arbitrary
pure $ putGetLaw $ runPureState s
describe "io state" $ do
prop "put >> put = put" $ do
s <- arbitrary
pure $ putPutLaw $ runIOState s
prop "get >>= put = pure ()" $ do
s <- arbitrary
pure $ getPutLaw $ runIOState s
prop "put >> get = put >> pure" $ do
s <- arbitrary
pure $ putGetLaw $ runIOState s
type LawConstraints f effs s r =
( Arbitrary s
, Members effs r
, Eq s
, Show s
, ArbitraryEff effs r
, f ~ (,) s
, effs ~ '[State s]
)
putPutLaw
:: forall s r res effs f
. ( res ~ ()
, LawConstraints f effs s r
)
=> (forall a. Sem r (res, a) -> IO (f (res, a)))
-> Property
putPutLaw = prepropLaw @effs $ do
s1 <- arbitrary
s2 <- arbitrary
pure
( do
put s1
put s2
, do
put s2
)
getPutLaw
:: forall s r res effs f
. ( res ~ ()
, LawConstraints f effs s r
)
=> (forall a. Sem r (res, a) -> IO (f (res, a)))
-> Property
getPutLaw = prepropLaw @effs $ do
pure
( get >>= put
, pure ()
)
putGetLaw
:: forall s r res effs f
. ( res ~ s
, LawConstraints f effs s r
)
=> (forall a. Sem r (res, a) -> IO (f (res, a)))
-> Property
putGetLaw = prepropLaw @effs $ do
s <- arbitrary
pure
( do
put s
get
, do
put s
pure s
)
runPureState :: Int -> Sem '[State Int] a -> IO (Int, a)
runPureState s = pure . run . runState s
runIOState :: Int -> Sem '[State Int, Embed IO] a -> IO (Int, a)
runIOState s sem = do
ref <- newIORef s
a <- runM . runStateIORef ref $ sem
r <- readIORef ref
pure (r, a)