Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add checks for Enum #23

Merged
merged 18 commits into from
Nov 10, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/Test/QuickCheck/Laws.purs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Test.QuickCheck.Laws

import Prelude
import Control.Monad.Eff.Console (log)
import Data.Enum (class BoundedEnum)
import Data.Enum (class Enum, class BoundedEnum)
import Data.Monoid (class Monoid)
import Test.QuickCheck (QC)
import Test.QuickCheck.Arbitrary (class Arbitrary, class Coarbitrary)
Expand All @@ -21,6 +21,7 @@ derive newtype instance arbitraryA ∷ Arbitrary A
derive newtype instance boundedA ∷ Bounded A
derive newtype instance boundedEnumA :: BoundedEnum A
derive newtype instance coarbitraryA ∷ Coarbitrary A
derive newtype instance enumA ∷ Enum A
derive newtype instance eqA ∷ Eq A
derive newtype instance ordA ∷ Ord A
derive newtype instance semigroupA ∷ Semigroup A
Expand All @@ -32,6 +33,7 @@ derive newtype instance arbitraryB ∷ Arbitrary B
derive newtype instance boundedB ∷ Bounded B
derive newtype instance boundedEnumB :: BoundedEnum B
derive newtype instance coarbitraryB ∷ Coarbitrary B
derive newtype instance enumB ∷ Enum B
derive newtype instance eqB ∷ Eq B
derive newtype instance ordB ∷ Ord B
derive newtype instance semigroupB ∷ Semigroup B
Expand All @@ -43,6 +45,7 @@ derive newtype instance arbitraryC ∷ Arbitrary C
derive newtype instance boundedC ∷ Bounded C
derive newtype instance boundedEnumC :: BoundedEnum C
derive newtype instance coarbitraryC ∷ Coarbitrary C
derive newtype instance enumC ∷ Enum C
derive newtype instance eqC ∷ Eq C
derive newtype instance ordC ∷ Ord C
derive newtype instance semigroupC ∷ Semigroup C
Expand All @@ -54,6 +57,7 @@ derive newtype instance arbitraryD ∷ Arbitrary D
derive newtype instance boundedD ∷ Bounded D
derive newtype instance boundedEnumD :: BoundedEnum D
derive newtype instance coarbitraryD ∷ Coarbitrary D
derive newtype instance enumD ∷ Enum D
derive newtype instance eqD ∷ Eq D
derive newtype instance ordD ∷ Ord D
derive newtype instance semigroupD ∷ Semigroup D
Expand All @@ -65,6 +69,7 @@ derive newtype instance arbitraryE ∷ Arbitrary E
derive newtype instance boundedE ∷ Bounded E
derive newtype instance boundedEnumE :: BoundedEnum E
derive newtype instance coarbitraryE ∷ Coarbitrary E
derive newtype instance enumE ∷ Enum E
derive newtype instance eqE ∷ Eq E
derive newtype instance ordE ∷ Ord E
derive newtype instance semigroupE ∷ Semigroup E
Expand Down
1 change: 1 addition & 0 deletions src/Test/QuickCheck/Laws/Data.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Test.QuickCheck.Laws.Data (module Exports) where
import Test.QuickCheck.Laws.Data.BooleanAlgebra (checkBooleanAlgebra) as Exports
import Test.QuickCheck.Laws.Data.Bounded (checkBounded) as Exports
import Test.QuickCheck.Laws.Data.CommutativeRing (checkCommutativeRing) as Exports
import Test.QuickCheck.Laws.Data.Enum (checkEnum) as Exports
import Test.QuickCheck.Laws.Data.Eq (checkEq) as Exports
import Test.QuickCheck.Laws.Data.BoundedEnum (checkBoundedEnum) as Exports
import Test.QuickCheck.Laws.Data.EuclideanRing (checkEuclideanRing) as Exports
Expand Down
5 changes: 4 additions & 1 deletion src/Test/QuickCheck/Laws/Data/BoundedEnum.purs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Data.Maybe (Maybe(Just))
import Data.Newtype (unwrap)
import Test.QuickCheck (QC, quickCheck')
import Test.QuickCheck.Arbitrary (class Arbitrary)
import Test.QuickCheck.Laws.Data.Enum (checkEnum)
import Type.Proxy (Proxy)


Expand All @@ -26,7 +27,9 @@ checkBoundedEnum
. (Arbitrary a, BoundedEnum a, Ord a)
⇒ Proxy a
→ QC eff Unit
checkBoundedEnum _ = do
checkBoundedEnum p = do

checkEnum p

log "Checking 'succ' law for BoundedEnum"
quickCheck' 1 succLaw
Expand Down
43 changes: 43 additions & 0 deletions src/Test/QuickCheck/Laws/Data/Enum.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

module Test.QuickCheck.Laws.Data.Enum where

import Prelude
import Control.Monad.Eff.Console (log)
import Data.Enum (pred, succ, class Enum)
import Data.Maybe (Maybe(Nothing))
import Test.QuickCheck (QC, quickCheck')
import Test.QuickCheck.Arbitrary (class Arbitrary)
import Type.Proxy (Proxy)

checkEnum
∷ ∀ eff a
. (Arbitrary a, Enum a, Ord a)
⇒ Proxy a
→ QC eff Unit
checkEnum _ = do

log "Checking 'GT ordering' law for Enum"
quickCheck' 1000 gtordering

log "Checking 'LT ordering' law for Enum"
quickCheck' 1000 ltordering

log "Checking 'predsuccpred' law for BoundedEnum"
quickCheck' 1000 predsuccpredLaw

log "Checking 'succpredsucc' law for BoundedEnum"
quickCheck' 1000 succpredsuccLaw

where
gtordering ∷ a → Boolean
gtordering a = succ a == Nothing || succ a > pred a

ltordering ∷ a → Boolean
ltordering a = succ a == Nothing || pred a < succ a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is redundant; if gtordering holds, and we have a law-abiding Ord instance, then this will certainly hold. I think we should remove this law from the Enum class, really.


predsuccpredLaw :: a -> Boolean
predsuccpredLaw a = succ a == Nothing || (pred a >>= succ >>= pred) == pred a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first I thought this might be a typo and we should be checking pred a == Nothing instead of succ a == Nothing, but actually I think we can remove that check altogether:

If pred a is Nothing, then (pred a >>= succ >>= pred) == pred a will always be true, regardless of whether you have a law-abiding Enum instance. If pred a is Just something, then whether (pred a >>= succ >>= pred) == pred a holds depends on whether you have a law-abiding Enum instance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the last two can get rid of the test.


succpredsuccLaw :: a -> Boolean
succpredsuccLaw a = succ a == Nothing || (succ a >>= pred >>= succ) == succ a