{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}

#if HAVE_QUANTIFIED_CONSTRAINTS
{-# LANGUAGE QuantifiedConstraints #-}
#endif

{-# OPTIONS_GHC -Wall #-}

module Test.QuickCheck.Classes.Semigroupoid
  (
#if defined(HAVE_SEMIGROUPOIDS) && defined(HAVE_BINARY_LAWS)
    semigroupoidLaws
  , commutativeSemigroupoidLaws
#endif
  ) where

#if defined(HAVE_SEMIGROUPOIDS) && defined(HAVE_BINARY_LAWS)
import Prelude hiding (id, (.))
import Data.Semigroupoid (Semigroupoid(..))
import Test.QuickCheck hiding ((.&.))
import Data.Functor.Classes (Eq2,Show2)
import Test.QuickCheck.Property (Property)

import Test.QuickCheck.Classes.Internal

-- | Tests the following 'Semigroupoid' properties:
--
-- [/Associativity/]
--   @f `'o'` (g `'o'` h) ≡ (f `'o'` g) `'o'` h@
--
-- /Note/: This property test is only available when this package is built with
-- @base-4.9+@ or @transformers-0.5+@.
semigroupoidLaws :: forall proxy s.
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Semigroupoid s, forall a b. (Eq a, Eq b) => Eq (s a b), forall a b. (Show a, Show b) => Show (s a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (s a b))
#else
  (Semigroupoid s, Eq2 s, Show2 s, Arbitrary2 s)
#endif
  => proxy s -> Laws
semigroupoidLaws :: proxy s -> Laws
semigroupoidLaws proxy s
p = String -> [(String, Property)] -> Laws
Laws String
"Semigroupoid"
  [ (String
"Associativity", proxy s -> Property
forall (proxy :: (* -> * -> *) -> *) (s :: * -> * -> *).
(Semigroupoid s, forall a b. (Eq a, Eq b) => Eq (s a b),
 forall a b. (Show a, Show b) => Show (s a b),
 forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (s a b)) =>
proxy s -> Property
semigroupoidAssociativity proxy s
p)
  ]

-- | Tests everything from 'semigroupoidLaws' plus the following:
--
-- [/Commutative/]
--   @f `'o'` g ≡ g `'o'` f@
--
-- /Note/: This property test is only available when this package is built with
-- @base-4.9+@ or @transformers-0.5+@.
commutativeSemigroupoidLaws :: forall proxy s.
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Semigroupoid s, forall a b. (Eq a, Eq b) => Eq (s a b), forall a b. (Show a, Show b) => Show (s a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (s a b))
#else
  (Semigroupoid s, Eq2 s, Show2 s, Arbitrary2 s)
#endif
  => proxy s -> Laws
commutativeSemigroupoidLaws :: proxy s -> Laws
commutativeSemigroupoidLaws proxy s
p = String -> [(String, Property)] -> Laws
Laws String
"Commutative Semigroupoid" ([(String, Property)] -> Laws) -> [(String, Property)] -> Laws
forall a b. (a -> b) -> a -> b
$ Laws -> [(String, Property)]
lawsProperties (proxy s -> Laws
forall (proxy :: (* -> * -> *) -> *) (s :: * -> * -> *).
(Semigroupoid s, forall a b. (Eq a, Eq b) => Eq (s a b),
 forall a b. (Show a, Show b) => Show (s a b),
 forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (s a b)) =>
proxy s -> Laws
semigroupoidLaws proxy s
p) [(String, Property)]
-> [(String, Property)] -> [(String, Property)]
forall a. [a] -> [a] -> [a]
++
  [ (String
"Commutative", proxy s -> Property
forall (proxy :: (* -> * -> *) -> *) (s :: * -> * -> *).
(Semigroupoid s, forall a b. (Eq a, Eq b) => Eq (s a b),
 forall a b. (Show a, Show b) => Show (s a b),
 forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (s a b)) =>
proxy s -> Property
semigroupoidCommutativity proxy s
p)
  ]

semigroupoidAssociativity :: forall proxy s.
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Semigroupoid s, forall a b. (Eq a, Eq b) => Eq (s a b), forall a b. (Show a, Show b) => Show (s a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (s a b))
#else
  (Semigroupoid s, Eq2 s, Show2 s, Arbitrary2 s)
#endif
  => proxy s -> Property
semigroupoidAssociativity :: proxy s -> Property
semigroupoidAssociativity proxy s
_ = (Apply2 s Integer Integer
 -> Apply2 s Integer Integer -> Apply2 s Integer Integer -> Bool)
-> Property
forall prop. Testable prop => prop -> Property
property ((Apply2 s Integer Integer
  -> Apply2 s Integer Integer -> Apply2 s Integer Integer -> Bool)
 -> Property)
-> (Apply2 s Integer Integer
    -> Apply2 s Integer Integer -> Apply2 s Integer Integer -> Bool)
-> Property
forall a b. (a -> b) -> a -> b
$ \(Apply2 (s Integer Integer
f :: s Integer Integer)) (Apply2 (s Integer Integer
g :: s Integer Integer)) (Apply2 (s Integer Integer
h :: s Integer Integer)) -> s Integer Integer -> s Integer Integer -> Bool
forall b (f :: * -> * -> *) a.
(forall a1. (Eq a1, Eq b) => Eq (f a1 b), Eq a, Eq b) =>
f a b -> f a b -> Bool
eq2 (s Integer Integer
f s Integer Integer -> s Integer Integer -> s Integer Integer
forall k (c :: k -> k -> *) (j :: k) (k1 :: k) (i :: k).
Semigroupoid c =>
c j k1 -> c i j -> c i k1
`o` (s Integer Integer
g s Integer Integer -> s Integer Integer -> s Integer Integer
forall k (c :: k -> k -> *) (j :: k) (k1 :: k) (i :: k).
Semigroupoid c =>
c j k1 -> c i j -> c i k1
`o` s Integer Integer
h)) ((s Integer Integer
f s Integer Integer -> s Integer Integer -> s Integer Integer
forall k (c :: k -> k -> *) (j :: k) (k1 :: k) (i :: k).
Semigroupoid c =>
c j k1 -> c i j -> c i k1
`o` s Integer Integer
g) s Integer Integer -> s Integer Integer -> s Integer Integer
forall k (c :: k -> k -> *) (j :: k) (k1 :: k) (i :: k).
Semigroupoid c =>
c j k1 -> c i j -> c i k1
`o` s Integer Integer
h)

semigroupoidCommutativity :: forall proxy s.
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Semigroupoid s, forall a b. (Eq a, Eq b) => Eq (s a b), forall a b. (Show a, Show b) => Show (s a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (s a b))
#else
  (Semigroupoid s, Eq2 s, Show2 s, Arbitrary2 s)
#endif
  => proxy s -> Property
semigroupoidCommutativity :: proxy s -> Property
semigroupoidCommutativity proxy s
_ = (Apply2 s Integer Integer -> Apply2 s Integer Integer -> Bool)
-> Property
forall prop. Testable prop => prop -> Property
property ((Apply2 s Integer Integer -> Apply2 s Integer Integer -> Bool)
 -> Property)
-> (Apply2 s Integer Integer -> Apply2 s Integer Integer -> Bool)
-> Property
forall a b. (a -> b) -> a -> b
$ \(Apply2 (s Integer Integer
f :: s Integer Integer)) (Apply2 (s Integer Integer
g :: s Integer Integer)) -> s Integer Integer -> s Integer Integer -> Bool
forall b (f :: * -> * -> *) a.
(forall a1. (Eq a1, Eq b) => Eq (f a1 b), Eq a, Eq b) =>
f a b -> f a b -> Bool
eq2 (s Integer Integer
f s Integer Integer -> s Integer Integer -> s Integer Integer
forall k (c :: k -> k -> *) (j :: k) (k1 :: k) (i :: k).
Semigroupoid c =>
c j k1 -> c i j -> c i k1
`o` s Integer Integer
g) (s Integer Integer
g s Integer Integer -> s Integer Integer -> s Integer Integer
forall k (c :: k -> k -> *) (j :: k) (k1 :: k) (i :: k).
Semigroupoid c =>
c j k1 -> c i j -> c i k1
`o` s Integer Integer
f)

#endif