falsify-0.4.0: Property-based testing with internal integrated shrinking
Safe HaskellNone
LanguageHaskell2010

Test.Falsify

Description

Main entry point for falsify

This provides all common definitions required for writing falsify tests and are intended for unqualified import. Typical usage:

import Test.Falsify
import qualified Test.Falsify.Generator as Gen
import qualified Test.Falsify.Predicate as P
import qualified Test.Falsify.Range     as Range

We do not export anything from the Data.Falsify.* module hierarchy to avoid name space pollution.

Synopsis

Property

data Property' e a Source #

Property

A Property' is a generator that can fail and keeps a track of some information about the test run.

In most cases, you will probably want to use Property instead, which fixes e at String.

Instances

Instances details
MonadFail (Property' String) Source # 
Instance details

Defined in Test.Falsify.Internal.Property

Methods

fail :: String -> Property' String a #

Applicative (Property' e) Source # 
Instance details

Defined in Test.Falsify.Internal.Property

Methods

pure :: a -> Property' e a #

(<*>) :: Property' e (a -> b) -> Property' e a -> Property' e b #

liftA2 :: (a -> b -> c) -> Property' e a -> Property' e b -> Property' e c #

(*>) :: Property' e a -> Property' e b -> Property' e b #

(<*) :: Property' e a -> Property' e b -> Property' e a #

Functor (Property' e) Source # 
Instance details

Defined in Test.Falsify.Internal.Property

Methods

fmap :: (a -> b) -> Property' e a -> Property' e b #

(<$) :: a -> Property' e b -> Property' e a #

Monad (Property' e) Source # 
Instance details

Defined in Test.Falsify.Internal.Property

Methods

(>>=) :: Property' e a -> (a -> Property' e b) -> Property' e b #

(>>) :: Property' e a -> Property' e b -> Property' e b #

return :: a -> Property' e a #

type Property = Property' String Source #

Property that uses strings as errors

Most of falsify's internal functions work with Property', but most user-facing functions use Property instead.

Generating values

data Gen a Source #

Generator of a random value

Generators can be combined through their Functor, Applicative and Monad interfaces. The primitive generator is prim, but most users will probably want to construct their generators using the predefined from Test.Falsify.Generator as building blocks.

Generators support "internal integrated shrinking". Shrinking is integrated in the sense of Hedgehog, meaning that we don't write a separate shrinker at all, but the shrink behaviour is implied by the generator. For example, if you have a generator genList for a list of numbers, then

filter even <$> genList

will only generate even numbers, and that property is automatically preserved during shrinking. Shrinking is internal in the sense of Hypothesis, meaning that unlike in Hedgehog, shrinking works correctly even in the context of monadic bind. For example, if you do

do n <- genListLength
   replicateM n someOtherGen

then we can shrink n and the results from someOtherGen in any order (that said, users may prefer to use the dedicated list generator for this purpose, which improves on this in a few ways).

NOTE: Gen is NOT an instance of Alternative; this would not be compatible with the generation of infinite data structures. For the same reason, we do not have a monad transformer version of Gen either.

Instances

Instances details
Applicative Gen Source # 
Instance details

Defined in Test.Falsify.Internal.Generator

Methods

pure :: a -> Gen a #

(<*>) :: Gen (a -> b) -> Gen a -> Gen b #

liftA2 :: (a -> b -> c) -> Gen a -> Gen b -> Gen c #

(*>) :: Gen a -> Gen b -> Gen b #

(<*) :: Gen a -> Gen b -> Gen a #

Functor Gen Source # 
Instance details

Defined in Test.Falsify.Internal.Generator

Methods

fmap :: (a -> b) -> Gen a -> Gen b #

(<$) :: a -> Gen b -> Gen a #

Monad Gen Source # 
Instance details

Defined in Test.Falsify.Internal.Generator

Methods

(>>=) :: Gen a -> (a -> Gen b) -> Gen b #

(>>) :: Gen a -> Gen b -> Gen b #

return :: a -> Gen a #

Selective Gen Source # 
Instance details

Defined in Test.Falsify.Internal.Generator

Methods

select :: Gen (Either a b) -> Gen (a -> b) -> Gen b #

data Range a Source #

Range of values

Instances

Instances details
Functor Range Source # 
Instance details

Defined in Test.Falsify.Internal.Range

Methods

fmap :: (a -> b) -> Range a -> Range b #

(<$) :: a -> Range b -> Range a #

gen :: (HasCallStack, Show a) => Gen a -> Property' e a Source #

Generate value and add it to the log

genWith :: HasCallStack => (a -> Maybe String) -> Gen a -> Property' e a Source #

Generalization of gen that doesn't depend on a Show instance

No log entry is added if Nothing.

Predicates

data Predicate (a :: [Type]) Source #

N-ary predicate

A predicate of type

Predicate '[Int, Bool, Char, ..]

is essentially a function Int -> Bool -> Char -> .. -> Bool, along with some metadata about that function that allows us to render it in a human readable way. In particular, we construct an Expr for the values that the predicate has been applied to.

Instances

Instances details
Monoid (Predicate a) Source # 
Instance details

Defined in Test.Falsify.Predicate

Semigroup (Predicate a) Source # 
Instance details

Defined in Test.Falsify.Predicate

Methods

(<>) :: Predicate a -> Predicate a -> Predicate a #

sconcat :: NonEmpty (Predicate a) -> Predicate a #

stimes :: Integral b => b -> Predicate a -> Predicate a #

(.$) :: forall x (xs :: [Type]). Show x => Predicate (x ': xs) -> (VarName, x) -> Predicate xs Source #

Infix version of at

Typical usage example:

assert $
     P.relatedBy ("equiv", equiv)
  .$ ("x", x)
  .$ ("y", y)

assert :: Predicate ('[] :: [Type]) -> Property' String () Source #

Fail the test if the predicate does not hold

Other Property features

testFailed :: e -> Property' e a Source #

Test failure

discard :: Property' e a Source #

Discard this test

label :: String -> [String] -> Property' e () Source #

Variation on collect that does not rely on Show

See collect for detailed discussion.

collect :: Show a => String -> [a] -> Property' e () Source #

Label this test

See also label, which does not rely on Show.

Motivation

Labelling is instrumental in understanding the distribution of test data. For example, consider testing a binary tree type, and we want to test some properties of an insert operation (example from "How to specify it!" by John Hughes):

prop_insert_insert :: Property ()
prop_insert_insert = do
  tree     <- gen $ ..
  (k1, v1) <- gen $ ..
  (k2, v2) <- gen $ ..
  assert $ .. (insert k1 v1 $ insert k2 v2 $ tree) ..

We might want to know in what percentage of tests k1 == k2:

collect "sameKey" [k1 == k2]

When we do, falsify will report in which percentage of tests the key are the same, and in which percentage of tests they are not.

Labels with multiple values

In general, a particular label can have multiple values in any given test run. Given a test of n test runs, for each value v reported, falsify will report what percentage of the n runs are labelled with v. That means that these percentages may not add up to 100%; indeed, if we had

collect "sameKey" [True]
..
collect "sameKey" [False]

or, equivalently,

collect "sameKey" [True, False]

then every test would have been reported as labelled with True (100%) as well as with False@ (also 100%). Of course, if we do (like above)

collect "sameKey" [k1 == k2]

each test will be labelled with either True or False, and the percentages will add up to 100%.

Difference from QuickCheck

Since you can call collect anywhere in a property, it is natural that the same label can have multiple values in any given test run. In this regard, collect is closer to QuickCheck's tabulate. However, the statistics of tabulate can be difficult to interpret; QuickCheck reports the frequency of a value as a percentage of the total number of values collected; the frequency reported by falsify here is always in terms of number of test runs, like collect does in QuickCheck. We therefore opted to use the name collect rather than tabulate.

info :: String -> Property' e () Source #

Log some additional information about the test

This will be shown in verbose mode.

getContext :: Property' e Context Source #

Get the context for the current test run

sized :: forall e a. (ProperFraction -> a) -> Property' e a Source #

Generate value depending on the test iteration

Rough analogue to QuickCheck's sized function: for test iteration i out of a total of n tests, the callback is passed i / n. This can be used for example to define a Range that starts small and gets larger in successive tests.

Note that this is just a convenience function around getContext; if you want to define ranges that depend on the test iteration i in a different way, use getContext instead.

Testing generators

testMinimum :: Show e => Predicate '[e] -> Property' e () -> Property' String () Source #

Test the minimum error thrown by the property

If the given property passes, we will discard this test (in that case, there is nothing to test); this test is also discarded if the given property discards.

NOTE: When testing a particular generator, you might still want to test with some particular property in mind. Otherwise, the minimum value will always simply be the value that the generator produces when given the Minimal sample tree.

See also testMinimumForIteration.

testMinimumForIteration :: Show e => Iteration -> Predicate '[e] -> Property' e () -> Property' String () Source #

Generalization of testMinimum

See testShrinkingForIteration for detailed discussion of the context.

testShrinking :: Show e => Predicate '[e, e] -> Property' e () -> Property' String () Source #

Test shrinking of a property

A property is normally only shrunk when it fails. We do the same here: if the property succeeds, we discard the test and try again.

If the given property itself discards immediately, then this generator will discard also; otherwise, only shrink steps are considered that do not lead to a discard.

See also testShrinkingForIteration.

testShrinkingForIteration :: Show e => Iteration -> Predicate '[e, e] -> Property' e () -> Property' String () Source #

Generalization of testShrinking for an arbitrary Iteration

Some properties may behave quite differently given a different iteration context, in which case it is important to be explicit about this.

The shrinking context is constructed so that it accurately reflects the path: Initial for the root of the tree, and then Shrinking as we follow edges downwards. There is no repeated Final step: testShrinkingForIteration and testShrinking are typically used to verify that successive shrink steps result in values that are closer to the generator's origin, which is trivially violated by that repeated final step.

The static context is inherited from the parent property.

testShrinkingOfGen :: Show a => Predicate '[a, a] -> Gen a -> Property' String () Source #

Test shrinking of a generator

We check any shrink step that the generator can make (independent of any property).

See also testShrinkingOfGenForIteration.

testShrinkingOfGenForIteration :: Show a => Iteration -> Predicate '[a, a] -> Gen a -> Property' String () Source #

Generalization of testShrinkingOfGen

See testShrinkingForIteration for detailed discussion of the context.

testGen :: Show a => Predicate '[a] -> Gen a -> Property' String () Source #

Test output of the generator

testGen' :: forall e a b. (a -> Either e b) -> Gen a -> Property' e b Source #

Generalization of testGen

Functions

data Fun a b Source #

Function a -> b which can be shown, generated, and shrunk

Instances

Instances details
Functor (Fun a) Source # 
Instance details

Defined in Test.Falsify.Internal.Fun

Methods

fmap :: (a0 -> b) -> Fun a a0 -> Fun a b #

(<$) :: a0 -> Fun a b -> Fun a a0 #

(Show a, Show b) => Show (Fun a b) Source # 
Instance details

Defined in Test.Falsify.Internal.Fun

Methods

showsPrec :: Int -> Fun a b -> ShowS #

show :: Fun a b -> String #

showList :: [Fun a b] -> ShowS #

Patterns

applyFun :: Fun a b -> a -> b Source #

Apply function to argument

See also the Fn, Fn2, and Fn3 patter synonyms.

applyFun2 :: Fun (a, b) c -> a -> b -> c Source #

Like applyFun, but for binary functions

applyFun3 :: Fun (a, b, c) d -> a -> b -> c -> d Source #

Like applyFun, but for ternary functions

pattern Fn :: (a -> b) -> Fun a b Source #

Pattern synonym useful when generating functions of one argument

pattern Fn2 :: (a -> b -> c) -> Fun (a, b) c Source #

Pattern synonym useful when generating functions of two arguments

pattern Fn3 :: (a -> b -> c -> d) -> Fun (a, b, c) d Source #

Pattern synonym useful when generating functions of three arguments

Specialised data structures

Marking

data Marked (f :: Type -> Type) a Source #

Marked element in a container

Marking elements can be a useful technique for dropping elements from a container.

  • Locally marking elements to Drop makes it possible to enforce some global constraints about minimum number of required elements before actually dropping them (see selectAllKept). Example: list.
  • For containers where we cannot remove random elements, the marks can be used for "outwards propagation": if this element is dropped, then those elements must also be dropped. Example: tree.

Constructors

Marked 

Fields

Instances

Instances details
Show (f a) => Show (Marked f a) Source # 
Instance details

Defined in Test.Falsify.Marked

Methods

showsPrec :: Int -> Marked f a -> ShowS #

show :: Marked f a -> String #

showList :: [Marked f a] -> ShowS #

Eq (f a) => Eq (Marked f a) Source # 
Instance details

Defined in Test.Falsify.Marked

Methods

(==) :: Marked f a -> Marked f a -> Bool #

(/=) :: Marked f a -> Marked f a -> Bool #

Ord (f a) => Ord (Marked f a) Source # 
Instance details

Defined in Test.Falsify.Marked

Methods

compare :: Marked f a -> Marked f a -> Ordering #

(<) :: Marked f a -> Marked f a -> Bool #

(<=) :: Marked f a -> Marked f a -> Bool #

(>) :: Marked f a -> Marked f a -> Bool #

(>=) :: Marked f a -> Marked f a -> Bool #

max :: Marked f a -> Marked f a -> Marked f a #

min :: Marked f a -> Marked f a -> Marked f a #

data Mark Source #

Should an element in a container be kept or dropped?

See also Marked.

Constructors

Keep 
Drop 

Instances

Instances details
Show Mark Source # 
Instance details

Defined in Test.Falsify.Marked

Methods

showsPrec :: Int -> Mark -> ShowS #

show :: Mark -> String #

showList :: [Mark] -> ShowS #

Eq Mark Source # 
Instance details

Defined in Test.Falsify.Marked

Methods

(==) :: Mark -> Mark -> Bool #

(/=) :: Mark -> Mark -> Bool #

Ord Mark Source # 
Instance details

Defined in Test.Falsify.Marked

Methods

compare :: Mark -> Mark -> Ordering #

(<) :: Mark -> Mark -> Bool #

(<=) :: Mark -> Mark -> Bool #

(>) :: Mark -> Mark -> Bool #

(>=) :: Mark -> Mark -> Bool #

max :: Mark -> Mark -> Mark #

min :: Mark -> Mark -> Mark #

Hedgehog and Quickcheck style shrinking

newtype ShrinkTree a Source #

Hedgehog-style shrink tree

Constructors

WrapShrinkTree 

Fields

Instances

Instances details
Functor ShrinkTree Source # 
Instance details

Defined in Test.Falsify.ShrinkTree

Methods

fmap :: (a -> b) -> ShrinkTree a -> ShrinkTree b #

(<$) :: a -> ShrinkTree b -> ShrinkTree a #

Show a => Show (ShrinkTree a) Source # 
Instance details

Defined in Test.Falsify.ShrinkTree

Eq a => Eq (ShrinkTree a) Source # 
Instance details

Defined in Test.Falsify.ShrinkTree

Methods

(==) :: ShrinkTree a -> ShrinkTree a -> Bool #

(/=) :: ShrinkTree a -> ShrinkTree a -> Bool #

Default generators

class GenDefault tag a where Source #

Default generators

GenDefault is similar to QuickCheck's Arbitrary class along with some deriving via helpers. Unlike Arbitrary, GenDefault allows one to choose between sets of default generators with user-defined tags. See Test.Falsify.GenDefault.Std for the standard tag with a few useful instances.

Methods

genDefault :: Proxy tag -> Gen a Source #

Default generator for a

The type-level tag allows types a to have multiple defaults.

Instances

Instances details
GenDefault Std Int16 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Int32 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Int64 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Int8 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word16 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word32 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word64 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word8 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std () Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen () Source #

GenDefault Std Bool Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Char Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Int Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std a => GenDefault Std (Maybe a) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (Maybe a) Source #

(Enum a, Bounded a) => GenDefault tag (ViaEnum a) Source # 
Instance details

Defined in Test.Falsify.GenDefault

Methods

genDefault :: Proxy tag -> Gen (ViaEnum a) Source #

(Integral a, FiniteBits a, Bounded a) => GenDefault tag (ViaIntegral a) Source # 
Instance details

Defined in Test.Falsify.GenDefault

Methods

genDefault :: Proxy tag -> Gen (ViaIntegral a) Source #

(GenDefault Std a, GenDefault Std b) => GenDefault Std (Either a b) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (Either a b) Source #

(GenDefault Std a, GenDefault Std b) => GenDefault Std (a, b) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (a, b) Source #

(Generic t, GGenDefault tag (Rep t)) => GenDefault tag (ViaGeneric tag t) Source # 
Instance details

Defined in Test.Falsify.GenDefault

Methods

genDefault :: Proxy tag -> Gen (ViaGeneric tag t) Source #

GenDefault tag' a => GenDefault tag (ViaTag tag' a) Source # 
Instance details

Defined in Test.Falsify.GenDefault

Methods

genDefault :: Proxy tag -> Gen (ViaTag tag' a) Source #

(GenDefault Std a, GenDefault Std b, GenDefault Std c) => GenDefault Std (a, b, c) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (a, b, c) Source #

(IsList l, GenDefault tag (Item l), KnownNat mn, KnownNat mx) => GenDefault tag (ViaList l mn mx) Source # 
Instance details

Defined in Test.Falsify.GenDefault

Methods

genDefault :: Proxy tag -> Gen (ViaList l mn mx) Source #

(IsString s, GenDefault tag Char, KnownNat mn, KnownNat mx) => GenDefault tag (ViaString s mn mx) Source # 
Instance details

Defined in Test.Falsify.GenDefault

Methods

genDefault :: Proxy tag -> Gen (ViaString s mn mx) Source #

(GenDefault Std a, GenDefault Std b, GenDefault Std c, GenDefault Std d) => GenDefault Std (a, b, c, d) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (a, b, c, d) Source #

(GenDefault Std a, GenDefault Std b, GenDefault Std c, GenDefault Std d, GenDefault Std e) => GenDefault Std (a, b, c, d, e) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (a, b, c, d, e) Source #

data Std Source #

Type tag for these "standard" default generators.

You can use this tag directly or choose type-by-type with ViaTag.

Instances

Instances details
GenDefault Std Int16 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Int32 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Int64 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Int8 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word16 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word32 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word64 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word8 Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std () Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen () Source #

GenDefault Std Bool Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Char Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Int Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std Word Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

GenDefault Std a => GenDefault Std (Maybe a) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (Maybe a) Source #

(GenDefault Std a, GenDefault Std b) => GenDefault Std (Either a b) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (Either a b) Source #

(GenDefault Std a, GenDefault Std b) => GenDefault Std (a, b) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (a, b) Source #

(GenDefault Std a, GenDefault Std b, GenDefault Std c) => GenDefault Std (a, b, c) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (a, b, c) Source #

(GenDefault Std a, GenDefault Std b, GenDefault Std c, GenDefault Std d) => GenDefault Std (a, b, c, d) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (a, b, c, d) Source #

(GenDefault Std a, GenDefault Std b, GenDefault Std c, GenDefault Std d, GenDefault Std e) => GenDefault Std (a, b, c, d, e) Source # 
Instance details

Defined in Test.Falsify.GenDefault.Std

Methods

genDefault :: Proxy Std -> Gen (a, b, c, d, e) Source #