QuickCheck 2.4.0.1 → 2.4.1
raw patch · 15 files changed
+256/−95 lines, 15 filesdep −mtldep ~template-haskellPVP ok
version bump matches the API change (PVP)
Dependencies removed: mtl
Dependency ranges changed: template-haskell
API changes (from Hackage documentation)
+ Test.QuickCheck.Test: safely :: State -> IO () -> IO ()
Files
- LICENSE +3/−2
- QuickCheck.cabal +48/−13
- README +5/−1
- Test/QuickCheck.hs +4/−1
- Test/QuickCheck/All.hs +37/−1
- Test/QuickCheck/Arbitrary.hs +5/−5
- Test/QuickCheck/Exception.hs +3/−0
- Test/QuickCheck/Function.hs +24/−9
- Test/QuickCheck/Gen.hs +1/−8
- Test/QuickCheck/Modifiers.hs +71/−32
- Test/QuickCheck/Monadic.hs +7/−0
- Test/QuickCheck/Poly.hs +26/−3
- Test/QuickCheck/Property.hs +9/−16
- Test/QuickCheck/State.hs +1/−1
- Test/QuickCheck/Test.hs +12/−3
LICENSE view
@@ -1,5 +1,6 @@-Copyright (c) 2000-2006, Koen Claessen-Copyright (c) 2006, Bjorn Bringert+Copyright (c) 2000-2011, Koen Claessen+Copyright (c) 2006-2008, Björn Bringert+Copyright (c) 2009-2011, Nick Smallbone All rights reserved. Redistribution and use in source and binary forms, with or without
QuickCheck.cabal view
@@ -1,13 +1,15 @@ Name: QuickCheck-Version: 2.4.0.1-Cabal-Version: >= 1.2+Version: 2.4.1+Cabal-Version: >= 1.6 Build-type: Simple License: BSD3 License-file: LICENSE Extra-source-files: README-Copyright: Koen Claessen <koen@chalmers.se>+Copyright: 2000-2011 Koen Claessen, 2006-2008 Björn Bringert, 2009-2001 Nick Smallbone Author: Koen Claessen <koen@chalmers.se> Maintainer: QuickCheck developers <quickcheck@projects.haskell.org>+Bug-reports: mailto:quickcheck@projects.haskell.org+Tested-with: GHC >=6.8, Hugs Homepage: http://code.haskell.org/QuickCheck Category: Testing Synopsis: Automatic testing of Haskell programs@@ -25,29 +27,46 @@ the distribution of test data, and define test data generators. -flag splitBase+source-repository head+ type: darcs+ location: http://code.haskell.org/QuickCheck/++source-repository this+ type: darcs+ location: http://code.haskell.org/QuickCheck+ tag: 2.4.1++flag base3 Description: Choose the new smaller, split-up base package. -flag extensibleExceptions- Description: Choose the even newer, even smaller, split-up base package.+flag base4+ Description: Choose the even newer base package with extensible exceptions. +flag templateHaskell+ Description: Build Test.QuickCheck.All, which uses Template Haskell.+ library- Build-depends: mtl- if flag(extensibleExceptions)+ -- Choose which library versions to use.+ if flag(base4) Build-depends: base >= 4 && < 5, random else- if flag(splitBase)+ if flag(base3) Build-depends: base >= 3 && < 4, random else Build-depends: base < 3++ -- On old versions of GHC use the ghc package to catch ctrl-C. if impl(ghc >= 6.7) && impl(ghc < 6.13) Build-depends: ghc++ -- We want to use extensible-exceptions even if linking against base-3. if impl(ghc >= 6.9) Build-depends: extensible-exceptions++ -- Modules that are always built. Exposed-Modules: Test.QuickCheck, Test.QuickCheck.Arbitrary,- Test.QuickCheck.Function, Test.QuickCheck.Gen, Test.QuickCheck.Monadic, Test.QuickCheck.Modifiers,@@ -56,9 +75,25 @@ Test.QuickCheck.Text, Test.QuickCheck.Poly, Test.QuickCheck.State- if impl(ghc >= 6.12)- Build-depends: template-haskell- Exposed-Modules: Test.QuickCheck.All++ -- Choose which optional features to build based on which compiler+ -- we're using. It would be nice to use flags for this but Cabal's+ -- dependency resolution isn't good enough.+ if impl(ghc)+ Exposed-Modules: Test.QuickCheck.Function+ if flag(templateHaskell) && impl(ghc >= 6.12)+ Build-depends: template-haskell >= 2.4+ Exposed-Modules: Test.QuickCheck.All+ -- GHC < 7.0 doesn't cope with multiple LANGUAGE pragmas in the same+ -- file, I think...+ if impl(ghc < 7)+ Extensions: GeneralizedNewtypeDeriving, MultiParamTypeClasses, Rank2Types, TypeOperators+ else+ -- If your Haskell compiler can cope without some of these, please+ -- send a message to the QuickCheck mailing list!+ cpp-options: -DNO_TIMEOUT -DNO_NEWTYPE_DERIVING+ if !impl(hugs)+ cpp-options: -DNO_ST_MONAD -DNO_MULTI_PARAM_TYPE_CLASSES Other-Modules: Test.QuickCheck.Exception GHC-options:
README view
@@ -1,4 +1,4 @@-This is QuickCheck 2.1.1, a library for random testing of program properties.+This is QuickCheck 2.4.1, a library for random testing of program properties. === Installation === @@ -11,6 +11,10 @@ $ runghc Setup.lhs configure $ runghc Setup.lhs build $ runghc Setup.lhs install++If you get errors about Template Haskell, try++$ cabal install -f-templateHaskell === Bugs ===
Test/QuickCheck.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} module Test.QuickCheck ( -- * Running tests@@ -37,7 +38,7 @@ , sample , sample' - -- * Arbitrary and CoArbitrary classes.+ -- * Arbitrary and CoArbitrary classes , Arbitrary(..) , CoArbitrary(..) @@ -68,7 +69,9 @@ , NonNegative(..) , Smart(..) , Shrink2(..)+#ifndef NO_MULTI_PARAM_TYPE_CLASSES , Shrinking(..)+#endif , ShrinkState(..) -- * Properties
Test/QuickCheck/All.hs view
@@ -1,5 +1,14 @@ {-# LANGUAGE TemplateHaskell, Rank2Types #-}-module Test.QuickCheck.All(forAllProperties, quickCheckAll, mono, polyQuickCheck) where+-- | Experimental features using Template Haskell.+-- You need to have a @{-\# LANGUAGE TemplateHaskell \#-}@ pragma in+-- your module for any of these to work.+module Test.QuickCheck.All(+ -- ** Testing all properties in a module.+ quickCheckAll,+ forAllProperties,+ -- ** Testing polymorphic properties.+ polyQuickCheck,+ mono) where import Language.Haskell.TH import Test.QuickCheck.Property hiding (Result)@@ -8,11 +17,20 @@ import Data.List import Control.Monad +-- | Test a polymorphic property, defaulting all type variables to 'Integer'.+--+-- Invoke as @$('polyQuickCheck' 'prop)@, where @prop@ is a property.+-- Note that just evaluating @'quickCheck' prop@ in GHCi will seem to+-- work, but will silently default all type variables to @()@! polyQuickCheck :: Name -> ExpQ polyQuickCheck x = [| quickCheck $(mono x) |] type Error = forall a. String -> a +-- | Monomorphise an arbitrary name by defaulting all type variables to 'Integer'.+--+-- For example, if @f@ has type @'Ord' a => [a] -> [a]@+-- then @$('mono' 'f)@ has type @['Integer'] -> ['Integer']@. mono :: Name -> ExpQ mono t = do ty0 <- fmap infoType (reify t)@@ -44,6 +62,13 @@ monomorphise err mono ty@(ForallT _ _ _) = err $ "Higher-ranked type" monomorphise err mono ty = return ty +-- | Test all properties in the current module, using a custom+-- 'quickCheck' function. The same caveats as with 'quickCheckAll'+-- apply.+-- +-- @$'forAllProperties'@ has type @('Property' -> 'IO' 'Result') -> 'IO' 'Bool'@.+-- An example invocation is @$'forAllProperties' 'quickCheckResult'@,+-- which does the same thing as @$'quickCheckAll'@. forAllProperties :: Q Exp -- :: (Property -> IO Result) -> IO Bool forAllProperties = do Loc { loc_filename = filename } <- location@@ -59,6 +84,17 @@ else return [] [| runQuickCheckAll $(fmap (ListE . concat) (mapM quickCheckOne idents)) |] +-- | Test all properties in the current module.+-- The name of the property must begin with @prop_@.+-- Polymorphic properties will be defaulted to 'Integer'.+-- Returns 'True' if all tests succeeded, 'False' otherwise.+--+-- Using 'quickCheckAll' interactively doesn't work.+-- Instead, add a definition to your module along the lines of+-- +-- > runTests = $quickCheckAll+-- +-- and then execute @runTests@. quickCheckAll :: Q Exp quickCheckAll = [| $(forAllProperties) quickCheckResult |]
Test/QuickCheck/Arbitrary.hs view
@@ -1,6 +1,6 @@ module Test.QuickCheck.Arbitrary ( - -- * Arbitrary and CoArbitrary classes.+ -- * Arbitrary and CoArbitrary classes Arbitrary(..) , CoArbitrary(..) @@ -255,12 +255,12 @@ ++ [' ','\n'] where a <. b = stamp a < stamp b- stamp a = ( not (isLower a)+ stamp a = ( (not (isLower a) , not (isUpper a)- , not (isDigit a)- , not (a==' ')+ , not (isDigit a))+ , (not (a==' ') , not (isSpace a)- , a+ , a) ) instance Arbitrary Float where
Test/QuickCheck/Exception.hs view
@@ -1,3 +1,6 @@+-- Hide away the nasty implementation-specific ways of catching+-- exceptions behind a nice API. The main trouble is catching ctrl-C.+ {-# LANGUAGE CPP #-} module Test.QuickCheck.Exception where
Test/QuickCheck/Function.hs view
@@ -1,4 +1,22 @@ {-# LANGUAGE TypeOperators, GADTs #-}+-- | Generation of random shrinkable, showable functions.+-- Not really documented at the moment!+--+-- Example of use:+-- +-- >>> :{+-- >>> let prop :: Fun String Integer -> Bool+-- >>> prop (Fun _ f) = f "monkey" == f "banana" || f "banana" == f "elephant"+-- >>> :}+-- >>> quickCheck prop+-- *** Failed! Falsifiable (after 3 tests and 134 shrinks): +-- {"elephant"->1, "monkey"->1, _->0}+--+-- To generate random values of type @'Fun' a b@,+-- you must have an instance @'Function' a@.+-- If your type has a 'Show' instance, you can use 'functionShow' to write the instance; otherwise,+-- use 'functionMap' to give a bijection between your type and a type that is already an instance of 'Function'.+-- See the @'Function' [a]@ instance for an example of the latter. module Test.QuickCheck.Function ( Fun(..) , apply@@ -12,11 +30,8 @@ -------------------------------------------------------------------------- -- imports -import Test.QuickCheck.Gen import Test.QuickCheck.Arbitrary-import Test.QuickCheck.Property import Test.QuickCheck.Poly-import Test.QuickCheck.Modifiers import Data.Char import Data.Word@@ -49,12 +64,12 @@ -- only use this on finite functions showFunction :: (Show a, Show b) => (a :-> b) -> Maybe b -> String showFunction p md =- "{" ++ concat (intersperse "," ( [ show x ++ "->" ++ show c- | (x,c) <- table p- ]- ++ [ "_->" ++ show d- | Just d <- [md]- ] )) ++ "}"+ "{" ++ concat (intersperse ", " ( [ show x ++ "->" ++ show c+ | (x,c) <- table p+ ]+ ++ [ "_->" ++ show d+ | Just d <- [md]+ ] )) ++ "}" -- turning a concrete function into an abstract function (with a default result) abstract :: (a :-> c) -> c -> (a -> c)
Test/QuickCheck/Gen.hs view
@@ -1,3 +1,4 @@+-- | Test case generation. module Test.QuickCheck.Gen where --------------------------------------------------------------------------@@ -19,14 +20,6 @@ import Control.Applicative ( Applicative(..) )--import Control.Monad.Reader()- -- needed for "instance Monad (a ->)"- - -- 2005-09-16:- -- GHC gives a warning for this. I reported this as a bug. /Koen---- * Test case generation -------------------------------------------------------------------------- -- ** Generator type
Test/QuickCheck/Modifiers.hs view
@@ -1,4 +1,40 @@-{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP #-}+#ifndef NO_MULTI_PARAM_TYPE_CLASSES+{-# LANGUAGE MultiParamTypeClasses #-}+#endif+#ifndef NO_NEWTYPE_DERIVING+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+#endif+-- | Modifiers for test data.+--+-- These types do things such as restricting the kind of test data that can be generated.+-- They can be pattern-matched on in properties as a stylistic+-- alternative to using explicit quantification.+-- +-- Examples:+-- +-- @+-- -- Functions cannot be shown (but see "Test.QuickCheck.Function")+-- prop_TakeDropWhile ('Blind' p) (xs :: ['A']) =+-- takeWhile p xs ++ dropWhile p xs == xs+-- @+--+-- @+-- prop_TakeDrop ('NonNegative' n) (xs :: ['A']) =+-- take n xs ++ drop n xs == xs+-- @+--+-- @+-- -- cycle does not work for empty lists+-- prop_Cycle ('NonNegative' n) ('NonEmpty' (xs :: ['A'])) =+-- take n (cycle xs) == take n (xs ++ cycle xs)+-- @+--+-- @+-- -- Instead of 'forAll' 'orderedList'+-- prop_Sort ('Ordered' (xs :: ['OrdA'])) =+-- sort xs == xs+-- @ module Test.QuickCheck.Modifiers ( -- ** Type-level modifiers for changing generator behavior@@ -27,32 +63,13 @@ ) ----------------------------------------------------------------------------- ** arbitrary modifiers---- These datatypes are mainly here to *pattern match* on in properties.--- This is a stylistic alternative to using explicit quantification.--- In other words, they should not be replaced by type synonyms, and their--- constructors should be exported.---- Examples:-{--prop_TakeDropWhile (Blind p) (xs :: [A]) = -- because functions cannot be shown- takeWhile p xs ++ dropWhile p xs == xs--prop_TakeDrop (NonNegative n) (xs :: [A]) = -- (BTW, also works for negative n)- take n xs ++ drop n xs == xs--prop_Cycle (NonNegative n) (NonEmpty (xs :: [A])) = -- cycle does not work for empty lists- take n (cycle xs) == take n (xs ++ cycle xs)--prop_Sort (Ordered (xs :: [OrdA])) = -- instead of "forAll orderedList"- sort xs == xs--}---------------------------------------------------------------------------- -- | @Blind x@: as x, but x does not have to be in the 'Show' class. newtype Blind a = Blind a- deriving ( Eq, Ord, Num, Integral, Real, Enum )+ deriving ( Eq, Ord+#ifndef NO_NEWTYPE_DERIVING+ , Num, Integral, Real, Enum+#endif+ ) instance Show (Blind a) where show _ = "(*)"@@ -65,7 +82,11 @@ -------------------------------------------------------------------------- -- | @Fixed x@: as x, but will not be shrunk. newtype Fixed a = Fixed a- deriving ( Eq, Ord, Num, Integral, Real, Enum, Show, Read )+ deriving ( Eq, Ord, Show, Read+#ifndef NO_NEWTYPE_DERIVING+ , Num, Integral, Real, Enum+#endif+ ) instance Arbitrary a => Arbitrary (Fixed a) where arbitrary = Fixed `fmap` arbitrary@@ -103,8 +124,11 @@ -------------------------------------------------------------------------- -- | @Positive x@: guarantees that @x \> 0@. newtype Positive a = Positive a- deriving ( Eq, Ord, Num, Integral, Real, Enum, Show, Read )-+ deriving ( Eq, Ord, Show, Read+#ifndef NO_NEWTYPE_DERIVING+ , Num, Integral, Real, Enum+#endif+ ) instance (Num a, Ord a, Arbitrary a) => Arbitrary (Positive a) where arbitrary = (Positive . abs) `fmap` (arbitrary `suchThat` (/= 0))@@ -118,7 +142,11 @@ -------------------------------------------------------------------------- -- | @NonZero x@: guarantees that @x \/= 0@. newtype NonZero a = NonZero a- deriving ( Eq, Ord, Num, Integral, Real, Enum, Show, Read )+ deriving ( Eq, Ord, Show, Read+#ifndef NO_NEWTYPE_DERIVING+ , Num, Integral, Real, Enum+#endif+ ) instance (Num a, Ord a, Arbitrary a) => Arbitrary (NonZero a) where arbitrary = fmap NonZero $ arbitrary `suchThat` (/= 0)@@ -128,14 +156,18 @@ -------------------------------------------------------------------------- -- | @NonNegative x@: guarantees that @x \>= 0@. newtype NonNegative a = NonNegative a- deriving ( Eq, Ord, Num, Integral, Real, Enum, Show, Read )+ deriving ( Eq, Ord, Show, Read+#ifndef NO_NEWTYPE_DERIVING+ , Num, Integral, Real, Enum+#endif+ ) instance (Num a, Ord a, Arbitrary a) => Arbitrary (NonNegative a) where arbitrary = frequency -- why is this distrbution like this? [ (5, (NonNegative . abs) `fmap` arbitrary)- , (1, return 0)+ , (1, return (NonNegative 0)) ] shrink (NonNegative x) =@@ -147,7 +179,11 @@ -------------------------------------------------------------------------- -- | @Shrink2 x@: allows 2 shrinking steps at the same time when shrinking x newtype Shrink2 a = Shrink2 a- deriving ( Eq, Ord, Num, Integral, Real, Enum, Show, Read )+ deriving ( Eq, Ord, Show, Read+#ifndef NO_NEWTYPE_DERIVING+ , Num, Integral, Real, Enum+#endif+ ) instance Arbitrary a => Arbitrary (Shrink2 a) where arbitrary =@@ -206,6 +242,7 @@ -- == take k ys ++ drop k ys -- == ys +#ifndef NO_MULTI_PARAM_TYPE_CLASSES -------------------------------------------------------------------------- -- | @Shrinking _ x@: allows for maintaining a state during shrinking. data Shrinking s a =@@ -227,6 +264,8 @@ [ Shrinking s' x' | (x',s') <- shrinkState x s ]++#endif /* NO_MULTI_PARAM_TYPE_CLASSES */ -------------------------------------------------------------------------- -- the end.
Test/QuickCheck/Monadic.hs view
@@ -1,5 +1,10 @@+{-# LANGUAGE CPP #-}+#ifndef NO_ST_MONAD {-# LANGUAGE Rank2Types #-}+#endif -- | Allows testing of monadic values.+-- See the paper \"Testing Monadic Code with QuickCheck\":+-- <http://www.cse.chalmers.se/~rjmh/Papers/QuickCheckST.ps>. module Test.QuickCheck.Monadic where --------------------------------------------------------------------------@@ -75,11 +80,13 @@ monadicIO :: PropertyM IO a -> Property monadicIO = monadic morallyDubiousIOProperty +#ifndef NO_ST_MONAD monadicST :: (forall s. PropertyM (ST s) a) -> Property monadicST m = property (runSTGen (monadic' m)) runSTGen :: (forall s. Gen (ST s a)) -> Gen a runSTGen g = MkGen $ \r n -> runST (unGen g r n)+#endif -------------------------------------------------------------------------- -- the end.
Test/QuickCheck/Poly.hs view
@@ -1,4 +1,15 @@+{-# LANGUAGE CPP #-}+#ifndef NO_NEWTYPE_DERIVING {-# LANGUAGE GeneralizedNewtypeDeriving #-}+#endif+-- | Types to help with testing polymorphic properties.+--+-- Types 'A', 'B' and 'C' are @newtype@ wrappers around 'Integer' that+-- implement 'Eq', 'Show', 'Arbitrary' and 'CoArbitrary'. Types+-- 'OrdA', 'OrdB' and 'OrdC' also implement 'Ord' and 'Num'.+--+-- See also "Test.QuickCheck.All" for an experimental way of testing+-- polymorphic properties. module Test.QuickCheck.Poly ( A(..), B(..), C(..) , OrdA(..), OrdB(..), OrdC(..)@@ -64,7 +75,11 @@ -- OrdA newtype OrdA = OrdA{ unOrdA :: Integer }- deriving ( Eq, Ord, Num )+ deriving ( Eq, Ord+#ifndef NO_NEWTYPE_DERIVING+ , Num+#endif+ ) instance Show OrdA where showsPrec n (OrdA x) = showsPrec n x@@ -79,7 +94,11 @@ -- OrdB newtype OrdB = OrdB{ unOrdB :: Integer }- deriving ( Eq, Ord, Num )+ deriving ( Eq, Ord+#ifndef NO_NEWTYPE_DERIVING+ , Num+#endif+ ) instance Show OrdB where showsPrec n (OrdB x) = showsPrec n x@@ -94,7 +113,11 @@ -- OrdC newtype OrdC = OrdC{ unOrdC :: Integer }- deriving ( Eq, Ord, Num )+ deriving ( Eq, Ord+#ifndef NO_NEWTYPE_DERIVING+ , Num+#endif+ ) instance Show OrdC where showsPrec n (OrdC x) = showsPrec n x
Test/QuickCheck/Property.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE CPP #-} module Test.QuickCheck.Property where --------------------------------------------------------------------------@@ -10,21 +10,9 @@ import Test.QuickCheck.Exception import Test.QuickCheck.State -import Control.Concurrent- ( forkIO- , threadDelay- , killThread- , newEmptyMVar- , takeMVar- , putMVar- )--import System.IO- ( hFlush- , stdout- )-+#ifndef NO_TIMEOUT import System.Timeout(timeout)+#endif import Data.Maybe --------------------------------------------------------------------------@@ -312,7 +300,9 @@ -> Int -- ^ The required percentage (0-100) of test cases. -> String -- ^ Label for the test case class. -> prop -> Property-cover True n s = mapTotalResult $ \res -> res { stamp = (s,n) : stamp res }+cover True n s = n `seq` s `listSeq` (mapTotalResult $ \res -> res { stamp = (s,n) : stamp res })+ where [] `listSeq` z = z+ (x:xs) `listSeq` z = x `seq` xs `listSeq` z cover False _ _ = property -- | Implication for properties: The resulting property holds if@@ -335,6 +325,9 @@ res' <- timeout n (protectResult (return res)) `orError` "within: timeout exception not caught in Result" return (MkRose res' (map f roses))+#ifdef NO_TIMEOUT+ timeout _ = fmap Just+#endif -- | Explicit universal quantification: uses an explicitly given -- test case generator.
Test/QuickCheck/State.hs view
@@ -7,7 +7,7 @@ -- State -- | State represents QuickCheck's internal state while testing a property.--- | The state is made visible to callback functions.+-- The state is made visible to callback functions. data State = MkState -- static
Test/QuickCheck/Test.hs view
@@ -9,7 +9,6 @@ import Test.QuickCheck.Text import Test.QuickCheck.State import Test.QuickCheck.Exception-import Data.IORef import System.Random ( split@@ -368,11 +367,21 @@ callbackPostTest :: State -> P.Result -> IO () callbackPostTest st res =- sequence_ [ f st res | PostTest _ f <- callbacks res ]+ sequence_ [ safely st (f st res) | PostTest _ f <- callbacks res ] callbackPostFinalFailure :: State -> P.Result -> IO () callbackPostFinalFailure st res =- sequence_ [ f st res | PostFinalFailure _ f <- callbacks res ]+ sequence_ [ safely st (f st res) | PostFinalFailure _ f <- callbacks res ]++safely :: State -> IO () -> IO ()+safely st x = do+ r <- tryEvaluateIO x+ case r of+ Left e ->+ putLine (terminal st)+ ("*** Exception in callback: " ++ show e)+ Right x ->+ return x -------------------------------------------------------------------------- -- the end.