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

    -- | Standard tests involving inverse functions
    module Test.Validity.Functions.Inverse
      ( inverseFunctionsOnGen,
        inverseFunctions,
        inverseFunctionsOnArbitrary,
        inverseFunctionsIfFirstSucceedsOnGen,
        inverseFunctionsIfFirstSucceeds,
        inverseFunctionsIfFirstSucceedsOnArbitrary,
        inverseFunctionsIfSecondSucceedsOnGen,
        inverseFunctionsIfSecondSucceeds,
        inverseFunctionsIfSecondSucceedsOnArbitrary,
        inverseFunctionsIfSucceedOnGen,
        inverseFunctionsIfSucceed,
        inverseFunctionsIfSucceedOnArbitrary,
      )
    where

    import Data.GenValidity
    import Test.Hspec
    import Test.QuickCheck
    import Test.Validity.Types

    inverseFunctionsOnGen ::
      (Show a, Eq a) => (a -> b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsOnGen :: forall a b.
    (Show a, Eq a) =>
    (a -> b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsOnGen a -> b
    f b -> a
    g 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 -> b -> a
    g (a -> b
    f a
    a) a -> a -> Expectation
    forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
    `shouldBe` a
    a

    inverseFunctions ::
      (Show a, Eq a, GenValid a) => (a -> b) -> (b -> a) -> Property
    inverseFunctions :: forall a b.
    (Show a, Eq a, GenValid a) =>
    (a -> b) -> (b -> a) -> Property
    inverseFunctions a -> b
    f b -> a
    g = (a -> b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    forall a b.
    (Show a, Eq a) =>
    (a -> b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsOnGen a -> b
    f b -> a
    g Gen a
    forall a. GenValid a => Gen a
    genValid a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    -- |
    -- 'id' is its own inverse function for every type:
    -- prop> inverseFunctionsOnArbitrary id (id :: Int -> Int)
    inverseFunctionsOnArbitrary ::
      (Show a, Eq a, Arbitrary a) => (a -> b) -> (b -> a) -> Property
    inverseFunctionsOnArbitrary :: forall a b.
    (Show a, Eq a, Arbitrary a) =>
    (a -> b) -> (b -> a) -> Property
    inverseFunctionsOnArbitrary a -> b
    f b -> a
    g = (a -> b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    forall a b.
    (Show a, Eq a) =>
    (a -> b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsOnGen a -> b
    f b -> a
    g Gen a
    forall a. Arbitrary a => Gen a
    arbitrary a -> [a]
    forall a. Arbitrary a => a -> [a]
    shrink

    inverseFunctionsIfFirstSucceedsOnGen ::
      (Show a, Eq a, CanFail f) =>
      (a -> f b) ->
      (b -> a) ->
      Gen a ->
      (a -> [a]) ->
      Property
    inverseFunctionsIfFirstSucceedsOnGen :: forall a (f :: * -> *) b.
    (Show a, Eq a, CanFail f) =>
    (a -> f b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfFirstSucceedsOnGen a -> f b
    f b -> a
    g 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 ->
        case f b -> Maybe b
    forall a. f a -> Maybe a
    forall (f :: * -> *) a. CanFail f => f a -> Maybe a
    resultIfSucceeded (a -> f b
    f a
    a) of
          Maybe b
    Nothing -> () -> Expectation
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return () -- fine
          Just b
    b -> b -> a
    g b
    b a -> a -> Expectation
    forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
    `shouldBe` a
    a

    inverseFunctionsIfFirstSucceeds ::
      (Show a, Eq a, GenValid a, CanFail f) =>
      (a -> f b) ->
      (b -> a) ->
      Property
    inverseFunctionsIfFirstSucceeds :: forall a (f :: * -> *) b.
    (Show a, Eq a, GenValid a, CanFail f) =>
    (a -> f b) -> (b -> a) -> Property
    inverseFunctionsIfFirstSucceeds a -> f b
    f b -> a
    g =
      (a -> f b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    forall a (f :: * -> *) b.
    (Show a, Eq a, CanFail f) =>
    (a -> f b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfFirstSucceedsOnGen a -> f b
    f b -> a
    g Gen a
    forall a. GenValid a => Gen a
    genValid a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    inverseFunctionsIfFirstSucceedsOnArbitrary ::
      (Show a, Eq a, Arbitrary a, CanFail f) =>
      (a -> f b) ->
      (b -> a) ->
      Property
    inverseFunctionsIfFirstSucceedsOnArbitrary :: forall a (f :: * -> *) b.
    (Show a, Eq a, Arbitrary a, CanFail f) =>
    (a -> f b) -> (b -> a) -> Property
    inverseFunctionsIfFirstSucceedsOnArbitrary a -> f b
    f b -> a
    g =
      (a -> f b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    forall a (f :: * -> *) b.
    (Show a, Eq a, CanFail f) =>
    (a -> f b) -> (b -> a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfFirstSucceedsOnGen a -> f b
    f b -> a
    g Gen a
    forall a. Arbitrary a => Gen a
    arbitrary a -> [a]
    forall a. Arbitrary a => a -> [a]
    shrink

    inverseFunctionsIfSecondSucceedsOnGen ::
      (Show a, Eq a, CanFail f) =>
      (a -> b) ->
      (b -> f a) ->
      Gen a ->
      (a -> [a]) ->
      Property
    inverseFunctionsIfSecondSucceedsOnGen :: forall a (f :: * -> *) b.
    (Show a, Eq a, CanFail f) =>
    (a -> b) -> (b -> f a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfSecondSucceedsOnGen a -> b
    f b -> f a
    g 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 ->
        case f a -> Maybe a
    forall a. f a -> Maybe a
    forall (f :: * -> *) a. CanFail f => f a -> Maybe a
    resultIfSucceeded (b -> f a
    g (a -> b
    f a
    a)) of
          Maybe a
    Nothing -> () -> Expectation
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return () -- fine
          Just a
    r -> a
    r a -> a -> Expectation
    forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
    `shouldBe` a
    a

    inverseFunctionsIfSecondSucceeds ::
      (Show a, Eq a, GenValid a, CanFail f) =>
      (a -> b) ->
      (b -> f a) ->
      Property
    inverseFunctionsIfSecondSucceeds :: forall a (f :: * -> *) b.
    (Show a, Eq a, GenValid a, CanFail f) =>
    (a -> b) -> (b -> f a) -> Property
    inverseFunctionsIfSecondSucceeds a -> b
    f b -> f a
    g =
      (a -> b) -> (b -> f a) -> Gen a -> (a -> [a]) -> Property
    forall a (f :: * -> *) b.
    (Show a, Eq a, CanFail f) =>
    (a -> b) -> (b -> f a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfSecondSucceedsOnGen a -> b
    f b -> f a
    g Gen a
    forall a. GenValid a => Gen a
    genValid a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    inverseFunctionsIfSecondSucceedsOnArbitrary ::
      (Show a, Eq a, Arbitrary a, CanFail f) =>
      (a -> b) ->
      (b -> f a) ->
      Property
    inverseFunctionsIfSecondSucceedsOnArbitrary :: forall a (f :: * -> *) b.
    (Show a, Eq a, Arbitrary a, CanFail f) =>
    (a -> b) -> (b -> f a) -> Property
    inverseFunctionsIfSecondSucceedsOnArbitrary a -> b
    f b -> f a
    g =
      (a -> b) -> (b -> f a) -> Gen a -> (a -> [a]) -> Property
    forall a (f :: * -> *) b.
    (Show a, Eq a, CanFail f) =>
    (a -> b) -> (b -> f a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfSecondSucceedsOnGen a -> b
    f b -> f a
    g Gen a
    forall a. Arbitrary a => Gen a
    arbitrary a -> [a]
    forall a. Arbitrary a => a -> [a]
    shrink

    inverseFunctionsIfSucceedOnGen ::
      (Show a, Eq a, CanFail f, CanFail g) =>
      (a -> f b) ->
      (b -> g a) ->
      Gen a ->
      (a -> [a]) ->
      Property
    inverseFunctionsIfSucceedOnGen :: forall a (f :: * -> *) (g :: * -> *) b.
    (Show a, Eq a, CanFail f, CanFail g) =>
    (a -> f b) -> (b -> g a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfSucceedOnGen a -> f b
    f b -> g a
    g 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 ->
        case do
          fa <- f b -> Maybe b
    forall a. f a -> Maybe a
    forall (f :: * -> *) a. CanFail f => f a -> Maybe a
    resultIfSucceeded (f b -> Maybe b) -> f b -> Maybe b
    forall a b. (a -> b) -> a -> b
    $ a -> f b
    f a
    a
          resultIfSucceeded $ g fa of
          Maybe a
    Nothing -> () -> Expectation
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return () -- fine
          Just a
    r -> a
    r a -> a -> Expectation
    forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
    `shouldBe` a
    a

    inverseFunctionsIfSucceed ::
      (Show a, Eq a, GenValid a, CanFail f, CanFail g) =>
      (a -> f b) ->
      (b -> g a) ->
      Property
    inverseFunctionsIfSucceed :: forall a (f :: * -> *) (g :: * -> *) b.
    (Show a, Eq a, GenValid a, CanFail f, CanFail g) =>
    (a -> f b) -> (b -> g a) -> Property
    inverseFunctionsIfSucceed a -> f b
    f b -> g a
    g =
      (a -> f b) -> (b -> g a) -> Gen a -> (a -> [a]) -> Property
    forall a (f :: * -> *) (g :: * -> *) b.
    (Show a, Eq a, CanFail f, CanFail g) =>
    (a -> f b) -> (b -> g a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfSucceedOnGen a -> f b
    f b -> g a
    g Gen a
    forall a. GenValid a => Gen a
    genValid a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    inverseFunctionsIfSucceedOnArbitrary ::
      (Show a, Eq a, Arbitrary a, CanFail f, CanFail g) =>
      (a -> f b) ->
      (b -> g a) ->
      Property
    inverseFunctionsIfSucceedOnArbitrary :: forall a (f :: * -> *) (g :: * -> *) b.
    (Show a, Eq a, Arbitrary a, CanFail f, CanFail g) =>
    (a -> f b) -> (b -> g a) -> Property
    inverseFunctionsIfSucceedOnArbitrary a -> f b
    f b -> g a
    g =
      (a -> f b) -> (b -> g a) -> Gen a -> (a -> [a]) -> Property
    forall a (f :: * -> *) (g :: * -> *) b.
    (Show a, Eq a, CanFail f, CanFail g) =>
    (a -> f b) -> (b -> g a) -> Gen a -> (a -> [a]) -> Property
    inverseFunctionsIfSucceedOnGen a -> f b
    f b -> g a
    g Gen a
    forall a. Arbitrary a => Gen a
    arbitrary a -> [a]
    forall a. Arbitrary a => a -> [a]
    shrink