-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | A simple test framework.
--
-- This is a simple testing library. It focuses mainly on making it easy
-- to run large test suites and collect the results together.
--
-- This package is currently fairly experimental. The API may change in
-- the near future. Hopefully this release should be relatively bug-free,
-- however.
--
-- Changes:
--
--
@package AC-MiniTest
@version 1.1.1
-- | This is the main testing module. Start reading here if you want to
-- know what this package is all about.
--
-- There's a documentation section at the bottom of this page. You might
-- want to start by reading that. Otherwise, here's a quick summary:
--
--
-- - You create Test objects to represent your tests.
-- - run_test :: Test -> IO
-- Bool to quickly run a test interactively (e.g., during
-- debugging activity).
-- - run_test_full allows more control, including recording
-- detailed test results to an XML log file.
-- - test :: Bool -> Test creates a
-- test from pure code.
-- - (?=) :: Eq x => x -> x ->
-- Test for tests with known answers.
-- - Tests can be annotated with title, argument,
-- temporary, note and so on.
-- - tests :: [Test] -> Test for
-- combining multiple tests into a single Test object. Tests can
-- be nested arbitrarily in this mannar to group related tests
-- together.
-- - testIO :: IO Bool -> Test
-- for tests that need to perform I/O.
-- - The TestM monad supports liftIO and allows limited
-- test annotations from within monadic code.
-- - testM :: TestM Bool ->
-- Test to use the TestM monad.
-- - throws, throwsIO, throwsM to test for
-- exceptions.
--
module Test.AC.Test
-- | An executable test.
data Test
-- | Create a Test from a simple Bool value.
--
-- The test passes if the value is True. The test fails if the
-- value is False, or if an exception is thrown in the course of
-- computing the value.
test :: Bool -> Test
-- | This test always succeeds, but writes a note in the log to say that
-- the test case was "inapplicable".
--
-- This is generally useful if you have a test generation function which
-- doesn't work for certain combinations of inputs. In that instance, the
-- test still passes, but there is a note in the log letting you know it
-- was only a "null" test.
inapplicable :: Test
-- | Test for exceptions.
--
-- Ordinarily, any test which throws an exception is deemed to have
-- failed. However, this test passes if evaluating the argument to
-- WHNF causes an exception to be thrown. The test fails if no
-- exception is thrown.
--
-- This can be useful for checking that functions reject invalid input by
-- throwing an exception. (Of course, you cannot check that the
-- correct exception is thrown!)
--
-- If WHNF is not enough to trigger the exception, you can wrap the
-- expression in some suitable forcing function. (The function
-- length . show can sometimes be used for this
-- purpose.)
--
-- Note that an infinite loop is not an exception (unless the loop
-- exhausts some resource).
--
-- If an exception is not thrown, the actual value returned is not
-- recorded. See throws for a function that records this
-- information. (Note that this requires adding a Show
-- constraint.)
throws_ :: x -> Test
-- | Test for exceptions.
--
-- Ordinarily, any test which throws an exception is deemed to have
-- failed. However, this test passes if evaluating the argument to
-- WHNF causes an exception to be thrown. The test fails if no
-- exception is thrown.
--
-- This can be useful for checking that functions reject invalid input by
-- throwing an exception. (Of course, you cannot check that the
-- correct exception is thrown!)
--
-- If WHNF is not enough to trigger the exception, you can wrap the
-- expression in some suitable forcing function. (The function
-- length . show can sometimes be used for this
-- purpose.)
--
-- Note that an infinite loop is not an exception (unless the loop
-- exhausts some resource).
--
-- If no exception is thrown, the actual value returned is recorded. This
-- requires adding a Show constraint. See throws_ for a
-- function without this constraint.
throws :: Show x => x -> Test
-- | Compare two values for equality.
--
-- The right-hand value is the "target" value, and the left-hand value
-- (next to the ? sign) is the "actual" value. The test passes
-- if both values are equal according to ==. The test fails if any
-- exceptions are thrown by == or show.
--
-- This operator has the same precedence as == (i.e., 4).
(?=) :: (Eq x, Show x) => x -> x -> Test
-- | Compare two values for inequality.
--
-- The right-hand value is the "target" value, and the left-hand value
-- (next to the ? sign) is the "actual" value. The test passes
-- if both values are unequal according to /=. The test fails if
-- any exceptions are thrown by /= or show.
--
-- This operator has the same precedence as /= (i.e., 4).
(?/=) :: (Eq x, Show x) => x -> x -> Test
-- | Compare two values for inequality.
--
-- The right-hand value is the "target" value, and the left-hand value
-- (next to the ? sign) is the "actual" value. The test passes
-- if the actual value is less than the target value according to
-- <. The test fails if any exceptions are thrown by
-- < or show.
--
-- This operator has the same precedence as < (i.e., 4).
(?<) :: (Ord x, Show x) => x -> x -> Test
-- | Compare two values for inequality.
--
-- The right-hand value is the "target" value, and the left-hand value
-- (next to the ? sign) is the "actual" value. The test passes
-- if the actual value is less than or equal to the target value
-- according to <=. The test fails if any exceptions are thrown
-- by <= or show.
--
-- This operator has the same precedence as <= (i.e., 4).
(?<=) :: (Ord x, Show x) => x -> x -> Test
-- | Compare two values for inequality.
--
-- The right-hand value is the "target" value, and the left-hand value
-- (next to the ? sign) is the "actual" value. The test passes
-- if the actual value is more than the target value according to
-- >. The test fails if any exceptions are thrown by
-- > or show.
--
-- This operator has the same precedence as > (i.e., 4).
(?>) :: (Ord x, Show x) => x -> x -> Test
-- | Compare two values for inequality.
--
-- The right-hand value is the "target" value, and the left-hand value
-- (next to the ? sign) is the "actual" value. The test passes
-- if the actual value is more than or equal to the target value
-- according to >=. The test fails if any exceptions are thrown
-- by >= or show.
--
-- This operator has the same precedence as >= (i.e., 4).
(?>=) :: (Ord x, Show x) => x -> x -> Test
-- | Attach a title to a test.
--
-- This title is an arbitrary human-readable label. It is recorded in
-- relation to the test, but has no other function.
title :: String -> Test -> Test
-- | Attach an argument value note.
--
-- The String is the argument name, and the x is that
-- argument's value, which must implement show.
argument :: Show x => String -> x -> Test -> Test
-- | Attach an argument value note.
--
-- The first String is the argument name, and the second is some
-- suitable textual representation of that argument's value.
argument_ :: String -> String -> Test -> Test
-- | Note down a temporary intermediate value computed in the process of
-- constructing a test.
--
-- The String is a name for this value, and the x is the
-- value itself, which must implement show.
temporary :: Show x => String -> x -> Test -> Test
-- | Note down a temporary intermediate value computed in the process of
-- constructing a test.
--
-- The first String is the temporary name, and the second is some
-- suitable textual representation of the temporary's value.
temporary_ :: String -> String -> Test -> Test
-- | Add a textual note to the test log.
note :: String -> Test -> Test
-- | Create a Test from an IO action that returns a
-- Bool.
--
-- The test passes if the value returned is True. The test fails
-- if the value returned is False, or if an uncaught exception
-- escapes.
testIO :: IO Bool -> Test
-- | Create a Test from an IO action with seperate set-up and
-- clean-up phases.
--
-- The first argument is a set-up action. This might be used to
-- initialise mutable storage or create disk structures, or just to open
-- some handles. Its result is passed to the second argument, which then
-- does the actual test propper. Finally, the third argument is run
-- (again with the set-up result as argument) to do any post-test
-- clean-up operations required. Its result is discarded.
--
-- If any of these IO actions throw an exception, the test is
-- marked failed. Note that if the set-up action throws an exception, the
-- test and clean-up actions are not run. (If only the main test action
-- throws an exception, the clean-up is still run.)
testIO3 :: IO x -> (x -> IO Bool) -> (x -> IO y) -> Test
-- | Test for exceptions in the IO monad.
--
-- Ordinarily, any test which throws an exception is deemed to have
-- failed. However, this test passes if evaluating the action's
-- result to WHNF causes an exception to be thrown. The test fails
-- if no exception is thrown.
--
-- This can be useful for checking that a function rejects invalid input
-- by throwing an exception, or that invalid I/O operations are reported.
-- (Of course, you cannot check that the correct exception is
-- thrown!)
--
-- Note that the IO action is run and its result is reduced
-- (to WHNF only). Note also that infinite loops are not exceptions
-- (unless the loop exhausts some resource).
--
-- If no exception is thrown, the actual value returned is not recorded.
-- See throwsIO for a function which does record this information.
-- (This requires adding a Show constraint.)
throws_IO :: IO x -> Test
-- | Test for exceptions in the IO monad.
--
-- Ordinarily, any test which throws an exception is deemed to have
-- failed. However, this test passes if evaluating the action's
-- result to WHNF causes an exception to be thrown. The test fails
-- if no exception is thrown.
--
-- This can be useful for checking that a function rejects invalid input
-- by throwing an exception, or that invalid I/O operations are reported.
-- (Of course, you cannot check that the correct exception is
-- thrown!)
--
-- Note that the IO action is run and its result is reduced
-- (to WHNF only). Note also that infinite loops are not exceptions
-- (unless the loop exhausts some resource).
--
-- If no exception is thrown, the actual value returned is recorded. This
-- requires adding a Show constraint; see throws_IO for a
-- function without this constraint.
throwsIO :: Show x => IO x -> Test
-- | The test monad.
--
-- Notice the MonadIO instance. This allows you to call
-- liftIO to perform arbitrary IO actions at any point
-- within the test monad.
data TestM x
-- | Create a Test from a TestM action.
--
-- The test passes if the TestM action returns True. The
-- test fails if it returns False or an uncaught exception
-- escapes.
testM :: TestM Bool -> Test
-- | Check a TestM action for exceptions.
--
-- Ordinarily, any test which throws an exception is deemed to have
-- failed. However, this test passes if evaluating the action's
-- result to WHNF causes an exception to be thrown. The test fails
-- if no exception is thrown.
--
-- This can be useful for checking that a function rejects invalid input
-- by throwing an exception, or that invalid I/O operations are reported.
-- (Of course, you cannot check that the correct exception is
-- thrown!)
--
-- Note that the TestM action is run and its result is
-- reduced (to WHNF only). Note also that infinite loops are not
-- exceptions (unless the loop exhausts some resource).
--
-- If no exception is thrown, the actual value returned is not recorded.
-- See throwsM for a function that does record the value. This
-- requires adding a Show constraint.
throws_M :: TestM x -> Test
-- | Check a TestM action for exceptions.
--
-- Ordinarily, any test which throws an exception is deemed to have
-- failed. However, this test passes if evaluating the action's
-- result to WHNF causes an exception to be thrown. The test fails
-- if no exception is thrown.
--
-- This can be useful for checking that a function rejects invalid input
-- by throwing an exception, or that invalid I/O operations are reported.
-- (Of course, you cannot check that the correct exception is
-- thrown!)
--
-- Note that the TestM action is run and its result is
-- reduced (to WHNF only). Note also that infinite loops are not
-- exceptions (unless the loop exhausts some resource).
--
-- If no exception is thrown, the actual value returns is recorded. This
-- requires adding a Show constraint. See throws_M for a
-- function without this constraint.
throwsM :: Show x => TestM x -> Test
-- | Mark the current test as "inapplicable" and return True. (See
-- inapplicable.)
inapplicableM :: TestM Bool
-- | Note down a temporary intermediate value computed in the process of
-- constructing a test.
--
-- The String is a name for this value, and the x is the
-- value itself, which must implement show.
temporaryM :: Show x => String -> x -> TestM ()
-- | Note down a temporary intermediate value computed in the process of
-- constructing a test.
--
-- The first String is the name, and the second is some suitable
-- textual representation of the value.
temporaryM_ :: String -> String -> TestM ()
-- | Add a textual note to the log file.
noteM :: String -> TestM ()
-- | Combine multiple tests into a single composite test.
--
-- The composite test fails if any of its constituent tests fail. Whether
-- the remaining tests are run depends on the testing mode (the
-- cfg_FailAbort parameter in TestConfig).
--
-- Essentially, this takes the logical-AND of several tests. You can
-- achieve the same result using the normal && operator or
-- the and function, operating on plain Bool values rather
-- than Test objects. However, by turning subexpressions into
-- Test objects and using tests, the result of each
-- subexpression will be logged to file in addition to the overall
-- result. Depending on the context, that may or may not be helpful. You
-- decide which you want.
tests :: [Test] -> Test
-- | Create a composite test which passes if at least one child test
-- passes.
--
-- All child tests are always run, regardless of error reporting mode. No
-- test failures are reported, unless all children fail.
--
-- Essentially, this takes the logical-OR of several tests. You can
-- achieve the same result using the normal || operator or the
-- or function, operating on plain Bool values rather than
-- Test objects. However, by turning subexpressions into
-- Test objects and using alternatives, the result of each
-- subexpression will be logged to file in addition to the overall
-- result. Depending on the context, that may or may not be helpful. You
-- decide which you want.
alternatives :: [Test] -> Test
-- | Execute a test.
--
-- Ordinarily, "the test" will be a composite test created with
-- tests, and will actually contain multiple sub-tests within it.
--
-- A Bool value is returned indicating whether the test was
-- successful or not. Test progress information is printed to
-- stdout. If any test fails, detailed information for that test
-- is printed to stdout, and testing aborts.
--
-- For more control, see run_test_full.
run_test :: Test -> IO Bool
-- | Execute a test.
--
-- Ordinarily, "the test" will be a composite test created with
-- tests, and will actually contain multiple sub-tests within it.
--
-- A Bool value is returned indicating whether the test was
-- successful or not. Test progress information is printed to
-- stdout. Various testing options can be configured using the
-- TestConfig argument. In particular, it is possible to log
-- detailed testing data to an XML log file (the cfg_LogFile
-- parameter).
--
-- The related run_test function runs a test with the
-- default_config test settings, which are useful for quick
-- interactive testing during a debugging session.
run_test_full :: TestConfig -> Test -> IO Bool
-- | Configuration settings for a test run.
data TestConfig
TestConfig :: Maybe FilePath -> Maybe String -> Bool -> Bool -> TestConfig
-- | If Nothing, no log file is produced. Otherwise, this is the
-- full path to the XML log file.
cfg_LogFile :: TestConfig -> Maybe FilePath
-- | Path to an XSL file. If given, the XML log file will use this XSL as a
-- stylesheet. This value is ignored if no XML log is produced.
cfg_LogXSL :: TestConfig -> Maybe String
-- | If True, report test failures to stdout. If
-- False, just report test progress to stdout.
cfg_FailReport :: TestConfig -> Bool
-- | If True, abort testing if a test fails, otherwise continue
-- testing. (In other words, False causes all tests to be
-- run, regardless of test failures, while True runs until a test
-- fails and then stops.)
cfg_FailAbort :: TestConfig -> Bool
-- | The default test configuration, as used by run_test.
--
--
-- cfg_LogFile = Nothing
-- cfg_LogXSL = Nothing
-- cfg_FailReport = True
-- cfg_FailAbort = True
--
--
-- You can use this as a starting point if you only want to customise a
-- few test settings. (More options may be added in future.)
default_config :: TestConfig
instance MonadIO TestM
instance Monad TestM
-- | Properties for testing that instances of the Eq class perform
-- correctly.
--
-- p_reflexive, p_symmetric and p_transitive check
-- the basic properties of an equity relation. In other words, they test
-- the == method. p_not_equal checks for the
-- extraordinarily unlikely case of == and /= not agreeing
-- on equity. (The default implementation of /= automatically
-- guarantees that this test will pass, and that's what most people
-- presumably use.)
module Test.AC.Class.Eq
-- | Check that x == x.
p_reflexive :: (Show x, Eq x) => x -> Test
-- | Check that if x == y then y == x as well.
p_symmetric :: (Show x, Eq x) => x -> x -> Test
-- | Check that if x == y and y == z then x ==
-- z.
p_transitive :: (Show x, Eq x) => x -> x -> x -> Test
-- | Check that x /= y is the same as not (x == y).
p_not_equal :: (Show x, Eq x) => x -> x -> Test
-- | Given a list of distinct values, perform all applicable tests
-- on all possible combinations of inputs. (If the inputs are not
-- distinct, some redundant tests are performed.)
p_Eq :: (Show x, Eq x) => [x] -> Test
-- | Properties for testing that instances of the Ord class perform
-- correctly.
--
-- p_symmetric and p_transitive check the basic properties
-- of the ordering. In other words, they test the compare method.
-- p_equal checks that Ord agrees with Eq (that is,
-- compare returns EQ when == returns True).
-- The Test.AC.Class.Eq module already checks that Eq is
-- reflexive, so if Ord agrees with Eq then Ord too
-- is reflexive, and we don't need a seperate test for that. The
-- remaining tests (i.e., p_compare, p_min and
-- p_max) check for the extraordinarily unlikely case that the
-- various Ord methods do not agree with each other. (Usually they
-- are implemented in terms of each other.)
module Test.AC.Class.Ord
-- | Check that compare agrees with == on equity.
p_equal :: (Show x, Ord x) => x -> x -> Test
-- | Check that swapping the arguments to compare works correctly.
p_symmetric :: (Show x, Ord x) => x -> x -> Test
-- | Check that if x < y and y < z then x <
-- z.
p_transitive :: (Show x, Ord x) => x -> x -> x -> Test
-- | Check that compare agrees with >, <, etc.
p_compare :: (Show x, Ord x) => x -> x -> Test
-- | Check that min works correctly.
p_min :: (Show x, Ord x) => x -> x -> Test
-- | Check that max works correctly.
p_max :: (Show x, Ord x) => x -> x -> Test
-- | Given a list of distinct values, perform all applicable tests
-- on all possible combinations of inputs. (If the inputs are not
-- distinct, some redundant tests are performed.)
p_Ord :: (Show x, Ord x) => [x] -> Test
-- | Defines the Label type, for making values showable.
module Test.AC.Label
-- | The Label type.
--
-- A value of type Label x is really a value of type x,
-- but with a textual label. The Show instance returns this label.
--
-- This can be tremendously useful for allowing you to show values
-- which would not otherwise be printable. For example, functions. Rather
-- than passing a function, you can pass a labelled function. This allows
-- you to know, at runtime, which function you're dealing with,
-- which is very useful for test purposes.
--
-- You can use label to extract the label text, and value
-- to extract the actual data value.
--
-- The Show instance uses the label, but the other
-- instances use only the value, ignoring the label. (In
-- particular, any operations which alter the value leave the
-- label untouched.)
data Label x
Label :: String -> !x -> Label x
label :: Label x -> String
value :: Label x -> !x
-- | This type is similar to Label. However, Label cannot be
-- made an instance of higher-kinded classes such as Functor and
-- Monad. This type gets around that irritating limitation.
data Label1 c x1
Label1 :: String -> c x1 -> Label1 c x1
label1 :: Label1 c x1 -> String
value1 :: Label1 c x1 -> c x1
instance Monad c => Monad (Label1 c)
instance Functor c => Functor (Label1 c)
instance Show (Label1 c x1)
instance Bounded (c x1) => Bounded (Label1 c x1)
instance Enum (c x1) => Enum (Label1 c x1)
instance Ord (c x1) => Ord (Label1 c x1)
instance Eq (c x1) => Eq (Label1 c x1)
instance Show (Label x)
instance Bounded x => Bounded (Label x)
instance Enum x => Enum (Label x)
instance Ord x => Ord (Label x)
instance Eq x => Eq (Label x)
-- | Properties for testing that instances of the Functor class
-- perform correctly.
--
-- This testing requires an Eq instance, which not all
-- Functors actually have. It also requires a Show
-- instance, which is also uncommon. The Label1 wrapper may be
-- useful in dealing with the Show requirement.
--
-- Tests are supplied both in regular "unlabelled" form, and also in a
-- special "labelled" form, where function objects have Labels
-- attached to them. Because of this, the function used for each test can
-- be recorded in the test log, which can be quite helpful.
module Test.AC.Class.Functor
-- | Check that fmap id == id.
p_map_id :: (Functor f, Eq (f x), Show (f x)) => f x -> Test
-- | Check that fmap (f . g) == fmap
-- f . fmap g.
p_map_compose :: (Functor f, Eq (f z), Show (f x), Show (f y), Show (f z)) => f x -> (x -> y) -> (y -> z) -> Test
-- | Given a list of distinct Functor values and functions,
-- perform all tests on all combinations of inputs. (If the inputs are
-- not distinct, some redundant tests will be performed.)
--
-- The argument types are somewhat constrained to keep the type signature
-- reasonably simple.
p_Functor :: (Functor f, Eq (f x), Show (f x)) => [f x] -> [x -> x] -> Test
-- | Check that fmap (f . g) == fmap
-- f . fmap g.
p_map_compose_L :: (Functor f, Eq (f z), Show (f x), Show (f y), Show (f z)) => f x -> Label (x -> y) -> Label (y -> z) -> Test
-- | Given a list of distinct Functor values and functions,
-- perform all tests on all combinations of inputs. (If the inputs are
-- not distinct, some redundant tests will be performed.)
--
-- The argument types are somewhat constrained to keep the function's
-- type signature reasonably simple.
p_Functor_L :: (Functor f, Eq (f x), Show (f x)) => [f x] -> [Label (x -> x)] -> Test
-- | Properties for testing that instances of the Monad class
-- perform correctly.
--
-- This testing requires an Eq instance, which not all
-- Monads actually have. It also requires a Show instance,
-- which is also uncommon. The Label1 wrapper may be useful in
-- dealing with the Show requirement.
--
-- Tests are supplied both in regular "unlabelled" form, and also in a
-- special "labelled" form, where function objects have Labels
-- attached to them. Because of this, the function used for each test can
-- be recorded in the test log, which can be quite helpful.
module Test.AC.Class.Monad
-- | Check that return x >>= f == f x.
p_return_bind :: (Monad m, Eq (m y), Show x, Show (m x), Show (m y)) => x -> (x -> m y) -> Test
-- | Check that mx >>= return == mx.
p_bind_return :: (Monad m, Eq (m x), Show (m x)) => m x -> Test
-- | Check that >>= is associative.
--
-- Approximately, mx >>= (f >>= g) == (mx
-- >>= f) >>= g, but that doesn't type-check. To be
-- exact, mx >>= (\ x -> f x >>= g) == (mx
-- >>= f) >>= g.
p_bind_associative :: (Monad m, Eq (m z), Show (m x), Show (m y), Show (m z)) => m x -> (x -> m y) -> (y -> m z) -> Test
-- | Given a list of distinct inputs, run all applicable
-- Monad tests on all combinations of inputs. (If the inputs are
-- not distinct, some redundant tests will be performed.)
--
-- The argument types have been constrainted a bit to keep the function's
-- type signature reasonably simple.
p_Monad :: (Monad m, Eq (m x), Show x, Show (m x)) => [x] -> [x -> m x] -> [m x] -> Test
-- | Check that fmap f mx == mx >>= return . f.
p_Functor_Monad :: (Functor m, Monad m, Eq (m y), Show (m x), Show (m y)) => m x -> (x -> y) -> Test
-- | Check that return x >>= f == f x.
p_return_bind_L :: (Monad m, Eq (m y), Show x, Show (m x), Show (m y)) => x -> Label (x -> m y) -> Test
-- | Check that >>= is associative.
--
-- Approximately, mx >>= (f >>= g) == (mx
-- >>= f) >>= g, but that doesn't type-check. To be
-- exact, mx >>= (\ x -> f x >>= g) == (mx
-- >>= f) >>= g.
p_bind_associative_L :: (Monad m, Eq (m z), Show (m x), Show (m y), Show (m z)) => m x -> Label (x -> m y) -> Label (y -> m z) -> Test
-- | Given a list of distinct inputs, run all applicable
-- Monad tests on all combinations of inputs. (If the inputs are
-- not distinct, some redundant tests will be performed.)
--
-- The argument types have been constrainted a bit to keep the function's
-- type signature reasonably simple.
p_Monad_L :: (Monad m, Eq (m x), Show x, Show (m x)) => [x] -> [Label (x -> m x)] -> [m x] -> Test
-- | Check that fmap f mx == mx >>= return . f.
p_Functor_Monad_L :: (Functor m, Monad m, Eq (m y), Show (m x), Show (m y)) => m x -> Label (x -> y) -> Test