packages feed

QuickCheck (empty) → 1.0

raw patch · 11 files changed

+885/−0 lines, 11 filesdep +basebuild-type:Customsetup-changed

Dependencies added: base

Files

+ Debug/QuickCheck.hs view
@@ -0,0 +1,21 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Debug.QuickCheck+-- Copyright   :  (c) Koen Claessen, John Hughes 2001+-- License     :  BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer  :  libraries@haskell.org+-- Stability   :  deprecated+-- Portability :  portable+--+-- implementation moved to Test.QuickCheck+-----------------------------------------------------------------------------++module Debug.QuickCheck+{-# DEPRECATED "Use module Test.QuickCheck instead" #-}+  ( module Test.QuickCheck+  )+ where++import Test.QuickCheck+
+ Debug/QuickCheck/Batch.hs view
@@ -0,0 +1,21 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Debug.QuickCheck.Batch+-- Copyright   :  (c) Andy Gill 2001+-- License     :  BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer  :  libraries@haskell.org+-- Stability   :  deprecated+-- Portability :  non-portable (uses Control.Exception, Control.Concurrent)+--+-- This is a batch driver for running QuickCheck (GHC only).+--+-----------------------------------------------------------------------------++module Debug.QuickCheck.Batch+{-# DEPRECATED "Use module Test.QuickCheck.Batch instead" #-}+   ( module Test.QuickCheck.Batch+   ) where++import Test.QuickCheck.Batch+
+ Debug/QuickCheck/Poly.hs view
@@ -0,0 +1,19 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Debug.QuickCheck.Poly+-- Copyright   :  (c) Andy Gill 2001+-- License     :  BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer  :  libraries@haskell.org+-- Stability   :  deprecated+-- Portability :  portable+--+-----------------------------------------------------------------------------++module Debug.QuickCheck.Poly+{-# DEPRECATED "Use module Test.QuickCheck.Poly instead" #-}+  ( module Test.QuickCheck.Poly+  ) where++import Test.QuickCheck.Poly+
+ Debug/QuickCheck/Utils.hs view
@@ -0,0 +1,21 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Debug.QuickCheck.Utils+-- Copyright   :  (c) Andy Gill 2001+-- License     :  BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer  :  libraries@haskell.org+-- Stability   :  deprecated+-- Portability :  portable+--+-- These are some general purpose utilities for use with QuickCheck.+--+-----------------------------------------------------------------------------++module Debug.QuickCheck.Utils+{-# DEPRECATED "Use module Test.QuickCheck.Utils instead" #-}+  ( module Test.QuickCheck.Utils+  ) where++import Test.QuickCheck.Utils+
+ LICENSE view
@@ -0,0 +1,31 @@+The Glasgow Haskell Compiler License++Copyright 2004, The University Court of the University of Glasgow. +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 name of the University nor the names of its contributors may be+used to endorse or promote products derived from this software without+specific prior written permission. ++THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF+GLASGOW AND THE 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+UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE 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.
+ QuickCheck.cabal view
@@ -0,0 +1,30 @@+name:		QuickCheck+version:	1.0+license:	BSD3+license-file:	LICENSE+author:		Koen Classen and John Hughes+maintainer:	libraries@haskell.org+category:	Testing+homepage:	http://www.math.chalmers.se/~rjmh/QuickCheck/+synopsis:	Automatic testing of Haskell programs+description:+	A library for testing Haskell programs automatically.+	The programmer provides a specification of the program, in+	the form of properties which functions should satisfy, and+	QuickCheck then tests that the properties hold in a large number+	of randomly generated cases.  Specifications are expressed in+	Haskell, using combinators defined in the QuickCheck library.+	QuickCheck provides combinators to define properties, observe+	the distribution of test data, and define test+	data generators.+exposed-modules:+	Debug.QuickCheck.Batch,+	Debug.QuickCheck.Poly,+	Debug.QuickCheck.Utils,+	Debug.QuickCheck,+	Test.QuickCheck.Batch,+	Test.QuickCheck.Poly,+	Test.QuickCheck.Utils,+	Test.QuickCheck+build-depends:	base+extensions:	CPP
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Test/QuickCheck.hs view
@@ -0,0 +1,355 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Test.QuickCheck+-- Copyright   :  (c) Koen Claessen, John Hughes 2001+-- License     :  BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer  :  libraries@haskell.org+-- Stability   :  experimental+-- Portability :  portable+--+-- QuickCheck v.0.2+-- DRAFT implementation; last update 000104.+-- Koen Claessen, John Hughes.+-- This file represents work in progress, and might change at a later date.+--+-----------------------------------------------------------------------------++module Test.QuickCheck+  -- testing functions+  ( quickCheck    -- :: prop -> IO ()+  , verboseCheck  -- :: prop -> IO ()+  , test          -- :: prop -> IO ()  -- = quickCheck+  +  , Config(..)    -- :: *+  , defaultConfig -- :: Config+  , check         -- :: Config -> prop -> IO ()+ +  -- property combinators+  , forAll        -- :: Gen a -> (a -> prop) -> prop+  , (==>)         -- :: Bool -> prop -> prop+  +  -- gathering test-case information+  , label         -- :: String         -> prop -> prop+  , collect       -- :: Show a => a    -> prop -> prop+  , classify      -- :: Bool -> String -> prop -> prop+  , trivial       -- :: Bool           -> prop -> prop+  +  -- generator combinators+  , Gen           -- :: * -> * ; Functor, Monad+  +  , elements      -- :: [a] -> Gen a+  , two           -- :: Gen a -> Gen (a,a)+  , three         -- :: Gen a -> Gen (a,a,a)+  , four          -- :: Gen a -> Gen (a,a,a,a)+  +  , sized         -- :: (Int -> Gen a) -> Gen a+  , resize        -- :: Int -> Gen a -> Gen a+  , choose        -- :: Random a => (a, a) -> Gen a+  , oneof         -- :: [Gen a] -> Gen a+  , frequency     -- :: [(Int, Gen a)] -> Gen a+  +  , vector        -- :: Arbitrary a => Int -> Gen [a]++  -- default generators+  , Arbitrary(..) -- :: class+  , rand          -- :: Gen StdGen+  , promote       -- :: (a -> Gen b) -> Gen (a -> b)+  , variant       -- :: Int -> Gen a -> Gen a++  -- testable+  , Testable(..)  -- :: class+  , Property      -- :: *++  -- For writing your own driver+  , Result(..)	 -- :: data+  , generate	 -- :: Int -> StdGen -> Gen a -> a+  , evaluate     -- :: Testable a => a -> Gen Result+  )+ where++import Prelude++import System.Random+import Data.List( group, sort, intersperse )+import Control.Monad( liftM2, liftM3, liftM4 )++infixr 0 ==>+infix  1 `classify`++--------------------------------------------------------------------+-- Generator++newtype Gen a+  = Gen (Int -> StdGen -> a)++sized :: (Int -> Gen a) -> Gen a+sized fgen = Gen (\n r -> let Gen m = fgen n in m n r)++resize :: Int -> Gen a -> Gen a+resize n (Gen m) = Gen (\_ r -> m n r)++rand :: Gen StdGen+rand = Gen (\n r -> r)++promote :: (a -> Gen b) -> Gen (a -> b)+promote f = Gen (\n r -> \a -> let Gen m = f a in m n r)++variant :: Int -> Gen a -> Gen a+variant v (Gen m) = Gen (\n r -> m n (rands r !! (v+1)))+ where+  rands r0 = r1 : rands r2 where (r1, r2) = split r0++generate :: Int -> StdGen -> Gen a -> a+generate n rnd (Gen m) = m size rnd'+ where+  (size, rnd') = randomR (0, n) rnd++instance Functor Gen where+  fmap f m = m >>= return . f++instance Monad Gen where+  return a    = Gen (\n r -> a)+  Gen m >>= k =+    Gen (\n r0 -> let (r1,r2) = split r0+                      Gen m'  = k (m n r1)+                   in m' n r2)++-- derived++choose :: Random a => (a, a) -> Gen a+choose bounds = (fst . randomR bounds) `fmap` rand++elements :: [a] -> Gen a+elements xs = (xs !!) `fmap` choose (0, length xs - 1)++vector :: Arbitrary a => Int -> Gen [a]+vector n = sequence [ arbitrary | i <- [1..n] ]++oneof :: [Gen a] -> Gen a+oneof gens = elements gens >>= id++frequency :: [(Int, Gen a)] -> Gen a+frequency xs = choose (1, tot) >>= (`pick` xs)+ where+  tot = sum (map fst xs)++  pick n ((k,x):xs)+    | n <= k    = x+    | otherwise = pick (n-k) xs++-- general monadic++two :: Monad m => m a -> m (a, a)+two m = liftM2 (,) m m++three :: Monad m => m a -> m (a, a, a)+three m = liftM3 (,,) m m m++four :: Monad m => m a -> m (a, a, a, a)+four m = liftM4 (,,,) m m m m++--------------------------------------------------------------------+-- Arbitrary++class Arbitrary a where+  arbitrary   :: Gen a+  coarbitrary :: a -> Gen b -> Gen b++instance Arbitrary () where+  arbitrary     = return ()+  coarbitrary _ = variant 0++instance Arbitrary Bool where+  arbitrary     = elements [True, False]+  coarbitrary b = if b then variant 0 else variant 1++instance Arbitrary Int where+  arbitrary     = sized $ \n -> choose (-n,n)+  coarbitrary n = variant (if n >= 0 then 2*n else 2*(-n) + 1)++instance Arbitrary Integer where+  arbitrary     = sized $ \n -> choose (-fromIntegral n,fromIntegral n)+  coarbitrary n = variant (fromInteger (if n >= 0 then 2*n else 2*(-n) + 1))++instance Arbitrary Float where+  arbitrary     = liftM3 fraction arbitrary arbitrary arbitrary +  coarbitrary x = coarbitrary (decodeFloat x)++instance Arbitrary Double where+  arbitrary     = liftM3 fraction arbitrary arbitrary arbitrary +  coarbitrary x = coarbitrary (decodeFloat x)++fraction a b c = fromInteger a + (fromInteger b / (abs (fromInteger c) + 1))++instance (Arbitrary a, Arbitrary b) => Arbitrary (a, b) where+  arbitrary          = liftM2 (,) arbitrary arbitrary+  coarbitrary (a, b) = coarbitrary a . coarbitrary b++instance (Arbitrary a, Arbitrary b, Arbitrary c) => Arbitrary (a, b, c) where+  arbitrary             = liftM3 (,,) arbitrary arbitrary arbitrary+  coarbitrary (a, b, c) = coarbitrary a . coarbitrary b . coarbitrary c++instance (Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d)+      => Arbitrary (a, b, c, d)+ where+  arbitrary = liftM4 (,,,) arbitrary arbitrary arbitrary arbitrary+  coarbitrary (a, b, c, d) =+    coarbitrary a . coarbitrary b . coarbitrary c . coarbitrary d++instance Arbitrary a => Arbitrary [a] where+  arbitrary          = sized (\n -> choose (0,n) >>= vector)+  coarbitrary []     = variant 0+  coarbitrary (a:as) = coarbitrary a . variant 1 . coarbitrary as++instance (Arbitrary a, Arbitrary b) => Arbitrary (a -> b) where+  arbitrary         = promote (`coarbitrary` arbitrary)+  coarbitrary f gen = arbitrary >>= ((`coarbitrary` gen) . f)++--------------------------------------------------------------------+-- Testable++data Result+  = Result { ok :: Maybe Bool, stamp :: [String], arguments :: [String] }++nothing :: Result+nothing = Result{ ok = Nothing, stamp = [], arguments = [] }++newtype Property+  = Prop (Gen Result)++result :: Result -> Property+result res = Prop (return res)++evaluate :: Testable a => a -> Gen Result+evaluate a = gen where Prop gen = property a++class Testable a where+  property :: a -> Property++instance Testable () where+  property _ = result nothing++instance Testable Bool where+  property b = result (nothing{ ok = Just b })++instance Testable Result where+  property res = result res++instance Testable Property where+  property prop = prop++instance (Arbitrary a, Show a, Testable b) => Testable (a -> b) where+  property f = forAll arbitrary f++forAll :: (Show a, Testable b) => Gen a -> (a -> b) -> Property+forAll gen body = Prop $+  do a   <- gen+     res <- evaluate (body a)+     return (argument a res)+ where+  argument a res = res{ arguments = show a : arguments res }++(==>) :: Testable a => Bool -> a -> Property+True  ==> a = property a+False ==> a = property ()++label :: Testable a => String -> a -> Property+label s a = Prop (add `fmap` evaluate a)+ where+  add res = res{ stamp = s : stamp res }++classify :: Testable a => Bool -> String -> a -> Property+classify True  name = label name+classify False _    = property++trivial :: Testable a => Bool -> a -> Property+trivial = (`classify` "trivial")++collect :: (Show a, Testable b) => a -> b -> Property+collect v = label (show v)++--------------------------------------------------------------------+-- Testing++data Config = Config+  { configMaxTest :: Int+  , configMaxFail :: Int+  , configSize    :: Int -> Int+  , configEvery   :: Int -> [String] -> String+  }++quick :: Config+quick = Config+  { configMaxTest = 100+  , configMaxFail = 1000+  , configSize    = (+ 3) . (`div` 2)+  , configEvery   = \n args -> let s = show n in s ++ [ '\b' | _ <- s ]+  }+         +verbose :: Config+verbose = quick+  { configEvery = \n args -> show n ++ ":\n" ++ unlines args+  }++defaultConfig :: Config+defaultConfig = quick++test, quickCheck, verboseCheck :: Testable a => a -> IO ()+test         = check quick+quickCheck   = check quick+verboseCheck = check verbose+         +check :: Testable a => Config -> a -> IO ()+check config a =+  do rnd <- newStdGen+     tests config (evaluate a) rnd 0 0 []++tests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO () +tests config gen rnd0 ntest nfail stamps+  | ntest == configMaxTest config = do done "OK, passed" ntest stamps+  | nfail == configMaxFail config = do done "Arguments exhausted after" ntest stamps+  | otherwise               =+      do putStr (configEvery config ntest (arguments result))+         case ok result of+           Nothing    ->+             tests config gen rnd1 ntest (nfail+1) stamps+           Just True  ->+             tests config gen rnd1 (ntest+1) nfail (stamp result:stamps)+           Just False ->+             putStr ( "Falsifiable, after "+                   ++ show ntest+                   ++ " tests:\n"+                   ++ unlines (arguments result)+                    )+     where+      result      = generate (configSize config ntest) rnd2 gen+      (rnd1,rnd2) = split rnd0++done :: String -> Int -> [[String]] -> IO ()+done mesg ntest stamps =+  do putStr ( mesg ++ " " ++ show ntest ++ " tests" ++ table )+ where+  table = display+        . map entry+        . reverse+        . sort+        . map pairLength+        . group+        . sort+        . filter (not . null)+        $ stamps++  display []  = ".\n"+  display [x] = " (" ++ x ++ ").\n"+  display xs  = ".\n" ++ unlines (map (++ ".") xs)++  pairLength xss@(xs:_) = (length xss, xs)+  entry (n, xs)         = percentage n ntest+                       ++ " "+                       ++ concat (intersperse ", " xs)++  percentage n m        = show ((100 * n) `div` m) ++ "%"++--------------------------------------------------------------------+-- the end.
+ Test/QuickCheck/Batch.hs view
@@ -0,0 +1,246 @@+{-# OPTIONS_GHC -cpp #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Test.QuickCheck.Batch+-- Copyright   :  (c) Andy Gill 2001+-- License     :  BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer  :  libraries@haskell.org+-- Stability   :  experimental+-- Portability :  non-portable (uses Control.Exception, Control.Concurrent)+--+-- A batch driver for running QuickCheck.+--+-- /Note:/ in GHC only, it is possible to place a time limit on each test,+-- to ensure that testing terminates.+--+-----------------------------------------------------------------------------++{-+ - Here is the key for reading the output.+ -  . = test successful+ -  ? = every example passed, but quickcheck did not find enough good examples+ -  * = test aborted for some reason (out-of-time, bottom, etc)+ -  # = test failed outright+ - + - We also provide the dangerous "isBottom".+ -+ - Here is is an example of use for sorting:+ - + - testOptions :: TestOptions+ - testOptions = TestOptions + -                 { no_of_tests = 100		-- number of tests to run+ -                 , length_of_tests = 1	-- 1 second max per check+ -						-- where a check == n tests+ -                 , debug_tests = False	-- True => debugging info+ -                 }+ - + - prop_sort1 xs = sort xs == sortBy compare xs+ -   where types = (xs :: [OrdALPHA])+ - prop_sort2 xs = + -         (not (null xs)) ==>+ -         (head (sort xs) == minimum xs)+ -   where types = (xs :: [OrdALPHA])+ - prop_sort3 xs = (not (null xs)) ==>+ -         last (sort xs) == maximum xs+ -   where types = (xs :: [OrdALPHA])+ - prop_sort4 xs ys =+ -         (not (null xs)) ==>+ -         (not (null ys)) ==>+ -         (head (sort (xs ++ ys)) == min (minimum xs) (minimum ys))+ -   where types = (xs :: [OrdALPHA], ys :: [OrdALPHA])+ - prop_sort6 xs ys =+ -         (not (null xs)) ==>+ -         (not (null ys)) ==>+ -         (last (sort (xs ++ ys)) == max (maximum xs) (maximum ys))+ -   where types = (xs :: [OrdALPHA], ys :: [OrdALPHA])+ - prop_sort5 xs ys =+ -         (not (null xs)) ==>+ -         (not (null ys)) ==>+ -         (head (sort (xs ++ ys)) == max (maximum xs) (maximum ys))+ -   where types = (xs :: [OrdALPHA], ys :: [OrdALPHA])+ - + - test_sort = runTests "sort" testOptions+ -         [ run prop_sort1+ -         , run prop_sort2+ -         , run prop_sort3+ -         , run prop_sort4+ -         , run prop_sort5+ -         ]+ - + - When run, this gives+ - Main> test_sort+ -                     sort : .....+ - + - You would tie together all the test_* functions+ - into one test_everything, on a per module basis.+ -+ -}++module Test.QuickCheck.Batch+   ( run		-- :: Testable a => a -> TestOptions -> IO TestResult+   , runTests		-- :: String -> TestOptions -> +			--	[TestOptions -> IO TestResult] -> IO ()+   , defOpt		-- :: TestOptions+   , TestOptions (..)+   , TestResult (..)+   , isBottom		-- :: a -> Bool+   , bottom		-- :: a 		{- _|_ -}+   ) where++import Prelude++import System.Random+#ifdef __GLASGOW_HASKELL__+import Control.Concurrent+#endif+import Control.Exception hiding (catch, evaluate)+import qualified Control.Exception as Exception (catch, evaluate)+import Test.QuickCheck+import System.IO.Unsafe++data TestOptions = TestOptions {+	no_of_tests     :: Int,	-- ^ number of tests to run.+	length_of_tests :: Int,	-- ^ time limit for test, in seconds.+				-- If zero, no time limit.+				-- /Note:/ only GHC supports time limits.+	debug_tests     :: Bool }++defOpt :: TestOptions+defOpt = TestOptions +	{ no_of_tests = 100+	, length_of_tests = 1+	, debug_tests = False+	}++data TestResult = TestOk 	String  Int [[String]]+		| TestExausted 	String  Int [[String]]+		| TestFailed   [String] Int+		| TestAborted   Exception++tests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] +      -> IO TestResult+tests config gen rnd0 ntest nfail stamps+  | ntest == configMaxTest config = return (TestOk  "OK, passed" ntest stamps)+  | nfail == configMaxFail config = return (TestExausted "Arguments exhausted after"+					 ntest stamps)+  | otherwise               =+      do (if not (null txt) then putStr txt else return ())+	 case ok result of+           Nothing    ->+             tests config gen rnd1 ntest (nfail+1) stamps+           Just True  ->+             tests config gen rnd1 (ntest+1) nfail (stamp result:stamps)+           Just False ->+             do return (TestFailed (arguments result) ntest)+     where+      txt         = configEvery config ntest (arguments result)+      result      = generate (configSize config ntest) rnd2 gen+      (rnd1,rnd2) = split rnd0++batch n v = Config+  { configMaxTest = n+  , configMaxFail = n * 10+  , configSize    = (+ 3) . (`div` 2)+  , configEvery   = \n args -> if v then show n ++ ":\n" ++ unlines args else ""+  }++-- | Run the test.+-- Here we use the same random number each time,+-- so we get reproducable results!+run :: Testable a => a -> TestOptions -> IO TestResult+run a TestOptions { no_of_tests = n, length_of_tests = len, debug_tests = debug } =+#ifdef __GLASGOW_HASKELL__+  do me <- myThreadId+     ready <- newEmptyMVar+     r <- if len == 0+	   then try theTest+	   else try (do+     	     -- This waits a bit, then raises an exception in its parent,+             -- saying, right, you've had long enough!+	     watcher <- forkIO (Exception.catch+			      (do threadDelay (len * 1000 * 1000)+				  takeMVar ready+				  throwTo me NonTermination+				  return ())+			      (\ _ -> return ()))+	     -- Tell the watcher we are starting...+	     putMVar ready ()+             -- This is cheating, because possibly some of the internal message+             -- inside "r" might be _|_, but anyway....+	     r <- theTest+	     -- Now, we turn off the watcher.+	     -- Ignored if the watcher is already dead,	+	     -- (unless some unlucky thread picks up the same name)+	     killThread watcher+	     return r)+     case r of+        Right r -> return r+        Left  e -> return (TestAborted e)+#else+     Exception.catch theTest $ \ e -> return (TestAborted e)+#endif+  where+	theTest = tests (batch n debug) (evaluate a) (mkStdGen 0) 0 0 []     ++-- | Prints a one line summary of various tests with common theme+runTests :: String -> TestOptions -> [TestOptions -> IO TestResult] -> IO ()+runTests name scale actions =+  do putStr (rjustify 25 name ++ " : ")+     f <- tr 1 actions [] 0+     mapM fa f+     return ()+  where+	rjustify n s = replicate (max 0 (n - length s)) ' ' ++ s++	tr n [] xs c = do+			putStr (rjustify (max 0 (35-n)) " (" ++ show c ++ ")\n")+			return xs+	tr n (action:actions) others c = +	   do r <- action scale+	      case r of+		(TestOk _ m _) +			-> do { putStr "." ;+			       tr (n+1) actions others (c+m) }+		(TestExausted s m ss) ++			-> do { putStr "?" ;+			       tr (n+1) actions others (c+m) }+		(TestAborted e) +			-> do { putStr "*" ;+			       tr (n+1) actions others c }+	  	(TestFailed f num)+			-> do { putStr "#" ;+			        tr (n+1) actions ((f,n,num):others) (c+num) }++	fa :: ([String],Int,Int) -> IO ()+	fa (f,n,no) = +	  do putStr "\n"+	     putStr ("    ** test " +			++ show (n  :: Int)+			++ " of "+			++ name+			++ " failed with the binding(s)\n")+	     sequence_ [putStr ("    **   " ++ v ++ "\n")+			| v <- f ]+  	     putStr "\n"++bottom :: a+bottom = error "_|_"++-- | Look out behind you! These can be misused badly.+-- However, in the context of a batch tester, can also be very useful.+--+-- Examples of use of bottom and isBottom:+--+-- >	{- test for abort -}+-- >	prop_head2 = isBottom (head [])+-- >	{- test for strictness -}+-- >	prop_head3 = isBottom (head bottom)++isBottom :: a -> Bool+isBottom a = unsafePerformIO (do+	a' <- try (Exception.evaluate a)+	case a' of+	   Left _ -> return True+	   Right _ -> return False)
+ Test/QuickCheck/Poly.hs view
@@ -0,0 +1,86 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Test.QuickCheck.Poly+-- Copyright   :  (c) Andy Gill 2001+-- License     :  BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer  :  libraries@haskell.org+-- Stability   :  experimental+-- Portability :  portable+--+-- This is an attempt to emulate polymorphic types for the +-- purposes of testing by using abstract monomorphic types.+-- +-- It is likely that future versions of QuickCheck will+-- include some polymorphic emulation testing facility,+-- but this module can be used for now.+--+-----------------------------------------------------------------------------++module Test.QuickCheck.Poly+  ( ALPHA+  , BETA+  , GAMMA+  , OrdALPHA+  , OrdBETA+  , OrdGAMMA+  ) where++import Prelude++import Test.QuickCheck+import Test.QuickCheck.Utils++{- This is the basic pseudo-polymorphic object.+ - The idea is you can't cheat, and use the integer+ - directly, but need to use the abstraction.+ - + - We use phantom types (ref: Domain Specific Embedded Compilers,+ - Daan Leijen & Erik Meijer, 2nd Conference of Domain Specific+ - Languages, Austin, TX, 1999)+ -}++newtype Poly a = Poly Int++instance Show (Poly a) where+        show (Poly a) = "_" ++ show a++instance Arbitrary (Poly a) where+    arbitrary            = sized $ \n -> (choose (1,n) >>= return . Poly)+    coarbitrary (Poly n) = variant (if n >= 0 then 2*n else 2*(-n) + 1)++instance Eq a => Eq (Poly a) where+        (Poly a) == (Poly b) = a == b++instance Ord a => Ord (Poly a) where+        (Poly a) `compare` (Poly b) = a `compare` b++{-+ - These are what we export, our pseudo-polymorphic instances.+ -}++type ALPHA = Poly ALPHA_+data ALPHA_ = ALPHA_ deriving (Eq)++type BETA = Poly BETA_+data BETA_ = BETA_ deriving (Eq)++type GAMMA = Poly GAMMA_+data GAMMA_ = GAMMA_ deriving (Eq)++type OrdALPHA = Poly OrdALPHA_+data OrdALPHA_ = OrdALPHA_ deriving (Eq,Ord)++type OrdBETA = Poly OrdBETA_+data OrdBETA_ = OrdBETA_ deriving (Eq,Ord)++type OrdGAMMA = Poly OrdGAMMA_+data OrdGAMMA_ = OrdGAMMA_ deriving (Eq,Ord)++{-+ - This is a condition on OrdALPHA, OrdBETA, etc, itself.+ - It states that all OrdALPHA objects obey total ordering.+ -}++prop_OrdPOLY x y = isTotalOrder x y+    where types = (x :: OrdALPHA, y :: OrdALPHA)
+ Test/QuickCheck/Utils.hs view
@@ -0,0 +1,53 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Test.QuickCheck.Utils+-- Copyright   :  (c) Andy Gill 2001+-- License     :  BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer  :  libraries@haskell.org+-- Stability   :  experimental+-- Portability :  portable+--+-- These are some general purpose utilities for use with QuickCheck.+--+-----------------------------------------------------------------------------++module Test.QuickCheck.Utils+  ( isAssociativeBy+  , isAssociative+  , isCommutableBy+  , isCommutable+  , isTotalOrder+  ) where++import Prelude++import Test.QuickCheck++isAssociativeBy :: (Show a,Testable prop) +		=> (a -> a -> prop) -> Gen a -> (a -> a -> a) -> Property+isAssociativeBy (===) src (**) = +     	forAll src $ \ a ->+     	forAll src $ \ b ->+     	forAll src $ \ c ->+	((a ** b) ** c) === (a ** (b ** c))++isAssociative :: (Arbitrary a,Show a,Eq a) => (a -> a -> a) -> Property+isAssociative = isAssociativeBy (==) arbitrary++isCommutableBy :: (Show a,Testable prop) +	       => (b -> b -> prop) -> Gen a -> (a -> a -> b) -> Property+isCommutableBy (===) src (**) =+	forAll src $ \ a ->+	forAll src $ \ b ->+	(a ** b) === (b ** a)++isCommutable :: (Arbitrary a,Show a,Eq b) => (a -> a -> b) -> Property+isCommutable = isCommutableBy (==) arbitrary++isTotalOrder :: (Arbitrary a,Show a,Ord a) => a -> a -> Property+isTotalOrder x y = +    classify (x > y)  "less than" $+    classify (x == y) "equals" $+    classify (x < y)  "greater than" $+    x < y || x == y || x > y