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

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

    import Data.Data
    import Data.GenValidity
    import Test.Hspec
    import Test.QuickCheck
    import Test.Validity.Utils
    import Text.Read

    -- | Standard test spec for properties of Show and Read instances for valid values
    --
    -- Example usage:
    --
    -- > showReadSpec @Int
    showReadSpec ::
      forall a.
      (Show a, Eq a, Read a, Typeable a, GenValid a) =>
      Spec
    showReadSpec :: forall a. (Show a, Eq a, Read a, Typeable a, GenValid a) => Spec
    showReadSpec = 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 String
    "valid" a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    -- | 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 :: forall a. (Show a, Eq a, Read a, Typeable a, Arbitrary a) => Spec
    showReadSpecOnArbitrary = 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 String
    "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 :: forall a.
    (Show a, Eq a, Read a, Typeable a) =>
    Gen a -> String -> (a -> [a]) -> Spec
    showReadSpecOnGen Gen a
    gen String
    n a -> [a]
    s =
      String -> Spec -> Spec
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe ([String] -> String
    unwords [String
    "Show", forall a. Typeable a => String
    forall {k} (a :: k). Typeable a => String
    nameOf @a, String
    "and Read", forall a. 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 -> SpecM (Arg Property) ()
    forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    it ([String] -> String
    unwords [String
    "are implemented such that read . show == id for", String
    n, String
    "values"]) (Property -> SpecM (Arg Property) ())
    -> Property -> SpecM (Arg Property) ()
    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> showReadRoundTrip @Int
    showReadRoundTrip ::
      forall a.
      (Show a, Eq a, Read a, GenValid a) =>
      Property
    showReadRoundTrip :: forall a. (Show a, Eq a, Read a, GenValid a) => 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. GenValid a => Gen a
    genValid :: Gen a) a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    -- |
    --
    -- prop> showReadRoundTripOnArbitrary @Double
    showReadRoundTripOnArbitrary ::
      forall a.
      (Show a, Eq a, Read a, Arbitrary a) =>
      Property
    showReadRoundTripOnArbitrary :: forall a. (Show a, Eq a, Read a, Arbitrary a) => 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 <$> genValid :: Gen Int) (const [])
    showReadRoundTripOnGen ::
      (Show a, Eq a, Read a) => Gen a -> (a -> [a]) -> Property
    showReadRoundTripOnGen :: forall a. (Show a, Eq a, Read a) => Gen a -> (a -> [a]) -> Property
    showReadRoundTripOnGen 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
    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