quickcheck-dynamic 3.0.3 → 3.1.0
raw patch · 3 files changed
+31/−5 lines, 3 files
Files
- CHANGELOG.md +7/−0
- quickcheck-dynamic.cabal +2/−1
- src/Test/QuickCheck/StateModel.hs +22/−4
CHANGELOG.md view
@@ -9,6 +9,13 @@ ## UNRELEASED +## 3.1.0 - 2023-04-10++* **BREAKING**: Change the type of `postcondition` to allow you to+ express property monitoring (e.g. stats or counterexamples) in the+ postcondition itself - rather than duplicating code for counterexamples+ in the `monitoring` function.+ ## 3.0.3 - 2023-04-18 * Added `hasNoVariablesQ` and `forAllNonVariableDL` functions to help make
quickcheck-dynamic.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: quickcheck-dynamic-version: 3.0.3+version: 3.1.0 license: Apache-2.0 license-files: LICENSE@@ -54,6 +54,7 @@ TypeOperators DerivingVia DeriveGeneric+ GeneralizedNewtypeDeriving ghc-options: -Wall -Wnoncanonical-monad-instances -Wunused-packages
src/Test/QuickCheck/StateModel.hs view
@@ -11,6 +11,7 @@ module Test.QuickCheck.StateModel.Variables, StateModel (..), RunModel (..),+ PostconditionM (..), WithUsedVars (..), Annotated (..), Step (..),@@ -22,6 +23,8 @@ Env, Realized, Generic,+ monitorPost,+ counterexamplePost, stateAfter, runActions, lookUpVar,@@ -37,7 +40,7 @@ import Control.Monad.Identity import Control.Monad.Reader import Control.Monad.State-import Control.Monad.Writer (WriterT)+import Control.Monad.Writer (Endo (..), WriterT, runWriterT, tell) import Data.Data import Data.Kind import Data.List@@ -137,6 +140,19 @@ type instance Realized (WriterT w m) a = Realized m a type instance Realized Identity a = a +newtype PostconditionM m a = PostconditionM {runPost :: WriterT (Endo Property, Endo Property) m a}+ deriving (Functor, Applicative, Monad, MonadTrans)++-- | Apply the property transformation to the property after evaluating+-- the postcondition. Useful for collecting statistics while avoiding+-- duplication between `monitoring` and `postcondition`.+monitorPost :: Monad m => (Property -> Property) -> PostconditionM m ()+monitorPost m = PostconditionM $ tell (Endo m, mempty)++-- | Acts as `Test.QuickCheck.counterexample` if the postcondition fails.+counterexamplePost :: Monad m => String -> PostconditionM m ()+counterexamplePost c = PostconditionM $ tell (mempty, Endo $ counterexample c)+ class Monad m => RunModel state m where -- | Perform an `Action` in some `state` in the `Monad` `m`. This -- is the function that's used to exercise the actual stateful@@ -153,10 +169,10 @@ -- | Postcondition on the `a` value produced at some step. -- The result is `assert`ed and will make the property fail should it be `False`. This is useful -- to check the implementation produces expected values.- postcondition :: forall a. (state, state) -> Action state a -> LookUp m -> Realized m a -> m Bool+ postcondition :: forall a. (state, state) -> Action state a -> LookUp m -> Realized m a -> PostconditionM m Bool postcondition _ _ _ _ = pure True - -- | Allows the user to attach information to the `Property` at each step of the process.+ -- | Allows the user to attach additional information to the `Property` at each step of the process. -- This function is given the full transition that's been executed, including the start and ending -- `state`, the `Action`, the current environment to `Lookup` and the value produced by `perform` -- while executing this step.@@ -381,6 +397,8 @@ s' = computeNextState s act var env' = (var :== ret) : env monitor (monitoring @state @m (underlyingState s, underlyingState s') act (lookUpVar env') ret)- b <- run $ postcondition @state @m (underlyingState s, underlyingState s') act (lookUpVar env) ret+ (b, (Endo mon, Endo onFail)) <- run . runWriterT . runPost $ postcondition @state @m (underlyingState s, underlyingState s') act (lookUpVar env) ret+ monitor mon+ unless b $ monitor onFail assert b loop s' env' as