-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A library for stateful property-based testing -- -- Please see the README on GitHub at -- https://github.com/input-output-hk/quickcheck-dynamic#readme @package quickcheck-dynamic @version 2.0.0 module Test.QuickCheck.DynamicLogic.CanGenerate -- | canGenerate prob g p returns False if we are sure -- Prob(g generates x satisfying p) >= prob otherwise -- True (and we know such an x can be generated). canGenerate :: Double -> Gen a -> (a -> Bool) -> Bool -- | This module defines Quantifications, which are used together with -- forAllQ in DynamicLogic. A `Quantification t` can be used to generate -- a t, shrink a t, and recognise a generated -- t. module Test.QuickCheck.DynamicLogic.Quantify -- | A Quantification over a type a is a generator that can -- be used with forAllQ to generate random values in DL scenarios. -- In addition to a QuickCheck generator a Quantification contains -- a shrinking strategy that ensures that shrunk values stay in the range -- of the generator. data Quantification a isEmptyQ :: Quantification a -> Bool generateQ :: Quantification a -> Gen a shrinkQ :: Quantification a -> a -> [a] -- | Pack up an Arbitrary instance as a Quantification. -- Treats all values as being in range. arbitraryQ :: Arbitrary a => Quantification a -- | Generates exactly the given value. Does not shrink. exactlyQ :: Eq a => a -> Quantification a -- | Pick a random value from a list. Treated as an empty choice if the -- list is empty: -- --
-- forAllQ (elementsQ []) == empty --elementsQ :: Eq a => [a] -> Quantification a -- | Choose from a list of quantifications. Same as frequencyQ with -- all weights the same (and > 0). oneofQ :: [Quantification a] -> Quantification a -- | Choose from a weighted list of quantifications. Treated as an -- empty choice if no quantification has weight > 0. frequencyQ :: [(Int, Quantification a)] -> Quantification a -- | Quantification is not a Functor, since it also keeps -- track of the range of the generators. However, if you have two -- functions to :: a -> b from :: b -> a satisfying -- from . to = id you can go from a quantification over -- a to one over b. Note that the from -- function need only be defined on the image of to. mapQ :: (a -> b, b -> a) -> Quantification a -> Quantification b -- | Restrict the range of a quantification. whereQ :: Quantification a -> (a -> Bool) -> Quantification a -- | Generate a random value in a given range (inclusive). chooseQ :: (Arbitrary a, Random a, Ord a) => (a, a) -> Quantification a -- | Wrap a `Gen a` generator in a `Quantification a`. Uses given shrinker. withGenQ :: Gen a -> (a -> [a]) -> Quantification a validQuantification :: Show a => Quantification a -> Property -- | Generalization of Quantifications, which lets you treat lists -- and tuples of quantifications as quantifications. For instance, -- --
-- ... -- (die1, die2) <- forAllQ (chooseQ (1, 6), chooseQ (1, 6)) -- ... --class (Eq (Quantifies q), Show (Quantifies q), Typeable (Quantifies q)) => Quantifiable q where { -- | The type of values quantified over. -- --
-- Quantifies (Quantification a) = a
--
type Quantifies q;
}
-- | Computing the actual Quantification.
quantify :: Quantifiable q => q -> Quantification (Quantifies q)
instance (GHC.Classes.Eq a, GHC.Show.Show a, Data.Typeable.Internal.Typeable a) => Test.QuickCheck.DynamicLogic.Quantify.Quantifiable (Test.QuickCheck.DynamicLogic.Quantify.Quantification a)
instance (Test.QuickCheck.DynamicLogic.Quantify.Quantifiable a, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable b) => Test.QuickCheck.DynamicLogic.Quantify.Quantifiable (a, b)
instance (Test.QuickCheck.DynamicLogic.Quantify.Quantifiable a, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable b, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable c) => Test.QuickCheck.DynamicLogic.Quantify.Quantifiable (a, b, c)
instance (Test.QuickCheck.DynamicLogic.Quantify.Quantifiable a, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable b, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable c, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable d) => Test.QuickCheck.DynamicLogic.Quantify.Quantifiable (a, b, c, d)
instance (Test.QuickCheck.DynamicLogic.Quantify.Quantifiable a, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable b, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable c, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable d, Test.QuickCheck.DynamicLogic.Quantify.Quantifiable e) => Test.QuickCheck.DynamicLogic.Quantify.Quantifiable (a, b, c, d, e)
instance Test.QuickCheck.DynamicLogic.Quantify.Quantifiable a => Test.QuickCheck.DynamicLogic.Quantify.Quantifiable [a]
module Test.QuickCheck.DynamicLogic.SmartShrinking
-- | This combinator captures the 'smart shrinking' implemented for the
-- Smart type wrapper in Test.QuickCheck.Modifiers.
shrinkSmart :: (a -> [a]) -> Smart a -> [Smart a]
module Test.QuickCheck.DynamicLogic.Utils
withSize :: Testable prop => (Int -> prop) -> Property
-- | Simple (stateful) Model-Based Testing library for use with Haskell
-- QuickCheck.
--
-- This module provides the basic machinery to define a StateModel
-- from which traces can be generated and executed against some
-- actual implementation code to define monadic Property to
-- be asserted by QuickCheck.
module Test.QuickCheck.StateModel
-- | The typeclass users implement to define a model against which to
-- validate some implementation.
--
-- To implement a StateModel, user needs to provide at least the
-- following:
--
--
-- data Action RegState a where
-- Spawn :: Action RegState ThreadId
-- Register :: String -> Var ThreadId -> Action RegState (Either ErrorCall ())
-- KillThread :: Var ThreadId -> Action RegState ()
--
--
-- The Spawn action should produce a ThreadId, whereas
-- the KillThread action does not return anything.
data Action state a;
}
-- | Display name for Action. This is useful to provide sensible
-- statistics about the distribution of Actions run when checking
-- a property.
--
-- Default implementation uses a poor-man's string manipulation method to
-- extract the constructor name from the value.
actionName :: StateModel state => Action state a -> String
-- | Generator for Action depending on state. The generated
-- values are wrapped in Any type to allow the model to not
-- generate an action under some circumstances: Any generated
-- Error value will be ignored when generating a trace for
-- testing.
arbitraryAction :: StateModel state => state -> Gen (Any (Action state))
-- | Shrinker for Action. Defaults to no-op but as usual, defining a
-- good shrinker greatly enhances the usefulness of property-based
-- testing.
shrinkAction :: (StateModel state, Typeable a) => state -> Action state a -> [Any (Action state)]
-- | Initial state of generated traces.
initialState :: StateModel state => state
-- | Transition function for the model. The `Var a` parameter is useful to
-- keep reference to actual value of type a produced by
-- performing the Action inside the state so that
-- further actions can use Lookup to retrieve that data. This
-- allows the model to be ignorant of those values yet maintain some
-- references that can be compared and looked for.
nextState :: (StateModel state, Typeable a) => state -> Action state a -> Var a -> state
-- | Precondition for filtering generated Action. This function is
-- applied before the action is performed, it is useful to refine
-- generators that can produce more values than are useful.
precondition :: StateModel state => state -> Action state a -> Bool
class Monad m => RunModel state m
-- | Perform an Action in some state in the Monad
-- m. This is the function that's used to exercise the actual
-- stateful implementation, usually through various side-effects as
-- permitted by m. It produces a value of type a, eg.
-- some observable output from the Action that should later be
-- kept in the environment through a `Var a` also passed to the
-- nextState function.
--
-- The Lookup parameter provides an environment to lookup
-- `Var a` instances from previous steps.
perform :: forall a. (RunModel state m, Typeable a) => state -> Action state a -> LookUp m -> m (Realized m a)
-- | Postcondition on the a value produced at some step. The
-- result is asserted and will make the property fail should it be
-- False. This is useful to check the implementation produces
-- expected values.
postcondition :: forall a. RunModel state m => (state, state) -> Action state a -> LookUp m -> Realized m a -> m Bool
-- | Allows the user to attach 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.
monitoring :: forall a. RunModel state m => (state, state) -> Action state a -> LookUp m -> Realized m a -> Property -> Property
data Any f
[Some] :: (Typeable a, Eq (f a)) => f a -> Any f
[Error] :: String -> Any f
data Step state
[:=] :: (Typeable a, Eq (Action state a), Show (Action state a)) => Var a -> Action state a -> Step state
infix 5 :=
type LookUp m = forall a. Typeable a => Var a -> Realized m a
newtype Var a
Var :: Int -> Var a
data Actions state
Actions_ :: [String] -> Smart [Step state] -> Actions state
pattern Actions :: [Step state] -> Actions state
data EnvEntry m
[:==] :: Typeable a => Var a -> Realized m a -> EnvEntry m
infix 5 :==
pattern (:=?) :: forall a m. Typeable a => Var a -> Realized m a -> EnvEntry m
type Env m = [EnvEntry m]
type family Realized (m :: Type -> Type) a :: Type
stateAfter :: StateModel state => Actions state -> state
runActions :: forall state m. (StateModel state, RunModel state m) => Actions state -> PropertyM m (state, Env m)
runActionsInState :: forall state m. (StateModel state, RunModel state m) => state -> Actions state -> PropertyM m (state, Env m)
lookUpVar :: Typeable a => Env m -> Var a -> Realized m a
lookUpVarMaybe :: forall a m. Typeable a => Env m -> Var a -> Maybe (Realized m a)
instance Data.Data.Data a => Data.Data.Data (Test.QuickCheck.StateModel.Var a)
instance GHC.Show.Show (Test.QuickCheck.StateModel.Var a)
instance GHC.Classes.Ord (Test.QuickCheck.StateModel.Var a)
instance GHC.Classes.Eq (Test.QuickCheck.StateModel.Var a)
instance (forall a. GHC.Show.Show (Test.QuickCheck.StateModel.Action state a)) => GHC.Show.Show (Test.QuickCheck.StateModel.Any (Test.QuickCheck.StateModel.Action state))
instance (forall a. GHC.Show.Show (Test.QuickCheck.StateModel.Action state a)) => GHC.Show.Show (Test.QuickCheck.StateModel.Step state)
instance GHC.Base.Semigroup (Test.QuickCheck.StateModel.Actions state)
instance GHC.Classes.Eq (Test.QuickCheck.StateModel.Actions state)
instance (forall a. GHC.Show.Show (Test.QuickCheck.StateModel.Action state a)) => GHC.Show.Show (Test.QuickCheck.StateModel.Actions state)
instance Test.QuickCheck.StateModel.StateModel state => Test.QuickCheck.Arbitrary.Arbitrary (Test.QuickCheck.StateModel.Actions state)
instance GHC.Classes.Eq (Test.QuickCheck.StateModel.Step state)
instance GHC.Classes.Eq (Test.QuickCheck.StateModel.Any f)
module Test.QuickCheck.DynamicLogic.Core
-- | Base Dynamic logic formulae language. Formulae are parameterised over
-- the type of state s to which they apply. A DynLogic
-- value cannot be constructed directly, one has to use the various
-- "smart constructors" provided, see the Building formulae
-- section.
data DynLogic s
type DynPred s = s -> DynLogic s
-- | A DynFormula may depend on the QuickCheck size parameter
data DynFormula s
-- | Restricted calls are not generated by AfterAny; they are
-- included in tests explicitly using After in order to check
-- specific properties at controlled times, so they are likely to fail if
-- invoked at other times.
class StateModel s => DynLogicModel s
restricted :: DynLogicModel s => Action s a -> Bool
data DynLogicTest s
BadPrecondition :: [TestStep s] -> [Any (Action s)] -> s -> DynLogicTest s
Looping :: [TestStep s] -> DynLogicTest s
Stuck :: [TestStep s] -> s -> DynLogicTest s
DLScript :: [TestStep s] -> DynLogicTest s
data TestStep s
Do :: Step s -> TestStep s
Witness :: a -> TestStep s
-- | False for DL formulae.
ignore :: DynFormula s
-- | True for DL formulae.
passTest :: DynFormula s
-- | Given f must be True given any state.
afterAny :: (s -> DynFormula s) -> DynFormula s
-- | Given f must be True after some action.
-- f is passed the state resulting from executing the
-- Action.
after :: (Typeable a, Eq (Action s a)) => Action s a -> (s -> DynFormula s) -> DynFormula s
-- | Disjunction for DL formulae. Is True if either formula is
-- True. The choice is angelic, ie. it is always made by
-- the "caller". This is mostly important in case a test is Stuck.
(|||) :: DynFormula s -> DynFormula s -> DynFormula s
-- | First-order quantification of variables. Formula f is
-- True iff. it is True for all possible values of
-- q. The underlying framework will generate values of
-- q and check the formula holds for those values.
-- Quantifiable values are thus values that can be generated and
-- checked and the Quantify module defines basic combinators to
-- build those from building blocks.
forAllQ :: Quantifiable q => q -> (Quantifies q -> DynFormula s) -> DynFormula s
-- | Adjust weight for selecting formula. This is mostly useful in relation
-- with (|||) combinator, in order to tweak the priority for
-- generating the next step(s) of the test that matches the formula.
weight :: Double -> DynFormula s -> DynFormula s
withSize :: (Int -> DynFormula s) -> DynFormula s
toStop :: DynFormula s -> DynFormula s
-- | Successfully ends the test.
done :: s -> DynFormula s
-- | Ends test with given error message.
errorDL :: String -> DynFormula s
-- | Embed QuickCheck's monitoring functions (eg. label,
-- tabulate) in a formula. This is useful to improve the reporting
-- from test execution, esp. in the case of failures.
monitorDL :: (Property -> Property) -> DynFormula s -> DynFormula s
-- | Formula should hold at any state. In effect this leads to exploring
-- alternatives from a given state s and ensuring formula holds
-- in all those states.
always :: (s -> DynFormula s) -> s -> DynFormula s
-- | Simplest "execution" function for DynFormula. Turns a given a
-- DynFormula paired with an interpreter function to produce some
-- result from an
forAllScripts :: (DynLogicModel s, Testable a) => DynFormula s -> (Actions s -> a) -> Property
forAllScripts_ :: (DynLogicModel s, Testable a) => DynFormula s -> (Actions s -> a) -> Property
withDLScript :: (DynLogicModel s, Testable a) => DynLogic s -> (Actions s -> a) -> DynLogicTest s -> Property
withDLScriptPrefix :: (DynLogicModel s, Testable a) => DynFormula s -> (Actions s -> a) -> DynLogicTest s -> Property
-- | Creates a Property from DynFormula with some specialised
-- isomorphism for shrinking purpose. ??
forAllMappedScripts :: (DynLogicModel s, Testable a, Show rep) => (rep -> DynLogicTest s) -> (DynLogicTest s -> rep) -> DynFormula s -> (Actions s -> a) -> Property
forAllMappedScripts_ :: (DynLogicModel s, Testable a, Show rep) => (rep -> DynLogicTest s) -> (DynLogicTest s -> rep) -> DynFormula s -> (Actions s -> a) -> Property
-- | Property function suitable for formulae without choice.
forAllUniqueScripts :: (DynLogicModel s, Testable a) => Int -> s -> DynFormula s -> (Actions s -> a) -> Property
propPruningGeneratedScriptIsNoop :: DynLogicModel s => DynLogic s -> Property
instance GHC.Show.Show Test.QuickCheck.DynamicLogic.Core.ChoiceType
instance GHC.Classes.Eq Test.QuickCheck.DynamicLogic.Core.ChoiceType
instance Test.QuickCheck.StateModel.StateModel s => GHC.Show.Show (Test.QuickCheck.DynamicLogic.Core.DynLogicTest s)
instance GHC.Classes.Eq (Test.QuickCheck.DynamicLogic.Core.TestStep s)
instance Test.QuickCheck.StateModel.StateModel s => GHC.Show.Show (Test.QuickCheck.DynamicLogic.Core.TestStep s)
-- | Monadic interface for writing Dynamic Logic properties.
--
-- This interface offers a much nicer experience than manipulating the
-- expressions it is implemented on top of, especially as it improves
-- readability. It's still possible to express properties as pure
-- expressions using the Core module and it might make sense
-- depending on the context and the kind of properties one wants to
-- express.
module Test.QuickCheck.DynamicLogic
-- | The DL monad provides a nicer interface to dynamic logic
-- formulae than the plain API. It's a continuation monad producing a
-- DynFormula formula, with a state component threaded through.
data DL s a
action :: (Typeable a, Eq (Action s a)) => Action s a -> DL s ()
anyAction :: DL s ()
anyActions :: Int -> DL s ()
anyActions_ :: DL s ()
stopping :: DL s ()
weight :: Double -> DL s ()
getSize :: DL s Int
getModelStateDL :: DL s s
-- | Fail if the boolean is False.
--
-- Equivalent to
--
-- -- assert msg b = unless b (fail msg) --assert :: String -> Bool -> DL s () assertModel :: String -> (s -> Bool) -> DL s () monitorDL :: (Property -> Property) -> DL s () -- | Generate a random value using the given Quantification (or -- list/tuple of quantifications). Generated values will only shrink to -- smaller values that could also have been generated. forAllQ :: Quantifiable q => q -> DL s (Quantifies q) forAllDL :: (DynLogicModel s, Testable a) => DL s () -> (Actions s -> a) -> Property forAllDL_ :: (DynLogicModel s, Testable a) => DL s () -> (Actions s -> a) -> Property forAllMappedDL :: (DynLogicModel s, Testable a, Show rep) => (rep -> DynLogicTest s) -> (DynLogicTest s -> rep) -> (Actions s -> srep) -> DL s () -> (srep -> a) -> Property forAllMappedDL_ :: (DynLogicModel s, Testable a, Show rep) => (rep -> DynLogicTest s) -> (DynLogicTest s -> rep) -> (Actions s -> srep) -> DL s () -> (srep -> a) -> Property forAllUniqueDL :: (DynLogicModel s, Testable a) => Int -> s -> DL s () -> (Actions s -> a) -> Property withDLTest :: (DynLogicModel s, Testable a) => DL s () -> (Actions s -> a) -> DynLogicTest s -> Property -- | Base Dynamic logic formulae language. Formulae are parameterised over -- the type of state s to which they apply. A DynLogic -- value cannot be constructed directly, one has to use the various -- "smart constructors" provided, see the Building formulae -- section. data DynLogic s -- | Restricted calls are not generated by AfterAny; they are -- included in tests explicitly using After in order to check -- specific properties at controlled times, so they are likely to fail if -- invoked at other times. class StateModel s => DynLogicModel s restricted :: DynLogicModel s => Action s a -> Bool data DynLogicTest s BadPrecondition :: [TestStep s] -> [Any (Action s)] -> s -> DynLogicTest s Looping :: [TestStep s] -> DynLogicTest s Stuck :: [TestStep s] -> s -> DynLogicTest s DLScript :: [TestStep s] -> DynLogicTest s data TestStep s Do :: Step s -> TestStep s Witness :: a -> TestStep s instance GHC.Base.Functor (Test.QuickCheck.DynamicLogic.DL s) instance GHC.Base.Applicative (Test.QuickCheck.DynamicLogic.DL s) instance GHC.Base.Alternative (Test.QuickCheck.DynamicLogic.DL s) instance GHC.Base.Monad (Test.QuickCheck.DynamicLogic.DL s) instance Control.Monad.Fail.MonadFail (Test.QuickCheck.DynamicLogic.DL s)