    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE ScopedTypeVariables #-}

    -- | Standard tests involving validity
    module Test.Validity.Functions.Idempotence
      ( idempotentOnGen,
        idempotent,
        idempotentOnArbitrary,
      )
    where

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

    idempotentOnGen :: (Show a, Eq a) => (a -> a) -> Gen a -> (a -> [a]) -> Property
    idempotentOnGen :: forall a.
    (Show a, Eq a) =>
    (a -> a) -> Gen a -> (a -> [a]) -> Property
    idempotentOnGen a -> a
    f Gen a
    gen a -> [a]
    s = Gen a -> (a -> [a]) -> (a -> Expectation) -> Property
    forall a prop.
    (Show a, Testable prop) =>
    Gen a -> (a -> [a]) -> (a -> prop) -> Property
    forAllShrink Gen a
    gen a -> [a]
    s ((a -> Expectation) -> Property) -> (a -> Expectation) -> Property
    forall a b. (a -> b) -> a -> b
    $ \a
    a -> a -> a
    f (a -> a
    f a
    a) a -> a -> Expectation
    forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
    `shouldBe` a -> a
    f a
    a

    idempotent :: (Show a, Eq a, GenValid a) => (a -> a) -> Property
    idempotent :: forall a. (Show a, Eq a, GenValid a) => (a -> a) -> Property
    idempotent a -> a
    func = (a -> a) -> Gen a -> (a -> [a]) -> Property
    forall a.
    (Show a, Eq a) =>
    (a -> a) -> Gen a -> (a -> [a]) -> Property
    idempotentOnGen a -> a
    func Gen a
    forall a. GenValid a => Gen a
    genValid a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    -- |
    --
    -- 'id' is idempotent for any type:
    --
    -- prop> idempotentOnArbitrary (id :: Int -> Int)
    --
    -- 'const', given any input, is idempotent for any type as well:
    --
    -- prop> \int -> idempotentOnArbitrary (const int :: Int -> Int)
    idempotentOnArbitrary :: (Show a, Eq a, Arbitrary a) => (a -> a) -> Property
    idempotentOnArbitrary :: forall a. (Show a, Eq a, Arbitrary a) => (a -> a) -> Property
    idempotentOnArbitrary a -> a
    func = (a -> a) -> Gen a -> (a -> [a]) -> Property
    forall a.
    (Show a, Eq a) =>
    (a -> a) -> Gen a -> (a -> [a]) -> Property
    idempotentOnGen a -> a
    func Gen a
    forall a. Arbitrary a => Gen a
    arbitrary a -> [a]
    forall a. Arbitrary a => a -> [a]
    shrink