{-# LANGUAGE FlexibleContexts, RankNTypes, ScopedTypeVariables, TypeApplications #-} module State ( tests , gen0 , test ) where import qualified Control.Carrier.State.Lazy as LazyStateC import qualified Control.Carrier.State.Strict as StrictStateC import Control.Effect.State import qualified Control.Monad.Trans.RWS.Lazy as LazyRWST import qualified Control.Monad.Trans.RWS.Strict as StrictRWST import qualified Control.Monad.Trans.State.Lazy as LazyStateT import qualified Control.Monad.Trans.State.Strict as StrictStateT import Data.Tuple (swap) import Gen import qualified Monad import qualified MonadFix import Test.Tasty import Test.Tasty.Hedgehog tests :: TestTree tests = testGroup "State" [ testGroup "StateC (Lazy)" $ [ testMonad , testMonadFix , testState ] >>= ($ runC LazyStateC.runState) , testGroup "StateC (Strict)" $ [ testMonad , testMonadFix , testState ] >>= ($ runC StrictStateC.runState) , testGroup "StateT (Lazy)" $ testState (runC (fmap (fmap swap) . flip LazyStateT.runStateT)) , testGroup "StateT (Strict)" $ testState (runC (fmap (fmap swap) . flip StrictStateT.runStateT)) , testGroup "RWST (Lazy)" $ testState (runC (runRWST LazyRWST.runRWST)) , testGroup "RWST (Strict)" $ testState (runC (runRWST StrictRWST.runRWST)) ] where testMonad run = Monad.test (m (gen0 s) (\ _ _ -> [])) a b c (pair <*> s <*> unit) run testMonadFix run = MonadFix.test (m (gen0 s) (\ _ _ -> [])) a b (pair <*> s <*> unit) run testState run = State.test (m (gen0 s) (\ _ _ -> [])) a s run runRWST f s m = (\ (a, s, ()) -> (s, a)) <$> f m s s gen0 :: forall s m a sig . (Has (State s) sig m, Arg s, Show s, Vary s) => GenTerm s -> GenTerm a -> [GenTerm (m a)] gen0 s a = [ label "gets" (gets @s) <*> fn a , infixL 4 "<$" (<$) <*> a <*> (label "put" put <*> s) ] test :: (Has (State s) sig m, Arg s, Eq a, Eq s, Show a, Show s, Vary s) => GenM m -> GenTerm a -> GenTerm s -> Run ((,) s) ((,) s) m -> [TestTree] test m a s (Run runState) = [ testProperty "get returns the state variable" . forall (s :. fn (m a) :. Nil) $ \ s k -> runState (s, get >>= k) === runState (s, k s) , testProperty "put updates the state variable" . forall (s :. s :. m a :. Nil) $ \ s s' m -> runState (s, put s' >> m) === runState (s', m) ]