-- import Data.Constraint
import Data.Constraint.Extras
import Data.Constraint.Extras.TH
import Data.IORef
import Data.GADT.Compare
import Data.GADT.Show
import Data.Kind
import Data.Some
import Data.StateVar (($=))
import Data.Typeable
-- import Data.Type.Equality
import Foreign.Marshal.Alloc
import Foreign.Ptr
import Polysemy
-- import Polysemy.Internal
import Polysemy.Membership
import Polysemy.State
import Polysemy.State.Keyed
import Polysemy.State.Keyed.Law
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck as QuickCheck
import Test.QuickCheck.Monadic as QuickCheck
data TestKey :: Type -> Type where
A, B :: TestKey Int
C :: TestKey Double
D :: TestKey Bool
deriveArgDict ''TestKey
deriving instance Eq (TestKey a)
deriving instance Show (TestKey a)
instance GShow TestKey where
gshowsPrec = showsPrec
instance GEq TestKey where
geq (k :: TestKey a) (k' :: TestKey b) =
has @Typeable k $ has @Typeable k' $ eqT @a @b
instance Arbitrary (Some TestKey) where
arbitrary = elements [Some A, Some B, Some C, Some D]
propertyM :: Applicative m => Property -> PropertyM m ()
propertyM = MkPropertyM . const . pure . pure
spec :: Spec
spec = do
describe "runKeyedStates" $ do
prop "obeys the KeyedState laws" $
\(a :: Int) (b :: Int) (c :: Double) (d :: Bool) -> do
prop_lawfulKeyedState @_ @'[Embed IO] $
evalState d
. evalState c
. evalState b
. evalState a
. runKeyedStates (\case A -> Here; B -> There Here; C -> There $ There Here; D -> There $ There $ There Here)
. raiseUnder
. raiseUnder
. raiseUnder
. raiseUnder
describe "runKeyedStateStore" $ do
prop "obeys the KeyedState laws" $
\(a :: Int) (b :: Int) (c :: Double) (d :: Bool) -> do
prop_lawfulKeyedState @_ @'[Embed IO] $
evalState (KeyedStore (\case A -> a; B -> b; C -> c; D -> d)) .
runKeyedStateStore @TestKey .
raiseUnder
describe "runKeyedStateVarsIO" $ do
prop "obeys the KeyedState laws with IORef storage" $
\(a :: Int) (b :: Int) (c :: Double) (d :: Bool) -> monadicIO $ do
(refA,refB,refC,refD) <- QuickCheck.run $ (,,,) <$> newIORef a <*> newIORef b <*> newIORef c <*> newIORef d
propertyM $ prop_lawfulKeyedState @_ @'[Embed IO] $
runKeyedStateVarsIO @IORef $ \case A -> refA; B -> refB; C -> refC; D -> refD
describe "runStorableKeyedStateVarsIO" $ do
prop "obeys the KeyedState laws with Ptr storage" $
\(a :: Int) (b :: Int) (c :: Double) (d :: Bool) -> monadicIO $ do
(refA,refB,refC,refD) <- QuickCheck.run $ (,,,) <$> malloc <*> malloc <*> malloc <*> malloc
refA $= a; refB $= b; refC $= c; refD $= d
propertyM $ prop_lawfulKeyedState @_ @'[Embed IO] $
runStorableKeyedStateVarsIO @Ptr $ \case A -> refA; B -> refB; C -> refC; D -> refD
QuickCheck.run $ do free refA; free refB; free refC; free refD
main :: IO ()
main = hspec spec