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

    -- | Tests for GenValidity instances
    --
    -- You will need @TypeApplications@ to use these.
    module Test.Validity.GenValidity
        ( genValiditySpec
        , genValidSpec
        , genInvalidSpec
        , genValidGeneratesValid
        , genGeneratesValid
        , genInvalidGeneratesInvalid
        , genGeneratesInvalid
        ) where

    import Data.Data

    import Data.GenValidity

    import Test.Hspec
    import Test.QuickCheck

    import Test.Validity.GenValidity.Property
    import Test.Validity.Utils

    -- | A spec for properties of 'GenValid' and 'GenInvalid' instances.
    --
    -- In general it is a good idea to add this spec to your test suite if you
    -- write a custom implementation of @genValid@ or @genInvalid@.
    --
    -- __It is not a good idea to use this function if invalid values are broken in such a way that 'Show' or even 'isValid' is broken.__
    -- In that case you probably want 'genValidSpec'.
    --
    -- Example usage:
    --
    -- > genValiditySpec @Int
    genValiditySpec ::
           forall a. (Typeable a, Show a, GenValid a, GenInvalid a)
        => Spec
    genValiditySpec :: Spec
    genValiditySpec = do
        (Typeable a, Show a, GenValid a) => Spec
    forall a. (Typeable a, Show a, GenValid a) => Spec
    genValidSpec @a
        (Typeable a, Show a, GenInvalid a) => Spec
    forall a. (Typeable a, Show a, GenInvalid a) => Spec
    genInvalidSpec @a

    -- | A @Spec@ that specifies that @genValid@ only generates valid data.
    --
    -- In general it is a good idea to add this spec to your test suite if you
    -- write a custom implementation of @genValid@.
    --
    -- Example usage:
    --
    -- > genValidSpec @Int
    genValidSpec ::
           forall a. (Typeable a, Show a, GenValid a)
        => Spec
    genValidSpec :: Spec
    genValidSpec =
        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
            String -> Spec -> Spec
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe ("GenValid " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name) (Spec -> Spec) -> Spec -> Spec
    forall a b. (a -> b) -> a -> b
    $
                String -> Spec -> Spec
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe ("genValid   :: Gen " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name) (Spec -> Spec) -> Spec -> Spec
    forall a b. (a -> b) -> a -> b
    $
                String -> Property -> SpecWith (Arg Property)
    forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    it ("only generates valid \'" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "\'s") (Property -> Spec) -> Property -> Spec
    forall a b. (a -> b) -> a -> b
    $
                    (Show a, GenValid a) => Property
    forall a. (Show a, GenValid a) => Property
    genValidGeneratesValid @a

    -- | A @Spec@ that specifies that @genInvalid@ only generates invalid data.
    --
    -- Note that it is not a good idea to use this function if invalid values are broken in such a way that 'Show' or even 'isValid' is broken.
    --
    -- Example usage:
    --
    -- > genInvalidSpec @Rational
    genInvalidSpec ::
           forall a. (Typeable a, Show a, GenInvalid a)
        => Spec
    genInvalidSpec :: Spec
    genInvalidSpec =
        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
            String -> Spec -> Spec
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe ("GenInvalid " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name) (Spec -> Spec) -> Spec -> Spec
    forall a b. (a -> b) -> a -> b
    $
                String -> Spec -> Spec
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe ("genInvalid :: Gen " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name) (Spec -> Spec) -> Spec -> Spec
    forall a b. (a -> b) -> a -> b
    $
                String -> Property -> SpecWith (Arg Property)
    forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    it ("only generates invalid \'" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "\'s") (Property -> Spec) -> Property -> Spec
    forall a b. (a -> b) -> a -> b
    $
                    (Show a, GenInvalid a) => Property
    forall a. (Show a, GenInvalid a) => Property
    genInvalidGeneratesInvalid @a

    -- | @genValid@ only generates valid data
    --
    -- prop> genValidGeneratesValid @()
    -- prop> genValidGeneratesValid @Bool
    -- prop> genValidGeneratesValid @Ordering
    -- prop> genValidGeneratesValid @Char
    -- prop> genValidGeneratesValid @Int
    -- prop> genValidGeneratesValid @Float
    -- prop> genValidGeneratesValid @Double
    -- prop> genValidGeneratesValid @Integer
    -- prop> genValidGeneratesValid @(Maybe Int)
    -- prop> genValidGeneratesValid @[Int]
    genValidGeneratesValid ::
           forall a. (Show a, GenValid a)
        => Property
    genValidGeneratesValid :: Property
    genValidGeneratesValid = Gen a -> Property
    forall a. (Show a, Validity a) => Gen a -> Property
    genGeneratesValid @a Gen a
    forall a. GenValid a => Gen a
    genValid

    -- | @genValid@ only generates invalid data
    --
    -- prop> genInvalidGeneratesInvalid @Rational
    -- prop> genInvalidGeneratesInvalid @Rational
    -- prop> genInvalidGeneratesInvalid @(Maybe Rational)
    -- prop> genInvalidGeneratesInvalid @[Rational]
    genInvalidGeneratesInvalid ::
           forall a. (Show a, GenInvalid a)
        => Property
    genInvalidGeneratesInvalid :: Property
    genInvalidGeneratesInvalid = Gen a -> Property
    forall a. (Show a, Validity a) => Gen a -> Property
    genGeneratesInvalid @a Gen a
    forall a. GenInvalid a => Gen a
    genInvalid