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

    -- | 'Show' and 'Read' properties
    module Test.Validity.Show
        ( showReadSpecOnValid
        , showReadSpec
        , showReadSpecOnArbitrary
        , showReadSpecOnGen
        , showReadRoundTripOnValid
        , showReadRoundTrip
        , showReadRoundTripOnArbitrary
        , showReadRoundTripOnGen
        ) where

    import Data.GenValidity

    import Data.Data

    import Text.Read

    import Test.Hspec
    import Test.QuickCheck

    import Test.Validity.Utils

    -- | Standard test spec for properties of Show and Read instances for valid values
    --
    -- Example usage:
    --
    -- > showReadSpecOnValid @Double
    showReadSpecOnValid ::
           forall a. (Show a, Eq a, Read a, Typeable a, GenValid a)
        => Spec
    showReadSpecOnValid :: Spec
    showReadSpecOnValid = Gen a -> String -> (a -> [a]) -> Spec
    forall a.
    (Show a, Eq a, Read a, Typeable a) =>
    Gen a -> String -> (a -> [a]) -> Spec
    showReadSpecOnGen @a Gen a
    forall a. GenValid a => Gen a
    genValid "valid" a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    -- | Standard test spec for properties of Show and Read instances for unchecked values
    --
    -- Example usage:
    --
    -- > showReadSpec @Int
    showReadSpec ::
           forall a. (Show a, Eq a, Read a, Typeable a, GenUnchecked a)
        => Spec
    showReadSpec :: Spec
    showReadSpec = Gen a -> String -> (a -> [a]) -> Spec
    forall a.
    (Show a, Eq a, Read a, Typeable a) =>
    Gen a -> String -> (a -> [a]) -> Spec
    showReadSpecOnGen @a Gen a
    forall a. GenUnchecked a => Gen a
    genUnchecked "unchecked" a -> [a]
    forall a. GenUnchecked a => a -> [a]
    shrinkUnchecked

    -- | Standard test spec for properties of Show and Read instances for arbitrary values
    --
    -- Example usage:
    --
    -- > showReadSpecOnArbitrary @Double
    showReadSpecOnArbitrary ::
           forall a. (Show a, Eq a, Read a, Typeable a, Arbitrary a)
        => Spec
    showReadSpecOnArbitrary :: Spec
    showReadSpecOnArbitrary = Gen a -> String -> (a -> [a]) -> Spec
    forall a.
    (Show a, Eq a, Read a, Typeable a) =>
    Gen a -> String -> (a -> [a]) -> Spec
    showReadSpecOnGen @a Gen a
    forall a. Arbitrary a => Gen a
    arbitrary "arbitrary" a -> [a]
    forall a. Arbitrary a => a -> [a]
    shrink

    -- | Standard test spec for properties of Show and Read instances for values generated by a custom generator
    --
    -- Example usage:
    --
    -- > showReadSpecOnGen ((* 2) <$> genValid @Int) "even" (const [])
    showReadSpecOnGen ::
           forall a. (Show a, Eq a, Read a, Typeable a)
        => Gen a
        -> String
        -> (a -> [a])
        -> Spec
    showReadSpecOnGen :: Gen a -> String -> (a -> [a]) -> Spec
    showReadSpecOnGen gen :: Gen a
    gen n :: String
    n s :: a -> [a]
    s =
        String -> Spec -> Spec
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe ([String] -> String
    unwords ["Show", Typeable a => String
    forall k (a :: k). Typeable a => String
    nameOf @a, "and Read", Typeable a => String
    forall k (a :: k). Typeable a => String
    nameOf @a]) (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 ([String] -> String
    unwords ["are implemented such that read . show == id for", String
    n, "values"]) (Property -> Spec) -> Property -> Spec
    forall a b. (a -> b) -> a -> b
    $
        Gen a -> (a -> [a]) -> Property
    forall a. (Show a, Eq a, Read a) => Gen a -> (a -> [a]) -> Property
    showReadRoundTripOnGen Gen a
    gen a -> [a]
    s

    -- |
    --
    -- prop> showReadRoundTripOnValid @Rational
    showReadRoundTripOnValid ::
           forall a. (Show a, Eq a, Read a, GenValid a)
        => Property
    showReadRoundTripOnValid :: Property
    showReadRoundTripOnValid =
        Gen a -> (a -> [a]) -> Property
    forall a. (Show a, Eq a, Read a) => Gen a -> (a -> [a]) -> Property
    showReadRoundTripOnGen (Gen a
    forall a. GenValid a => Gen a
    genValid :: Gen a) a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    -- |
    --
    -- prop> showReadRoundTrip @Int
    showReadRoundTrip ::
           forall a. (Show a, Eq a, Read a, GenUnchecked a)
        => Property
    showReadRoundTrip :: Property
    showReadRoundTrip =
        Gen a -> (a -> [a]) -> Property
    forall a. (Show a, Eq a, Read a) => Gen a -> (a -> [a]) -> Property
    showReadRoundTripOnGen (Gen a
    forall a. GenUnchecked a => Gen a
    genUnchecked :: Gen a) a -> [a]
    forall a. GenUnchecked a => a -> [a]
    shrinkUnchecked

    -- |
    --
    -- prop> showReadRoundTripOnArbitrary @Double
    showReadRoundTripOnArbitrary ::
           forall a. (Show a, Eq a, Read a, Arbitrary a)
        => Property
    showReadRoundTripOnArbitrary :: Property
    showReadRoundTripOnArbitrary =
        Gen a -> (a -> [a]) -> Property
    forall a. (Show a, Eq a, Read a) => Gen a -> (a -> [a]) -> Property
    showReadRoundTripOnGen (Gen a
    forall a. Arbitrary a => Gen a
    arbitrary :: Gen a) a -> [a]
    forall a. Arbitrary a => a -> [a]
    shrink

    -- |
    --
    -- prop> showReadRoundTripOnGen (abs <$> genUnchecked :: Gen Int) (const [])
    showReadRoundTripOnGen ::
           (Show a, Eq a, Read a) => Gen a -> (a -> [a]) -> Property
    showReadRoundTripOnGen :: Gen a -> (a -> [a]) -> Property
    showReadRoundTripOnGen gen :: Gen a
    gen s :: 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
    $ \v :: a
    v -> String -> Maybe a
    forall a. Read a => String -> Maybe a
    readMaybe (a -> String
    forall a. Show a => a -> String
    show a
    v) Maybe a -> Maybe a -> Expectation
    forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
    `shouldBe` a -> Maybe a
    forall a. a -> Maybe a
    Just a
    v