packages feed

filepather-0.7.0.0: test/Laws.hs

{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -Wall #-}

-- | Laws of lenses and prisms.
module Laws (
  Laws,
  lensLaws,
  prismLaws,
) where

import Control.Lens (ALens', APrism', cloneLens, clonePrism, preview, review, set, view)
import Data.String (fromString)
import Hedgehog

type Laws = [(PropertyName, Property)]

-- | The lens laws: view-set, set-view and set-set.
lensLaws :: (Eq s, Show s, Eq a, Show a) => String -> ALens' s a -> Gen s -> Gen a -> Laws
lensLaws name l genS genA =
  [
    ( fromString (name <> " view . set")
    , property $
        do
          s <- forAll genS
          a <- forAll genA
          view (cloneLens l) (set (cloneLens l) a s) === a
    )
  ,
    ( fromString (name <> " set . view")
    , property $
        do
          s <- forAll genS
          set (cloneLens l) (view (cloneLens l) s) s === s
    )
  ,
    ( fromString (name <> " set . set")
    , property $
        do
          s <- forAll genS
          a <- forAll genA
          b <- forAll genA
          set (cloneLens l) b (set (cloneLens l) a s) === set (cloneLens l) b s
    )
  ]

-- | The prism laws: preview-review and review-preview.
prismLaws :: (Eq s, Show s, Eq a, Show a) => String -> APrism' s a -> Gen s -> Gen a -> Laws
prismLaws name p genS genA =
  [
    ( fromString (name <> " preview . review")
    , property $
        do
          a <- forAll genA
          preview (clonePrism p) (review (clonePrism p) a) === Just a
    )
  ,
    ( fromString (name <> " review . preview")
    , property $
        do
          s <- forAll genS
          maybe s (review (clonePrism p)) (preview (clonePrism p) s) === s
    )
  ]