|
Packit |
6375e3 |
{-# LANGUAGE CPP #-}
|
|
Packit |
6375e3 |
{-# LANGUAGE ConstraintKinds #-}
|
|
Packit |
6375e3 |
{-# LANGUAGE KindSignatures #-}
|
|
Packit |
6375e3 |
{-# LANGUAGE ImplicitParams #-}
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- Introductory documentation: <https://github.com/sol/hspec-expectations#readme>
|
|
Packit |
6375e3 |
module Test.Hspec.Expectations (
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- * Setting expectations
|
|
Packit |
6375e3 |
Expectation
|
|
Packit |
6375e3 |
, expectationFailure
|
|
Packit |
6375e3 |
, shouldBe
|
|
Packit |
6375e3 |
, shouldSatisfy
|
|
Packit |
6375e3 |
, shouldStartWith
|
|
Packit |
6375e3 |
, shouldEndWith
|
|
Packit |
6375e3 |
, shouldContain
|
|
Packit |
6375e3 |
, shouldMatchList
|
|
Packit |
6375e3 |
, shouldReturn
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
, shouldNotBe
|
|
Packit |
6375e3 |
, shouldNotSatisfy
|
|
Packit |
6375e3 |
, shouldNotContain
|
|
Packit |
6375e3 |
, shouldNotReturn
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- * Expecting exceptions
|
|
Packit |
6375e3 |
, shouldThrow
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- ** Selecting exceptions
|
|
Packit |
6375e3 |
, Selector
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- ** Predefined type-based selectors
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- There are predefined selectors for some standard exceptions. Each selector
|
|
Packit |
6375e3 |
-- is just @const True@ with an appropriate type.
|
|
Packit |
6375e3 |
, anyException
|
|
Packit |
6375e3 |
, anyErrorCall
|
|
Packit |
6375e3 |
, anyIOException
|
|
Packit |
6375e3 |
, anyArithException
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- ** Combinators for defining value-based selectors
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- Some exceptions (most prominently `ErrorCall`) have no `Eq` instance.
|
|
Packit |
6375e3 |
-- Selecting a specific value would require pattern matching.
|
|
Packit |
6375e3 |
--
|
|
Packit |
6375e3 |
-- For such exceptions, combinators that construct selectors are provided.
|
|
Packit |
6375e3 |
-- Each combinator corresponds to a constructor; it takes the same arguments,
|
|
Packit |
6375e3 |
-- and has the same name (but starting with a lower-case letter).
|
|
Packit |
6375e3 |
, errorCall
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- * Re-exports
|
|
Packit |
6375e3 |
, HasCallStack
|
|
Packit |
6375e3 |
) where
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
import qualified Test.HUnit
|
|
Packit |
6375e3 |
import Test.HUnit ((@?=))
|
|
Packit |
6375e3 |
import Control.Exception
|
|
Packit |
6375e3 |
import Data.Typeable
|
|
Packit |
6375e3 |
import Data.List
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
import Control.Monad (unless)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
import Test.Hspec.Expectations.Matcher
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
#if MIN_VERSION_HUnit(1,4,0)
|
|
Packit |
6375e3 |
import Data.CallStack (HasCallStack)
|
|
Packit |
6375e3 |
#else
|
|
Packit |
6375e3 |
#if MIN_VERSION_base(4,8,1)
|
|
Packit |
6375e3 |
import qualified GHC.Stack as GHC
|
|
Packit |
6375e3 |
type HasCallStack = (?loc :: GHC.CallStack)
|
|
Packit |
6375e3 |
#else
|
|
Packit |
6375e3 |
import GHC.Exts (Constraint)
|
|
Packit |
6375e3 |
type HasCallStack = (() :: Constraint)
|
|
Packit |
6375e3 |
#endif
|
|
Packit |
6375e3 |
#endif
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
type Expectation = Test.HUnit.Assertion
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
expectationFailure :: HasCallStack => String -> Expectation
|
|
Packit |
6375e3 |
expectationFailure = Test.HUnit.assertFailure
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
expectTrue :: HasCallStack => String -> Bool -> Expectation
|
|
Packit |
6375e3 |
expectTrue msg b = unless b (expectationFailure msg)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
infix 1 `shouldBe`, `shouldSatisfy`, `shouldStartWith`, `shouldEndWith`, `shouldContain`, `shouldMatchList`, `shouldReturn`, `shouldThrow`
|
|
Packit |
6375e3 |
infix 1 `shouldNotBe`, `shouldNotSatisfy`, `shouldNotContain`, `shouldNotReturn`
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @actual \`shouldBe\` expected@ sets the expectation that @actual@ is equal
|
|
Packit |
6375e3 |
-- to @expected@.
|
|
Packit |
6375e3 |
shouldBe :: (HasCallStack, Show a, Eq a) => a -> a -> Expectation
|
|
Packit |
6375e3 |
actual `shouldBe` expected = actual @?= expected
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @v \`shouldSatisfy\` p@ sets the expectation that @p v@ is @True@.
|
|
Packit |
6375e3 |
shouldSatisfy :: (HasCallStack, Show a) => a -> (a -> Bool) -> Expectation
|
|
Packit |
6375e3 |
v `shouldSatisfy` p = expectTrue ("predicate failed on: " ++ show v) (p v)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
compareWith :: (HasCallStack, Show a) => (a -> a -> Bool) -> String -> a -> a -> Expectation
|
|
Packit |
6375e3 |
compareWith comparator errorDesc result expected = expectTrue errorMsg (comparator expected result)
|
|
Packit |
6375e3 |
where
|
|
Packit |
6375e3 |
errorMsg = show result ++ " " ++ errorDesc ++ " " ++ show expected
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @list \`shouldStartWith\` prefix@ sets the expectation that @list@ starts with @prefix@,
|
|
Packit |
6375e3 |
shouldStartWith :: (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation
|
|
Packit |
6375e3 |
shouldStartWith = compareWith isPrefixOf "does not start with"
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @list \`shouldEndWith\` suffix@ sets the expectation that @list@ ends with @suffix@,
|
|
Packit |
6375e3 |
shouldEndWith :: (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation
|
|
Packit |
6375e3 |
shouldEndWith = compareWith isSuffixOf "does not end with"
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @list \`shouldContain\` sublist@ sets the expectation that @sublist@ is contained,
|
|
Packit |
6375e3 |
-- wholly and intact, anywhere in @list@.
|
|
Packit |
6375e3 |
shouldContain :: (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation
|
|
Packit |
6375e3 |
shouldContain = compareWith isInfixOf "does not contain"
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @xs \`shouldMatchList\` ys@ sets the expectation that @xs@ has the same
|
|
Packit |
6375e3 |
-- elements that @ys@ has, possibly in another order
|
|
Packit |
6375e3 |
shouldMatchList :: (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation
|
|
Packit |
6375e3 |
xs `shouldMatchList` ys = maybe (return ()) expectationFailure (matchList xs ys)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @action \`shouldReturn\` expected@ sets the expectation that @action@
|
|
Packit |
6375e3 |
-- returns @expected@.
|
|
Packit |
6375e3 |
shouldReturn :: (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
|
|
Packit |
6375e3 |
action `shouldReturn` expected = action >>= (`shouldBe` expected)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @actual \`shouldNotBe\` notExpected@ sets the expectation that @actual@ is not
|
|
Packit |
6375e3 |
-- equal to @notExpected@
|
|
Packit |
6375e3 |
shouldNotBe :: (HasCallStack, Show a, Eq a) => a -> a -> Expectation
|
|
Packit |
6375e3 |
actual `shouldNotBe` notExpected = expectTrue ("not expected: " ++ show actual) (actual /= notExpected)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @v \`shouldNotSatisfy\` p@ sets the expectation that @p v@ is @False@.
|
|
Packit |
6375e3 |
shouldNotSatisfy :: (HasCallStack, Show a) => a -> (a -> Bool) -> Expectation
|
|
Packit |
6375e3 |
v `shouldNotSatisfy` p = expectTrue ("predicate succeeded on: " ++ show v) ((not . p) v)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @list \`shouldNotContain\` sublist@ sets the expectation that @sublist@ is not
|
|
Packit |
6375e3 |
-- contained anywhere in @list@.
|
|
Packit |
6375e3 |
shouldNotContain :: (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation
|
|
Packit |
6375e3 |
list `shouldNotContain` sublist = expectTrue errorMsg ((not . isInfixOf sublist) list)
|
|
Packit |
6375e3 |
where
|
|
Packit |
6375e3 |
errorMsg = show list ++ " does contain " ++ show sublist
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @action \`shouldNotReturn\` notExpected@ sets the expectation that @action@
|
|
Packit |
6375e3 |
-- does not return @notExpected@.
|
|
Packit |
6375e3 |
shouldNotReturn :: (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
|
|
Packit |
6375e3 |
action `shouldNotReturn` notExpected = action >>= (`shouldNotBe` notExpected)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- A @Selector@ is a predicate; it can simultaneously constrain the type and
|
|
Packit |
6375e3 |
-- value of an exception.
|
|
Packit |
6375e3 |
type Selector a = (a -> Bool)
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
-- |
|
|
Packit |
6375e3 |
-- @action \`shouldThrow\` selector@ sets the expectation that @action@ throws
|
|
Packit |
6375e3 |
-- an exception. The precise nature of the expected exception is described
|
|
Packit |
6375e3 |
-- with a 'Selector'.
|
|
Packit |
6375e3 |
shouldThrow :: (HasCallStack, Exception e) => IO a -> Selector e -> Expectation
|
|
Packit |
6375e3 |
action `shouldThrow` p = do
|
|
Packit |
6375e3 |
r <- try action
|
|
Packit |
6375e3 |
case r of
|
|
Packit |
6375e3 |
Right _ ->
|
|
Packit |
6375e3 |
expectationFailure $
|
|
Packit |
6375e3 |
"did not get expected exception: " ++ exceptionType
|
|
Packit |
6375e3 |
Left e ->
|
|
Packit |
6375e3 |
(`expectTrue` p e) $
|
|
Packit |
6375e3 |
"predicate failed on expected exception: " ++ exceptionType ++ " (" ++ show e ++ ")"
|
|
Packit |
6375e3 |
where
|
|
Packit |
6375e3 |
-- a string repsentation of the expected exception's type
|
|
Packit |
6375e3 |
exceptionType = (show . typeOf . instanceOf) p
|
|
Packit |
6375e3 |
where
|
|
Packit |
6375e3 |
instanceOf :: Selector a -> a
|
|
Packit |
6375e3 |
instanceOf _ = error "Test.Hspec.Expectations.shouldThrow: broken Typeable instance"
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
anyException :: Selector SomeException
|
|
Packit |
6375e3 |
anyException = const True
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
anyErrorCall :: Selector ErrorCall
|
|
Packit |
6375e3 |
anyErrorCall = const True
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
errorCall :: String -> Selector ErrorCall
|
|
Packit |
6375e3 |
#if MIN_VERSION_base(4,9,0)
|
|
Packit |
6375e3 |
errorCall s (ErrorCallWithLocation msg _) = s == msg
|
|
Packit |
6375e3 |
#else
|
|
Packit |
6375e3 |
errorCall s (ErrorCall msg) = s == msg
|
|
Packit |
6375e3 |
#endif
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
anyIOException :: Selector IOException
|
|
Packit |
6375e3 |
anyIOException = const True
|
|
Packit |
6375e3 |
|
|
Packit |
6375e3 |
anyArithException :: Selector ArithException
|
|
Packit |
6375e3 |
anyArithException = const True
|