prolens-0.0.0.1: test/Test/Prolens/Property.hs
module Test.Prolens.Property
( lensPropertySpecs
, typeclassesPropertySpecs
) where
import Hedgehog (Gen)
import Test.Hspec (Spec, describe, it)
import Test.Hspec.Hedgehog (PropertyT, forAll, forAllWith, hedgehog, (===))
import Prolens
import Test.Data (genFun, genFunction, genForget, genHaskeller, genInt, genName, nameL)
lensPropertySpecs :: Spec
lensPropertySpecs = describe "Lens Laws" $ do
it "view lens (set lens value source) ≡ value" $ hedgehog $ do
source <- forAll genHaskeller
value <- forAll genName
view nameL (set nameL value source) === value
it "set lens (view lens source) source ≡ source" $ hedgehog $ do
source <- forAll genHaskeller
set nameL (view nameL source) source === source
it "set lens valueNew (set lens value source) ≡ set lens valueNew source" $ hedgehog $ do
source <- forAll genHaskeller
value <- forAll genName
valueNew <- forAll genName
set nameL valueNew (set nameL value source) === set nameL valueNew source
typeclassesPropertySpecs :: Spec
typeclassesPropertySpecs = describe "Class Laws" $ do
profunctorsSpec
monoidalSpec
profunctorsSpec :: Spec
profunctorsSpec = describe "Profunctor" $ do
profunctorLaws "(->)" genFunction eqFunction
profunctorLaws "Fun" genFun eqFun
profunctorLaws "Forget" genForget eqForget
profunctorLaws
:: Profunctor p
=> String
-> Gen (p Int Int)
-> (p Int Int -> p Int Int -> PropertyT IO ())
-> Spec
profunctorLaws name genProfunctor cmp =
describe name $ do
it "Identity: dimap id id ≡ id" $ hedgehog $ do
f <- forAllWith (const "f") genProfunctor
dimap id id f `cmp` f
it "Composition: dimap (ab . bc) (yz . xy) ≡ dimap bc yz . dimap ab xy" $ hedgehog $ do
f <- forAllWith (const "f") genProfunctor
ab <- forAllWith (const "ab") genFunction
bc <- forAllWith (const "bc") genFunction
xy <- forAllWith (const "xy") genFunction
yz <- forAllWith (const "xy") genFunction
dimap (ab . bc) (yz . xy) f `cmp` (dimap bc yz . dimap ab xy) f
eqFunction :: (Int -> Int) -> (Int -> Int) -> PropertyT IO ()
eqFunction f g = do
n <- forAll genInt
f n === g n
eqFun :: Fun Maybe Int Int -> Fun Maybe Int Int -> PropertyT IO ()
eqFun fun1 fun2 = do
x <- forAll genInt
unFun fun1 x === unFun fun2 x
eqForget :: Forget Int Int a -> Forget Int Int a -> PropertyT IO ()
eqForget forget1 forget2 = do
x <- forAll genInt
unForget forget1 x === unForget forget2 x
monoidalSpec :: Spec
monoidalSpec = describe "Monoidal" $ do
describe "(->)" $ do
it "Identity: pappend f pempty ≡ first f" $ hedgehog $ do
f <- forAllWith (const "f") genFunction
x <- forAll genInt
y <- forAll genInt
pappend f pempty (x, y) === first f (x, y)
it "Identity: pappend pempty f ≡ second f" $ hedgehog $ do
f <- forAllWith (const "f") genFunction
x <- forAll genInt
y <- forAll genInt
pappend pempty f (x, y) === second f (x, y)
it "Associativity (right)" $ hedgehog $ do
f <- forAllWith (const "f") genFunction
g <- forAllWith (const "g") genFunction
h <- forAllWith (const "h") genFunction
x <- forAll genInt
y <- forAll genInt
z <- forAll genInt
pappend f (pappend g h) (x, (y, z)) === (f x, (g y, h z))
it "Associativity (left)" $ hedgehog $ do
f <- forAllWith (const "f") genFunction
g <- forAllWith (const "g") genFunction
h <- forAllWith (const "h") genFunction
x <- forAll genInt
y <- forAll genInt
z <- forAll genInt
pappend (pappend f g) h ((x, y), z) === ((f x, g y), h z)