Safe Haskell | None |
---|---|
Language | Haskell2010 |
Synopsis
- showsPrec1 :: (Show1 f, Show a) => Int -> f a -> ShowS
- compare1 :: (Ord1 f, Ord a) => f a -> f a -> Ordering
- eq1 :: (Eq1 f, Eq a) => f a -> f a -> Bool
- class Eq1 (f :: Type -> Type)
- class Eq1 f => Ord1 (f :: Type -> Type)
- class Show1 (f :: Type -> Type)
- checkParallel :: MonadIO m => Group -> m Bool
- checkSequential :: MonadIO m => Group -> m Bool
- recheck :: MonadIO m => Size -> Seed -> Property -> m ()
- check :: MonadIO m => Property -> m Bool
- discoverPrefix :: String -> TExpQ Group
- discover :: TExpQ Group
- executeParallel :: (MonadTest m, MonadCatch m, MonadBaseControl IO m, HasCallStack) => (forall (v :: Type -> Type). state v) -> Parallel m state -> m ()
- executeSequential :: (MonadTest m, MonadCatch m, HasCallStack) => (forall (v :: Type -> Type). state v) -> Sequential m state -> m ()
- parallel :: forall gen (m :: Type -> Type) state. (MonadGen gen, MonadTest m) => Range Int -> Range Int -> (forall (v :: Type -> Type). state v) -> [Command gen m state] -> gen (Parallel m state)
- sequential :: forall gen (m :: Type -> Type) state. (MonadGen gen, MonadTest m) => Range Int -> (forall (v :: Type -> Type). state v) -> [Command gen m state] -> gen (Sequential m state)
- opaque :: Var (Opaque a) Concrete -> a
- concrete :: Var a Concrete -> a
- data Symbolic a
- newtype Concrete a where
- newtype Var a (v :: Type -> Type) = Var (v a)
- data Callback (input :: (Type -> Type) -> Type) output (state :: (Type -> Type) -> Type)
- data Command (gen :: Type -> Type) (m :: Type -> Type) (state :: (Type -> Type) -> Type) = (HTraversable input, Show (input Symbolic), Show output, Typeable output) => Command {
- commandGen :: state Symbolic -> Maybe (gen (input Symbolic))
- commandExecute :: input Concrete -> m output
- commandCallbacks :: [Callback input output state]
- data Action (m :: Type -> Type) (state :: (Type -> Type) -> Type)
- newtype Sequential (m :: Type -> Type) (state :: (Type -> Type) -> Type) = Sequential {
- sequentialActions :: [Action m state]
- data Parallel (m :: Type -> Type) (state :: (Type -> Type) -> Type) = Parallel {
- parallelPrefix :: [Action m state]
- parallelBranch1 :: [Action m state]
- parallelBranch2 :: [Action m state]
- tripping :: (MonadTest m, Applicative f, Show b, Show (f a), Eq (f a), HasCallStack) => a -> (a -> b) -> (b -> f a) -> m ()
- collect :: (MonadTest m, Show a, HasCallStack) => a -> m ()
- label :: (MonadTest m, HasCallStack) => LabelName -> m ()
- classify :: (MonadTest m, HasCallStack) => LabelName -> Bool -> m ()
- cover :: (MonadTest m, HasCallStack) => CoverPercentage -> LabelName -> Bool -> m ()
- property :: HasCallStack => PropertyT IO () -> Property
- withRetries :: ShrinkRetries -> Property -> Property
- withShrinks :: ShrinkLimit -> Property -> Property
- withDiscards :: DiscardLimit -> Property -> Property
- withTests :: TestLimit -> Property -> Property
- verifiedTermination :: Property -> Property
- withConfidence :: Confidence -> Property -> Property
- discard :: forall (m :: Type -> Type) a. Monad m => PropertyT m a
- forAll :: forall (m :: Type -> Type) a. (Monad m, Show a, HasCallStack) => Gen a -> PropertyT m a
- forAllWith :: forall (m :: Type -> Type) a. (Monad m, HasCallStack) => (a -> String) -> Gen a -> PropertyT m a
- evalMaybeM :: (MonadTest m, Show a, MonadCatch m, HasCallStack) => m (Maybe a) -> m a
- evalMaybe :: (MonadTest m, Show a, HasCallStack) => Maybe a -> m a
- evalExceptT :: (MonadTest m, Show x, HasCallStack) => ExceptT x m a -> m a
- evalEitherM :: (MonadTest m, Show x, MonadCatch m, HasCallStack) => m (Either x a) -> m a
- evalEither :: (MonadTest m, Show x, HasCallStack) => Either x a -> m a
- evalIO :: (MonadTest m, MonadIO m, HasCallStack) => IO a -> m a
- evalM :: (MonadTest m, MonadCatch m, HasCallStack) => m a -> m a
- evalNF :: (MonadTest m, NFData a, HasCallStack) => a -> m a
- eval :: (MonadTest m, HasCallStack) => a -> m a
- (/==) :: (MonadTest m, Eq a, Show a, HasCallStack) => a -> a -> m ()
- (===) :: (MonadTest m, Eq a, Show a, HasCallStack) => a -> a -> m ()
- diff :: (MonadTest m, Show a, Show b, HasCallStack) => a -> (a -> b -> Bool) -> b -> m ()
- assert :: (MonadTest m, HasCallStack) => Bool -> m ()
- success :: MonadTest m => m ()
- failure :: (MonadTest m, HasCallStack) => m a
- footnoteShow :: (MonadTest m, Show a) => a -> m ()
- footnote :: MonadTest m => String -> m ()
- annotateShow :: (MonadTest m, Show a, HasCallStack) => a -> m ()
- annotate :: (MonadTest m, HasCallStack) => String -> m ()
- data Property
- data PropertyT (m :: Type -> Type) a
- type Test = TestT Identity
- data TestT (m :: Type -> Type) a
- data PropertyName
- data Confidence
- data TestLimit
- data DiscardLimit
- data ShrinkLimit
- data ShrinkRetries
- data Group = Group {
- groupName :: !GroupName
- groupProperties :: ![(PropertyName, Property)]
- data GroupName
- data LabelName
- class Monad m => MonadTest (m :: Type -> Type) where
- printTreeWith :: (MonadIO m, Show a) => Size -> Seed -> Gen a -> m ()
- printTree :: (MonadIO m, Show a) => Gen a -> m ()
- printWith :: (MonadIO m, Show a) => Size -> Seed -> Gen a -> m ()
- sample :: MonadIO m => Gen a -> m a
- shuffle :: MonadGen m => [a] -> m [a]
- subsequence :: MonadGen m => [a] -> m [a]
- subterm3 :: MonadGen m => m a -> m a -> m a -> (a -> a -> a -> a) -> m a
- subtermM3 :: MonadGen m => m a -> m a -> m a -> (a -> a -> a -> m a) -> m a
- subterm2 :: MonadGen m => m a -> m a -> (a -> a -> a) -> m a
- subtermM2 :: MonadGen m => m a -> m a -> (a -> a -> m a) -> m a
- subterm :: MonadGen m => m a -> (a -> a) -> m a
- subtermM :: MonadGen m => m a -> (a -> m a) -> m a
- freeze :: MonadGen m => m a -> m (a, m a)
- map :: (MonadGen m, Ord k) => Range Int -> m (k, v) -> m (Map k v)
- set :: (MonadGen m, Ord a) => Range Int -> m a -> m (Set a)
- nonEmpty :: MonadGen m => Range Int -> m a -> m (NonEmpty a)
- seq :: MonadGen m => Range Int -> m a -> m (Seq a)
- list :: MonadGen m => Range Int -> m a -> m [a]
- either_ :: MonadGen m => m a -> m b -> m (Either a b)
- either :: MonadGen m => m a -> m b -> m (Either a b)
- maybe :: MonadGen m => m a -> m (Maybe a)
- justT :: MonadGen m => m (Maybe a) -> m a
- just :: (MonadGen m, GenBase m ~ Identity) => m (Maybe a) -> m a
- mapMaybeT :: MonadGen m => (a -> Maybe b) -> m a -> m b
- filterT :: MonadGen m => (a -> Bool) -> m a -> m a
- mapMaybe :: (MonadGen m, GenBase m ~ Identity) => (a -> Maybe b) -> m a -> m b
- filter :: (MonadGen m, GenBase m ~ Identity) => (a -> Bool) -> m a -> m a
- recursive :: MonadGen m => ([m a] -> m a) -> [m a] -> [m a] -> m a
- frequency :: MonadGen m => [(Int, m a)] -> m a
- choice :: MonadGen m => [m a] -> m a
- element :: MonadGen m => [a] -> m a
- constant :: MonadGen m => a -> m a
- bytes :: MonadGen m => Range Int -> m ByteString
- utf8 :: MonadGen m => Range Int -> m Char -> m ByteString
- text :: MonadGen m => Range Int -> m Char -> m Text
- string :: MonadGen m => Range Int -> m Char -> m String
- unicodeAll :: MonadGen m => m Char
- unicode :: MonadGen m => m Char
- latin1 :: MonadGen m => m Char
- ascii :: MonadGen m => m Char
- alphaNum :: MonadGen m => m Char
- alpha :: MonadGen m => m Char
- upper :: MonadGen m => m Char
- lower :: MonadGen m => m Char
- hexit :: MonadGen m => m Char
- digit :: MonadGen m => m Char
- octit :: MonadGen m => m Char
- binit :: MonadGen m => m Char
- bool_ :: MonadGen m => m Bool
- bool :: MonadGen m => m Bool
- enumBounded :: (MonadGen m, Enum a, Bounded a) => m a
- enum :: (MonadGen m, Enum a) => a -> a -> m a
- double :: MonadGen m => Range Double -> m Double
- float :: MonadGen m => Range Float -> m Float
- realFrac_ :: (MonadGen m, RealFrac a) => Range a -> m a
- realFloat :: (MonadGen m, RealFloat a) => Range a -> m a
- word64 :: MonadGen m => Range Word64 -> m Word64
- word32 :: MonadGen m => Range Word32 -> m Word32
- word16 :: MonadGen m => Range Word16 -> m Word16
- word8 :: MonadGen m => Range Word8 -> m Word8
- word :: MonadGen m => Range Word -> m Word
- int64 :: MonadGen m => Range Int64 -> m Int64
- int32 :: MonadGen m => Range Int32 -> m Int32
- int16 :: MonadGen m => Range Int16 -> m Int16
- int8 :: MonadGen m => Range Int8 -> m Int8
- int :: MonadGen m => Range Int -> m Int
- integral_ :: (MonadGen m, Integral a) => Range a -> m a
- integral :: (MonadGen m, Integral a) => Range a -> m a
- small :: MonadGen m => m a -> m a
- scale :: MonadGen m => (Size -> Size) -> m a -> m a
- resize :: MonadGen m => Size -> m a -> m a
- sized :: MonadGen m => (Size -> m a) -> m a
- prune :: MonadGen m => m a -> m a
- shrink :: MonadGen m => (a -> [a]) -> m a -> m a
- type Gen = GenT Identity
- data GenT (m :: Type -> Type) a
- type family GenBase (m :: Type -> Type) :: Type -> Type
- class (Monad m, Monad (GenBase m)) => MonadGen (m :: Type -> Type) where
- data Seed = Seed {}
- newtype Size = Size {}
- data Range a
- newtype Opaque a = Opaque {
- unOpaque :: a
- class HTraversable (t :: (Type -> Type) -> Type) where
- htraverse :: Applicative f => (forall a. g a -> f (h a)) -> t g -> f (t h)
- distributeT :: forall f (m :: Type -> Type) a. (MonadTransDistributive g, Transformer f g m) => g (f m) a -> f (g m) a
- withResource :: IO a -> (a -> IO ()) -> (IO a -> TestTree) -> TestTree
- askOption :: IsOption v => (v -> TestTree) -> TestTree
- localOption :: IsOption v => v -> TestTree -> TestTree
- adjustOption :: IsOption v => (v -> v) -> TestTree -> TestTree
- defaultMain :: TestTree -> IO ()
- defaultIngredients :: [Ingredient]
- defaultMainWithIngredients :: [Ingredient] -> TestTree -> IO ()
- includingOptions :: [OptionDescription] -> Ingredient
- singleTest :: IsTest t => TestName -> t -> TestTree
- foldTestTree :: Monoid b => TreeFold b -> OptionSet -> TestTree -> b
- trivialFold :: Monoid b => TreeFold b
- after :: DependencyType -> String -> TestTree -> TestTree
- after_ :: DependencyType -> Expr -> TestTree -> TestTree
- testGroup :: TestName -> [TestTree] -> TestTree
- type TestName = String
- data DependencyType
- data TestTree
- = IsTest t => SingleTest TestName t
- | TestGroup TestName [TestTree]
- | PlusTestOptions (OptionSet -> OptionSet) TestTree
- | WithResource (ResourceSpec a) (IO a -> TestTree)
- | AskOptions (OptionSet -> TestTree)
- | After DependencyType Expr TestTree
- foldSingle :: TreeFold b -> forall t. IsTest t => OptionSet -> TestName -> t -> b
- mkTimeout :: Integer -> Timeout
- data Timeout
- safeReadBool :: String -> Maybe Bool
- safeRead :: Read a => String -> Maybe a
- mkOptionCLParser :: IsOption v => Mod OptionFields v -> Parser v
- mkFlagCLParser :: IsOption v => Mod FlagFields v -> v -> Parser v
- flagCLParser :: IsOption v => Maybe Char -> v -> Parser v
- uniqueOptionDescriptions :: [OptionDescription] -> [OptionDescription]
- singleOption :: IsOption v => v -> OptionSet
- changeOption :: IsOption v => (v -> v) -> OptionSet -> OptionSet
- lookupOption :: IsOption v => OptionSet -> v
- setOption :: IsOption v => v -> OptionSet -> OptionSet
- class Typeable v => IsOption v where
- defaultValue :: v
- parseValue :: String -> Maybe v
- optionName :: Tagged v String
- optionHelp :: Tagged v String
- showDefaultValue :: v -> Maybe String
- optionCLParser :: Parser v
- data OptionSet
- data OptionDescription where
- Option :: forall v. IsOption v => Proxy v -> OptionDescription
- module Test.Tasty.HedgehogTest
- prop :: HasCallStack => TestName -> PropertyT IO () -> TestTree
- test :: HasCallStack => TestName -> PropertyT IO () -> TestTree
- minTestsOk :: Int -> TestTree -> TestTree
- noShrink :: TestTree -> TestTree
- withSeed :: String -> TestTree -> TestTree
- run :: Runnable t => t -> IO ()
- runOnly :: Runnable t => Text -> t -> IO ()
- gotException :: forall a. (HasCallStack, Show a) => a -> PropertyT IO ()
- printDifference :: (MonadIO m, Show a, Show b, HasCallStack) => a -> b -> m ()
- display :: (Show a, Monad m, HasCallStack) => a -> PropertyT m a
Documentation
compare1 :: (Ord1 f, Ord a) => f a -> f a -> Ordering #
Lift the standard compare
function through the type constructor.
Since: base-4.9.0.0
eq1 :: (Eq1 f, Eq a) => f a -> f a -> Bool #
Lift the standard (
function through the type constructor.==
)
Since: base-4.9.0.0
class Eq1 (f :: Type -> Type) #
Lifting of the Eq
class to unary type constructors.
Since: base-4.9.0.0
Instances
Eq1 [] | Since: base-4.9.0.0 |
Defined in Data.Functor.Classes | |
Eq1 Maybe | Since: base-4.9.0.0 |
Eq1 Identity | Since: base-4.9.0.0 |
Eq1 Down | Since: base-4.12.0.0 |
Eq1 NonEmpty | Since: base-4.10.0.0 |
Eq1 IntMap | Since: containers-0.5.9 |
Eq1 SCC | Since: containers-0.5.9 |
Eq1 Seq | Since: containers-0.5.9 |
Eq1 Set | Since: containers-0.5.9 |
Eq1 Hashed | |
Eq1 Symbolic | |
Eq1 Concrete | |
Eq1 HashSet | |
Eq a => Eq1 (Either a) | Since: base-4.9.0.0 |
Eq a => Eq1 ((,) a) | Since: base-4.9.0.0 |
Defined in Data.Functor.Classes | |
Eq1 (Proxy :: Type -> Type) | Since: base-4.9.0.0 |
Eq k => Eq1 (Map k) | Since: containers-0.5.9 |
Eq1 m => Eq1 (MaybeT m) | |
Eq1 m => Eq1 (ListT m) | |
Eq k => Eq1 (HashMap k) | |
Eq a => Eq1 (Const a :: Type -> Type) | Since: base-4.9.0.0 |
Eq2 p => Eq1 (Join p) | |
Eq1 f => Eq1 (IdentityT f) | |
(Eq e, Eq1 m) => Eq1 (ExceptT e m) | |
(Eq w, Eq1 m) => Eq1 (WriterT w m) | |
(Eq e, Eq1 m) => Eq1 (ErrorT e m) | |
(Eq w, Eq1 m) => Eq1 (WriterT w m) | |
Eq1 (Tagged s) | |
(Eq2 p, Eq a) => Eq1 (WrappedBifunctor p a) | |
Defined in Data.Bifunctor.Wrapped liftEq :: (a0 -> b -> Bool) -> WrappedBifunctor p a a0 -> WrappedBifunctor p a b -> Bool # | |
Eq1 g => Eq1 (Joker g a) | |
(Eq2 p, Eq a) => Eq1 (Flip p a) | |
(Eq1 f, Eq a) => Eq1 (Clown f a :: Type -> Type) | |
(Eq2 f, Eq2 g, Eq a) => Eq1 (Product f g a) | |
(Eq1 f, Eq2 p, Eq a) => Eq1 (Tannen f p a) | |
(Eq2 p, Eq1 f, Eq1 g, Eq a) => Eq1 (Biff p f g a) | |
class Eq1 f => Ord1 (f :: Type -> Type) #
Lifting of the Ord
class to unary type constructors.
Since: base-4.9.0.0
Instances
class Show1 (f :: Type -> Type) #
Lifting of the Show
class to unary type constructors.
Since: base-4.9.0.0
Instances
Show1 [] | Since: base-4.9.0.0 |
Defined in Data.Functor.Classes | |
Show1 Maybe | Since: base-4.9.0.0 |
Show1 Identity | Since: base-4.9.0.0 |
Show1 Down | Since: base-4.12.0.0 |
Show1 NonEmpty | Since: base-4.10.0.0 |
Show1 IntMap | Since: containers-0.5.9 |
Show1 SCC | Since: containers-0.5.9 |
Show1 Seq | Since: containers-0.5.9 |
Show1 Set | Since: containers-0.5.9 |
Show1 Hashed | |
Show1 Symbolic | |
Show1 Concrete | |
Show1 HashSet | |
Show a => Show1 (Either a) | Since: base-4.9.0.0 |
Show a => Show1 ((,) a) | Since: base-4.9.0.0 |
Defined in Data.Functor.Classes | |
Show1 (Proxy :: Type -> Type) | Since: base-4.9.0.0 |
Show k => Show1 (Map k) | Since: containers-0.5.9 |
Show1 m => Show1 (MaybeT m) | |
Show1 m => Show1 (TreeT m) | |
Show1 m => Show1 (NodeT m) | |
Show1 m => Show1 (ListT m) | |
Show k => Show1 (HashMap k) | |
Show a => Show1 (Const a :: Type -> Type) | Since: base-4.9.0.0 |
Show2 p => Show1 (Join p) | |
Show1 f => Show1 (IdentityT f) | |
(Show e, Show1 m) => Show1 (ExceptT e m) | |
(Show w, Show1 m) => Show1 (WriterT w m) | |
(Show e, Show1 m) => Show1 (ErrorT e m) | |
(Show w, Show1 m) => Show1 (WriterT w m) | |
Show1 (Tagged s) | |
(Show2 p, Show a) => Show1 (WrappedBifunctor p a) | |
Defined in Data.Bifunctor.Wrapped liftShowsPrec :: (Int -> a0 -> ShowS) -> ([a0] -> ShowS) -> Int -> WrappedBifunctor p a a0 -> ShowS # liftShowList :: (Int -> a0 -> ShowS) -> ([a0] -> ShowS) -> [WrappedBifunctor p a a0] -> ShowS # | |
Show1 g => Show1 (Joker g a) | |
(Show2 p, Show a) => Show1 (Flip p a) | |
(Show1 f, Show a) => Show1 (Clown f a :: Type -> Type) | |
(Show2 f, Show2 g, Show a) => Show1 (Product f g a) | |
(Show1 f, Show2 p, Show a) => Show1 (Tannen f p a) | |
(Show2 p, Show1 f, Show1 g, Show a) => Show1 (Biff p f g a) | |
checkParallel :: MonadIO m => Group -> m Bool #
Check a group of properties in parallel.
Warning: although this check function runs tests faster than
checkSequential
, it should be noted that it may cause problems with
properties that are not self-contained. For example, if you have a group
of tests which all use the same database table, you may find that they
interfere with each other when being run in parallel.
Using Template Haskell for property discovery:
tests :: IO Bool tests = checkParallel $$(discover)
With manually specified properties:
tests :: IO Bool tests = checkParallel $ Group "Test.Example" [ ("prop_reverse", prop_reverse) ]
checkSequential :: MonadIO m => Group -> m Bool #
Check a group of properties sequentially.
Using Template Haskell for property discovery:
tests :: IO Bool tests = checkSequential $$(discover)
With manually specified properties:
tests :: IO Bool tests = checkSequential $ Group "Test.Example" [ ("prop_reverse", prop_reverse) ]
recheck :: MonadIO m => Size -> Seed -> Property -> m () #
Check a property using a specific size and seed.
discoverPrefix :: String -> TExpQ Group #
Discover all the properties in a module.
Functions starting with prop_
are assumed to be properties.
executeParallel :: (MonadTest m, MonadCatch m, MonadBaseControl IO m, HasCallStack) => (forall (v :: Type -> Type). state v) -> Parallel m state -> m () #
Executes the prefix actions sequentially, then executes the two branches in parallel, verifying that no exceptions are thrown and that there is at least one sequential interleaving where all the post-conditions are met.
To generate parallel actions to execute, see the parallel
combinator in the Hedgehog.Gen module.
executeSequential :: (MonadTest m, MonadCatch m, HasCallStack) => (forall (v :: Type -> Type). state v) -> Sequential m state -> m () #
Executes a list of actions sequentially, verifying that all post-conditions are met and no exceptions are thrown.
To generate a sequence of actions to execute, see the
sequential
combinator in the Hedgehog.Gen module.
parallel :: forall gen (m :: Type -> Type) state. (MonadGen gen, MonadTest m) => Range Int -> Range Int -> (forall (v :: Type -> Type). state v) -> [Command gen m state] -> gen (Parallel m state) #
Given the initial model state and set of commands, generates prefix actions to be run sequentially, followed by two branches to be run in parallel.
sequential :: forall gen (m :: Type -> Type) state. (MonadGen gen, MonadTest m) => Range Int -> (forall (v :: Type -> Type). state v) -> [Command gen m state] -> gen (Sequential m state) #
Generates a sequence of actions from an initial model state and set of commands.
Symbolic values: Because hedgehog generates actions in a separate phase before execution, you will sometimes need to refer to the result of a previous action in a generator without knowing the value of the result (e.g., to get the ID of a previously-created user).
Symbolic variables provide a token to stand in for the actual variables at
generation time (and in Require
/Update
callbacks). At execution time,
real values are available, so your execute actions work on Concrete
variables.
Instances
Eq1 Symbolic | |
Ord1 Symbolic | |
Defined in Hedgehog.Internal.State | |
Show1 Symbolic | |
Eq (Symbolic a) | |
Ord (Symbolic a) | |
Show (Symbolic a) | |
Concrete values: At test-execution time, Symbolic
values from generation
are replaced with Concrete
values from performing actions. This type
gives us something of the same kind as Symbolic
to pass as a type
argument to Var
.
Instances
Functor Concrete | |
Foldable Concrete | |
Defined in Hedgehog.Internal.State fold :: Monoid m => Concrete m -> m # foldMap :: Monoid m => (a -> m) -> Concrete a -> m # foldMap' :: Monoid m => (a -> m) -> Concrete a -> m # foldr :: (a -> b -> b) -> b -> Concrete a -> b # foldr' :: (a -> b -> b) -> b -> Concrete a -> b # foldl :: (b -> a -> b) -> b -> Concrete a -> b # foldl' :: (b -> a -> b) -> b -> Concrete a -> b # foldr1 :: (a -> a -> a) -> Concrete a -> a # foldl1 :: (a -> a -> a) -> Concrete a -> a # elem :: Eq a => a -> Concrete a -> Bool # maximum :: Ord a => Concrete a -> a # minimum :: Ord a => Concrete a -> a # | |
Traversable Concrete | |
Eq1 Concrete | |
Ord1 Concrete | |
Defined in Hedgehog.Internal.State | |
Show1 Concrete | |
Eq a => Eq (Concrete a) | |
Ord a => Ord (Concrete a) | |
Show a => Show (Concrete a) | |
newtype Var a (v :: Type -> Type) #
Variables are the potential or actual result of executing an action. They
are parameterised by either Symbolic
or Concrete
depending on the
phase of the test.
Symbolic
variables are the potential results of actions. These are used
when generating the sequence of actions to execute. They allow actions
which occur later in the sequence to make use of the result of an action
which came earlier in the sequence.
Concrete
variables are the actual results of actions. These are used
during test execution. They provide access to the actual runtime value of
a variable.
The state update Callback
for a command needs to be polymorphic in the
type of variable because it is used in both the generation and the
execution phase.
The order of arguments makes Var
HTraverable
, which is how Symbolic
values are turned into Concrete
ones.
Var (v a) |
data Callback (input :: (Type -> Type) -> Type) output (state :: (Type -> Type) -> Type) #
Optional command configuration.
Require (state Symbolic -> input Symbolic -> Bool) | A pre-condition for a command that must be verified before the command can be executed. This is mainly used during shrinking to ensure that it is still OK to run a command despite the fact that some previously executed commands may have been removed from the sequence. |
Update (forall (v :: Type -> Type). Ord1 v => state v -> input v -> Var output v -> state v) | Updates the model state, given the input and output of the command. Note
that this function is polymorphic in the type of values. This is because
it must work over |
Ensure (state Concrete -> state Concrete -> input Concrete -> output -> Test ()) | A post-condition for a command that must be verified for the command to be considered a success. This callback receives the state prior to execution as the first argument, and the state after execution as the second argument. |
data Command (gen :: Type -> Type) (m :: Type -> Type) (state :: (Type -> Type) -> Type) #
The specification for the expected behaviour of an
Action
. These are used to generate sequences of actions to test.
This is the main type you will use when writing state machine
tests. gen
is usually an instance of MonadGen
, and m
is usually
an instance of MonadTest
. These constraints appear when you pass
your Command
list to sequential
or parallel
.
(HTraversable input, Show (input Symbolic), Show output, Typeable output) => Command | |
|
data Action (m :: Type -> Type) (state :: (Type -> Type) -> Type) #
An instantiation of a Command
which can be executed, and its effect
evaluated.
newtype Sequential (m :: Type -> Type) (state :: (Type -> Type) -> Type) #
A sequence of actions to execute.
Sequential | |
|
Instances
Show (Sequential m state) | |
Defined in Hedgehog.Internal.State showsPrec :: Int -> Sequential m state -> ShowS # show :: Sequential m state -> String # showList :: [Sequential m state] -> ShowS # |
data Parallel (m :: Type -> Type) (state :: (Type -> Type) -> Type) #
A sequential prefix of actions to execute, with two branches to execute in parallel.
Parallel | |
|
tripping :: (MonadTest m, Applicative f, Show b, Show (f a), Eq (f a), HasCallStack) => a -> (a -> b) -> (b -> f a) -> m () #
Test that a pair of encode / decode functions are compatible.
Given a printer from some type a -> b
, and a parser with a
potential failure case b -> f a
. Ensure that a valid a
round
trips through the "print" and "parse" to yield the same a
.
For example, types should have tripping Read
and Show
instances:
trippingShowRead :: (Show a, Read a, Eq a, MonadTest m) => a -> m () trippingShowRead a = tripping a show readEither
collect :: (MonadTest m, Show a, HasCallStack) => a -> m () #
label :: (MonadTest m, HasCallStack) => LabelName -> m () #
Add a label for each test run. It produces a table showing the percentage of test runs that produced each label.
classify :: (MonadTest m, HasCallStack) => LabelName -> Bool -> m () #
Records the proportion of tests which satisfy a given condition.
prop_with_classifier :: Property prop_with_classifier = property $ do xs <- forAll $ Gen.list (Range.linear 0 100) Gen.alpha for_ xs $ \x -> do classify "newborns" $ x == 0 classify "children" $ x > 0 && x < 13 classify "teens" $ x > 12 && x < 20
cover :: (MonadTest m, HasCallStack) => CoverPercentage -> LabelName -> Bool -> m () #
Require a certain percentage of the tests to be covered by the classifier.
prop_with_coverage :: Property prop_with_coverage = property $ do match <- forAll Gen.bool cover 30 True $ match cover 30 False $ not match
The example above requires a minimum of 30% coverage for both classifiers. If these requirements are not met, it will fail the test.
property :: HasCallStack => PropertyT IO () -> Property #
Creates a property with the default configuration.
withRetries :: ShrinkRetries -> Property -> Property #
Set the number of times a property will be executed for each shrink before
the test runner gives up and tries a different shrink. See ShrinkRetries
for more information.
withShrinks :: ShrinkLimit -> Property -> Property #
Set the number of times a property is allowed to shrink before the test runner gives up and prints the counterexample.
withDiscards :: DiscardLimit -> Property -> Property #
Set the number of times a property is allowed to discard before the test runner gives up.
withTests :: TestLimit -> Property -> Property #
Set the number of times a property should be executed before it is considered successful.
If you have a test that does not involve any generators and thus does not
need to run repeatedly, you can use withTests 1
to define a property that
will only be checked once.
verifiedTermination :: Property -> Property #
withConfidence :: Confidence -> Property -> Property #
Make sure that the result is statistically significant in accordance to
the passed Confidence
discard :: forall (m :: Type -> Type) a. Monad m => PropertyT m a #
Discards the current test entirely.
forAll :: forall (m :: Type -> Type) a. (Monad m, Show a, HasCallStack) => Gen a -> PropertyT m a #
Generates a random input for the test by running the provided generator.
forAllWith :: forall (m :: Type -> Type) a. (Monad m, HasCallStack) => (a -> String) -> Gen a -> PropertyT m a #
evalMaybeM :: (MonadTest m, Show a, MonadCatch m, HasCallStack) => m (Maybe a) -> m a #
evalExceptT :: (MonadTest m, Show x, HasCallStack) => ExceptT x m a -> m a #
evalEitherM :: (MonadTest m, Show x, MonadCatch m, HasCallStack) => m (Either x a) -> m a #
evalEither :: (MonadTest m, Show x, HasCallStack) => Either x a -> m a #
evalM :: (MonadTest m, MonadCatch m, HasCallStack) => m a -> m a #
Fails the test if the action throws an exception.
The benefit of using this over simply letting the exception bubble up is
that the location of the closest evalM
will be shown in the output.
evalNF :: (MonadTest m, NFData a, HasCallStack) => a -> m a #
Fails the test if the value throws an exception when evaluated to normal form (NF).
eval :: (MonadTest m, HasCallStack) => a -> m a #
Fails the test if the value throws an exception when evaluated to weak head normal form (WHNF).
(/==) :: (MonadTest m, Eq a, Show a, HasCallStack) => a -> a -> m () infix 4 #
Fails the test if the two arguments provided are equal.
(===) :: (MonadTest m, Eq a, Show a, HasCallStack) => a -> a -> m () infix 4 #
Fails the test if the two arguments provided are not equal.
diff :: (MonadTest m, Show a, Show b, HasCallStack) => a -> (a -> b -> Bool) -> b -> m () #
Fails the test and shows a git-like diff if the comparison operation
evaluates to False
when applied to its arguments.
The comparison function is the second argument, which may be counter-intuitive to Haskell programmers. However, it allows operators to be written infix for easy reading:
diff y (<) 87
diff x (<=) r
This function behaves like the unix diff
tool, which gives a 0 exit
code if the compared files are identical, or a 1 exit code code
otherwise. Like unix diff
, if the arguments fail the comparison, a
/diff is shown.
assert :: (MonadTest m, HasCallStack) => Bool -> m () #
Fails the test if the condition provided is False
.
failure :: (MonadTest m, HasCallStack) => m a #
Causes a test to fail.
footnoteShow :: (MonadTest m, Show a) => a -> m () #
Logs a value to be displayed as additional information in the footer of the failure report.
footnote :: MonadTest m => String -> m () #
Logs a message to be displayed as additional information in the footer of the failure report.
annotateShow :: (MonadTest m, Show a, HasCallStack) => a -> m () #
Annotates the source code with a value that might be useful for debugging a test failure.
annotate :: (MonadTest m, HasCallStack) => String -> m () #
Annotates the source code with a message that might be useful for debugging a test failure.
A property test, along with some configurable limits like how many times to run the test.
data PropertyT (m :: Type -> Type) a #
The property monad transformer allows both the generation of test inputs and the assertion of expectations.
Instances
data TestT (m :: Type -> Type) a #
A test monad transformer allows the assertion of expectations.
Instances
data PropertyName #
The name of a property.
Should be constructed using OverloadedStrings
:
"apples" :: PropertyName
Instances
data Confidence #
The acceptable occurrence of false positives
Example, Confidence 10^9
would mean that you'd accept a false positive
for 1 in 10^9 tests.
Instances
The number of successful tests that need to be run before a property test is considered successful.
Can be constructed using numeric literals:
200 :: TestLimit
Instances
Enum TestLimit | |
Defined in Hedgehog.Internal.Property succ :: TestLimit -> TestLimit # pred :: TestLimit -> TestLimit # fromEnum :: TestLimit -> Int # enumFrom :: TestLimit -> [TestLimit] # enumFromThen :: TestLimit -> TestLimit -> [TestLimit] # enumFromTo :: TestLimit -> TestLimit -> [TestLimit] # enumFromThenTo :: TestLimit -> TestLimit -> TestLimit -> [TestLimit] # | |
Eq TestLimit | |
Integral TestLimit | |
Defined in Hedgehog.Internal.Property | |
Num TestLimit | |
Defined in Hedgehog.Internal.Property | |
Ord TestLimit | |
Defined in Hedgehog.Internal.Property | |
Real TestLimit | |
Defined in Hedgehog.Internal.Property toRational :: TestLimit -> Rational # | |
Show TestLimit | |
Lift TestLimit | |
data DiscardLimit #
The number of discards to allow before giving up.
Can be constructed using numeric literals:
10000 :: DiscardLimit
Instances
data ShrinkLimit #
The number of shrinks to try before giving up on shrinking.
Can be constructed using numeric literals:
1000 :: ShrinkLimit
Instances
data ShrinkRetries #
The number of times to re-run a test during shrinking. This is useful if you are testing something which fails non-deterministically and you want to increase the change of getting a good shrink.
If you are doing parallel state machine testing, you should probably set
shrink retries to something like 10
. This will mean that during
shrinking, a parallel test case requires 10 successful runs before it is
passes and we try a different shrink.
Can be constructed using numeric literals:
0 :: ShrinkRetries
Instances
A named collection of property tests.
Group | |
|
The name of a group of properties.
Should be constructed using OverloadedStrings
:
"fruit" :: GroupName
The name of a classifier.
Should be constructed using OverloadedStrings
:
"apples" :: LabelName
class Monad m => MonadTest (m :: Type -> Type) where #
Instances
printTreeWith :: (MonadIO m, Show a) => Size -> Seed -> Gen a -> m () #
Print the shrink tree produced by a generator, for the given size and seed.
Use printTree
to generate a value from a random seed.
printTree :: (MonadIO m, Show a) => Gen a -> m () #
Run a generator with a random seed and print the resulting shrink tree.
Gen.printTree (Gen.enum
'a' 'f')
'd' ├╼'a' ├╼'b' │ └╼'a' └╼'c' ├╼'a' └╼'b' └╼'a'
This may not terminate when the tree is very large.
printWith :: (MonadIO m, Show a) => Size -> Seed -> Gen a -> m () #
Print the value produced by a generator, and the first level of shrinks, for the given size and seed.
Use print
to generate a value from a random seed.
shuffle :: MonadGen m => [a] -> m [a] #
Generates a random permutation of a list.
This shrinks towards the order of the list being identical to the input list.
subsequence :: MonadGen m => [a] -> m [a] #
Generates a random subsequence of a list.
subterm3 :: MonadGen m => m a -> m a -> m a -> (a -> a -> a -> a) -> m a #
Constructs a generator from three sub-term generators.
Shrinks to one of the sub-terms if possible.
subtermM3 :: MonadGen m => m a -> m a -> m a -> (a -> a -> a -> m a) -> m a #
Constructs a generator from three sub-term generators.
Shrinks to one of the sub-terms if possible.
subterm2 :: MonadGen m => m a -> m a -> (a -> a -> a) -> m a #
Constructs a generator from two sub-term generators.
Shrinks to one of the sub-terms if possible.
subtermM2 :: MonadGen m => m a -> m a -> (a -> a -> m a) -> m a #
Constructs a generator from two sub-term generators.
Shrinks to one of the sub-terms if possible.
subterm :: MonadGen m => m a -> (a -> a) -> m a #
Constructs a generator from a sub-term generator.
Shrinks to the sub-term if possible.
subtermM :: MonadGen m => m a -> (a -> m a) -> m a #
Constructs a generator from a sub-term generator.
Shrinks to the sub-term if possible.
freeze :: MonadGen m => m a -> m (a, m a) #
Freeze the size and seed used by a generator, so we can inspect the value which it will produce.
This is used for implementing list
and subtermMVec
. It allows us to
shrink the list itself before trying to shrink the values inside the list.
map :: (MonadGen m, Ord k) => Range Int -> m (k, v) -> m (Map k v) #
Generates a map using a Range
to determine the length.
This may fail to generate anything if the keys produced by the generator do not account for a large enough number of unique items to satify the required map size.
set :: (MonadGen m, Ord a) => Range Int -> m a -> m (Set a) #
Generates a set using a Range
to determine the length.
This may fail to generate anything if the element generator cannot produce a large enough number of unique items to satify the required set size.
nonEmpty :: MonadGen m => Range Int -> m a -> m (NonEmpty a) #
Generates a non-empty list using a Range
to determine the length.
seq :: MonadGen m => Range Int -> m a -> m (Seq a) #
Generates a seq using a Range
to determine the length.
list :: MonadGen m => Range Int -> m a -> m [a] #
Generates a list using a Range
to determine the length.
either_ :: MonadGen m => m a -> m b -> m (Either a b) #
Generates either an a
or a b
, without bias.
This generator generates as many Right
s as it does Left
s.
either :: MonadGen m => m a -> m b -> m (Either a b) #
Generates either an a
or a b
.
As the size grows, this generator generates Right
s more often than Left
s.
filter :: (MonadGen m, GenBase m ~ Identity) => (a -> Bool) -> m a -> m a #
Generates a value that satisfies a predicate.
This is essentially:
filter p gen =mfilter
p gen<|>
filter p gen
It differs from the above in that we keep some state to avoid looping forever. If we trigger these limits then the whole generator is discarded.
recursive :: MonadGen m => ([m a] -> m a) -> [m a] -> [m a] -> m a #
Modifies combinators which choose from a list of generators, like choice
or frequency
, so that they can be used in recursive scenarios.
This combinator modifies its target to select one of the generators in
either the non-recursive or the recursive list. When a selection is made
from the recursive list, the Size
is halved. When the Size
gets to one
or less, selections are no longer made from the recursive list, this
ensures termination.
A good example of where this might be useful is abstract syntax trees:
data Expr = Var String | Lam String Expr | App Expr Expr -- Assuming we have a name generator genName ::MonadGen
m => m String -- We can write a generator for expressions genExpr ::MonadGen
m => m Expr genExpr = Gen.recursive
Gen.choice
[ -- non-recursive generators Var<$>
genName ] [ -- recursive generators Gen.subtermM
genExpr (x -> Lam<$>
genName<*>
pure x) , Gen.subterm2
genExpr genExpr App ]
If we wrote the above example using only choice
, it is likely that it
would fail to terminate. This is because for every call to genExpr
,
there is a 2 in 3 chance that we will recurse again.
frequency :: MonadGen m => [(Int, m a)] -> m a #
Uses a weighted distribution to randomly select one of the generators in the list.
This generator shrinks towards the first generator in the list.
The input list must be non-empty.
choice :: MonadGen m => [m a] -> m a #
Randomly selects one of the generators in the list.
This generator shrinks towards the first generator in the list.
The input list must be non-empty.
element :: MonadGen m => [a] -> m a #
Randomly selects one of the elements in the list.
This generator shrinks towards the first element in the list.
The input list must be non-empty.
bytes :: MonadGen m => Range Int -> m ByteString #
Generates a random ByteString
, using Range
to determine the
length.
utf8 :: MonadGen m => Range Int -> m Char -> m ByteString #
Generates a UTF-8 encoded string, using Range
to determine the length.
text :: MonadGen m => Range Int -> m Char -> m Text #
Generates a string using Range
to determine the length.
unicodeAll :: MonadGen m => m Char #
Generates a Unicode character, including noncharacters and invalid standalone surrogates:
'0'..'1114111'
unicode :: MonadGen m => m Char #
Generates a Unicode character, excluding noncharacters and invalid standalone surrogates:
'0'..'1114111' (excluding '55296'..'57343', '65534', '65535')
bool :: MonadGen m => m Bool #
Generates a random boolean.
This generator shrinks to False
.
This is a specialization of enumBounded
, offered for convenience.
enumBounded :: (MonadGen m, Enum a, Bounded a) => m a #
double :: MonadGen m => Range Double -> m Double #
Generates a random floating-point number in the [inclusive,exclusive)
range.
This is a specialization of realFloat
, offered for convenience.
float :: MonadGen m => Range Float -> m Float #
Generates a random floating-point number in the [inclusive,exclusive)
range.
This is a specialization of realFloat
, offered for convenience.
realFrac_ :: (MonadGen m, RealFrac a) => Range a -> m a #
Generates a random fractional number in the [inclusive,exclusive) range.
This generator does not shrink.
realFloat :: (MonadGen m, RealFloat a) => Range a -> m a #
Generates a random floating-point number in the [inclusive,exclusive)
range.
This generator works the same as integral
, but for floating point numbers.
word64 :: MonadGen m => Range Word64 -> m Word64 #
Generates a random 64-bit word in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
word32 :: MonadGen m => Range Word32 -> m Word32 #
Generates a random 32-bit word in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
word16 :: MonadGen m => Range Word16 -> m Word16 #
Generates a random 16-bit word in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
word8 :: MonadGen m => Range Word8 -> m Word8 #
Generates a random byte in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
word :: MonadGen m => Range Word -> m Word #
Generates a random machine word in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
int64 :: MonadGen m => Range Int64 -> m Int64 #
Generates a random 64-bit integer in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
int32 :: MonadGen m => Range Int32 -> m Int32 #
Generates a random 32-bit integer in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
int16 :: MonadGen m => Range Int16 -> m Int16 #
Generates a random 16-bit integer in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
int8 :: MonadGen m => Range Int8 -> m Int8 #
Generates a random 8-bit integer in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
int :: MonadGen m => Range Int -> m Int #
Generates a random machine integer in the given [inclusive,inclusive]
range.
This is a specialization of integral
, offered for convenience.
integral_ :: (MonadGen m, Integral a) => Range a -> m a #
Generates a random integral number in the [inclusive,inclusive] range.
This generator does not shrink.
integral :: (MonadGen m, Integral a) => Range a -> m a #
Generates a random integral number in the given [inclusive,inclusive]
range.
When the generator tries to shrink, it will shrink towards the
origin
of the specified Range
.
For example, the following generator will produce a number between 1970
and 2100
, but will shrink towards 2000
:
integral (Range.constantFrom
2000 1970 2100) ::Gen
Int
Some sample outputs from this generator might look like:
=== Outcome === 1973 === Shrinks === 2000 1987 1980 1976 1974
=== Outcome === 2061 === Shrinks === 2000 2031 2046 2054 2058 2060
scale :: MonadGen m => (Size -> Size) -> m a -> m a #
Adjust the size parameter by transforming it with the given function.
resize :: MonadGen m => Size -> m a -> m a #
Override the size parameter. Returns a generator which uses the given size instead of the runtime-size parameter.
sized :: MonadGen m => (Size -> m a) -> m a #
Construct a generator that depends on the size parameter.
shrink :: MonadGen m => (a -> [a]) -> m a -> m a #
Apply a shrinking function to a generator.
This will give the generator additional shrinking options, while keeping the existing shrinks intact.
data GenT (m :: Type -> Type) a #
Monad transformer which can generate random values of a
.
Instances
type family GenBase (m :: Type -> Type) :: Type -> Type #
Instances
type GenBase (MaybeT m) | |
Defined in Hedgehog.Internal.Gen | |
type GenBase (GenT m) | |
Defined in Hedgehog.Internal.Gen | |
type GenBase (IdentityT m) | |
Defined in Hedgehog.Internal.Gen | |
type GenBase (ExceptT x m) | |
Defined in Hedgehog.Internal.Gen | |
type GenBase (StateT r m) | |
Defined in Hedgehog.Internal.Gen | |
type GenBase (ReaderT r m) | |
Defined in Hedgehog.Internal.Gen | |
type GenBase (WriterT w m) | |
Defined in Hedgehog.Internal.Gen | |
type GenBase (StateT r m) | |
Defined in Hedgehog.Internal.Gen | |
type GenBase (WriterT w m) | |
Defined in Hedgehog.Internal.Gen |
class (Monad m, Monad (GenBase m)) => MonadGen (m :: Type -> Type) where #
Class of monads which can generate input data for tests.
Instances
MonadGen m => MonadGen (MaybeT m) | |
Monad m => MonadGen (GenT m) | |
MonadGen m => MonadGen (IdentityT m) | |
MonadGen m => MonadGen (ExceptT x m) | |
MonadGen m => MonadGen (StateT r m) | |
MonadGen m => MonadGen (ReaderT r m) | |
(MonadGen m, Monoid w) => MonadGen (WriterT w m) | |
MonadGen m => MonadGen (StateT r m) | |
(MonadGen m, Monoid w) => MonadGen (WriterT w m) | |
A splittable random number generator.
Instances
Eq Seed | |
Ord Seed | |
Read Seed | |
Show Seed | |
RandomGen Seed | |
Defined in Hedgehog.Internal.Seed genWord8 :: Seed -> (Word8, Seed) # genWord16 :: Seed -> (Word16, Seed) # genWord32 :: Seed -> (Word32, Seed) # genWord64 :: Seed -> (Word64, Seed) # genWord32R :: Word32 -> Seed -> (Word32, Seed) # genWord64R :: Word64 -> Seed -> (Word64, Seed) # genShortByteString :: Int -> Seed -> (ShortByteString, Seed) # |
Tests are parameterized by the size of the randomly-generated data. The
meaning of a Size
value depends on the particular generator used, but
it must always be a number between 0 and 99 inclusive.
Opaque values.
Useful if you want to put something without a Show
instance inside
something which you'd like to be able to display.
For example:
data State v = State { stateRefs :: [Var (Opaque (IORef Int)) v] } deriving (Eq, Show)
class HTraversable (t :: (Type -> Type) -> Type) where #
Higher-order traversable functors.
This is used internally to make symbolic variables concrete given an Environment
.
htraverse :: Applicative f => (forall a. g a -> f (h a)) -> t g -> f (t h) #
Instances
HTraversable (Var a) | |
Defined in Hedgehog.Internal.State htraverse :: Applicative f => (forall a0. g a0 -> f (h a0)) -> Var a g -> f (Var a h) # |
distributeT :: forall f (m :: Type -> Type) a. (MonadTransDistributive g, Transformer f g m) => g (f m) a -> f (g m) a #
Distribute one monad transformer over another.
:: IO a | initialize the resource |
-> (a -> IO ()) | free the resource |
-> (IO a -> TestTree) |
|
-> TestTree |
Acquire the resource to run this test (sub)tree and release it afterwards
askOption :: IsOption v => (v -> TestTree) -> TestTree #
Customize the test tree based on the run-time options
localOption :: IsOption v => v -> TestTree -> TestTree #
Locally set the option value for the given test subtree
adjustOption :: IsOption v => (v -> v) -> TestTree -> TestTree #
Locally adjust the option value for the given test subtree
defaultMain :: TestTree -> IO () #
Parse the command line arguments and run the tests.
When the tests finish, this function calls exitWith
with the exit code
that indicates whether any tests have failed. Most external systems
(stack, cabal, travis-ci, jenkins etc.) rely on the exit code to detect
whether the tests pass. If you want to do something else after
defaultMain
returns, you need to catch the exception and then re-throw
it. Example:
import Test.Tasty import Test.Tasty.HUnit import System.Exit import Control.Exception test = testCase "Test 1" (2 @?= 3) main = defaultMain test `catch` (\e -> do if e == ExitSuccess then putStrLn "Yea" else putStrLn "Nay" throwIO e)
defaultIngredients :: [Ingredient] #
List of the default ingredients. This is what defaultMain
uses.
At the moment it consists of listingTests
and consoleTestReporter
.
defaultMainWithIngredients :: [Ingredient] -> TestTree -> IO () #
Parse the command line arguments and run the tests using the provided ingredient list.
When the tests finish, this function calls exitWith
with the exit code
that indicates whether any tests have failed. See defaultMain
for
details.
includingOptions :: [OptionDescription] -> Ingredient #
This ingredient doesn't do anything apart from registering additional options.
The option values can be accessed using askOption
.
:: Monoid b | |
=> TreeFold b | the algebra (i.e. how to fold a tree) |
-> OptionSet | initial options |
-> TestTree | the tree to fold |
-> b |
Fold a test tree into a single value.
The fold result type should be a monoid. This is used to fold multiple
results in a test group. In particular, empty groups get folded into mempty
.
Apart from pure convenience, this function also does the following useful things:
- Keeping track of the current options (which may change due to
PlusTestOptions
nodes) - Filtering out the tests which do not match the patterns
Thus, it is preferred to an explicit recursive traversal of the tree.
Note: right now, the patterns are looked up only once, and won't be affected by the subsequent option changes. This shouldn't be a problem in practice; OTOH, this behaviour may be changed later.
trivialFold :: Monoid b => TreeFold b #
trivialFold
can serve as the basis for custom folds. Just override
the fields you need.
Here's what it does:
- single tests are mapped to
mempty
(you probably do want to override that) - test groups are returned unmodified
- for a resource, an IO action that throws an exception is passed (you want to override this for runners/ingredients that execute tests)
:: DependencyType | whether to run the tests even if some of the dependencies fail |
-> String | the pattern |
-> TestTree | the subtree that depends on other tests |
-> TestTree | the subtree annotated with dependency information |
The after
combinator declares dependencies between tests.
If a TestTree
is wrapped in after
, the tests in this tree will not run
until certain other tests («dependencies») have finished. These
dependencies are specified using an AWK pattern (see the «Patterns» section
in the README).
Moreover, if the DependencyType
argument is set to AllSucceed
and
at least one dependency has failed, this test tree will not run at all.
Tasty does not check that the pattern matches any tests (let alone the correct set of tests), so it is on you to supply the right pattern.
Examples
The following test will be executed only after all tests that contain
Foo
anywhere in their path finish.
after
AllFinish
"Foo" $testCase
"A test that depends on Foo.Bar" $ ...
Note, however, that our test also happens to contain Foo
as part of its name,
so it also matches the pattern and becomes a dependency of itself. This
will result in a DependencyLoop
exception. To avoid this, either
change the test name so that it doesn't mention Foo
or make the
pattern more specific.
You can use AWK patterns, for instance, to specify the full path to the dependency.
after
AllFinish
"$0 == \"Tests.Foo.Bar\"" $testCase
"A test that depends on Foo.Bar" $ ...
Or only specify the dependency's own name, ignoring the group names:
after
AllFinish
"$NF == \"Bar\"" $testCase
"A test that depends on Foo.Bar" $ ...
Since: tasty-1.2
:: DependencyType | whether to run the tests even if some of the dependencies fail |
-> Expr | the pattern |
-> TestTree | the subtree that depends on other tests |
-> TestTree | the subtree annotated with dependency information |
Like after
, but accepts the pattern as a syntax tree instead
of a string. Useful for generating a test tree programmatically.
Examples
Only match on the test's own name, ignoring the group names:
after_
AllFinish
(EQ
(Field
NF
) (StringLit
"Bar")) $testCase
"A test that depends on Foo.Bar" $ ...
Since: tasty-1.2
data DependencyType #
These are the two ways in which one test may depend on the others.
This is the same distinction as the hard vs soft dependencies in TestNG.
Since: tasty-1.2
AllSucceed | The current test tree will be executed after its dependencies finish, and only if all of the dependencies succeed. |
AllFinish | The current test tree will be executed after its dependencies finish, regardless of whether they succeed or not. |
Instances
Eq DependencyType | |
Defined in Test.Tasty.Core (==) :: DependencyType -> DependencyType -> Bool # (/=) :: DependencyType -> DependencyType -> Bool # | |
Show DependencyType | |
Defined in Test.Tasty.Core showsPrec :: Int -> DependencyType -> ShowS # show :: DependencyType -> String # showList :: [DependencyType] -> ShowS # |
The main data structure defining a test suite.
It consists of individual test cases and properties, organized in named groups which form a tree-like hierarchy.
There is no generic way to create a test case. Instead, every test
provider (tasty-hunit, tasty-smallcheck etc.) provides a function to
turn a test case into a TestTree
.
Groups can be created using testGroup
.
IsTest t => SingleTest TestName t | A single test of some particular type |
TestGroup TestName [TestTree] | Assemble a number of tests into a cohesive group |
PlusTestOptions (OptionSet -> OptionSet) TestTree | Add some options to child tests |
WithResource (ResourceSpec a) (IO a -> TestTree) | Acquire the resource before the tests in the inner tree start and
release it after they finish. The tree gets an |
AskOptions (OptionSet -> TestTree) | Ask for the options and customize the tests based on them |
After DependencyType Expr TestTree | Only run after all tests that match a given pattern finish
(and, depending on the |
Timeout to be applied to individual tests
Timeout Integer String |
|
NoTimeout |
Instances
Show Timeout | |
IsOption Timeout | |
Defined in Test.Tasty.Options.Core defaultValue :: Timeout # parseValue :: String -> Maybe Timeout # optionName :: Tagged Timeout String # optionHelp :: Tagged Timeout String # showDefaultValue :: Timeout -> Maybe String # |
safeRead :: Read a => String -> Maybe a #
Safe read function. Defined here for convenience to use for
parseValue
.
mkOptionCLParser :: IsOption v => Mod OptionFields v -> Parser v #
Command-line option parser that takes additional option modifiers.
:: IsOption v | |
=> Mod FlagFields v | option modifier |
-> v | non-default value (when the flag is supplied) |
-> Parser v |
Command-line flag parser that takes additional option modifiers.
:: IsOption v | |
=> Maybe Char | optional short flag |
-> v | non-default value (when the flag is supplied) |
-> Parser v |
Command-line parser to use with flags
uniqueOptionDescriptions :: [OptionDescription] -> [OptionDescription] #
Remove duplicated OptionDescription
, preserving existing order otherwise
Since: tasty-1.4.1
singleOption :: IsOption v => v -> OptionSet #
Create a singleton OptionSet
changeOption :: IsOption v => (v -> v) -> OptionSet -> OptionSet #
Change the option value
lookupOption :: IsOption v => OptionSet -> v #
Query the option value
class Typeable v => IsOption v where #
An option is a data type that inhabits the IsOption
type class.
defaultValue :: v #
The value to use if the option was not supplied explicitly
parseValue :: String -> Maybe v #
Try to parse an option value from a string. Consider using
safeReadBool
for boolean options and safeRead
for numeric options.
optionName :: Tagged v String #
The option name. It is used to form the command line option name, for instance. Therefore, it had better not contain spaces or other fancy characters. It is recommended to use dashes instead of spaces.
optionHelp :: Tagged v String #
The option description or help string. This can be an arbitrary string.
showDefaultValue :: v -> Maybe String #
How a defaultValue
should be displayed in the help string. Nothing
(the default implementation) will result in nothing being displayed, while
will result in Just
defdef
being advertised as the default in the
help string.
optionCLParser :: Parser v #
A command-line option parser.
It has a default implementation in terms of the other methods.
You may want to override it in some cases (e.g. add a short flag) and
flagCLParser
, mkFlagCLParser
and mkOptionCLParser
might come in
handy.
Even if you override this, you still should implement all the methods above, to allow alternative interfaces.
Do not supply a default value (e.g., with the value
function) here
for this parser! This is because if no value was provided on the command
line we may lookup the option e.g. in the environment. But if the parser
always succeeds, we have no way to tell whether the user really provided
the option on the command line.
Similarly, do not use showDefaultWith
here, as it will be ignored. Use
the showDefaultValue
method of IsOption
instead.
Instances
IsOption NumThreads | |
Defined in Test.Tasty.Options.Core | |
IsOption Timeout | |
Defined in Test.Tasty.Options.Core defaultValue :: Timeout # parseValue :: String -> Maybe Timeout # optionName :: Tagged Timeout String # optionHelp :: Tagged Timeout String # showDefaultValue :: Timeout -> Maybe String # | |
IsOption ModuleName Source # | This option is not used on the command line, it is just used to annotate test groups |
Defined in Test.Tasty.HedgehogTest | |
IsOption HedgehogShrinkRetries Source # | |
IsOption HedgehogShrinkLimit Source # | |
Defined in Test.Tasty.HedgehogTest | |
IsOption HedgehogDiscardLimit Source # | |
Defined in Test.Tasty.HedgehogTest | |
IsOption HedgehogTestLimit Source # | |
Defined in Test.Tasty.HedgehogTest | |
IsOption HedgehogShowReplay Source # | |
Defined in Test.Tasty.HedgehogTest | |
IsOption HedgehogReplay Source # | |
A set of options. Only one option of each type can be kept.
If some option has not been explicitly set, the default value is used.
data OptionDescription where #
The purpose of this data type is to capture the dictionary corresponding to a particular option.
Option :: forall v. IsOption v => Proxy v -> OptionDescription |
module Test.Tasty.HedgehogTest
Tests definition
prop :: HasCallStack => TestName -> PropertyT IO () -> TestTree Source #
Create a Tasty test from a Hedgehog property
test :: HasCallStack => TestName -> PropertyT IO () -> TestTree Source #
Create a Tasty test from a Hedgehog property called only once
Tests settings
minTestsOk :: Int -> TestTree -> TestTree Source #
Set the minimum number of tests which must be successful for a property to pass
Running tests
run :: Runnable t => t -> IO () Source #
Run either a test tree (a test or a property) whether it is in IO or not
Assertions
gotException :: forall a. (HasCallStack, Show a) => a -> PropertyT IO () Source #
Assert that an exception is thrown
Display
printDifference :: (MonadIO m, Show a, Show b, HasCallStack) => a -> b -> m () Source #