packages feed

quickcheck-properties (empty) → 0.1

raw patch · 8 files changed

+382/−0 lines, 8 filesdep +basesetup-changed

Dependencies added: base

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Aleksey Khudyakov++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Aleksey Khudyakov nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Test/QuickCheck/Property/Common.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE TypeFamilies      #-}+{-# 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+-- property for checking associativity of 'mappend' could have+-- following type:+--+-- > prop_mappend :: (Eq a, Monoid a) => a -> a -> a -> Bool+--+-- But if one tries to pass this expression to 'quickCheck' GHC will+-- rightfully complain that type is too generic. Indeed there is no+-- way to figure out what is type of a. Obvious way to fix type of @a@+-- is to add type signature. However it's too cumbersome to write+-- signature for 3 parameter function. +--+-- Another approach was taken instead. All properties take dummy+-- parameter which fix type:+--+-- > prop_Mappend :: (Eq a, Monoid a) => T a -> a -> a -> a -> Bool+--+-- 'T' is phanom typed unit. It ensures that only type information+-- could be passed to function. For example test invokation could look+-- like this:+--+-- > quickCheck $ prop_Mappend (T :: T [Int])+--+-- By convention all user supplied parameters are placed before T and+-- all quickcheck supplied parameters are after T.+--+-- /Comparing for equality/+--+-- 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 are most prominent example.+--+-- There are three generic ways to compare values for equality.+--+--  (1) Use '==' operator+--+--  2. Convert value to some type with Eq instance and compare+--     them. Caller must ensure that such conversion make sence+--+--  3. Most generic: use custom comparison function.+--+-- Functions 'eq', 'eqOn' and 'eqWith' transform property with delayed+-- comparison of equality to one which could be tested with quickCheck.+--+-- 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 (+    -- * Convert to QuickCheck properies+    eq+  , eqOn+  , eqWith+    -- * Compose properties+  , (.==.)+  , (.&&.)+  , (.||.)+  , notE+    -- * Utils+  , T(..)+  ) where++import Data.Function (on)+import Test.QuickCheck.Property.Common.Internal++-- | Convenience sinonym for 'Equal'. Delay comparison for equality+(.==.) :: a -> a -> Equal a+(.==.) = Equal++-- | Both properties are true.+(.&&.) :: Equalable a => a -> a -> a+(.&&.) = zipEquals AndE++-- | One of properties is true+(.||.) :: Equalable a => a -> a -> a+(.||.) = zipEquals OrE++-- | Property is false+notE :: Equalable a => a -> a+notE = mapEqual NotE++-- | Compare values using @==@ +eq :: (Equalable a, Eq (Result a)) => a -> Compared a+eq = equalWith (==)++-- | Convert values to types which could be compare+eqOn :: (Equalable a, Eq b) => (Result a -> b) -> a -> Compared a+eqOn f = equalWith ((==) `on` f)++-- | Compare with custom function. Just a shorter sinonym for equalWith+eqWith :: (Equalable a) => (Result a -> Result a -> Bool) -> a -> Compared a+eqWith = equalWith+++-- | Data type is used to fix concrete data in properties+data T a = T
+ Test/QuickCheck/Property/Common/Internal.hs view
@@ -0,0 +1,55 @@+{-# 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)
+ Test/QuickCheck/Property/Functor.hs view
@@ -0,0 +1,26 @@+-- | Functor laws+-- +-- > fmap id = id+-- > fmap f . fmap g = fmap (f . g)+module Test.QuickCheck.Property.Functor (+    module Test.QuickCheck.Property.Common+  , prop_FunctorId+  , prop_FunctorCompose+  ) 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)+prop_FunctorId T f = f .==. fmap id f++-- | It's not possible to generate arbitrary functions. Therefore they+--   are passed as arguments. +prop_FunctorCompose :: Functor f => +                       (a -> b) -- ^ f+                    -> (b -> c) -- ^ g+                    -> T (f a)+                    -> f a+                    -> Equal (f c)+prop_FunctorCompose f g T x = (fmap g $ fmap f $ x) .==. (fmap (g . f) x)
+ Test/QuickCheck/Property/Generic.hs view
@@ -0,0 +1,81 @@+-- | Generic properties of functions+module Test.QuickCheck.Property.Generic (+    module Test.QuickCheck.Property.Common+    -- * General+  , prop_Reflexive+    -- * Monoids & group+  , prop_Associative+  , prop_Commutative+  , prop_LeftIdentity+  , prop_RightIdentity+  , prop_Identity+  , prop_GroupInverse+    -- ** General+  , prop_GenMonoid+  , prop_Group+  ) where++import Test.QuickCheck.Property.Common+import Test.QuickCheck.Property.Common.Internal++-- | Test that relation is reflective. +--+-- > f x x = True+prop_Reflexive :: (a -> a -> Bool) -> T a -> a -> Bool+prop_Reflexive f T x = f x x+++----------------------------------------------------------------+-- Monoids & Co+----------------------------------------------------------------++-- | Test that function is commutative+prop_Commutative :: (a -> a -> b) -> T (a,b) -> a -> a -> Equal b+prop_Commutative f T x y = f x y .==. f y x++-- | Test that function is associative+prop_Associative :: (a -> a -> a) -> T a -> a -> a -> a -> Equal a+prop_Associative (<>) T a b c = ((a <> b) <> c) .==. (a <> (b <> c))++-- | Test that value is a left identity+prop_LeftIdentity :: a             -- ^ Left identity+                  -> (a -> a -> a) -- ^ Associative operation+                  -> T a -> a -> Equal a+prop_LeftIdentity e (<>) T x = (e <> x) .==. x++-- | Test that value is a left identity+prop_RightIdentity :: a             -- ^ Right identity+                   -> (a -> a -> a) -- ^ Associative operation+                   -> T a -> a -> Equal a+prop_RightIdentity e (<>) T x = (x <> e) .==. x++-- | Test that value is both right and left identity+prop_Identity :: a             -- ^ Identity element+              -> (a -> a -> a) -- ^ Associative operation+              -> T a -> a -> Equal a+prop_Identity = prop_LeftIdentity .&&. prop_RightIdentity+  ++-- | Test that inverse operation is correct.+prop_GroupInverse :: a             -- ^ Identity element+                  -> (a -> a -> a) -- ^ Group operation+                  -> (a -> a)      -- ^ Find inverse +                  -> T a -> a -> Equal a+prop_GroupInverse e (<>) inv T x =  ((x <> inv x) .==. e)+                               .&&. ((inv x <> x) .==. e)++-- | Test that identity and associative operation satisfy monoid laws.+prop_GenMonoid :: a             -- ^ Identity element+               -> (a -> a -> a) -- ^ Associative operation+               -> T a -> a -> a -> a -> Equal a+prop_GenMonoid e (<>) T x y z =  prop_Associative   (<>) T x y z+                         .&&. prop_Identity    e (<>) T x   ++-- | Test that identity, associative operation and inverse satisfy group laws+prop_Group :: a                -- ^ Identity element+           -> (a -> a -> a)    -- ^ Associative operation+           -> (a -> a)         -- ^ Find inverse element+           -> T a -> a -> a -> a -> Equal a+prop_Group e (<>) inv T x y z =  prop_Identity     e (<>)     T x +                            .&&. prop_Associative    (<>)     T x y z+                            .&&. prop_GroupInverse e (<>) inv T x
+ Test/QuickCheck/Property/Monoid.hs view
@@ -0,0 +1,37 @@+-- | Properties for 'Monoid' type class+module Test.QuickCheck.Property.Monoid (+    module Test.QuickCheck.Property.Common+  , prop_MonoidLeft+  , prop_MonoidRight+  , prop_MonoidIdentity+  , prop_Mappend+  , prop_Monoid+  ) where++import Data.Monoid++import Test.QuickCheck.Property.Common+import Test.QuickCheck.Property.Common.Internal+import Test.QuickCheck.Property.Generic+++-- | 'mempty' is left identity+prop_MonoidLeft :: Monoid a => T a -> a -> Equal a+prop_MonoidLeft = prop_LeftIdentity mempty mappend++-- | 'mempty' is right identity+prop_MonoidRight :: Monoid a => T a -> a -> Equal a+prop_MonoidRight = prop_RightIdentity mempty mappend++-- | 'mempty' is identity+prop_MonoidIdentity :: Monoid a => T a -> a -> Equal a+prop_MonoidIdentity = prop_Identity mempty mappend++-- | 'mappend' is associative+prop_Mappend :: Monoid a => T a -> a -> a -> a -> Equal a+prop_Mappend = prop_Associative mappend++-- | All properties of monoid+prop_Monoid :: Monoid a => T a -> a -> a -> a -> Equal a+prop_Monoid = prop_GenMonoid mempty mappend+
+ quickcheck-properties.cabal view
@@ -0,0 +1,31 @@+Name:                quickcheck-properties+Version:             0.1+Synopsis:            QuickCheck properties for standard type classes+License:             BSD3+License-file:        LICENSE+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:+  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.++source-repository head+  type:     hg+  location: https://bitbucket.org/Shimuuar/quickcheck-properties++Library+  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