quickcheck-classes-0.4.14: QuickCheck common typeclasses

Safe HaskellNone
LanguageHaskell2010

Test.QuickCheck.Classes

Contents

Description

This library provides sets of properties that should hold for common typeclasses.

Synopsis

Running

lawsCheck :: Laws -> IO () Source #

A convenience function for testing properties in GHCi. For example, at GHCi:

>>> lawsCheck (monoidLaws (Proxy :: Proxy Ordering))
Monoid: Associative +++ OK, passed 100 tests.
Monoid: Left Identity +++ OK, passed 100 tests.
Monoid: Right Identity +++ OK, passed 100 tests.

Assuming that the Arbitrary instance for Ordering is good, we now have confidence that the Monoid instance for Ordering satisfies the monoid laws.

lawsCheckMany Source #

Arguments

:: [(String, [Laws])]

Element is type name paired with typeclass laws

-> IO () 

A convenience function for checking multiple typeclass instances of multiple types. Consider the following Haskell source file:

import Data.Proxy (Proxy(..))
import Data.Map (Map)
import Data.Set (Set)

-- A Proxy for Set Int. 
setInt :: Proxy (Set Int)
setInt = Proxy

-- A Proxy for Map Int Int.
mapInt :: Proxy (Map Int Int)
mapInt = Proxy

myLaws :: Proxy a -> [Laws]
myLaws p = [eqLaws p, monoidLaws p]

namedTests :: [(String, [Laws])]
namedTests =
  [ ("Set Int", myLaws setInt)
  , ("Map Int Int", myLaws mapInt)
  ]

Now, in GHCi:

>>> lawsCheckMany namedTests
Testing properties for common typeclasses
-------------
-- Set Int --
-------------

Eq: Transitive +++ OK, passed 100 tests.
Eq: Symmetric +++ OK, passed 100 tests.
Eq: Reflexive +++ OK, passed 100 tests.
Monoid: Associative +++ OK, passed 100 tests.
Monoid: Left Identity +++ OK, passed 100 tests.
Monoid: Right Identity +++ OK, passed 100 tests.
Monoid: Concatenation +++ OK, passed 100 tests.

-----------------
-- Map Int Int --
-----------------

Eq: Transitive +++ OK, passed 100 tests.
Eq: Symmetric +++ OK, passed 100 tests.
Eq: Reflexive +++ OK, passed 100 tests.
Monoid: Associative +++ OK, passed 100 tests.
Monoid: Left Identity +++ OK, passed 100 tests.
Monoid: Right Identity +++ OK, passed 100 tests.
Monoid: Concatenation +++ OK, passed 100 tests.

lawsCheckOne :: Proxy a -> [Proxy a -> Laws] -> IO () Source #

A convenience function that allows one to check many typeclass instances of the same type.

>>> specialisedLawsCheckMany (Proxy :: Proxy Word) [jsonLaws, showReadLaws]
ToJSON/FromJSON: Encoding Equals Value +++ OK, passed 100 tests.
ToJSON/FromJSON: Partial Isomorphism +++ OK, passed 100 tests.
Show/Read: Partial Isomorphism +++ OK, passed 100 tests.

specialisedLawsCheckMany :: Proxy a -> [Proxy a -> Laws] -> IO () Source #

Deprecated: Use the better-named lawsCheckOne instead

A convenience function that allows one to check many typeclass instances of the same type.

>>> specialisedLawsCheckMany (Proxy :: Proxy Word) [jsonLaws, showReadLaws]
ToJSON/FromJSON: Encoding Equals Value +++ OK, passed 100 tests.
ToJSON/FromJSON: Partial Isomorphism +++ OK, passed 100 tests.
Show/Read: Partial Isomorphism +++ OK, passed 100 tests.

Properties

Ground types

