packages feed

hedgehog-fn-1.1: example/Example.hs

{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell     #-}
{-# LANGUAGE TypeApplications    #-}

module Main where

import           Hedgehog
import qualified Hedgehog.Gen      as Gen
import qualified Hedgehog.Range    as Range
import           Hedgehog.Function

funIdempotent
  :: forall m a
  . (Monad m, Arg a, Vary a, Eq a, Show a)
  => Gen a
  -> PropertyT m ()
funIdempotent genA = do
  a <- forAll genA
  f <- forAllFn $ fn @a genA
  f a === f (f a)

prop_unit_funIdempotent :: Property
prop_unit_funIdempotent =
  property $
    funIdempotent $ Gen.choice [Right <$> Gen.bool :: Gen (Either () Bool)]

funCongEquality
  :: forall m a
  . (Monad m, Arg a, Vary a, Eq a, Show a)
  => Gen a
  -> Gen a
  -> PropertyT m ()
funCongEquality genA genB = do
  a <- forAll genA
  b <- forAll genB
  f <- forAllFn $ fn @a genA
  if a == b
    then f a === f b
    else pure ()

prop_funCongEquality :: Property
prop_funCongEquality =
  property $
    funCongEquality (Gen.int (Range.linear 1 10)) (Gen.int (Range.linear 1 10))

-- | map (f . g) xs = map f (map g xs)
mapCompose
  :: forall f a b c
   . ( Functor f
     , Show (f a)
     , Show a, Arg a, Vary a
     , Show b, Arg b, Vary b
     , Show c
     , Eq (f c)
     , Show (f c)
     )
  => (forall x. Gen x -> Gen (f x))
  -> Gen a
  -> Gen b
  -> Gen c
  -> Property
mapCompose genF genA genB genC =
  property $ do
    g <- forAllFn $ fn @a genB
    f <- forAllFn $ fn @b genC
    xs <- forAll $ genF genA
    fmap (f . g) xs === fmap f (fmap g xs)

prop_map_list :: Property
prop_map_list =
  mapCompose
    (Gen.list (Range.constant 0 100))
    Gen.bool
    Gen.bool
    Gen.bool

main :: IO Bool
main = checkParallel $$discover