Test.QuickCheck.Monadic

QuickCheck-2.15.0.1: Automatic testing of Haskell programs

Safe Haskell | Safe
Language | Haskell2010

Test.QuickCheck.Monadic

Contents

- Property monad
- Monadic specification combinators
- Run functions
- Exceptions

Description

Allows testing of monadic values. Will generally follow this form:

    prop_monadic a b = monadicIO $ do
      a' <- run (f a)
      b' <- run (f b)
      -- ...
      assert someBoolean

Example using the `FACTOR(1)` command-line utility:

    import System.Process
    import Test.QuickCheck
    import Test.QuickCheck.Monadic

    -- $ factor 16
    -- 16: 2 2 2 2
    factor :: Integer -> IO [Integer]
    factor n = parse `fmap` readProcess "factor" [show n] "" where

      parse :: String -> [Integer]
      parse = map read . tail . words

    prop_factor :: Positive Integer -> Property
    prop_factor (Positive n) = monadicIO $ do
      factors <- run (factor n)

      assert (product factors == n)

    >>> quickCheck prop_factor
    +++ OK, passed 100 tests.

See the paper "Testing Monadic Code with QuickCheck".

Synopsis

- newtype PropertyM (m :: Type -> Type) a = MkPropertyM {
  - unPropertyM :: (a -> Gen (m Property)) -> Gen (m Property)
  }
- run :: Monad m => m a -> PropertyM m a
- assert :: forall (m :: Type -> Type). Monad m => Bool -> PropertyM m ()
- assertWith :: forall (m :: Type -> Type). Monad m => Bool -> String -> PropertyM m ()
- pre :: forall (m :: Type -> Type). Monad m => Bool -> PropertyM m ()
- wp :: Monad m => m a -> (a -> PropertyM m b) -> PropertyM m b
- pick :: forall (m :: Type -> Type) a. (Monad m, Show a) => Gen a -> PropertyM m a
- forAllM :: forall (m :: Type -> Type) a b. (Monad m, Show a) => Gen a -> (a -> PropertyM m b) -> PropertyM m b
- monitor :: forall (m :: Type -> Type). Monad m => (Property -> Property) -> PropertyM m ()
- stop :: forall prop (m :: Type -> Type) a. (Testable prop, Monad m) => prop -> PropertyM m a
- monadic :: (Testable a, Monad m) => (m Property -> Property) -> PropertyM m a -> Property
- monadic' :: (Testable a, Monad m) => PropertyM m a -> Gen (m Property)
- monadicIO :: Testable a => PropertyM IO a -> Property
- monadicST :: Testable a => (forall s. PropertyM (ST s) a) -> Property
- runSTGen :: (forall s. Gen (ST s a)) -> Gen a
- assertException :: Exception exc => (exc -> Bool) -> a -> Property
- assertExceptionIO :: Exception exc => (exc -> Bool) -> IO a -> Property
- assertDeepException :: (NFData a, Exception exc) => (exc -> Bool) -> a -> Property
- assertDeepExceptionIO :: (NFData a, Exception exc) => (exc -> Bool) -> IO a -> Property

# Property monad

newtype PropertyM (m :: Type -> Type) a #

The property monad is really a monad transformer that can contain monadic computations in the monad `m` it is parameterized by:

- `m` - the `m`-computations that may be performed within `PropertyM`

Elements of `PropertyM m a` may mix property operations and `m`-computations.

Constructors

MkPropertyM |
Fields unPropertyM :: (a -> Gen (m Property)) -> Gen (m Property)

#### Instances

Instances details

MonadTrans PropertyM # |
Instance details Defined in Test.QuickCheck.Monadic Methods lift :: Monad m => m a -> PropertyM m a #
MonadIO m => MonadIO (PropertyM m) # |
Instance details Defined in Test.QuickCheck.Monadic Methods liftIO :: IO a -> PropertyM m a #
Applicative (PropertyM m) # |
Instance details Defined in Test.QuickCheck.Monadic Methods pure :: a -> PropertyM m a # (<*>) :: PropertyM m (a -> b) -> PropertyM m a -> PropertyM m b # liftA2 :: (a -> b -> c) -> PropertyM m a -> PropertyM m b -> PropertyM m c # (*>) :: PropertyM m a -> PropertyM m b -> PropertyM m b # (<*) :: PropertyM m a -> PropertyM m b -> PropertyM m a #
Functor (PropertyM m) # |
Instance details Defined in Test.QuickCheck.Monadic Methods fmap :: (a -> b) -> PropertyM m a -> PropertyM m b # (<$) :: a -> PropertyM m b -> PropertyM m a #
Monad m => Monad (PropertyM m) # |
Instance details Defined in Test.QuickCheck.Monadic Methods (>>=) :: PropertyM m a -> (a -> PropertyM m b) -> PropertyM m b # (>>) :: PropertyM m a -> PropertyM m b -> PropertyM m b # return :: a -> PropertyM m a #
Monad m => MonadFail (PropertyM m) # |
Instance details Defined in Test.QuickCheck.Monadic Methods fail :: String -> PropertyM m a #

