packages feed

validation-0.6.1: test/hedgehog.hs

{-# LANGUAGE OverloadedStrings #-}

import Control.Applicative (liftA3)
import Control.Monad (join, unless)
import Data.Semigroup ((<>))
import Data.Monoid (Monoid (mappend))
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import System.IO (BufferMode(..), hSetBuffering, stdout, stderr)
import System.Exit (exitFailure)

import Data.Validation (AccValidation (AccSuccess, AccFailure))

main :: IO ()
main = do
  hSetBuffering stdout LineBuffering
  hSetBuffering stderr LineBuffering

  result <- checkParallel $ Group "Validation"
    [ ("prop_semigroup", prop_semigroup)
    , ("prop_monoid_assoc", prop_monoid_assoc)
    , ("prop_monoid_left_id", prop_monoid_left_id)
    , ("prop_monoid_right_id", prop_monoid_right_id)
    ]

  unless result $
    exitFailure

genAccValidation :: Gen e -> Gen a -> Gen (AccValidation e a)
genAccValidation e a = Gen.choice [fmap AccFailure e, fmap AccSuccess a]

testGen :: Gen (AccValidation [String] Int)
testGen =
  let range = Range.linear 1 50
      string = Gen.string range Gen.unicode
      strings = Gen.list range string
  in  genAccValidation strings Gen.enumBounded

mkAssoc :: (AccValidation [String] Int -> AccValidation [String] Int -> AccValidation [String] Int) -> Property
mkAssoc f =
  let g = forAll testGen
      assoc = \x y z -> ((x `f` y) `f` z) === (x `f` (y `f` z))
  in  property $ join (liftA3 assoc g g g)

prop_semigroup :: Property
prop_semigroup = mkAssoc (<>)

prop_monoid_assoc :: Property
prop_monoid_assoc = mkAssoc mappend

prop_monoid_left_id :: Property
prop_monoid_left_id =
  property $ do
    x <- forAll testGen
    (mempty `mappend` x) === x

prop_monoid_right_id :: Property
prop_monoid_right_id =
  property $ do
    x <- forAll testGen
    (x `mappend` mempty) === x