{-| Module : Test.Aeson.Internal.ADT.RoundtripSpecs Description : Roundtrip tests for ToADTArbitrary Copyright : (c) Plow Technologies, 2016 License : BSD3 Maintainer : mchaver@gmail.com Stability : Beta Internal module, use at your own risk. -} {-# LANGUAGE ScopedTypeVariables #-} module Test.Aeson.Internal.ADT.RoundtripSpecs where import Control.Arrow import qualified Data.Aeson as Aeson import Data.Aeson as Aeson hiding (encode) import Data.Typeable import Test.Aeson.Internal.Utils import Test.Hspec import Test.QuickCheck import Test.QuickCheck.Arbitrary.ADT import Control.Monad -- | A roundtrip test to check whether values of all of constructors of the -- given type can be successfully converted to JSON and back to a Haskell value. -- -- 'roundtripADTSpecs' will -- -- - create random values for each constructor using 'ToADTArbitrary', -- - convert them into JSON using 'ToJSON', -- - read them back into Haskell using 'FromJSON' and -- - make sure that the result is the same as the value it started with -- using 'Eq'. roundtripADTSpecs :: forall a. (ToADTArbitrary a, Eq a, Show a, Arbitrary a, ToJSON a, FromJSON a) => Proxy a -> Spec roundtripADTSpecs proxy = genericAesonRoundtripADTWithNote proxy Nothing -- | Same as 'roundtripADTSpecs' but has the option of passing a note to the -- 'describe' function. genericAesonRoundtripADTWithNote :: forall a. (ToADTArbitrary a, Eq a, Show a, Arbitrary a, ToJSON a, FromJSON a) => Proxy a -> Maybe String -> Spec genericAesonRoundtripADTWithNote _ mNote = do adt <- runIO $ generate (toADTArbitrary (Proxy :: Proxy a)) describe ("JSON encoding of " ++ addBrackets (adtTypeName adt) ++ note) $ it "allows to encode values with aeson and read them back" $ forM_ (adtCAPs adt) $ \cap -> (Aeson.encode >>> aesonDecodeIO) (capArbitrary cap) `shouldReturn` capArbitrary cap where note = maybe "" (" " ++) mNote