module Test.Toml.Codec.Combinator.Common ( codecRoundtrip , exactCodecRoundtrip -- * Double helpers , Batman (..) , _BatmanDouble , batmanDoubleCodec , batmanFloatCodec ) where import Data.Text (Text) import Hedgehog (Gen, forAll, tripping) import Test.Hspec (Arg, Expectation, SpecWith, it) import Test.Hspec.Hedgehog (hedgehog) import Toml.Codec.BiMap (TomlBiMap) import Toml.Codec.Code (decode, decodeExact, encode) import Toml.Codec.Error (TomlDecodeError) import Toml.Codec.Types (TomlCodec) import Toml.Type.AnyValue (AnyValue) import Toml.Type.Key (Key) import qualified Toml.Codec as Toml codecRoundtripWith :: forall a . (Eq a, Show a) => (TomlCodec a -> Text -> Either [TomlDecodeError] a) -> String -> (Key -> TomlCodec a) -> Gen a -> SpecWith (Arg Expectation) codecRoundtripWith dcode typeName mkCodec genA = it label $ hedgehog $ do a <- forAll genA let codec = mkCodec "a" tripping a (encode codec) (dcode codec) where label :: String label = typeName ++ ": decode . encode ≡ id" codecRoundtrip :: forall a . (Eq a, Show a) => String -> (Key -> TomlCodec a) -> Gen a -> SpecWith (Arg Expectation) codecRoundtrip = codecRoundtripWith decode exactCodecRoundtrip :: forall a . (Eq a, Show a) => String -> (Key -> TomlCodec a) -> Gen a -> SpecWith (Arg Expectation) exactCodecRoundtrip str = codecRoundtripWith decodeExact ("Exact " <> str) -- | Wrapper over 'Double' and 'Float' to be equal on @NaN@ values. newtype Batman a = Batman { unBatman :: a } deriving stock (Show) instance Toml.HasCodec a => Toml.HasCodec (Batman a) where hasCodec = Toml.diwrap . Toml.hasCodec @a instance RealFloat a => Eq (Batman a) where Batman a == Batman b = if isNaN a then isNaN b else a == b _BatmanDouble :: TomlBiMap (Batman Double) AnyValue _BatmanDouble = Toml._Coerce Toml._Double batmanDoubleCodec :: Key -> TomlCodec (Batman Double) batmanDoubleCodec = Toml.match _BatmanDouble batmanFloatCodec :: Key -> TomlCodec (Batman Float) batmanFloatCodec = Toml.diwrap . Toml.float