content: -- | Unit testing support for tasty, inspired by the HUnit package.
  --
  -- Here's an example (a single tasty test case consisting of three
  -- assertions):
  --
  -- >import Test.Tasty
  -- >import Test.Tasty.HUnit
  -- >
  -- >main = defaultMain $
  -- >  testCase "Example test case" $ do
  -- >    -- assertion no. 1 (passes)
  -- >    2 + 2 @?= 4
  -- >    -- assertion no. 2 (fails)
  -- >    assertBool "the list is not empty" $ null [1]
  -- >    -- assertion no. 3 (would have failed, but won't be executed because
  -- >    -- the previous assertion has already failed)
  -- >    "foo" @?= "bar"
  {-# LANGUAGE TypeFamilies #-}
  module Test.Tasty.HUnit
    (
      -- * Constructing test cases
      testCase
    , testCaseInfo
    , testCaseSteps
      -- * Constructing assertions
    , assertFailure
    , assertBool
    , assertEqual
    , (@=?)
    , (@?=)
    , (@?)
    , AssertionPredicable(..)
      -- * Data types
    , Assertion
    , HUnitFailure(..)
      -- * Accurate location for domain-specific assertion functions
      -- | It is common to define domain-specific assertion functions based
      -- on the standard ones, e.g.
      --
      -- > assertNonEmpty = assertBool "List is empty" . not . null
      --
      -- The problem is that if a test fails, tasty-hunit will point to the
      -- definition site of @assertNonEmpty@ as the source of failure, not
      -- its use site.
      --
      -- To correct this, add a 'HasCallStack' constraint (re-exported from
      -- this module) to your function:
      --
      -- > assertNonEmpty :: HasCallStack => [a] -> Assertion
      -- > assertNonEmpty = assertBool "List is empty" . not . null
      --
      , HasCallStack
      -- * Deprecated functions and types
      -- | These definitions come from HUnit, but I don't see why one would
      -- need them. If you have a valid use case for them, please contact me
      -- or file an issue for tasty. Otherwise, they will eventually be
      -- removed.
    , assertString
    , Assertable(..)
    , AssertionPredicate
    ) where
  
  import Test.Tasty.Providers
  
  import Test.Tasty.HUnit.Orig
  import Test.Tasty.HUnit.Steps
  
  import Data.CallStack (HasCallStack)
  import Control.Exception
  
  -- | Turn an 'Assertion' into a tasty test case
  testCase :: TestName -> Assertion -> TestTree
  testCase name = singleTest name . TestCase . (fmap (const ""))
  
  -- | Like 'testCase', except in case the test succeeds, the returned string
  -- will be shown as the description. If the empty string is returned, it
  -- will be ignored.
  testCaseInfo :: TestName -> IO String -> TestTree
  testCaseInfo name = singleTest name . TestCase
  
  -- IO String is a computation that throws an exception upon failure or
  -- returns an informational string otherwise. This allows us to unify the
  -- implementation of 'testCase' and 'testCaseInfo'.
  --
  -- In case of testCase, we simply make the result string empty, which makes
  -- tasty ignore it.
  newtype TestCase = TestCase (IO String)
  
  instance IsTest TestCase where
    run _ (TestCase assertion) _ = do
    -- The standard HUnit's performTestCase catches (almost) all exceptions.
    --
    -- This is bad for a few reasons:
    -- - it interferes with timeout handling
    -- - it makes exception reporting inconsistent across providers
    -- - it doesn't provide enough information for ingredients such as
    -- tasty-rerun
    --
    -- So we do it ourselves.
      hunitResult <- try assertion
      return $
        case hunitResult of
          Right info -> testPassed info
          Left (HUnitFailure mbloc message) -> testFailed $ prependLocation mbloc message
  
    testOptions = return []
  