{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE QuantifiedConstraints #-}
module Hedgehog.Classes.Common.Property
( heq, heq1, heq2
, heqCtx, heqCtx1, heqCtx2
, hneq, hneq1, hneq2
, hneqCtx, hneqCtx1, hneqCtx2
, himplCtx
, hLessThan, hGreaterThan
, hLessThanCtx, hGreaterThanCtx
, bar
, Context(..)
) where
import Control.Exception (SomeException(..), displayException)
import Data.Typeable (typeOf)
import GHC.Stack
import Hedgehog.Classes.Common.Compat
import Hedgehog.Internal.Exception (tryEvaluate)
import Hedgehog.Internal.Property (MonadTest, liftTest, mkTest, success, discard, Failure(..), PropertyT)
import Text.Show.Pretty (ppShow)
import qualified Data.Char as Char
import qualified Data.List as List
bar :: String
bar = "━━━"
bar5 :: String
bar5 = "━━━━━━━━━━━━━━━"
evalNoSrc :: (MonadTest m, HasCallStack) => a -> m a
evalNoSrc x = either (withFrozenCallStack failExceptionNoSrc) pure (tryEvaluate x)
failWithNoSrc :: (MonadTest m, HasCallStack) => String -> m a
failWithNoSrc msg = do
liftTest $ mkTest (Left $ Failure Nothing msg Nothing, mempty)
failExceptionNoSrc :: (MonadTest m, HasCallStack) => SomeException -> m a
failExceptionNoSrc (SomeException x) = withFrozenCallStack $
failWithNoSrc $ unlines
[ bar ++ " Exception: " ++ show (typeOf x) ++ " " ++ bar
, List.dropWhileEnd Char.isSpace (displayException x)
]
data Context = NoContext | Context String
contextToString :: Context -> String
contextToString = \case
NoContext -> "No Context provided."
Context ctx -> bar ++ " Context " ++ bar ++ "\n" ++ ctx ++ "\n" ++ bar5
failContext::
( MonadTest m, HasCallStack
) => Context -> m ()
failContext ctx = withFrozenCallStack $
failWithNoSrc $ contextToString ctx
hLessThanCtx ::
( MonadTest m
, Ord a
, Show a
, HasCallStack
) => a -> a -> Context -> m ()
hLessThanCtx x y ctx = do
ok <- withFrozenCallStack $ evalNoSrc (x < y)
if ok
then success
else withFrozenCallStack $ failContext ctx
hGreaterThanCtx ::
( MonadTest m
, Ord a
, Show a
, HasCallStack
) => a -> a -> Context -> m ()
hGreaterThanCtx x y ctx = do
ok <- withFrozenCallStack $ evalNoSrc (x > y)
if ok
then success
else withFrozenCallStack $ failContext ctx
hLessThan :: (MonadTest m, Ord a, Show a, HasCallStack) => a -> a -> m ()
hLessThan x y = do
ok <- withFrozenCallStack $ evalNoSrc (x < y)
if ok
then success
else withFrozenCallStack $ failWithNoSrc $ unlines
[ bar ++ "Not Less Than " ++ bar
, ppShow x ++ " is not less than " ++ ppShow y
]
hGreaterThan :: (MonadTest m, Ord a, Show a, HasCallStack) => a -> a -> m ()
hGreaterThan x y = do
ok <- withFrozenCallStack $ evalNoSrc (x > y)
if ok
then success
else withFrozenCallStack $ failWithNoSrc $ unlines
[ bar ++ "Not Greater Than " ++ bar
, ppShow x ++ " is not greater than " ++ ppShow y
]
infix 4 `hneq`
hneqCtx ::
( MonadTest m
, HasCallStack
, Eq a
, Show a
) => a -> a -> Context -> m ()
hneqCtx x y ctx = do
ok <- withFrozenCallStack $ evalNoSrc (x `neq` y)
if ok
then success
else withFrozenCallStack $ failContext ctx
hneq ::
( MonadTest m
, HasCallStack
, Eq a
, Show a
) => a -> a -> m ()
hneq x y = hneqCtx x y NoContext
infix 4 `heq`
heqCtx ::
( MonadTest m
, HasCallStack
, Eq a
, Show a
) => a -> a -> Context -> m ()
heqCtx x y ctx = do
ok <- withFrozenCallStack $ evalNoSrc (x `eq` y)
if ok
then success
else withFrozenCallStack $ failContext ctx
heq ::
( MonadTest m
, HasCallStack
, Eq a
, Show a
) => a -> a -> m ()
heq x y = heqCtx x y NoContext
infix 4 `heq1`
hneqCtx1 ::
( MonadTest m
, HasCallStack
, Eq a
, Show a
, forall x. Eq x => Eq (f x)
, forall x. Show x => Show (f x)
) => f a -> f a -> Context -> m ()
hneqCtx1 x y ctx = do
ok <- withFrozenCallStack $ evalNoSrc (x `neq1` y)
if ok
then success
else withFrozenCallStack $ failContext ctx
hneq1 ::
( MonadTest m
, HasCallStack
, Eq a
, Show a
, forall x. Eq x => Eq (f x)
, forall x. Show x => Show (f x)
) => f a -> f a -> m ()
hneq1 x y = hneqCtx1 x y NoContext
heqCtx1 ::
( MonadTest m
, HasCallStack
, Eq a
, Show a
, forall x. Eq x => Eq (f x)
, forall x. Show x => Show (f x)
) => f a -> f a -> Context -> m ()
heqCtx1 x y ctx = do
ok <- withFrozenCallStack $ evalNoSrc (x `eq1` y)
if ok
then success
else withFrozenCallStack $ failContext ctx
heq1 ::
( MonadTest m
, HasCallStack
, Eq a
, Show a
, forall x. Eq x => Eq (f x)
, forall x. Show x => Show (f x)
) => f a -> f a -> m ()
heq1 x y = heqCtx1 x y NoContext
infix 4 `heq2`
heqCtx2 ::
( MonadTest m
, HasCallStack
, Eq a
, Eq b
, Show a
, Show b
, forall x y. (Eq x, Eq y) => Eq (f x y)
, forall x y. (Show x, Show y) => Show (f x y)
) => f a b -> f a b -> Context -> m ()
heqCtx2 x y ctx = do
ok <- withFrozenCallStack $ evalNoSrc (x `eq2` y)
if ok
then success
else withFrozenCallStack $ failContext ctx
heq2 ::
( MonadTest m
, HasCallStack
, Eq a
, Eq b
, Show a
, Show b
, forall x y. (Eq x, Eq y) => Eq (f x y)
, forall x y. (Show x, Show y) => Show (f x y)
) => f a b -> f a b -> m ()
heq2 x y = heqCtx2 x y NoContext
infix 4 `hneq2`
hneqCtx2 ::
( MonadTest m
, HasCallStack
, Eq a
, Eq b
, Show a
, Show b
, forall x y. (Eq x, Eq y) => Eq (f x y)
, forall x y. (Show x, Show y) => Show (f x y)
) => f a b -> f a b -> Context -> m ()
hneqCtx2 x y ctx = do
ok <- withFrozenCallStack $ evalNoSrc (x `neq2` y)
if ok
then success
else withFrozenCallStack $ failContext ctx
hneq2 ::
( MonadTest m
, HasCallStack
, Eq a
, Eq b
, Show a
, Show b
, forall x y. (Eq x, Eq y) => Eq (f x y)
, forall x y. (Show x, Show y) => Show (f x y)
) => f a b -> f a b -> m ()
hneq2 x y = hneqCtx2 x y NoContext
himplCtx ::
( Monad m
, HasCallStack
) => Bool -> Bool -> Context -> PropertyT m ()
himplCtx False _ _ = discard
himplCtx True b ctx = if b
then success
else withFrozenCallStack $ failContext ctx