bitsLaws :: (FiniteBits a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following properties:

Conjunction Idempotence
n .&. n ≡ n
Disjunction Idempotence
n .|. n ≡ n
Double Complement
complement (complement n) ≡ n
Set Bit
setBit n i ≡ n .|. bit i
Clear Bit
clearBit n i ≡ n .&. complement (bit i)
Complement Bit
complementBit n i ≡ xor n (bit i)
Clear Zero
clearBit zeroBits i ≡ zeroBits
Set Zero
setBit zeroBits i ≡ bit i
Test Zero
testBit zeroBits i ≡ False
Pop Zero
popCount zeroBits ≡ 0
Count Leading Zeros of Zero
countLeadingZeros zeroBits ≡ finiteBitSize ⊥
Count Trailing Zeros of Zero
countTrailingZeros zeroBits ≡ finiteBitSize ⊥

All of the useful instances of the Bits typeclass also have FiniteBits instances, so these property tests actually require that instance as well.

Note: This property test is only available when using base-4.7 or newer.

eqLaws :: (Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following properties:

Transitive
a == b ∧ b == c ⇒ a == c
Symmetric
a == b ⇒ b == a
Reflexive
a == a

Some of these properties involve implication. In the case that the left hand side of the implication arrow does not hold, we do not retry. Consequently, these properties only end up being useful when the data type has a small number of inhabitants.

integralLaws :: (Integral a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following properties:

Quotient Remainder
(quot x y) * y + (rem x y) ≡ x
Division Modulus
(div x y) * y + (mod x y) ≡ x
Integer Roundtrip
fromInteger (toInteger x) ≡ x

isListLaws :: (IsList a, Show a, Show (Item a), Arbitrary a, Arbitrary (Item a), Eq a) => Proxy a -> Laws Source #

Tests the following properties:

Partial Isomorphism
fromList . toList ≡ id
Length Preservation
fromList xs ≡ fromListN (length xs) xs

Note: This property test is only available when using base-4.7 or newer.

jsonLaws :: (ToJSON a, FromJSON a, Show a, Arbitrary a, Eq a) => Proxy a -> Laws Source #

Tests the following properties:

Partial Isomorphism
decode . encode ≡ Just
Encoding Equals Value
decode . encode ≡ Just . toJSON

Note that in the second property, the type of decode is ByteString -> Value, not ByteString -> a

monoidLaws :: (Monoid a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following properties:

Associative
mappend a (mappend b c) ≡ mappend (mappend a b) c
Left Identity
mappend mempty a ≡ a
Right Identity
mappend a mempty ≡ a
Concatenation
mconcat as ≡ foldr mappend mempty as

commutativeMonoidLaws :: (Monoid a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests everything from monoidLaws plus the following:

Commutative
mappend a b ≡ mappend b a

ordLaws :: (Ord a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following properties:

Antisymmetry
a ≤ b ∧ b ≤ a ⇒ a = b
Transitivity
a ≤ b ∧ b ≤ c ⇒ a ≤ c
Totality
a ≤ b ∨ a > b

enumLaws :: (Enum a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following properties:

Succ Pred Identity
succ (pred x) ≡ x
Pred Succ Identity
pred (succ x) ≡ x

This only works for Enum types that are not bounded, meaning that succ and pred must be total. This means that these property tests work correctly for types like Integer but not for Int.

Sadly, there is not a good way to test fromEnum and toEnum, since many types that have reasonable implementations for succ and pred have more inhabitants than Int does.

boundedEnumLaws :: (Enum a, Bounded a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the same properties as enumLaws except that it requires the type to have a Bounded instance. These tests avoid taking the successor of the maximum element or the predecessor of the minimal element.

primLaws :: (Prim a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Test that a Prim instance obey the several laws.

semigroupLaws :: (Semigroup a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following properties:

Associative
a <> (b <> c) ≡ (a <> b) <> c
Concatenation
sconcat as ≡ foldr1 (<>) as
Times
stimes n a ≡ foldr1 (<>) (replicate n a)

commutativeSemigroupLaws :: (Semigroup a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests everything from semigroupLaws, plus the following:

Commutative
a <> b ≡ b <> a

semiringLaws :: (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following properties:

Additive Commutativity
a + b ≡ b + a
Additive Left Identity
0 + a ≡ a
Additive Right Identity
a + 0 ≡ a
Multiplicative Associativity
a * (b * c) ≡ (a * b) * c
Multiplicative Left Identity
1 * a ≡ a
Multiplicative Right Identity
a * 1 ≡ a
Multiplication Left Distributes Over Addition
a * (b + c) ≡ (a * b) + (a * c)
Multiplication Right Distributes Over Addition
(a + b) * c ≡ (a * c) + (b * c)
Multiplicative Left Annihilation
0 * a ≡ 0
Multiplicative Right Annihilation
a * 0 ≡ 0

showReadLaws :: (Show a, Read a, Eq a, Arbitrary a) => Proxy a -> Laws Source #

Tests the following properties:

Partial Isomorphism
readMaybe (show a) == Just a

Note: When using base-4.5 or older, this instead test the following:

Partial Isomorphism
read (show a) == a

storableLaws :: (Storable a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #

Tests the following alternative properties:

Set-Get
runST (pokeElemOff ptr ix a >> peekElemOff ptr ix') ≡ a
Get-Set
runST (peekElemOff ptr ix >> pokeElemOff ptr ix a) ≡ a

Higher-Kinded Types

alternativeLaws :: (Alternative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following alternative properties:

Left Identity
empty <|> x ≡ x
Right Identity
x <|> empty ≡ x
Associativity
a <|> (b <|> c) ≡ (a <|> b) <|> c)

altLaws :: (Alt f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following alt properties:

Associativity
(a <!> b) <!> c ≡ a <!> (b <!> c)
Left Distributivity
f <$> (a <!> b) ≡ (f <$> a) <!> (f <$> b)

applyLaws :: (Apply f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following alt properties:

LiftF2 (1)
(<.>) ≡ liftF2 id

applicativeLaws :: (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following applicative properties:

Identity
pure id <*> v ≡ v
Composition
pure (.) <*> u <*> v <*> w ≡ u <*> (v <*> w)
Homomorphism
pure f <*> pure x ≡ pure (f x)
Interchange
u <*> pure y ≡ pure ($ y) <*> u
LiftA2 (1)
(<*>) ≡ liftA2 id

bifunctorLaws :: (Bifunctor f, Eq2 f, Show2 f, Arbitrary2 f) => proxy f -> Laws Source #

Tests the following Bifunctor properties:

Identity
bimap id idid
First Identity
first idid
Second Identity
second idid
Bifunctor Composition
bimap f g ≡ first f . second g

Note: This property test is only available when this package is built with base-4.9+ or transformers-0.5+.

categoryLaws :: (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Laws Source #

Tests the following Category properties:

Right Identity
f . id ≡ f
Left Identity
id . f ≡ f
Associativity
f . (g . h) ≡ (f . g) . h

Note: This property test is only available when this package is built with base-4.9+ or transformers-0.5+.

commutativeCategoryLaws :: (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Laws Source #

Test everything from categoryLaws plus the following:

Commutative
f . g ≡ g . f

Note: This property test is only available when this package is built with base-4.9+ or transformers-0.5+.

foldableLaws :: (Foldable f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following Foldable properties:

fold
foldfoldMap id
foldMap
foldMap f ≡ foldr (mappend . f) mempty
foldr
foldr f z t ≡ appEndo (foldMap (Endo . f) t ) z
foldr'
foldr' f z0 xs ≡ let f' k x z = k $! f x z in foldl f' id xs z0
foldr1
foldr1 f t ≡ let Just (xs,x) = unsnoc (toList t) in foldr f x xs
foldl
foldl f z t ≡ appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z
foldl'
foldl' f z0 xs ≡ let f' x k z = k $! f z x in foldr f' id xs z0
foldl1
foldl1 f t ≡ let x : xs = toList t in foldl f x xs
toList
toListfoldr (:) []
null
nullfoldr (const (const False)) True
length
lengthgetSum . foldMap (const (Sum 1))

Note that this checks to ensure that foldl' and foldr' are suitably strict.

functorLaws :: (Functor f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following functor properties:

Identity
fmap idid
Composition
fmap (f . g) ≡ fmap f . fmap g
Const
(<$) ≡ fmap const

monadLaws :: (Monad f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following monadic properties:

Left Identity
return a >>= k ≡ k a
Right Identity
m >>= return ≡ m
Associativity
m >>= (\x -> k x >>= h) ≡ (m >>= k) >>= h
Return
purereturn
Ap
(<*>) ≡ ap

monadPlusLaws :: (MonadPlus f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following monad plus properties:

Left Identity
mplus empty x ≡ x
Right Identity
mplus x empty ≡ x
Associativity
mplus a (mplus b c) ≡ mplus (mplus a b) c)
Left Zero
mzero >>= f ≡ mzero
Right Zero
m >> mzeromzero

monadZipLaws :: (MonadZip f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following monadic zipping properties:

Naturality
liftM (f *** g) (mzip ma mb) = mzip (liftM f ma) (liftM g mb)

In the laws above, the infix function *** refers to a typeclass method of Arrow.

plusLaws :: (Plus f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following alt properties:

Left Identity
zero <!> m ≡ m
Right Identity
m <!> zero ≡ m

extendedPlusLaws :: (Plus f, Alternative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests everything from altLaws, plus the following:

Congruency
zeroempty

semigroupoidLaws :: (Semigroupoid sem, Eq2 sem, Show2 sem, Arbitrary2 sem) => proxy sem -> Laws Source #

Tests the following Semigroupoid properties:

Associativity
f `o' (g `o' h) ≡ (f `o' g) `o' h

Note: This property test is only available when this package is built with base-4.9+ or transformers-0.5+.

commutativeSemigroupoidLaws :: (Semigroupoid sem, Eq2 sem, Show2 sem, Arbitrary2 sem) => proxy sem -> Laws Source #

Tests everything from semigroupoidLaws plus the following:

Commutative
f `o' g ≡ g `o' f

Note: This property test is only available when this package is built with base-4.9+ or transformers-0.5+.

traversableLaws :: (Traversable f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #

Tests the following Traversable properties:

Naturality
t . traverse f ≡ traverse (t . f) for every applicative transformation t
Identity
traverse IdentityIdentity
Composition
traverse (Compose . fmap g . f) ≡ Compose . fmap (traverse g) . traverse f
Sequence Naturality
t . sequenceAsequenceA . fmap t for every applicative transformation t
Sequence Identity
sequenceA . fmap IdentityIdentity
Sequence Composition
sequenceA . fmap ComposeCompose . fmap sequenceA . sequenceA
foldMap
foldMapfoldMapDefault
fmap
fmapfmapDefault

Where an applicative transformation is a function

t :: (Applicative f, Applicative g) => f a -> g a

preserving the Applicative operations, i.e.

  • Identity: t (pure x) ≡ pure x
  • Distributivity: t (x <*> y) ≡ t x <*> t y

Types

data Laws Source #

A set of laws associated with a typeclass.

Constructors

Laws 

Fields

data Proxy1 (f :: * -> *) Source #

In older versions of GHC, Proxy is not poly-kinded, so we provide Proxy1.

Constructors

Proxy1 

data Proxy2 (f :: * -> * -> *) Source #

In older versions of GHC, Proxy is not poly-kinded, so we provide Proxy2.

Constructors

Proxy2