# Monadic specification combinators

run :: Monad m => m a -> PropertyM m a #

The lifting operation of the property monad. Allows embedding monadic/`IO`-actions in properties:

    log :: Int -> IO ()

    prop_foo n = monadicIO $ do
      run (log n)
      -- ...

assert :: forall (m :: Type -> Type). Monad m => Bool -> PropertyM m () #

Allows embedding non-monadic properties into monadic ones.

assertWith :: forall (m :: Type -> Type). Monad m => Bool -> String -> PropertyM m () #

Like `assert` but allows caller to specify an explicit message to show on failure.

Example:

    do
      assertWith True  "My first predicate."
      assertWith False "My other predicate."
      ...

    Assertion failed (after 2 tests):
        Passed: My first predicate
        Failed: My other predicate

pre :: forall (m :: Type -> Type). Monad m => Bool -> PropertyM m () #

Tests preconditions. Unlike `assert` this does not cause the property to fail, rather it discards them just like using the implication combinator `==>`.

This allows representing the Hoare triple

    {p} x ← e{q}

as

    pre p
    x <- run e
    assert q

wp :: Monad m => m a -> (a -> PropertyM m b) -> PropertyM m b #

The weakest precondition

    wp(x ← e, p)

can be expressed as in code as `wp e (\x -> p)`.

pick :: forall (m :: Type -> Type) a. (Monad m, Show a) => Gen a -> PropertyM m a #

Quantification in a monadic property, fits better with do-notation than `forAllM`. Note: values generated by `pick` do not shrink.

forAllM :: forall (m :: Type -> Type) a b. (Monad m, Show a) => Gen a -> (a -> PropertyM m b) -> PropertyM m b #

Quantification in monadic properties to `pick`, with a notation similar to `forAll`. Note: values generated by `forAllM` do not shrink.

monitor :: forall (m :: Type -> Type). Monad m => (Property -> Property) -> PropertyM m () #

Allows making observations about the test data:

    monitor (collect e)

collects the distribution of value of `e`.

    monitor (counterexample "Failure!")

Adds `"Failure!"` to the counterexamples.

stop :: forall prop (m :: Type -> Type) a. (Testable prop, Monad m) => prop -> PropertyM m a #

# Run functions

monadic :: (Testable a, Monad m) => (m Property -> Property) -> PropertyM m a -> Property #

monadic' :: (Testable a, Monad m) => PropertyM m a -> Gen (m Property) #

monadicIO :: Testable a => PropertyM IO a -> Property #

Runs the property monad for `IO`-computations.

    prop_cat msg = monadicIO $ do
      (exitCode, stdout, _) <- run (readProcessWithExitCode "cat" [] msg)

      pre (ExitSuccess == exitCode)

      assert (stdout == msg)

    >>> quickCheck prop_cat
    +++ OK, passed 100 tests.

monadicST :: Testable a => (forall s. PropertyM (ST s) a) -> Property #

Runs the property monad for `ST`-computations.

    -- Your mutable sorting algorithm here
    sortST :: Ord a => [a] -> ST s (MVector s a)
    sortST = thaw . fromList . sort

    prop_sortST xs = monadicST $ do
      sorted  <- run (freeze =<< sortST xs)
      assert (toList sorted == sort xs)

    >>> quickCheck prop_sortST
    +++ OK, passed 100 tests.

runSTGen :: (forall s. Gen (ST s a)) -> Gen a #

# Exceptions

assertException #

Arguments

:: Exception exc |
=> (exc -> Bool) | Return `True` if that is the exception that was expected
-> a | Value that should result in an exception, when evaluated to WHNF
-> Property |

Evaluate the value to Weak Head Normal Form (WHNF) and fail if it does not result in an expected exception being thrown.

assertExceptionIO #

Arguments

:: Exception exc |
=> (exc -> Bool) | Return `True` if that is the exception that was expected
-> IO a | An action that should throw the expected exception
-> Property |

Make sure that a specific exception is thrown during an IO action. The result is evaluated to WHNF.

assertDeepException #

Arguments

:: (NFData a, Exception exc) |
=> (exc -> Bool) | Return True if that is the exception that was expected
-> a | Value that should result in an exception, when fully evaluated to NF
-> Property |

Same as `assertException`, but evaluate the value to Normal Form (NF) and fail if it does not result in an expected exception being thrown.

assertDeepExceptionIO #

Arguments

:: (NFData a, Exception exc) |
=> (exc -> Bool) | Return True if that is the exception that was expected
-> IO a | An action that should throw the expected exception
-> Property |

Make sure that a specific exception is thrown during an IO action. The result is evaluated to NF.