packages feed

aeson-gadt-th-0.2.1.2: test/Expectations.hs

-- | Some useful helper expectations for use with Hspec.
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Expectations where

import Control.Exception (PatternMatchFail, evaluate, throwIO, try)
import Data.Maybe
import GHC.Stack (HasCallStack, callStack, getCallStack, SrcLoc)
import Test.Hspec
import qualified Test.HUnit.Lang as HUnit

-- | Assert that a pattern match succeeds; may require -fno-warn-incomplete-patterns
expectPattern :: (HasCallStack, Show a) => (a -> b) -> a -> IO b
expectPattern f a =
  try (evaluate $ f a) >>= \case
    Right b -> pure b
    Left (e :: PatternMatchFail) ->
      throwHUnit $ "Pattern match failed, value was: " ++ show a

-- | Same as 'expectPattern' but with its arguments flipped.
shouldMatchPattern :: (HasCallStack, Show a) => a -> (a -> b) -> IO b
shouldMatchPattern = flip expectPattern

-- | Same as 'shouldMatchPattern' but with the return type specialized as unit.
-- Useful for pattern matching on GADTs.
shouldMatchPattern_ :: (HasCallStack, Show a) => a -> (a -> ()) -> IO ()
shouldMatchPattern_ = shouldMatchPattern

-- | Obtain the source location given a reverse call stack index.
callStackLoc :: (HasCallStack) => Int -> Maybe SrcLoc
callStackLoc index = fmap snd $ listToMaybe $ drop index $ reverse $ getCallStack callStack

-- | Throw an test failed exception, defaulting the source location to the caller's caller.
throwHUnit :: (HasCallStack) => String -> IO a
throwHUnit = throwHUnitWithLoc 0

-- | Throw a test failure exception with source location determined by the supplied reverse call stack index.
throwHUnitWithLoc :: (HasCallStack) => Int -> String -> IO a
throwHUnitWithLoc index msg = throwIO $ HUnit.HUnitFailure (callStackLoc index) $ HUnit.Reason msg