Copyright | (C) 2014-2022 Merijn Verstraaten |
---|---|
License | BSD-style (see the file LICENSE) |
Maintainer | Merijn Verstraaten <merijn@inconsistent.nl> |
Stability | experimental |
Portability | haha |
Safe Haskell | Trustworthy |
Language | Haskell2010 |
BroadcastChan.Test
Description
Module containing testing helpers shared across all broadcast-chan packages.
Synopsis
- (@?) :: IO Bool -> String -> Assertion
- expect :: (Eq e, Exception e) => e -> IO a -> Assertion
- genStreamTests :: (Eq r, Show r) => String -> ([Int] -> (Int -> IO Int) -> IO r) -> (Handler IO Int -> [Int] -> (Int -> IO Int) -> Int -> IO r) -> TestTree
- runTests :: String -> [TestTree] -> IO ()
- withLoggedOutput :: FilePath -> (Handle -> IO r) -> IO (r, Text)
- class Monad m => MonadIO (m :: Type -> Type) where
- mapHandler :: (m Action -> n Action) -> Handler m a -> Handler n a
- module Test.Tasty
- type HasCallStack = ?callStack :: CallStack
- type AssertionPredicate = IO Bool
- class Assertable t where
- data HUnitFailure = HUnitFailure (Maybe SrcLoc) String
- class AssertionPredicable t where
- assertionPredicate :: t -> IO Bool
- type Assertion = IO ()
- assertFailure :: HasCallStack => String -> IO a
- assertBool :: HasCallStack => String -> Bool -> Assertion
- assertEqual :: (Eq a, Show a, HasCallStack) => String -> a -> a -> Assertion
- (@=?) :: (Eq a, Show a, HasCallStack) => a -> a -> Assertion
- (@?=) :: (Eq a, Show a, HasCallStack) => a -> a -> Assertion
- assertString :: HasCallStack => String -> Assertion
- testCaseSteps :: TestName -> ((String -> IO ()) -> Assertion) -> TestTree
- testCase :: TestName -> Assertion -> TestTree
- testCaseInfo :: TestName -> IO String -> TestTree
Documentation
(@?) :: IO Bool -> String -> Assertion infix 0 Source #
Monomorphised version of @?
to avoid ambiguous type
errors when combined with predicates that are MonadIO m => m Bool
.
Since: 0.2.0
expect :: (Eq e, Exception e) => e -> IO a -> Assertion Source #
Test which fails if the expected exception is not thrown by the IO
action.
Since: 0.2.0
Arguments
:: (Eq r, Show r) | |
=> String | Name to group tests under |
-> ([Int] -> (Int -> IO Int) -> IO r) | Sequential sink |
-> (Handler IO Int -> [Int] -> (Int -> IO Int) -> Int -> IO r) | Parallel sink |
-> TestTree |
Takes a name, a sequential sink, and a parallel sink and generates tasty tests from these.
The parallel and sequential sink should perform the same tasks so their results can be compared to check correctness.
The sinks should take a list of input data, a function processing the data, and return a result that can be compared for equality.
Furthermore the parallel sink should take a number indicating how many concurrent consumers should be used.
Since: 0.2.0
runTests :: String -> [TestTree] -> IO () Source #
Run a list of TestTree
's and group them under the specified name.
Since: 0.2.0
withLoggedOutput :: FilePath -> (Handle -> IO r) -> IO (r, Text) Source #
Run an IO action while logging the output to a Handle
. Returns the
result and the logged output.
Since: 0.2.0
class Monad m => MonadIO (m :: Type -> Type) where #
Monads in which IO
computations may be embedded.
Any monad built by applying a sequence of monad transformers to the
IO
monad will be an instance of this class.
Instances should satisfy the following laws, which state that liftIO
is a transformer of monads:
Methods
Lift a computation from the IO
monad.
This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations
(i.e. IO
is the base monad for the stack).
Example
import Control.Monad.Trans.State -- from the "transformers" library printState :: Show s => StateT s IO () printState = do state <- get liftIO $ print state
Had we omitted
, we would have ended up with this error:liftIO
• Couldn't match type ‘IO’ with ‘StateT s IO’ Expected type: StateT s IO () Actual type: IO ()
The important part here is the mismatch between StateT s IO ()
and
.IO
()
Luckily, we know of a function that takes an
and returns an IO
a(m a)
:
,
enabling us to run the program and see the expected results:liftIO
> evalStateT printState "hello" "hello" > evalStateT printState 3 3
Instances
Re-exports of tasty
and tasty-hunit
module Test.Tasty
type HasCallStack = ?callStack :: CallStack #
Request a CallStack.
NOTE: The implicit parameter ?callStack :: CallStack
is an
implementation detail and should not be considered part of the
CallStack
API, we may decide to change the implementation in the
future.
Since: base-4.9.0.0
type AssertionPredicate = IO Bool #
The result of an assertion that hasn't been evaluated yet.
Most test cases follow the following steps:
- Do some processing or an action.
- Assert certain conditions.
However, this flow is not always suitable. AssertionPredicate
allows for
additional steps to be inserted without the initial action to be affected
by side effects. Additionally, clean-up can be done before the test case
has a chance to end. A potential work flow is:
- Write data to a file.
- Read data from a file, evaluate conditions.
- Clean up the file.
- Assert that the side effects of the read operation meet certain conditions.
- Assert that the conditions evaluated in step 2 are met.
class Assertable t where #
Allows the extension of the assertion mechanism.
Since an Assertion
can be a sequence of Assertion
s and IO
actions,
there is a fair amount of flexibility of what can be achieved. As a rule,
the resulting Assertion
should be the body of a TestCase
or part of
a TestCase
; it should not be used to assert multiple, independent
conditions.
If more complex arrangements of assertions are needed, Test
and
Testable
should be used.
Instances
Assertable String | |
Defined in Test.Tasty.HUnit.Orig | |
Assertable () | |
Defined in Test.Tasty.HUnit.Orig | |
Assertable Bool | |
Defined in Test.Tasty.HUnit.Orig | |
Assertable t => Assertable (IO t) | |
Defined in Test.Tasty.HUnit.Orig |
data HUnitFailure #
Exception thrown by assertFailure
etc.
Constructors
HUnitFailure (Maybe SrcLoc) String |
Instances
Exception HUnitFailure | |
Defined in Test.Tasty.HUnit.Orig Methods toException :: HUnitFailure -> SomeException # fromException :: SomeException -> Maybe HUnitFailure # displayException :: HUnitFailure -> String # | |
Show HUnitFailure | |
Defined in Test.Tasty.HUnit.Orig Methods showsPrec :: Int -> HUnitFailure -> ShowS # show :: HUnitFailure -> String # showList :: [HUnitFailure] -> ShowS # | |
Eq HUnitFailure | |
Defined in Test.Tasty.HUnit.Orig |
class AssertionPredicable t where #
An ad-hoc class used to overload the @?
operator.
The only intended instances of this class are
and Bool
.IO
Bool
You shouldn't need to interact with this class directly.
Methods
assertionPredicate :: t -> IO Bool #
Instances
AssertionPredicable Bool | |
Defined in Test.Tasty.HUnit.Orig Methods assertionPredicate :: Bool -> IO Bool # | |
AssertionPredicable t => AssertionPredicable (IO t) | |
Defined in Test.Tasty.HUnit.Orig Methods assertionPredicate :: IO t -> IO Bool # |
An assertion is simply an IO
action. Assertion failure is indicated
by throwing an exception, typically HUnitFailure
.
Instead of throwing the exception directly, you should use
functions like assertFailure
and assertBool
.
Test cases are composed of a sequence of one or more assertions.
Arguments
:: HasCallStack | |
=> String | A message that is displayed with the assertion failure |
-> IO a |
Unconditionally signals that a failure has occured. All other assertions can be expressed with the form:
if conditionIsMet then return () else assertFailure msg
Arguments
:: HasCallStack | |
=> String | The message that is displayed if the assertion fails |
-> Bool | The condition |
-> Assertion |
Asserts that the specified condition holds.
Arguments
:: (Eq a, Show a, HasCallStack) | |
=> String | The message prefix |
-> a | The expected value |
-> a | The actual value |
-> Assertion |
Asserts that the specified actual value is equal to the expected value. The output message will contain the prefix, the expected value, and the actual value.
If the prefix is the empty string (i.e., ""
), then the prefix is omitted
and only the expected and actual values are output.
Arguments
:: (Eq a, Show a, HasCallStack) | |
=> a | The expected value |
-> a | The actual value |
-> Assertion |
Asserts that the specified actual value is equal to the expected value (with the expected value on the left-hand side).
Arguments
:: (Eq a, Show a, HasCallStack) | |
=> a | The actual value |
-> a | The expected value |
-> Assertion |
Asserts that the specified actual value is equal to the expected value (with the actual value on the left-hand side).
Arguments
:: HasCallStack | |
=> String | The message that is displayed with the assertion failure |
-> Assertion |
Signals an assertion failure if a non-empty message (i.e., a message
other than ""
) is passed.
testCaseSteps :: TestName -> ((String -> IO ()) -> Assertion) -> TestTree #
Create a multi-step unit test.
Example:
main = defaultMain $ testCaseSteps "Multi-step test" $ \step -> do step "Preparing..." -- do something step "Running part 1" -- do something step "Running part 2" -- do something assertFailure "BAM!" step "Running part 3" -- do something
The step
calls are mere annotations. They let you see which steps were
performed successfully, and which step failed.
You can think of step
as putStrLn
, except putStrLn
would mess up the output with the
console reporter and get lost with the others.
For the example above, the output will be
Multi-step test: FAIL Preparing... Running part 1 Running part 2 BAM! 1 out of 1 tests failed (0.00s)
Note that:
- Tasty still treats this as a single test, even though it consists of multiple steps.
- The execution stops after the first failure. When we are looking at a failed test, we know that all displayed steps but the last one were successful, and the last one failed. The steps after the failed one are not displayed, since they didn't run.