Commits

Aleksey Khudyakov  committed 8e37e2f

* Split Equal data type and Equalable into separate module
* Improve documentation

  • Participants
  • Parent commits 15969ca
  • Tags v0.1

Comments (0)

Files changed (6)

File Test/QuickCheck/Property/Common.hs

 {-# LANGUAGE FlexibleContexts  #-}
 {-# LANGUAGE FlexibleInstances #-}
 -- | 
+--
+-- This library provide set of generic properties for laws of standard
+-- type classes and limited way to compose them. Here are some
+-- examples:
+--
+-- Testing monoid laws
+--
+-- >>> quickCheck $ eq $ prop_Monoid (T :: T [Int])
+-- +++ OK, passed 100 tests.
+-- >>> quickCheck $ eq $ prop_Monoid (T :: T (Maybe [Int]))
+-- +++ OK, passed 100 tests.
+-- 
+-- Testing functor laws
+--
+-- >>> quickCheck $ eq $ prop_FunctorCompose (+2) (+199) (T :: T [Int])
+-- +++ OK, passed 100 tests.
+--
 -- /Fixing type/
 --
 -- All properties in this library are polymorphic. For example
 --
 -- A lot of QuickCheck properties have form @expression = another
 -- expression@. It's natural to compare them for equality however not
--- all types have 'Eq' instance. Functions for example and hence many
--- monads.
+-- all types have 'Eq' instance. Functions are most prominent example.
 --
 -- There are three generic ways to compare values for equality.
 --
 --
 --  3. Most generic: use custom comparison function.
 --
--- Functions 'eq', 'eqOn' and 'eqWith' provide this functionality.
+-- Functions 'eq', 'eqOn' and 'eqWith' transform property with delayed
+-- comparison of equality to one which could be tested with quickCheck.
 --
--- Additionally properties of same type could be composed using
--- boolean expressions. 
+-- This approach naturally generelizes to arbitrary boolean
+-- expressions of properties with this form. 
+--
+-- Delaying of comparison and composition of properties is implemented
+-- using 'Equal' data type and 'Equalable' type class.
 module Test.QuickCheck.Property.Common (
-    -- * Comparison for equality
-    Equal(..)
-  , appEqual
-  , Equalable(..)
-    -- ** Compose properties
+    -- * Convert to QuickCheck properies
+    eq
+  , eqOn
+  , eqWith
+    -- * Compose properties
   , (.==.)
   , (.&&.)
   , (.||.)
   , notE
-    -- ** Convert to QuickCheck properies
-  , eq
-  , eqOn
-  , eqWith
     -- * Utils
   , T(..)
-    -- * Examples
-    -- $examples
   ) where
 
 import Data.Function (on)
-
-
--- | Values to be compared for equality
-data Equal a = Equal a a
-             | NotE (Equal a)
-             | AndE (Equal a) (Equal a)
-             | OrE  (Equal a) (Equal a)
-
-appEqual :: (a -> a -> Bool) -> Equal a -> Bool
-appEqual f (Equal a b) = f a b
-appEqual f (NotE e)    = not $ appEqual f e
-appEqual f (AndE e g)  = appEqual f e && appEqual f g
-appEqual f (OrE  e g)  = appEqual f e && appEqual f g
-
--- | Recurse through function to apply comparison to 'Equal'.
-class Equalable a where
-  -- | Type which should be compared for equality
-  type Result a :: *
-  -- | Result of comparison. Could be passed to 'quickCheck'
-  type Compared a :: *
-  -- | Compare value using custom comparison function
-  equalWith :: (Result a -> Result a -> Bool) -> a -> Compared a
-  -- | Map property 
-  mapEqual  :: (Equal (Result a) -> Equal (Result a)) -> a -> a
-  -- | Zip properties
-  zipEquals :: (Equal (Result a) -> Equal (Result a) -> Equal (Result a)) -> a -> a -> a
+import Test.QuickCheck.Property.Common.Internal
 
 -- | Convenience sinonym for 'Equal'. Delay comparison for equality
 (.==.) :: a -> a -> Equal a
 notE :: Equalable a => a -> a
 notE = mapEqual NotE
 
-instance Equalable (Equal a) where
-  type Result   (Equal a) = a
-  type Compared (Equal a) = Bool
-  equalWith = appEqual
-  mapEqual  = id
-  zipEquals = id
-
-instance Equalable a => Equalable (x -> a) where
-  type Result   (x -> a) = Result a
-  type Compared (x -> a) = x -> Compared a
-  equalWith f fun = equalWith f . fun
-  mapEqual  f fun = mapEqual  f . fun
-  zipEquals f fun1 fun2 = \x -> zipEquals f (fun1 x) (fun2 x)
-
 -- | Compare values using @==@ 
 eq :: (Equalable a, Eq (Result a)) => a -> Compared a
 eq = equalWith (==)
 
 -- | Data type is used to fix concrete data in properties
 data T a = T
-
--- $examples
--- 
--- Some example invocation of tests
---
--- Testing monoid laws
---
--- >>> quickCheck $ eq $ prop_Monoid (T :: T [Int])
--- +++ OK, passed 100 tests.
--- >>> quickCheck $ eq $ prop_Monoid (T :: T (Maybe [Int]))
--- +++ OK, passed 100 tests.
--- 
--- Testing functor laws
---
--- >>> quickCheck $ eq $ prop_FunctorCompose (+2) (+199) (T :: T [Int])
--- +++ OK, passed 100 tests.
-

File Test/QuickCheck/Property/Common/Internal.hs

+{-# LANGUAGE TypeFamilies      #-}
+{-# LANGUAGE FlexibleContexts  #-}
+{-# LANGUAGE FlexibleInstances #-}
+-- | Implementation of delayed comparison and composition of
+--   properties
+module Test.QuickCheck.Property.Common.Internal (
+    -- * Comparison for equality
+    Equal(..)
+  , runEqual
+  , Equalable(..)
+  ) where
+
+
+
+-- | Values to be compared for equality
+data Equal a = Equal a a
+             | NotE (Equal a)
+             | AndE (Equal a) (Equal a)
+             | OrE  (Equal a) (Equal a)
+
+-- | Evaluate boolean expression inside 'Equal'
+runEqual :: (a -> a -> Bool) -> Equal a -> Bool
+runEqual f (Equal a b) = f a b
+runEqual f (NotE e)    = not $ runEqual f e
+runEqual f (AndE e g)  = runEqual f e && runEqual f g
+runEqual f (OrE  e g)  = runEqual f e && runEqual f g
+
+
+
+-- | Recurse through function to apply comparison to 'Equal'.
+class Equalable a where
+  -- | Type which should be compared for equality
+  type Result a :: *
+  -- | Result of comparison. Could be passed to 'quickCheck'
+  type Compared a :: *
+  -- | Compare value using custom comparison function
+  equalWith :: (Result a -> Result a -> Bool) -> a -> Compared a
+  -- | Map property 
+  mapEqual  :: (Equal (Result a) -> Equal (Result a)) -> a -> a
+  -- | Zip properties
+  zipEquals :: (Equal (Result a) -> Equal (Result a) -> Equal (Result a)) -> a -> a -> a
+
+instance Equalable (Equal a) where
+  type Result   (Equal a) = a
+  type Compared (Equal a) = Bool
+  equalWith = runEqual
+  mapEqual  = id
+  zipEquals = id
+
+instance Equalable a => Equalable (x -> a) where
+  type Result   (x -> a) = Result a
+  type Compared (x -> a) = x -> Compared a
+  equalWith f fun = equalWith f . fun
+  mapEqual  f fun = mapEqual  f . fun
+  zipEquals f fun1 fun2 = \x -> zipEquals f (fun1 x) (fun2 x)

File Test/QuickCheck/Property/Functor.hs

   ) where
 
 import Test.QuickCheck.Property.Common
+import Test.QuickCheck.Property.Common.Internal
 
 -- | @fmap id = id@
 prop_FunctorId :: Functor f => T (f a) -> f a -> Equal (f a)

File Test/QuickCheck/Property/Generic.hs

   ) where
 
 import Test.QuickCheck.Property.Common
+import Test.QuickCheck.Property.Common.Internal
 
 -- | Test that relation is reflective. 
 --

File Test/QuickCheck/Property/Monoid.hs

 import Data.Monoid
 
 import Test.QuickCheck.Property.Common
+import Test.QuickCheck.Property.Common.Internal
 import Test.QuickCheck.Property.Generic
 
 

File quickcheck-properties.cabal

 Name:                quickcheck-properties
 Version:             0.1
-Synopsis:            QuickCheck properties for type classes from base
+Synopsis:            QuickCheck properties for standard type classes
 License:             BSD3
 License-file:        LICENSE
-Author:              Aleksey Khudyakov
+Author:              Aleksey Khudyakov <alexey.skladnoy@gmail.com>
 Maintainer:          Aleksey Khudyakov <alexey.skladnoy@gmail.com>
 Category:            Testing
 Build-type:          Simple
 Cabal-version:       >=1.6
 Synopsis:            QuickCheck properties for standard type classes.
 Description:
-  Generic QuickCheck properties for standard type classes. Library
-  provide set of generic properties for testing. It doesn't have any
-  QuickCheck specific features and could be used with smallcheck as well.
+  Package provide set of generic QuickCheck properties for testing
+  laws of standard type classes. At the moment is not complete. It do
+  not depend on QuickCheck and could be used with smallcheck as well.
   .
   See module Test.QuickCheck.Property.Common for general description
   of library and examples.
   Ghc-options:         -Wall
   Build-depends:       base >= 3 && < 5
   Exposed-modules:     Test.QuickCheck.Property.Common
+                       Test.QuickCheck.Property.Common.Internal
                        Test.QuickCheck.Property.Generic
                        Test.QuickCheck.Property.Monoid
                        Test.QuickCheck.Property.Functor