{-# 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 = binRelStr @a "<=" geTypeStr :: forall a. Typeable a => String geTypeStr = binRelStr @a ">=" ltTypeStr :: forall a. Typeable a => String ltTypeStr = binRelStr @a "<" gtTypeStr :: forall a. Typeable a => String gtTypeStr = 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 = ordSpecOnGen @a genValid "valid" 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 = ordSpecOnGen @a genInvalid "invalid" 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 = ordSpecOnGen @a genUnchecked "unchecked" 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 = ordSpecOnGen @a arbitrary "arbitrary" 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 genname s = parallel $ do let name = nameOf @a funlestr = leTypeStr @a fungestr = geTypeStr @a funltstr = ltTypeStr @a fungtstr = gtTypeStr @a cmple = (<=) @a cmpge = (>=) @a cmplt = (<) @a cmpgt = (>) @a gen2 = (,) <$> gen <*> gen gen3 = (,,) <$> gen <*> gen <*> gen s2 = shrinkT2 s describe ("Ord " ++ name) $ do describe funlestr $ do it (unwords [ "is reflexive for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ reflexivityOnGen cmple gen s it (unwords [ "is antisymmetric for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ antisymmetryOnGens cmple gen2 s it (unwords [ "is transitive for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ transitivityOnGens cmple gen3 s it (unwords [ "is equivalent to (\\a b -> compare a b /= GT) for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ equivalentOnGens2 cmple (\a b -> compare a b /= GT) gen2 s2 describe fungestr $ do it (unwords [ "is reflexive for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ reflexivityOnGen cmpge gen s it (unwords [ "is antisymmetric for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ antisymmetryOnGens cmpge gen2 s it (unwords [ "is transitive for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ transitivityOnGens cmpge gen3 s it (unwords [ "is equivalent to (\\a b -> compare a b /= LT) for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ equivalentOnGens2 cmpge (\a b -> compare a b /= LT) gen2 s2 describe funltstr $ do it (unwords [ "is antireflexive for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ antireflexivityOnGen cmplt gen s it (unwords [ "is transitive for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ transitivityOnGens cmplt gen3 s it (unwords [ "is equivalent to (\\a b -> compare a b == LT) for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ equivalentOnGens2 cmplt (\a b -> compare a b == LT) gen2 s2 describe fungtstr $ do it (unwords [ "is antireflexive for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ antireflexivityOnGen cmpgt gen s it (unwords [ "is transitive for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ transitivityOnGens cmpgt gen3 s it (unwords [ "is equivalent to (\\a b -> compare a b == GT) for" , "\"" ++ genname , name ++ "\"" ++ "'s" ]) $ equivalentOnGens2 cmpgt (\a b -> compare a b == GT) gen2 s2