{-# LANGUAGE ScopedTypeVariables #-} module Hedgehog.Classes.Json (jsonLaws) where import Hedgehog import Hedgehog.Classes.Common import Data.Aeson (FromJSON, ToJSON(toJSON)) import qualified Data.Aeson as Aeson -- | Tests the following 'ToJSON' / 'FromJSON' laws: -- -- [__Encoding Partial Isomorphism__]: @'Aeson.decode' '.' 'Aeson.encode'@ ≡ @'Just'@ -- [__Encoding Equals Value__]: @'Aeson.decode' '.' 'Aeson.encode'@ ≡ @'Just' '.' 'Aeson.toJSON'@ jsonLaws :: (FromJSON a, ToJSON a, Eq a, Show a) => Gen a -> Laws jsonLaws gen = Laws "ToJSON/FromJSON" [ ("Partial Isomorphism", jsonEncodingPartialIsomorphism gen) , ("Encoding equals value", jsonEncodingEqualsValue gen) ] jsonEncodingPartialIsomorphism :: forall a. (ToJSON a, FromJSON a, Show a, Eq a) => Gen a -> Property jsonEncodingPartialIsomorphism gen = property $ do x <- forAll gen let encoded = Aeson.encode x let lhs = Aeson.decode encoded let rhs = Just x let ctx = contextualise $ LawContext { lawContextLawName = "Partial Isomorphism", lawContextTcName = "ToJSON/FromJSON" , lawContextLawBody = "decode . encode" `congruency` "Just" , lawContextTcProp = let showX = show x showEncoded = show encoded in lawWhere [ "decode . encode $ x" `congruency` "Just x, where" , "x = " ++ showX , "encode x = " ++ showEncoded ] , lawContextReduced = reduced lhs rhs } heqCtx lhs rhs ctx jsonEncodingEqualsValue :: forall a. (ToJSON a, Show a) => Gen a -> Property jsonEncodingEqualsValue gen = property $ do x <- forAll gen let encoded = Aeson.encode x let decoded = Aeson.decode encoded :: Maybe Aeson.Value let lhs = decoded let rhs = Just (toJSON x) let ctx = contextualise $ LawContext { lawContextLawName = "Encoding equals value", lawContextTcName = "ToJSON" , lawContextLawBody = "decode . encode" `congruency` "Just . toJSON" , lawContextTcProp = let showX = show x showEncoded = show encoded showDecoded = show decoded in lawWhere [ "decode . encode $ x" `congruency` "Just . toJSON, where" , "x = " ++ showX , "encoded = " ++ showEncoded , "decoded = " ++ showDecoded ] , lawContextReduced = reduced lhs rhs } heqCtx lhs rhs ctx