{-# OPTIONS_GHC -fplugin=Polysemy.Plugin #-} module BigKeySpec where import qualified Data.Map as M import Data.Map (Map) import Polysemy import Polysemy.Check import Test.Hspec import Test.QuickCheck import Test.Hspec.QuickCheck import Polysemy.State import Data.Functor.Identity import Data.Word data KVStore k v m a where Store :: k -> v -> KVStore k v m () Delete :: k -> KVStore k v m () Retrieve :: k -> KVStore k v m (Maybe v) deriving instance (Show k, Show v) => Show (KVStore k v m a) makeSem ''KVStore deriveGenericK ''KVStore data Bug = HasBug | NoBug runKVStore :: forall k v r a. Ord k => Bug -> Sem (KVStore k v ': r) a -> Sem r a runKVStore bug = (evalState (mempty @(Map k v)) .) $ reinterpret $ \case Store k v -> modify $ M.insert k v Delete k -> case bug of HasBug -> pure () NoBug -> modify $ M.delete k Retrieve k -> gets $ M.lookup k deleteGetLaw :: forall r . r ~ '[KVStore Word64 Bool] => Bug -> (Word64 -> Bool -> [Sem r ()]) -> Property deleteGetLaw bug prel = prepropLaw @r (do k <- arbitrary v <- arbitrary pure $ Law { lawLhs = do delete k retrieve k , lawRhs = do delete k pure Nothing , lawPrelude = prel k v , lawPostlude = [] :: [Sem r ()] } ) Nothing -- (Just $ constructorLabel . runIdentity) (pure . Identity . run . runKVStore @Word64 @Bool bug) spec :: Spec spec = do describe "without prelude" $ do -- prop "with bug" $ deleteGetLaw HasBug $ \_ _ -> [] prop "without bug" $ deleteGetLaw NoBug $ \_ _ -> [] describe "with prelude" $ do prop "with bug" $ expectFailure $ deleteGetLaw HasBug $ \k v -> [store k v] prop "without bug" $ deleteGetLaw NoBug $ \k v -> [store k v]