{-# LANGUAGE CPP #-}

module Test.Validity.Property.Utils
    ( forAllUnchecked
    , forAllValid
    , forAllInvalid
    , shouldBeValid
    , shouldBeInvalid
    , (<==>)
    , (===>)
    ) where

import Data.GenValidity
import Test.Hspec
import Test.QuickCheck

#if !MIN_VERSION_base(4,8,0)
import Control.Applicative (pure)
#endif

import Text.Show.Pretty (ppShow)

forAllUnchecked ::
       (Show a, GenUnchecked a, Testable prop) => (a -> prop) -> Property
forAllUnchecked :: (a -> prop) -> Property
forAllUnchecked = Gen a -> (a -> [a]) -> (a -> prop) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> [a]) -> (a -> prop) -> Property
forAllShrink Gen a
forall a. GenUnchecked a => Gen a
genUnchecked a -> [a]
forall a. GenUnchecked a => a -> [a]
shrinkUnchecked

forAllValid :: (Show a, GenValid a, Testable prop) => (a -> prop) -> Property
forAllValid :: (a -> prop) -> Property
forAllValid = Gen a -> (a -> [a]) -> (a -> prop) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> [a]) -> (a -> prop) -> Property
forAllShrink Gen a
forall a. GenValid a => Gen a
genValid a -> [a]
forall a. GenValid a => a -> [a]
shrinkValid

forAllInvalid ::
       (Show a, GenInvalid a, Testable prop) => (a -> prop) -> Property
forAllInvalid :: (a -> prop) -> Property
forAllInvalid = Gen a -> (a -> [a]) -> (a -> prop) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> [a]) -> (a -> prop) -> Property
forAllShrink Gen a
forall a. GenInvalid a => Gen a
genInvalid a -> [a]
forall a. GenInvalid a => a -> [a]
shrinkInvalid

(===>) :: Bool -> Bool -> Bool
===> :: Bool -> Bool -> Bool
(===>) a :: Bool
a b :: Bool
b = Bool -> Bool
not Bool
a Bool -> Bool -> Bool
|| Bool
b

(<==>) :: Bool -> Bool -> Bool
<==> :: Bool -> Bool -> Bool
(<==>) a :: Bool
a b :: Bool
b = Bool
a Bool -> Bool -> Bool
===> Bool
b Bool -> Bool -> Bool
&& Bool
b Bool -> Bool -> Bool
===> Bool
a

shouldBeValid :: (Show a, Validity a) => a -> Expectation
shouldBeValid :: a -> Expectation
shouldBeValid a :: a
a =
    case a -> Either String a
forall a. Validity a => a -> Either String a
prettyValidate a
a of
        Right _ -> () -> Expectation
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        Left err :: String
err ->
            HasCallStack => String -> Expectation
String -> Expectation
expectationFailure (String -> Expectation) -> String -> Expectation
forall a b. (a -> b) -> a -> b
$
            [String] -> String
unlines
                [ "'validate' reported this value to be invalid: "
                , a -> String
forall a. Show a => a -> String
show a
a
                , "pretty version:"
                , a -> String
forall a. Show a => a -> String
ppShow a
a
                , "with explanation:"
                , String
err
                , ""
                ]

shouldBeInvalid :: (Show a, Validity a) => a -> Expectation
shouldBeInvalid :: a -> Expectation
shouldBeInvalid a :: a
a =
    case a -> Either String a
forall a. Validity a => a -> Either String a
prettyValidate a
a of
        Right _ ->
            HasCallStack => String -> Expectation
String -> Expectation
expectationFailure (String -> Expectation) -> String -> Expectation
forall a b. (a -> b) -> a -> b
$
            [String] -> String
unlines
                [ "'validate' reported this value to be valid: "
                , a -> String
forall a. Show a => a -> String
show a
a
                , "pretty version:"
                , a -> String
forall a. Show a => a -> String
ppShow a
a
                , "where we expected it to be invalid"
                ]
        Left _ -> () -> Expectation
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()