{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} module Decoder.Laws (decoderLaws) where import Control.Applicative (Applicative, pure) import Control.Monad.Except (throwError) import Data.Functor.Alt (Alt ((<!>))) import Data.Functor.Identity (Identity) import Test.Tasty (TestTree, testGroup) import Test.Tasty.Hedgehog (testProperty) import Hedgehog import qualified Hedgehog.Gen as Gen import qualified Waargonaut.Attoparsec as WA import qualified Waargonaut.Decode as D import Waargonaut.Decode.Error (DecodeError (ConversionFailure)) import Waargonaut.Decode.Types (Decoder) import qualified Laws runD :: Decoder Identity a -> Either (DecodeError, D.CursorHistory) a runD d = WA.pureDecodeAttoparsecText d "true" newtype ShowDecoder a = SD (Decoder Identity a) deriving (Functor, Monad, Applicative) instance Alt ShowDecoder where (SD a) <!> (SD b) = SD (a <!> b) instance Eq a => Eq (ShowDecoder a) where (SD a) == (SD b) = runD a == runD b instance Show a => Show (ShowDecoder a) where show (SD d) = show $ runD d genShowDecoder :: Gen a -> Gen (ShowDecoder a) genShowDecoder genA = Gen.choice [ SD . pure <$> genA , SD <$> Gen.constant (throwError $ ConversionFailure "Intentional DecodeError (TEST)") ] decoderLaws :: TestTree decoderLaws = testGroup "Decoder Laws" [ testGroup "Applicative" [ testProperty "identity" $ Laws.applicative_id genShowDecoder Gen.bool , testProperty "composition" $ Laws.applicative_composition genShowDecoder Gen.bool Gen.bool Gen.bool , testProperty "homomorphism" $ Laws.applicative_homomorphism sdPure Gen.bool Gen.bool , testProperty "interchange" $ Laws.applicative_interchange sdPure Gen.bool Gen.bool ] , testGroup "Alt" [ testProperty "associativity" $ Laws.alt_associativity genShowDecoder Gen.bool , testProperty "left distributes" $ Laws.alt_left_distributes genShowDecoder Gen.bool Gen.bool ] , testGroup "Monad" [ testProperty "return a >>= k = k a" $ Laws.monad_return_bind genShowDecoder Gen.bool Gen.bool , testProperty "m >>= return = m" $ Laws.monad_bind_return_id genShowDecoder Gen.bool , testProperty "associativity" $ Laws.monad_associativity genShowDecoder Gen.bool Gen.bool Gen.bool ] , testGroup "Functor" [ testProperty "'fmap compose'" $ Laws.fmap_compose genShowDecoder Gen.bool Gen.bool Gen.bool ] ] where sdPure = (pure :: a -> ShowDecoder a)