{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE AllowAmbiguousTypes #-}

-- | Ord properties
--
-- You will need @TypeApplications@ to use these.
module Test.Validity.Ord
    ( ordSpecOnGen
    , ordSpecOnValid
    , ordSpecOnInvalid
    , ordSpec
    , ordSpecOnArbitrary
    ) where

import Data.Data

import Data.GenValidity

import Test.Hspec
import Test.QuickCheck

import Test.Validity.Functions
import Test.Validity.Relations
import Test.Validity.Utils

{-# ANN module "HLint: ignore Use <=" #-}

{-# ANN module "HLint: ignore Use >=" #-}

{-# ANN module "HLint: ignore Use <" #-}

{-# ANN module "HLint: ignore Use >" #-}

leTypeStr ::
       forall a. Typeable a
    => String
leTypeStr :: String
leTypeStr = String -> String
forall k (a :: k). Typeable a => String -> String
binRelStr @a "<="

geTypeStr ::
       forall a. Typeable a
    => String
geTypeStr :: String
geTypeStr = String -> String
forall k (a :: k). Typeable a => String -> String
binRelStr @a ">="

ltTypeStr ::
       forall a. Typeable a
    => String
ltTypeStr :: String
ltTypeStr = String -> String
forall k (a :: k). Typeable a => String -> String
binRelStr @a "<"

gtTypeStr ::
       forall a. Typeable a
    => String
gtTypeStr :: String
gtTypeStr = String -> String
forall k (a :: k). Typeable a => String -> String
binRelStr @a ">"

-- | Standard test spec for properties of Ord instances for valid values
--
-- Example usage:
--
-- > ordSpecOnValid @Double
ordSpecOnValid ::
       forall a. (Show a, Ord a, Typeable a, GenValid a)
    => Spec
ordSpecOnValid :: Spec
ordSpecOnValid = Gen a -> String -> (a -> [a]) -> Spec
forall a.
(Show a, Eq a, Ord a, Typeable a) =>
Gen a -> String -> (a -> [a]) -> Spec
ordSpecOnGen @a Gen a
forall a. GenValid a => Gen a
genValid "valid" a -> [a]
forall a. GenValid a => a -> [a]
shrinkValid

-- | Standard test spec for properties of Ord instances for invalid values
--
-- Example usage:
--
-- > ordSpecOnInvalid @Double
ordSpecOnInvalid ::
       forall a. (Show a, Ord a, Typeable a, GenInvalid a)
    => Spec
ordSpecOnInvalid :: Spec
ordSpecOnInvalid = Gen a -> String -> (a -> [a]) -> Spec
forall a.
(Show a, Eq a, Ord a, Typeable a) =>
Gen a -> String -> (a -> [a]) -> Spec
ordSpecOnGen @a Gen a
forall a. GenInvalid a => Gen a
genInvalid "invalid" a -> [a]
forall a. GenInvalid a => a -> [a]
shrinkInvalid

-- | Standard test spec for properties of Ord instances for unchecked values
--
-- Example usage:
--
-- > ordSpec @Int
ordSpec ::
       forall a. (Show a, Ord a, Typeable a, GenUnchecked a)
    => Spec
ordSpec :: Spec
ordSpec = Gen a -> String -> (a -> [a]) -> Spec
forall a.
(Show a, Eq a, Ord a, Typeable a) =>
Gen a -> String -> (a -> [a]) -> Spec
ordSpecOnGen @a Gen a
forall a. GenUnchecked a => Gen a
genUnchecked "unchecked" a -> [a]
forall a. GenUnchecked a => a -> [a]
shrinkUnchecked

-- | Standard test spec for properties of Ord instances for arbitrary values
--
-- Example usage:
--
-- > ordSpecOnArbitrary @Int
ordSpecOnArbitrary ::
       forall a. (Show a, Ord a, Typeable a, Arbitrary a)
    => Spec
ordSpecOnArbitrary :: Spec
ordSpecOnArbitrary = Gen a -> String -> (a -> [a]) -> Spec
forall a.
(Show a, Eq a, Ord a, Typeable a) =>
Gen a -> String -> (a -> [a]) -> Spec
ordSpecOnGen @a Gen a
forall a. Arbitrary a => Gen a
arbitrary "arbitrary" a -> [a]
forall a. Arbitrary a => a -> [a]
shrink

-- | Standard test spec for properties of Ord instances for values generated by a given generator (and name for that generator).
--
-- Example usage:
--
-- > ordSpecOnGen ((* 2) <$> genValid @Int) "even"
ordSpecOnGen ::
       forall a. (Show a, Eq a, Ord a, Typeable a)
    => Gen a
    -> String
    -> (a -> [a])
    -> Spec
ordSpecOnGen :: Gen a -> String -> (a -> [a]) -> Spec
ordSpecOnGen gen :: Gen a
gen genname :: String
genname s :: a -> [a]
s =
    Spec -> Spec
forall a. SpecWith a -> SpecWith a
parallel (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
        let name :: String
name = Typeable a => String
forall k (a :: k). Typeable a => String
nameOf @a
            funlestr :: String
funlestr = Typeable a => String
forall a. Typeable a => String
leTypeStr @a
            fungestr :: String
fungestr = Typeable a => String
forall a. Typeable a => String
geTypeStr @a
            funltstr :: String
funltstr = Typeable a => String
forall a. Typeable a => String
ltTypeStr @a
            fungtstr :: String
fungtstr = Typeable a => String
forall a. Typeable a => String
gtTypeStr @a
            minmaxtstr :: String -> String
minmaxtstr = Typeable (a -> a -> a) => String -> String
forall k (a :: k). Typeable a => String -> String
genDescr @(a->a->a)
            itProp :: String -> a -> SpecWith (Arg a)
itProp s_ :: String
s_ = String -> a -> SpecWith (Arg a)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it (String -> a -> SpecWith (Arg a))
-> String -> a -> SpecWith (Arg a)
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
                [ String
s_
                  , "\"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
genname
                  , String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ "\"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ "'s"
                ]
            cmple :: a -> a -> Bool
cmple = Ord a => a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(<=) @a
            cmpge :: a -> a -> Bool
cmpge = Ord a => a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(>=) @a
            cmplt :: a -> a -> Bool
cmplt = Ord a => a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(<) @a
            cmpgt :: a -> a -> Bool
cmpgt = Ord a => a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(>) @a
            gen2 :: Gen (a, a)
gen2 = (,) (a -> a -> (a, a)) -> Gen a -> Gen (a -> (a, a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen a
gen Gen (a -> (a, a)) -> Gen a -> Gen (a, a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen a
gen
            gen3 :: Gen (a, a, a)
gen3 = (,,) (a -> a -> a -> (a, a, a)) -> Gen a -> Gen (a -> a -> (a, a, a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen a
gen Gen (a -> a -> (a, a, a)) -> Gen a -> Gen (a -> (a, a, a))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen a
gen Gen (a -> (a, a, a)) -> Gen a -> Gen (a, a, a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen a
gen
            s2 :: (a, a) -> [(a, a)]
s2 = (a -> [a]) -> (a, a) -> [(a, a)]
forall a. (a -> [a]) -> (a, a) -> [(a, a)]
shrinkT2 a -> [a]
s
        String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe ("Ord " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
            String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
funlestr (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is reflexive for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen a -> (a -> [a]) -> Property
forall a.
Show a =>
(a -> a -> Bool) -> Gen a -> (a -> [a]) -> Property
reflexivityOnGen a -> a -> Bool
cmple Gen a
gen a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is antisymmetric for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
forall a.
(Show a, Eq a) =>
(a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
antisymmetryOnGens a -> a -> Bool
cmple Gen (a, a)
gen2 a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is transitive for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen (a, a, a) -> (a -> [a]) -> Property
forall a.
Show a =>
(a -> a -> Bool) -> Gen (a, a, a) -> (a -> [a]) -> Property
transitivityOnGens a -> a -> Bool
cmple Gen (a, a, a)
gen3 a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is equivalent to (\\a b -> compare a b /= GT) for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool)
-> (a -> a -> Bool)
-> Gen (a, a)
-> ((a, a) -> [(a, a)])
-> Property
forall a b c.
(Show a, Show b, Show c, Eq c) =>
(a -> b -> c)
-> (a -> b -> c) -> Gen (a, b) -> ((a, b) -> [(a, b)]) -> Property
equivalentOnGens2 a -> a -> Bool
cmple (\a :: a
a b :: a
b -> a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
b Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
/= Ordering
GT) Gen (a, a)
gen2 (a, a) -> [(a, a)]
s2
            String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
fungestr (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is reflexive for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen a -> (a -> [a]) -> Property
forall a.
Show a =>
(a -> a -> Bool) -> Gen a -> (a -> [a]) -> Property
reflexivityOnGen a -> a -> Bool
cmpge Gen a
gen a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is antisymmetric for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
forall a.
(Show a, Eq a) =>
(a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
antisymmetryOnGens a -> a -> Bool
cmpge Gen (a, a)
gen2 a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is transitive for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen (a, a, a) -> (a -> [a]) -> Property
forall a.
Show a =>
(a -> a -> Bool) -> Gen (a, a, a) -> (a -> [a]) -> Property
transitivityOnGens a -> a -> Bool
cmpge Gen (a, a, a)
gen3 a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is equivalent to (\\a b -> compare a b /= LT) for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool)
-> (a -> a -> Bool)
-> Gen (a, a)
-> ((a, a) -> [(a, a)])
-> Property
forall a b c.
(Show a, Show b, Show c, Eq c) =>
(a -> b -> c)
-> (a -> b -> c) -> Gen (a, b) -> ((a, b) -> [(a, b)]) -> Property
equivalentOnGens2 a -> a -> Bool
cmpge (\a :: a
a b :: a
b -> a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
b Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
/= Ordering
LT) Gen (a, a)
gen2 (a, a) -> [(a, a)]
s2
            String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
funltstr (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is antireflexive for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen a -> (a -> [a]) -> Property
forall a.
Show a =>
(a -> a -> Bool) -> Gen a -> (a -> [a]) -> Property
antireflexivityOnGen a -> a -> Bool
cmplt Gen a
gen a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is transitive for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen (a, a, a) -> (a -> [a]) -> Property
forall a.
Show a =>
(a -> a -> Bool) -> Gen (a, a, a) -> (a -> [a]) -> Property
transitivityOnGens a -> a -> Bool
cmplt Gen (a, a, a)
gen3 a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is equivalent to (\\a b -> compare a b == LT) for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool)
-> (a -> a -> Bool)
-> Gen (a, a)
-> ((a, a) -> [(a, a)])
-> Property
forall a b c.
(Show a, Show b, Show c, Eq c) =>
(a -> b -> c)
-> (a -> b -> c) -> Gen (a, b) -> ((a, b) -> [(a, b)]) -> Property
equivalentOnGens2 a -> a -> Bool
cmplt (\a :: a
a b :: a
b -> a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
b Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT) Gen (a, a)
gen2 (a, a) -> [(a, a)]
s2
            String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
fungtstr (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is antireflexive for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen a -> (a -> [a]) -> Property
forall a.
Show a =>
(a -> a -> Bool) -> Gen a -> (a -> [a]) -> Property
antireflexivityOnGen a -> a -> Bool
cmpgt Gen a
gen a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is transitive for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool) -> Gen (a, a, a) -> (a -> [a]) -> Property
forall a.
Show a =>
(a -> a -> Bool) -> Gen (a, a, a) -> (a -> [a]) -> Property
transitivityOnGens a -> a -> Bool
cmpgt Gen (a, a, a)
gen3 a -> [a]
s
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is equivalent to (\\a b -> compare a b == GT) for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> Bool)
-> (a -> a -> Bool)
-> Gen (a, a)
-> ((a, a) -> [(a, a)])
-> Property
forall a b c.
(Show a, Show b, Show c, Eq c) =>
(a -> b -> c)
-> (a -> b -> c) -> Gen (a, b) -> ((a, b) -> [(a, b)]) -> Property
equivalentOnGens2 a -> a -> Bool
cmpgt (\a :: a
a b :: a
b -> a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
b Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT) Gen (a, a)
gen2 (a, a) -> [(a, a)]
s2
            String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String
minmaxtstr "min") (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is equivalent to (\\a b -> if a <= b then a else b) for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> a)
-> (a -> a -> a) -> Gen (a, a) -> ((a, a) -> [(a, a)]) -> Property
forall a b c.
(Show a, Show b, Show c, Eq c) =>
(a -> b -> c)
-> (a -> b -> c) -> Gen (a, b) -> ((a, b) -> [(a, b)]) -> Property
equivalentOnGens2 a -> a -> a
forall a. Ord a => a -> a -> a
min (\a :: a
a b :: a
b -> if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
b then a
a else a
b) Gen (a, a)
gen2 (a, a) -> [(a, a)]
s2
            String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String
minmaxtstr "max") (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
                String -> Property -> SpecWith (Arg Property)
forall a. Example a => String -> a -> SpecWith (Arg a)
itProp "is equivalent to (\\a b -> if a >= b then a else b) for" (Property -> Spec) -> Property -> Spec
forall a b. (a -> b) -> a -> b
$
                    (a -> a -> a)
-> (a -> a -> a) -> Gen (a, a) -> ((a, a) -> [(a, a)]) -> Property
forall a b c.
(Show a, Show b, Show c, Eq c) =>
(a -> b -> c)
-> (a -> b -> c) -> Gen (a, b) -> ((a, b) -> [(a, b)]) -> Property
equivalentOnGens2 a -> a -> a
forall a. Ord a => a -> a -> a
max (\a :: a
a b :: a
b -> if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
b then a
a else a
b) Gen (a, a)
gen2 (a, a) -> [(a, a)]
s2