QuickCheck 2.9.2 → 2.10
raw patch · 26 files changed
+2263/−398 lines, 26 filesdep +deepseqdep −natsdep −semigroupsdep −test-frameworkdep ~QuickCheckdep ~basedep ~randomPVP ok
version bump matches the API change (PVP)
Dependencies added: deepseq
Dependencies removed: nats, semigroups, test-framework
Dependency ranges changed: QuickCheck, base, random, transformers
API changes (from Hackage documentation)
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary (f a) => Test.QuickCheck.Arbitrary.Arbitrary (Data.Monoid.Alt f a)
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary GHC.Natural.Natural
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Data.Functor.Const.Const a b)
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Data.Functor.Constant.Constant a b)
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Data.List.NonEmpty.NonEmpty a)
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary (f a) => Test.QuickCheck.Arbitrary.CoArbitrary (Data.Monoid.Alt f a)
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary GHC.Natural.Natural
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Data.Functor.Const.Const a b)
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Data.Functor.Constant.Constant a b)
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Data.List.NonEmpty.NonEmpty a)
- Test.QuickCheck.Function: instance Test.QuickCheck.Function.Function GHC.Natural.Natural
- Test.QuickCheck.Function: instance Test.QuickCheck.Function.Function a => Test.QuickCheck.Function.Function (Data.List.NonEmpty.NonEmpty a)
- Test.QuickCheck.Monadic: instance GHC.Base.Monad m => GHC.Base.Applicative (Test.QuickCheck.Monadic.PropertyM m)
- Test.QuickCheck.Test: insufficientCoverage :: State -> Bool
- Test.QuickCheck.Test: labelPercentage :: String -> State -> Int
+ Test.QuickCheck: ASCIIString :: String -> ASCIIString
+ Test.QuickCheck: PrintableString :: String -> PrintableString
+ Test.QuickCheck: UnicodeString :: String -> UnicodeString
+ Test.QuickCheck: [failingTestCase] :: Result -> [String]
+ Test.QuickCheck: [getASCIIString] :: ASCIIString -> String
+ Test.QuickCheck: [getPrintableString] :: PrintableString -> String
+ Test.QuickCheck: [getUnicodeString] :: UnicodeString -> String
+ Test.QuickCheck: [maxShrinks] :: Args -> Int
+ Test.QuickCheck: applyFun :: Fun a b -> (a -> b)
+ Test.QuickCheck: applyFun2 :: Fun (a, b) c -> (a -> b -> c)
+ Test.QuickCheck: applyFun3 :: Fun (a, b, c) d -> (a -> b -> c -> d)
+ Test.QuickCheck: arbitrary1 :: (Arbitrary1 f, Arbitrary a) => Gen (f a)
+ Test.QuickCheck: arbitrary2 :: (Arbitrary2 f, Arbitrary a, Arbitrary b) => Gen (f a b)
+ Test.QuickCheck: arbitraryASCIIChar :: Gen Char
+ Test.QuickCheck: arbitraryPrintableChar :: Gen Char
+ Test.QuickCheck: arbitraryUnicodeChar :: Gen Char
+ Test.QuickCheck: class Arbitrary1 f where liftShrink _ _ = []
+ Test.QuickCheck: class Arbitrary2 f where liftShrink2 _ _ _ = []
+ Test.QuickCheck: class Function a where function = genericFunction
+ Test.QuickCheck: data Fun a b
+ Test.QuickCheck: function :: (Function a, Generic a, GFunction (Rep a)) => (a -> b) -> (a :-> b)
+ Test.QuickCheck: functionMap :: Function b => (a -> b) -> (b -> a) -> (a -> c) -> (a :-> c)
+ Test.QuickCheck: getSize :: Gen Int
+ Test.QuickCheck: liftArbitrary :: Arbitrary1 f => Gen a -> Gen (f a)
+ Test.QuickCheck: liftArbitrary2 :: Arbitrary2 f => Gen a -> Gen b -> Gen (f a b)
+ Test.QuickCheck: liftShrink :: Arbitrary1 f => (a -> [a]) -> f a -> [f a]
+ Test.QuickCheck: liftShrink2 :: Arbitrary2 f => (a -> [a]) -> (b -> [b]) -> f a b -> [f a b]
+ Test.QuickCheck: newtype ASCIIString
+ Test.QuickCheck: newtype PrintableString
+ Test.QuickCheck: newtype UnicodeString
+ Test.QuickCheck: shrink1 :: (Arbitrary1 f, Arbitrary a) => f a -> [f a]
+ Test.QuickCheck: shrink2 :: (Arbitrary2 f, Arbitrary a, Arbitrary b) => f a b -> [f a b]
+ Test.QuickCheck: shrinkMap :: Arbitrary a => (a -> b) -> (b -> a) -> b -> [b]
+ Test.QuickCheck: shrinkMapBy :: (a -> b) -> (b -> a) -> (a -> [a]) -> b -> [b]
+ Test.QuickCheck: suchThatMap :: Gen a -> (a -> Maybe b) -> Gen b
+ Test.QuickCheck: total :: NFData a => a -> Property
+ Test.QuickCheck: withMaxSuccess :: Testable prop => Int -> prop -> Property
+ Test.QuickCheck.Arbitrary: arbitrary1 :: (Arbitrary1 f, Arbitrary a) => Gen (f a)
+ Test.QuickCheck.Arbitrary: arbitrary2 :: (Arbitrary2 f, Arbitrary a, Arbitrary b) => Gen (f a b)
+ Test.QuickCheck.Arbitrary: arbitraryASCIIChar :: Gen Char
+ Test.QuickCheck.Arbitrary: arbitraryPrintableChar :: Gen Char
+ Test.QuickCheck.Arbitrary: arbitraryUnicodeChar :: Gen Char
+ Test.QuickCheck.Arbitrary: class Arbitrary1 f where liftShrink _ _ = []
+ Test.QuickCheck.Arbitrary: class Arbitrary2 f where liftShrink2 _ _ _ = []
+ Test.QuickCheck.Arbitrary: instance (GHC.Classes.Ord k, Test.QuickCheck.Arbitrary.Arbitrary k) => Test.QuickCheck.Arbitrary.Arbitrary1 (Data.Map.Base.Map k)
+ Test.QuickCheck.Arbitrary: instance (Test.QuickCheck.Arbitrary.Arbitrary1 f, Test.QuickCheck.Arbitrary.Arbitrary1 g) => Test.QuickCheck.Arbitrary.Arbitrary1 (Data.Functor.Compose.Compose f g)
+ Test.QuickCheck.Arbitrary: instance (Test.QuickCheck.Arbitrary.Arbitrary1 f, Test.QuickCheck.Arbitrary.Arbitrary1 g) => Test.QuickCheck.Arbitrary.Arbitrary1 (Data.Functor.Product.Product f g)
+ Test.QuickCheck.Arbitrary: instance (Test.QuickCheck.Arbitrary.Arbitrary1 f, Test.QuickCheck.Arbitrary.Arbitrary1 g, Test.QuickCheck.Arbitrary.Arbitrary a) => Test.QuickCheck.Arbitrary.Arbitrary (Data.Functor.Compose.Compose f g a)
+ Test.QuickCheck.Arbitrary: instance (Test.QuickCheck.Arbitrary.Arbitrary1 f, Test.QuickCheck.Arbitrary.Arbitrary1 g, Test.QuickCheck.Arbitrary.Arbitrary a) => Test.QuickCheck.Arbitrary.Arbitrary (Data.Functor.Product.Product f g a)
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary (a b c) => Test.QuickCheck.Arbitrary.Arbitrary (Control.Applicative.WrappedArrow a b c)
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary (m a) => Test.QuickCheck.Arbitrary.Arbitrary (Control.Applicative.WrappedMonad m a)
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CChar
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CClock
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CDouble
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CFloat
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CInt
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CIntMax
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CIntPtr
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CLLong
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CLong
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CPtrdiff
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CSChar
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CSUSeconds
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CShort
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CSigAtomic
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CSize
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CTime
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CUChar
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CUInt
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CUIntMax
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CUIntPtr
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CULLong
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CULong
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CUSeconds
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CUShort
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Foreign.C.Types.CWchar
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary GHC.IO.Exception.ExitCode
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary Test.QuickCheck.Random.QCGen
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary1 ((,) a)
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary1 (Data.Either.Either a)
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary1 (Data.Functor.Const.Const a)
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary1 (Data.Functor.Constant.Constant a)
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary1 Control.Applicative.ZipList
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary1 Data.Functor.Identity.Identity
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary1 Data.IntMap.Base.IntMap
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary1 Data.Sequence.Seq
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary1 GHC.Base.Maybe
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary1 []
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary2 (,)
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary2 Data.Either.Either
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary2 Data.Functor.Const.Const
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary2 Data.Functor.Constant.Constant
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.Arbitrary1 ((->) a)
+ Test.QuickCheck.Arbitrary: instance forall k (f :: k -> *) (a :: k). Test.QuickCheck.Arbitrary.Arbitrary (f a) => Test.QuickCheck.Arbitrary.Arbitrary (Data.Monoid.Alt f a)
+ Test.QuickCheck.Arbitrary: instance forall k (f :: k -> *) (a :: k). Test.QuickCheck.Arbitrary.CoArbitrary (f a) => Test.QuickCheck.Arbitrary.CoArbitrary (Data.Monoid.Alt f a)
+ Test.QuickCheck.Arbitrary: instance forall k a (b :: k). Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Data.Functor.Const.Const a b)
+ Test.QuickCheck.Arbitrary: instance forall k a (b :: k). Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Data.Functor.Constant.Constant a b)
+ Test.QuickCheck.Arbitrary: instance forall k a (b :: k). Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Data.Functor.Const.Const a b)
+ Test.QuickCheck.Arbitrary: instance forall k a (b :: k). Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Data.Functor.Constant.Constant a b)
+ Test.QuickCheck.Arbitrary: liftArbitrary :: Arbitrary1 f => Gen a -> Gen (f a)
+ Test.QuickCheck.Arbitrary: liftArbitrary2 :: Arbitrary2 f => Gen a -> Gen b -> Gen (f a b)
+ Test.QuickCheck.Arbitrary: liftShrink :: Arbitrary1 f => (a -> [a]) -> f a -> [f a]
+ Test.QuickCheck.Arbitrary: liftShrink2 :: Arbitrary2 f => (a -> [a]) -> (b -> [b]) -> f a b -> [f a b]
+ Test.QuickCheck.Arbitrary: shrink1 :: (Arbitrary1 f, Arbitrary a) => f a -> [f a]
+ Test.QuickCheck.Arbitrary: shrink2 :: (Arbitrary2 f, Arbitrary a, Arbitrary b) => f a b -> [f a b]
+ Test.QuickCheck.Arbitrary: shrinkMap :: Arbitrary a => (a -> b) -> (b -> a) -> b -> [b]
+ Test.QuickCheck.Arbitrary: shrinkMapBy :: (a -> b) -> (b -> a) -> (a -> [a]) -> b -> [b]
+ Test.QuickCheck.Function: applyFun :: Fun a b -> (a -> b)
+ Test.QuickCheck.Function: applyFun2 :: Fun (a, b) c -> (a -> b -> c)
+ Test.QuickCheck.Function: applyFun3 :: Fun (a, b, c) d -> (a -> b -> c -> d)
+ Test.QuickCheck.Function: instance GHC.Classes.Eq Test.QuickCheck.Function.Shrunk
+ Test.QuickCheck.Function: instance Test.QuickCheck.Function.Function GHC.Types.Word
+ Test.QuickCheck.Gen: getSize :: Gen Int
+ Test.QuickCheck.Gen: suchThatMap :: Gen a -> (a -> Maybe b) -> Gen b
+ Test.QuickCheck.Modifiers: ASCIIString :: String -> ASCIIString
+ Test.QuickCheck.Modifiers: PrintableString :: String -> PrintableString
+ Test.QuickCheck.Modifiers: UnicodeString :: String -> UnicodeString
+ Test.QuickCheck.Modifiers: [getASCIIString] :: ASCIIString -> String
+ Test.QuickCheck.Modifiers: [getPrintableString] :: PrintableString -> String
+ Test.QuickCheck.Modifiers: [getUnicodeString] :: UnicodeString -> String
+ Test.QuickCheck.Modifiers: instance GHC.Arr.Ix a => GHC.Arr.Ix (Test.QuickCheck.Modifiers.Large a)
+ Test.QuickCheck.Modifiers: instance GHC.Arr.Ix a => GHC.Arr.Ix (Test.QuickCheck.Modifiers.Small a)
+ Test.QuickCheck.Modifiers: instance GHC.Classes.Eq Test.QuickCheck.Modifiers.ASCIIString
+ Test.QuickCheck.Modifiers: instance GHC.Classes.Eq Test.QuickCheck.Modifiers.PrintableString
+ Test.QuickCheck.Modifiers: instance GHC.Classes.Eq Test.QuickCheck.Modifiers.UnicodeString
+ Test.QuickCheck.Modifiers: instance GHC.Classes.Ord Test.QuickCheck.Modifiers.ASCIIString
+ Test.QuickCheck.Modifiers: instance GHC.Classes.Ord Test.QuickCheck.Modifiers.PrintableString
+ Test.QuickCheck.Modifiers: instance GHC.Classes.Ord Test.QuickCheck.Modifiers.UnicodeString
+ Test.QuickCheck.Modifiers: instance GHC.Read.Read Test.QuickCheck.Modifiers.ASCIIString
+ Test.QuickCheck.Modifiers: instance GHC.Read.Read Test.QuickCheck.Modifiers.PrintableString
+ Test.QuickCheck.Modifiers: instance GHC.Read.Read Test.QuickCheck.Modifiers.UnicodeString
+ Test.QuickCheck.Modifiers: instance GHC.Show.Show Test.QuickCheck.Modifiers.ASCIIString
+ Test.QuickCheck.Modifiers: instance GHC.Show.Show Test.QuickCheck.Modifiers.PrintableString
+ Test.QuickCheck.Modifiers: instance GHC.Show.Show Test.QuickCheck.Modifiers.UnicodeString
+ Test.QuickCheck.Modifiers: instance Test.QuickCheck.Arbitrary.Arbitrary Test.QuickCheck.Modifiers.ASCIIString
+ Test.QuickCheck.Modifiers: instance Test.QuickCheck.Arbitrary.Arbitrary Test.QuickCheck.Modifiers.PrintableString
+ Test.QuickCheck.Modifiers: instance Test.QuickCheck.Arbitrary.Arbitrary Test.QuickCheck.Modifiers.UnicodeString
+ Test.QuickCheck.Modifiers: newtype ASCIIString
+ Test.QuickCheck.Modifiers: newtype PrintableString
+ Test.QuickCheck.Modifiers: newtype UnicodeString
+ Test.QuickCheck.Monadic: instance GHC.Base.Applicative (Test.QuickCheck.Monadic.PropertyM m)
+ Test.QuickCheck.Monadic: instance GHC.Base.Monad m => Control.Monad.Fail.MonadFail (Test.QuickCheck.Monadic.PropertyM m)
+ Test.QuickCheck.Property: [maybeNumTests] :: Result -> Maybe Int
+ Test.QuickCheck.Property: [testCase] :: Result -> [String]
+ Test.QuickCheck.Property: instance Test.QuickCheck.Property.Testable ()
+ Test.QuickCheck.Property: showCounterexample :: String -> IO String
+ Test.QuickCheck.Property: total :: NFData a => a -> Property
+ Test.QuickCheck.Property: withMaxSuccess :: Testable prop => Int -> prop -> Property
+ Test.QuickCheck.State: [numTotMaxShrinks] :: State -> !Int
+ Test.QuickCheck.Test: [failingTestCase] :: Result -> [String]
+ Test.QuickCheck.Test: [maxShrinks] :: Args -> Int
+ Test.QuickCheck.Test: formatLabel :: Int -> Bool -> (String, Double) -> String
+ Test.QuickCheck.Test: insufficientlyCovered :: State -> [(String, Int, Double)]
+ Test.QuickCheck.Test: labelCount :: String -> State -> Int
+ Test.QuickCheck.Test: percentage :: Integral a => State -> a -> Double
- Test.QuickCheck: Args :: Maybe (QCGen, Int) -> Int -> Int -> Int -> Bool -> Args
+ Test.QuickCheck: Args :: Maybe (QCGen, Int) -> Int -> Int -> Int -> Bool -> Int -> Args
- Test.QuickCheck: Failure :: Int -> Int -> Int -> Int -> QCGen -> Int -> String -> Maybe AnException -> [(String, Int)] -> String -> Result
+ Test.QuickCheck: Failure :: Int -> Int -> Int -> Int -> QCGen -> Int -> String -> Maybe AnException -> [(String, Double)] -> String -> [String] -> Result
- Test.QuickCheck: GaveUp :: Int -> [(String, Int)] -> String -> Result
+ Test.QuickCheck: GaveUp :: Int -> [(String, Double)] -> String -> Result
- Test.QuickCheck: InsufficientCoverage :: Int -> [(String, Int)] -> String -> Result
+ Test.QuickCheck: InsufficientCoverage :: Int -> [(String, Double)] -> String -> Result
- Test.QuickCheck: NoExpectedFailure :: Int -> [(String, Int)] -> String -> Result
+ Test.QuickCheck: NoExpectedFailure :: Int -> [(String, Double)] -> String -> Result
- Test.QuickCheck: Success :: Int -> [(String, Int)] -> String -> Result
+ Test.QuickCheck: Success :: Int -> [(String, Double)] -> String -> Result
- Test.QuickCheck: [labels] :: Result -> [(String, Int)]
+ Test.QuickCheck: [labels] :: Result -> [(String, Double)]
- Test.QuickCheck.Function: Fun :: (a :-> b, b, Bool) -> (a -> b) -> Fun a b
+ Test.QuickCheck.Function: Fun :: (a :-> b, b, Shrunk) -> (a -> b) -> Fun a b
- Test.QuickCheck.Monadic: monadic :: Monad m => (m Property -> Property) -> PropertyM m a -> Property
+ Test.QuickCheck.Monadic: monadic :: (Testable a, Monad m) => (m Property -> Property) -> PropertyM m a -> Property
- Test.QuickCheck.Monadic: monadic' :: Monad m => PropertyM m a -> Gen (m Property)
+ Test.QuickCheck.Monadic: monadic' :: (Testable a, Monad m) => PropertyM m a -> Gen (m Property)
- Test.QuickCheck.Monadic: monadicIO :: PropertyM IO a -> Property
+ Test.QuickCheck.Monadic: monadicIO :: Testable a => PropertyM IO a -> Property
- Test.QuickCheck.Monadic: monadicST :: (forall s. PropertyM (ST s) a) -> Property
+ Test.QuickCheck.Monadic: monadicST :: Testable a => (forall s. PropertyM (ST s) a) -> Property
- Test.QuickCheck.Property: MkResult :: Maybe Bool -> Bool -> String -> Maybe AnException -> Bool -> Map String Int -> Set String -> [Callback] -> Result
+ Test.QuickCheck.Property: MkResult :: Maybe Bool -> Bool -> String -> Maybe AnException -> Bool -> Maybe Int -> Map String Int -> Set String -> [Callback] -> [String] -> Result
- Test.QuickCheck.State: MkState :: Terminal -> Int -> Int -> (Int -> Int -> Int) -> !Int -> !Int -> !Int -> !(Map String Int) -> ![Set String] -> !Bool -> !QCGen -> !Int -> !Int -> !Int -> State
+ Test.QuickCheck.State: MkState :: Terminal -> Int -> Int -> (Int -> Int -> Int) -> !Int -> !Int -> !Int -> !Int -> !(Map String Int) -> ![Set String] -> !Bool -> !QCGen -> !Int -> !Int -> !Int -> State
- Test.QuickCheck.Test: Args :: Maybe (QCGen, Int) -> Int -> Int -> Int -> Bool -> Args
+ Test.QuickCheck.Test: Args :: Maybe (QCGen, Int) -> Int -> Int -> Int -> Bool -> Int -> Args
- Test.QuickCheck.Test: Failure :: Int -> Int -> Int -> Int -> QCGen -> Int -> String -> Maybe AnException -> [(String, Int)] -> String -> Result
+ Test.QuickCheck.Test: Failure :: Int -> Int -> Int -> Int -> QCGen -> Int -> String -> Maybe AnException -> [(String, Double)] -> String -> [String] -> Result
- Test.QuickCheck.Test: GaveUp :: Int -> [(String, Int)] -> String -> Result
+ Test.QuickCheck.Test: GaveUp :: Int -> [(String, Double)] -> String -> Result
- Test.QuickCheck.Test: InsufficientCoverage :: Int -> [(String, Int)] -> String -> Result
+ Test.QuickCheck.Test: InsufficientCoverage :: Int -> [(String, Double)] -> String -> Result
- Test.QuickCheck.Test: NoExpectedFailure :: Int -> [(String, Int)] -> String -> Result
+ Test.QuickCheck.Test: NoExpectedFailure :: Int -> [(String, Double)] -> String -> Result
- Test.QuickCheck.Test: Success :: Int -> [(String, Int)] -> String -> Result
+ Test.QuickCheck.Test: Success :: Int -> [(String, Double)] -> String -> Result
- Test.QuickCheck.Test: [labels] :: Result -> [(String, Int)]
+ Test.QuickCheck.Test: [labels] :: Result -> [(String, Double)]
- Test.QuickCheck.Test: foundFailure :: State -> Result -> [Rose Result] -> IO (Int, Int, Int)
+ Test.QuickCheck.Test: foundFailure :: State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
- Test.QuickCheck.Test: localMin :: State -> Result -> Result -> [Rose Result] -> IO (Int, Int, Int)
+ Test.QuickCheck.Test: localMin :: State -> Result -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
- Test.QuickCheck.Test: localMin' :: State -> Result -> [Rose Result] -> IO (Int, Int, Int)
+ Test.QuickCheck.Test: localMin' :: State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
- Test.QuickCheck.Test: localMinFound :: State -> Result -> IO (Int, Int, Int)
+ Test.QuickCheck.Test: localMinFound :: State -> Result -> IO (Int, Int, Int, Result)
- Test.QuickCheck.Test: summary :: State -> [(String, Int)]
+ Test.QuickCheck.Test: summary :: State -> [(String, Double)]
Files
- LICENSE +4/−3
- QuickCheck.cabal +46/−46
- README +2/−8
- Test/QuickCheck.hs +57/−54
- Test/QuickCheck/Arbitrary.hs +357/−82
- Test/QuickCheck/Exception.hs +13/−1
- Test/QuickCheck/Function.hs +82/−35
- Test/QuickCheck/Gen.hs +44/−14
- Test/QuickCheck/Gen/Unsafe.hs +3/−0
- Test/QuickCheck/Modifiers.hs +34/−2
- Test/QuickCheck/Monadic.hs +34/−11
- Test/QuickCheck/Poly.hs +63/−17
- Test/QuickCheck/Property.hs +152/−51
- Test/QuickCheck/Random.hs +1/−1
- Test/QuickCheck/State.hs +1/−1
- Test/QuickCheck/Test.hs +100/−68
- Test/QuickCheck/Text.hs +0/−1
- changelog +68/−0
- examples/Heap.hs +0/−2
- examples/Heap_Program.hs +197/−0
- examples/Heap_ProgramAlgebraic.hs +254/−0
- examples/Lambda.hs +363/−0
- examples/Merge.hs +116/−0
- examples/Set.hs +213/−0
- examples/Simple.hs +46/−0
- tests/Generators.hs +13/−1
LICENSE view
@@ -1,7 +1,8 @@-Copyright (c) 2000-2016, Koen Claessen+(The following is the 3-clause BSD license.)++Copyright (c) 2000-2017, Koen Claessen Copyright (c) 2006-2008, Björn Bringert-Copyright (c) 2009-2016, Nick Smallbone-All rights reserved.+Copyright (c) 2009-2017, Nick Smallbone Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
QuickCheck.cabal view
@@ -1,35 +1,47 @@ Name: QuickCheck-Version: 2.9.2+Version: 2.10 Cabal-Version: >= 1.8 Build-type: Simple License: BSD3 License-file: LICENSE-Extra-source-files: README changelog-Copyright: 2000-2016 Koen Claessen, 2006-2008 Björn Bringert, 2009-2016 Nick Smallbone+Copyright: 2000-2017 Koen Claessen, 2006-2008 Björn Bringert, 2009-2017 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 >= 7+Maintainer: Nick Smallbone <nick@smallbone.se>; see also QuickCheck mailing list (https://groups.google.com/forum/#!forum/haskell-quickcheck)+Bug-reports: https://github.com/nick8325/quickcheck/issues+Tested-with: GHC == 7.0.4, GHC == 7.2.2, GHC >= 7.4 Homepage: https://github.com/nick8325/quickcheck Category: Testing Synopsis: Automatic testing of Haskell programs Description: QuickCheck is a library for random testing of program properties. .- 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.+ 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.+ 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. .- You can find a (slightly out-of-date but useful) manual at- <http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html>.+ The <http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html official QuickCheck manual>+ explains how to write generators and properties;+ it is out-of-date in some details but still full of useful advice.+ .+ A user of QuickCheck has written an unofficial, but detailed, tutorial which+ you can find at+ <https://begriffs.com/posts/2017-01-14-design-use-quickcheck.html>. +extra-source-files:+ README+ changelog+ examples/Heap.hs+ examples/Heap_Program.hs+ examples/Heap_ProgramAlgebraic.hs+ examples/Lambda.hs+ examples/Merge.hs+ examples/Set.hs+ examples/Simple.hs+ source-repository head type: git location: https://github.com/nick8325/quickcheck@@ -37,7 +49,7 @@ source-repository this type: git location: https://github.com/nick8325/quickcheck- tag: 2.9.2+ tag: 2.10 flag templateHaskell Description: Build Test.QuickCheck.All, which uses Template Haskell.@@ -65,9 +77,9 @@ -- GHC-specific modules. if impl(ghc) Exposed-Modules: Test.QuickCheck.Function- Build-depends: transformers >= 0.2+ Build-depends: transformers >= 0.3, deepseq else- cpp-options: -DNO_TRANSFORMERS+ cpp-options: -DNO_TRANSFORMERS -DNO_DEEPSEQ if impl(ghc) && flag(templateHaskell) Build-depends: template-haskell >= 2.4@@ -76,6 +88,9 @@ else cpp-options: -DNO_TEMPLATE_HASKELL + if !impl(ghc >= 7.4)+ cpp-options: -DNO_CTYPES+ -- The new generics appeared in GHC 7.2... if impl(ghc < 7.2) cpp-options: -DNO_GENERICS@@ -93,19 +108,11 @@ else cpp-options: -DNO_TF_RANDOM - if impl(ghc)- if impl(ghc < 7.10)- -- `Numeric.Natural` is available in base only since GHC 7.10 / base 4.8- build-depends: nats>=1- else- cpp-options: -DNO_NATURALS+ if !impl(ghc >= 7.6)+ cpp-options: -DNO_POLYKINDS - if impl(ghc)- -- 'Data.List.NonEmpty' is available in base only since GHC 8.0 / base 4.9- if impl(ghc < 8.0)- build-depends: semigroups >=0.9- else- cpp-options: -DNO_NONEMPTY+ if !impl(ghc >= 8.0)+ cpp-options: -DNO_MONADFAIL -- Switch off most optional features on non-GHC systems. if !impl(ghc)@@ -131,23 +138,16 @@ hs-source-dirs: examples main-is: Heap.hs- build-depends:- base,- containers,- QuickCheck == 2.9.2,- template-haskell >= 2.4,- test-framework >= 0.4 && < 0.9- if flag(templateHaskell)- Buildable: True- else+ build-depends: base, QuickCheck+ if !flag(templateHaskell) Buildable: False Test-Suite test-quickcheck-gcoarbitrary type: exitcode-stdio-1.0 hs-source-dirs: tests main-is: GCoArbitraryExample.hs- build-depends: base, QuickCheck == 2.9.2- if impl(ghc < 7.2)+ build-depends: base, QuickCheck+ if !impl(ghc >= 7.2) buildable: False if impl(ghc >= 7.2) && impl(ghc < 7.6) build-depends: ghc-prim@@ -156,7 +156,7 @@ type: exitcode-stdio-1.0 hs-source-dirs: tests main-is: Generators.hs- build-depends: base, QuickCheck == 2.9.2+ build-depends: base, QuickCheck if !flag(templateHaskell) Buildable: False @@ -164,8 +164,8 @@ type: exitcode-stdio-1.0 hs-source-dirs: tests main-is: GShrinkExample.hs- build-depends: base, QuickCheck == 2.9.2- if impl(ghc < 7.2)+ build-depends: base, QuickCheck+ if !impl(ghc >= 7.2) buildable: False if impl(ghc >= 7.2) && impl(ghc < 7.6) build-depends: ghc-prim
README view
@@ -4,11 +4,5 @@ $ cabal install -Please report bugs to the QuickCheck mailing list at-quickcheck@projects.haskell.org.--If you get errors about Template Haskell, try--$ cabal install -f-templateHaskell--but please report this as a bug.+There is a Google group for user discussion and questions at+https://groups.google.com/forum/#!forum/haskell-quickcheck.
Test/QuickCheck.hs view
@@ -1,74 +1,42 @@-{-| For further information see the <http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html QuickCheck manual>.+{-|+The <http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html QuickCheck manual>+gives detailed information about using QuickCheck effectively. -To use QuickCheck to check a property, first define a function-expressing that property (functions expressing properties under test-tend to be prefixed with @prop_@). Testing that @n + m = m + n@ holds-for @Integer@s one might write:+To start using QuickCheck, write down your property as a function returning @Bool@.+For example, to check that reversing a list twice gives back the same list you can write: @ import Test.QuickCheck -prop_commutativeAdd :: Integer -> Integer -> Bool-prop_commutativeAdd n m = n + m == m + n+prop_reverse :: [Int] -> Bool+prop_reverse xs = reverse (reverse xs) == xs @ -and testing:-->>> quickCheck prop_commutativeAdd-+++ OK, passed 100 tests.--which tests @prop_commutativeAdd@ on 100 random @(Integer, Integer)@ pairs.--'verboseCheck' can be used to see the actual values generated:+You can then use QuickCheck to test @prop_reverse@ on 100 random lists: ->>> verboseCheck prop_commutativeAdd-Passed:-0-0- …98 tests omitted…-Passed:--68-6+>>> quickCheck prop_reverse +++ OK, passed 100 tests. -and if more than 100 tests are needed the number of tests can be-increased by updating the 'stdArgs' record:-->>> quickCheckWith stdArgs { maxSuccess = 500 } prop_commutativeAdd-+++ OK, passed 500 tests.--To let QuickCheck generate values of your own data type an 'Arbitrary'-instance must be defined:--@-data Point = MkPoint Int Int deriving Eq--instance Arbitrary Point where- arbitrary = do- x <- 'arbitrary'- y <- arbitrary- return (MkPoint x y)--swapPoint :: Point -> Point-swapPoint (MkPoint x y) = MkPoint y x---- swapPoint . swapPoint = id-prop_swapInvolution point = swapPoint (swapPoint point) == point-@+To run more tests you can use the 'withMaxSuccess' combinator: ->>> quickCheck prop_swapInvolution-+++ OK, passed 100 tests.+>>> quickCheck (withMaxSuccess 10000 prop_reverse)++++ OK, passed 10000 tests. -See "Test.QuickCheck.Function" for generating random shrinkable,-showable functions used for testing higher-order functions and-"Test.QuickCheck.Monadic" for testing impure or monadic code-(e.g. effectful code in 'IO').+To use QuickCheck on your own data types you will need to write 'Arbitrary'+instances for those types. See the+<http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html QuickCheck manual> for+details about how to do that. +This module exports most of QuickCheck's functionality, but see also+"Test.QuickCheck.Monadic" which helps with testing impure or monadic code. -} {-# LANGUAGE CPP #-} #ifndef NO_SAFE_HASKELL {-# LANGUAGE Safe #-} #endif+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708+{-# LANGUAGE PatternSynonyms #-}+#endif module Test.QuickCheck ( -- * Running tests@@ -103,9 +71,11 @@ , elements , growingElements , sized+ , getSize , resize , scale , suchThat+ , suchThatMap , suchThatMaybe , listOf , listOf1@@ -127,6 +97,14 @@ , Arbitrary(..) , CoArbitrary(..) + -- ** Unary and Binary classes+ , Arbitrary1(..)+ , arbitrary1+ , shrink1+ , Arbitrary2(..)+ , arbitrary2+ , shrink2+ -- ** Helper functions for implementing arbitrary , arbitrarySizedIntegral , arbitrarySizedNatural@@ -135,6 +113,9 @@ , arbitraryBoundedIntegral , arbitraryBoundedRandom , arbitraryBoundedEnum+ , arbitraryUnicodeChar+ , arbitraryASCIIChar+ , arbitraryPrintableChar -- ** Helper functions for implementing shrink #ifndef NO_GENERICS , genericCoarbitrary@@ -144,6 +125,8 @@ #endif , shrinkNothing , shrinkList+ , shrinkMap+ , shrinkMapBy , shrinkIntegral , shrinkRealFrac -- ** Helper functions for implementing coarbitrary@@ -170,7 +153,23 @@ , Shrinking(..) , ShrinkState(..) #endif+ , ASCIIString(..)+ , UnicodeString(..)+ , PrintableString(..) + -- ** Functions+ , Fun+ , applyFun+ , applyFun2+ , applyFun3+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708+ , pattern Fn+ , pattern Fn2+ , pattern Fn3+#endif+ , Function (..)+ , functionMap+ -- * Properties , Property, Testable(..) -- ** Property combinators@@ -179,11 +178,15 @@ , shrinking , (==>) , (===)+#ifndef NO_DEEPSEQ+ , total+#endif , ioProperty -- *** Controlling property execution , verbose , once , again+ , withMaxSuccess , within , noShrinking -- *** Conjunction and disjunction@@ -218,8 +221,8 @@ import Test.QuickCheck.Modifiers import Test.QuickCheck.Property hiding ( Result(..) ) import Test.QuickCheck.Test-import Test.QuickCheck.Text import Test.QuickCheck.Exception+import Test.QuickCheck.Function #ifndef NO_TEMPLATE_HASKELL import Test.QuickCheck.All #endif
Test/QuickCheck/Arbitrary.hs view
@@ -1,13 +1,20 @@ -- | Type classes for random generation of values. {-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-} #ifndef NO_GENERICS {-# LANGUAGE DefaultSignatures, FlexibleContexts, TypeOperators #-} {-# LANGUAGE FlexibleInstances, KindSignatures, ScopedTypeVariables #-} {-# LANGUAGE MultiParamTypeClasses #-}-#if __GLASGOW_HASKELL__ < 710+#if __GLASGOW_HASKELL__ >= 710+#define OVERLAPPING_ {-# OVERLAPPING #-}+#else {-# LANGUAGE OverlappingInstances #-}+#define OVERLAPPING_ #endif #endif+#ifndef NO_POLYKINDS+{-# LANGUAGE PolyKinds #-}+#endif #ifndef NO_SAFE_HASKELL {-# LANGUAGE Safe #-} #endif@@ -17,6 +24,14 @@ Arbitrary(..) , CoArbitrary(..) + -- ** Unary and Binary classes+ , Arbitrary1(..)+ , arbitrary1+ , shrink1+ , Arbitrary2(..)+ , arbitrary2+ , shrink2+ -- ** Helper functions for implementing arbitrary , arbitrarySizedIntegral -- :: Integral a => Gen a , arbitrarySizedNatural -- :: Integral a => Gen a@@ -25,6 +40,10 @@ , arbitrarySizedFractional -- :: Fractional a => Gen a , arbitraryBoundedRandom -- :: (Bounded a, Random a) => Gen a , arbitraryBoundedEnum -- :: (Bounded a, Enum a) => Gen a+ -- ** Generators for various kinds of character+ , arbitraryUnicodeChar -- :: Gen Char+ , arbitraryASCIIChar -- :: Gen Char+ , arbitraryPrintableChar -- :: Gen Char -- ** Helper functions for implementing shrink #ifndef NO_GENERICS , genericShrink -- :: (Generic a, Arbitrary a, RecursivelyShrink (Rep a), GSubterms (Rep a) a) => a -> [a]@@ -34,6 +53,8 @@ #endif , shrinkNothing -- :: a -> [a] , shrinkList -- :: (a -> [a]) -> [a] -> [[a]]+ , shrinkMap -- :: Arbitrary a -> (a -> b) -> (b -> a) -> b -> [b]+ , shrinkMapBy -- :: (a -> b) -> (b -> a) -> (a -> [a]) -> b -> [b] , shrinkIntegral -- :: Integral a => a -> [a] , shrinkRealFrac -- :: RealFrac a => a -> [a] -- ** Helper functions for implementing coarbitrary@@ -57,6 +78,7 @@ import Data.Foldable(toList) import System.Random(Random) import Test.QuickCheck.Gen+import Test.QuickCheck.Random import Test.QuickCheck.Gen.Unsafe {-@@ -68,13 +90,15 @@ -} import Data.Char- ( chr- , ord+ ( ord , isLower , isUpper , toLower , isDigit , isSpace+ , isPrint+ , generalCategory+ , GeneralCategory(..) ) #ifndef NO_FIXED@@ -84,10 +108,6 @@ ) #endif -#ifndef NO_NATURALS-import Numeric.Natural-#endif- import Data.Ratio ( Ratio , (%)@@ -103,11 +123,6 @@ , nub ) -#ifndef NO_NONEMPTY-import Data.List.NonEmpty (NonEmpty (..), nonEmpty)-import Data.Maybe (mapMaybe)-#endif- import Data.Version (Version (..)) import Control.Monad@@ -120,6 +135,10 @@ import Data.Int(Int8, Int16, Int32, Int64) import Data.Word(Word, Word8, Word16, Word32, Word64)+import System.Exit (ExitCode(..))+#ifndef NO_CTYPES+import Foreign.C.Types+#endif #ifndef NO_GENERICS import GHC.Generics@@ -136,25 +155,52 @@ #ifndef NO_TRANSFORMERS import Data.Functor.Identity import Data.Functor.Constant+import Data.Functor.Compose+import Data.Functor.Product #endif -------------------------------------------------------------------------- -- ** class Arbitrary -- | Random generation and shrinking of values.+--+-- QuickCheck provides @Arbitrary@ instances for most types in @base@,+-- except those which incur extra dependencies.+-- For a wider range of @Arbitrary@ instances see the+-- <http://hackage.haskell.org/package/quickcheck-instances quickcheck-instances>+-- package. class Arbitrary a where -- | A generator for values of the given type.+ --+ -- It is worth spending time thinking about what sort of test data+ -- you want - good generators are often the difference between+ -- finding bugs and not finding them. You can use 'sample',+ -- 'label' and 'classify' to check the quality of your test data.+ --+ -- There is no generic @arbitrary@ implementation included because we don't+ -- know how to make a high-quality one. If you want one, consider using the+ -- <http://hackage.haskell.org/package/testing-feat testing-feat> package.+ --+ -- The <http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html QuickCheck manual>+ -- goes into detail on how to write good generators. Make sure to look at it,+ -- especially if your type is recursive! arbitrary :: Gen a -- | Produces a (possibly) empty list of all the possible- -- immediate shrinks of the given value. The default implementation- -- returns the empty list, so will not try to shrink the value.+ -- immediate shrinks of the given value. --+ -- The default implementation returns the empty list, so will not try to+ -- shrink the value. If your data type has no special invariants, you can+ -- enable shrinking by defining @shrink = 'genericShrink'@, but by customising+ -- the behaviour of @shrink@ you can often get simpler counterexamples.+ -- -- Most implementations of 'shrink' should try at least three things: -- -- 1. Shrink a term to any of its immediate subterms.+ -- You can use 'subterms' to do this. -- -- 2. Recursively apply 'shrink' to all immediate subterms.+ -- You can use 'recursivelyShrink' to do this. -- -- 3. Type-specific shrinkings such as replacing a constructor by a -- simpler constructor.@@ -188,8 +234,7 @@ -- the three is fully shrunk. -- -- There is a fair bit of boilerplate in the code above.- -- We can avoid it with the help of some generic functions;- -- note that these only work on GHC 7.2 and above.+ -- We can avoid it with the help of some generic functions. -- The function 'genericShrink' tries shrinking a term to all of its -- subterms and, failing that, recursively shrinks the subterms. -- Using it, we can define 'shrink' as:@@ -214,6 +259,30 @@ shrink :: a -> [a] shrink _ = [] +-- | Lifting of the 'Arbitrary' class to unary type constructors.+class Arbitrary1 f where+ liftArbitrary :: Gen a -> Gen (f a)+ liftShrink :: (a -> [a]) -> f a -> [f a]+ liftShrink _ _ = []++arbitrary1 :: (Arbitrary1 f, Arbitrary a) => Gen (f a)+arbitrary1 = liftArbitrary arbitrary++shrink1 :: (Arbitrary1 f, Arbitrary a) => f a -> [f a]+shrink1 = liftShrink shrink++-- | Lifting of the 'Arbitrary' class to binary type constructors.+class Arbitrary2 f where+ liftArbitrary2 :: Gen a -> Gen b -> Gen (f a b)+ liftShrink2 :: (a -> [a]) -> (b -> [b]) -> f a b -> [f a b]+ liftShrink2 _ _ _ = []++arbitrary2 :: (Arbitrary2 f, Arbitrary a, Arbitrary b) => Gen (f a b)+arbitrary2 = liftArbitrary2 arbitrary arbitrary++shrink2 :: (Arbitrary2 f, Arbitrary a, Arbitrary b) => f a b -> [f a b]+shrink2 = liftShrink2 shrink shrink+ #ifndef NO_GENERICS -- | Shrink a term to any of its immediate subterms, -- and also recursively shrink all subterms.@@ -314,18 +383,21 @@ gSubtermsIncl (M1 x) = gSubtermsIncl x -- This is the important case: We've found a term of the same type.-instance {-# OVERLAPPING #-} GSubtermsIncl (K1 i a) a where+instance OVERLAPPING_ GSubtermsIncl (K1 i a) a where gSubtermsIncl (K1 x) = [x] -instance {-# OVERLAPPING #-} GSubtermsIncl (K1 i a) b where+instance OVERLAPPING_ GSubtermsIncl (K1 i a) b where gSubtermsIncl (K1 _) = [] #endif -- instances +instance (CoArbitrary a) => Arbitrary1 ((->) a) where+ liftArbitrary arbB = promote (`coarbitrary` arbB)+ instance (CoArbitrary a, Arbitrary b) => Arbitrary (a -> b) where- arbitrary = promote (`coarbitrary` arbitrary)+ arbitrary = arbitrary1 instance Arbitrary () where arbitrary = return ()@@ -341,27 +413,37 @@ shrink LT = [EQ] shrink EQ = [] +instance Arbitrary1 Maybe where+ liftArbitrary arb = frequency [(1, return Nothing), (3, liftM Just arb)]++ liftShrink shr (Just x) = Nothing : [ Just x' | x' <- shr x ]+ liftShrink _ Nothing = []+ instance Arbitrary a => Arbitrary (Maybe a) where- arbitrary = frequency [(1, return Nothing), (3, liftM Just arbitrary)]+ arbitrary = arbitrary1+ shrink = shrink1 - shrink (Just x) = Nothing : [ Just x' | x' <- shrink x ]- shrink _ = []+instance Arbitrary2 Either where+ liftArbitrary2 arbA arbB = oneof [liftM Left arbA, liftM Right arbB] + liftShrink2 shrA _ (Left x) = [ Left x' | x' <- shrA x ]+ liftShrink2 _ shrB (Right y) = [ Right y' | y' <- shrB y ]++instance Arbitrary a => Arbitrary1 (Either a) where+ liftArbitrary = liftArbitrary2 arbitrary+ liftShrink = liftShrink2 shrink+ instance (Arbitrary a, Arbitrary b) => Arbitrary (Either a b) where- arbitrary = oneof [liftM Left arbitrary, liftM Right arbitrary]+ arbitrary = arbitrary2+ shrink = shrink2 - shrink (Left x) = [ Left x' | x' <- shrink x ]- shrink (Right y) = [ Right y' | y' <- shrink y ]+instance Arbitrary1 [] where+ liftArbitrary = listOf+ liftShrink = shrinkList instance Arbitrary a => Arbitrary [a] where- arbitrary = listOf arbitrary- shrink xs = shrinkList shrink xs--#ifndef NO_NONEMPTY-instance Arbitrary a => Arbitrary (NonEmpty a) where- arbitrary = liftM2 (:|) arbitrary arbitrary- shrink (x :| xs) = mapMaybe nonEmpty . shrinkList shrink $ x : xs-#endif+ arbitrary = arbitrary1+ shrink = shrink1 -- | Shrink a list of values given a shrinking function for individual values. shrinkList :: (a -> [a]) -> [a] -> [[a]]@@ -405,15 +487,20 @@ shrink = shrinkRealFrac #endif -instance (Arbitrary a, Arbitrary b)- => Arbitrary (a,b)- where- arbitrary = liftM2 (,) arbitrary arbitrary+instance Arbitrary2 (,) where+ liftArbitrary2 = liftM2 (,)+ liftShrink2 shrA shrB (x, y) =+ [ (x', y) | x' <- shrA x ]+ ++ [ (x, y') | y' <- shrB y ] - shrink (x, y) =- [ (x', y) | x' <- shrink x ]- ++ [ (x, y') | y' <- shrink y ]+instance (Arbitrary a) => Arbitrary1 ((,) a) where+ liftArbitrary = liftArbitrary2 arbitrary+ liftShrink = liftShrink2 shrink +instance (Arbitrary a, Arbitrary b) => Arbitrary (a,b) where+ arbitrary = arbitrary2+ shrink = shrink2+ instance (Arbitrary a, Arbitrary b, Arbitrary c) => Arbitrary (a,b,c) where@@ -517,12 +604,6 @@ arbitrary = arbitrarySizedIntegral shrink = shrinkIntegral -#ifndef NO_NATURALS-instance Arbitrary Natural where- arbitrary = arbitrarySizedNatural- shrink = shrinkIntegral-#endif- instance Arbitrary Int where arbitrary = arbitrarySizedIntegral shrink = shrinkIntegral@@ -564,22 +645,26 @@ shrink = shrinkIntegral instance Arbitrary Char where- arbitrary = chr `fmap` oneof [choose (0,127), choose (0,255)]- shrink c = filter (<. c) $ nub+ arbitrary =+ frequency+ [(3, arbitraryASCIIChar),+ (1, arbitraryUnicodeChar)]++ shrink c = filter (<. c) $ nub $ ['a','b','c']- ++ [ toLower c | isUpper c ]- ++ ['A','B','C']- ++ ['1','2','3']- ++ [' ','\n']- where- a <. b = stamp a < stamp b- stamp a = ( (not (isLower a)- , not (isUpper a)- , not (isDigit a))- , (not (a==' ')- , not (isSpace a)- , a)- )+ ++ [ toLower c | isUpper c ]+ ++ ['A','B','C']+ ++ ['1','2','3']+ ++ [' ','\n']+ where+ a <. b = stamp a < stamp b+ stamp a = ( (not (isLower a)+ , not (isUpper a)+ , not (isDigit a))+ , (not (a==' ')+ , not (isSpace a)+ , a)+ ) instance Arbitrary Float where arbitrary = arbitrarySizedFractional@@ -589,44 +674,199 @@ arbitrary = arbitrarySizedFractional shrink = shrinkRealFrac +#ifndef NO_CTYPES+instance Arbitrary CChar where+ arbitrary = CChar <$> arbitrary+ shrink (CChar x) = CChar <$> shrink x++instance Arbitrary CSChar where+ arbitrary = CSChar <$> arbitrary+ shrink (CSChar x) = CSChar <$> shrink x++instance Arbitrary CUChar where+ arbitrary = CUChar <$> arbitrary+ shrink (CUChar x) = CUChar <$> shrink x++instance Arbitrary CShort where+ arbitrary = CShort <$> arbitrary+ shrink (CShort x) = CShort <$> shrink x++instance Arbitrary CUShort where+ arbitrary = CUShort <$> arbitrary+ shrink (CUShort x) = CUShort <$> shrink x++instance Arbitrary CInt where+ arbitrary = CInt <$> arbitrary+ shrink (CInt x) = CInt <$> shrink x++instance Arbitrary CUInt where+ arbitrary = CUInt <$> arbitrary+ shrink (CUInt x) = CUInt <$> shrink x++instance Arbitrary CLong where+ arbitrary = CLong <$> arbitrary+ shrink (CLong x) = CLong <$> shrink x++instance Arbitrary CULong where+ arbitrary = CULong <$> arbitrary+ shrink (CULong x) = CULong <$> shrink x++instance Arbitrary CPtrdiff where+ arbitrary = CPtrdiff <$> arbitrary+ shrink (CPtrdiff x) = CPtrdiff <$> shrink x++instance Arbitrary CSize where+ arbitrary = CSize <$> arbitrary+ shrink (CSize x) = CSize <$> shrink x++instance Arbitrary CWchar where+ arbitrary = CWchar <$> arbitrary+ shrink (CWchar x) = CWchar <$> shrink x++instance Arbitrary CSigAtomic where+ arbitrary = CSigAtomic <$> arbitrary+ shrink (CSigAtomic x) = CSigAtomic <$> shrink x++instance Arbitrary CLLong where+ arbitrary = CLLong <$> arbitrary+ shrink (CLLong x) = CLLong <$> shrink x++instance Arbitrary CULLong where+ arbitrary = CULLong <$> arbitrary+ shrink (CULLong x) = CULLong <$> shrink x++instance Arbitrary CIntPtr where+ arbitrary = CIntPtr <$> arbitrary+ shrink (CIntPtr x) = CIntPtr <$> shrink x++instance Arbitrary CUIntPtr where+ arbitrary = CUIntPtr <$> arbitrary+ shrink (CUIntPtr x) = CUIntPtr <$> shrink x++instance Arbitrary CIntMax where+ arbitrary = CIntMax <$> arbitrary+ shrink (CIntMax x) = CIntMax <$> shrink x++instance Arbitrary CUIntMax where+ arbitrary = CUIntMax <$> arbitrary+ shrink (CUIntMax x) = CUIntMax <$> shrink x++instance Arbitrary CClock where+ arbitrary = CClock <$> arbitrary+ shrink (CClock x) = CClock <$> shrink x++instance Arbitrary CTime where+ arbitrary = CTime <$> arbitrary+ shrink (CTime x) = CTime <$> shrink x++instance Arbitrary CUSeconds where+ arbitrary = CUSeconds <$> arbitrary+ shrink (CUSeconds x) = CUSeconds <$> shrink x++instance Arbitrary CSUSeconds where+ arbitrary = CSUSeconds <$> arbitrary+ shrink (CSUSeconds x) = CSUSeconds <$> shrink x++instance Arbitrary CFloat where+ arbitrary = CFloat <$> arbitrary+ shrink (CFloat x) = CFloat <$> shrink x++instance Arbitrary CDouble where+ arbitrary = CDouble <$> arbitrary+ shrink (CDouble x) = CDouble <$> shrink x+#endif+ -- Arbitrary instances for container types instance (Ord a, Arbitrary a) => Arbitrary (Set.Set a) where arbitrary = fmap Set.fromList arbitrary shrink = map Set.fromList . shrink . Set.toList+instance (Ord k, Arbitrary k) => Arbitrary1 (Map.Map k) where+ liftArbitrary = fmap Map.fromList . liftArbitrary . liftArbitrary+ liftShrink shr = map Map.fromList . liftShrink (liftShrink shr) . Map.toList instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map.Map k v) where- arbitrary = fmap Map.fromList arbitrary- shrink = map Map.fromList . shrink . Map.toList+ arbitrary = arbitrary1+ shrink = shrink1 instance Arbitrary IntSet.IntSet where arbitrary = fmap IntSet.fromList arbitrary shrink = map IntSet.fromList . shrink . IntSet.toList+instance Arbitrary1 IntMap.IntMap where+ liftArbitrary = fmap IntMap.fromList . liftArbitrary . liftArbitrary+ liftShrink shr = map IntMap.fromList . liftShrink (liftShrink shr) . IntMap.toList instance Arbitrary a => Arbitrary (IntMap.IntMap a) where- arbitrary = fmap IntMap.fromList arbitrary- shrink = map IntMap.fromList . shrink . IntMap.toList+ arbitrary = arbitrary1+ shrink = shrink1+instance Arbitrary1 Sequence.Seq where+ liftArbitrary = fmap Sequence.fromList . liftArbitrary+ liftShrink shr = map Sequence.fromList . liftShrink shr . toList instance Arbitrary a => Arbitrary (Sequence.Seq a) where- arbitrary = fmap Sequence.fromList arbitrary- shrink = map Sequence.fromList . shrink . toList+ arbitrary = arbitrary1+ shrink = shrink1 -- Arbitrary instance for Ziplist+instance Arbitrary1 ZipList where+ liftArbitrary = fmap ZipList . liftArbitrary+ liftShrink shr = map ZipList . liftShrink shr . getZipList instance Arbitrary a => Arbitrary (ZipList a) where- arbitrary = fmap ZipList arbitrary- shrink = map ZipList . shrink . getZipList+ arbitrary = arbitrary1+ shrink = shrink1 #ifndef NO_TRANSFORMERS -- Arbitrary instance for transformers' Functors+instance Arbitrary1 Identity where+ liftArbitrary = fmap Identity+ liftShrink shr = map Identity . shr . runIdentity instance Arbitrary a => Arbitrary (Identity a) where- arbitrary = fmap Identity arbitrary- shrink = map Identity . shrink . runIdentity+ arbitrary = arbitrary1+ shrink = shrink1 +instance Arbitrary2 Constant where+ liftArbitrary2 arbA _ = fmap Constant arbA+ liftShrink2 shrA _ = fmap Constant . shrA . getConstant+instance Arbitrary a => Arbitrary1 (Constant a) where+ liftArbitrary = liftArbitrary2 arbitrary+ liftShrink = liftShrink2 shrink+-- Have to be defined explicitly, as Constant is kind polymorphic instance Arbitrary a => Arbitrary (Constant a b) where arbitrary = fmap Constant arbitrary shrink = map Constant . shrink . getConstant++instance (Arbitrary1 f, Arbitrary1 g) => Arbitrary1 (Product f g) where+ liftArbitrary arb = liftM2 Pair (liftArbitrary arb) (liftArbitrary arb)+ liftShrink shr (Pair f g) =+ [ Pair f' g | f' <- liftShrink shr f ] +++ [ Pair f g' | g' <- liftShrink shr g ]+instance (Arbitrary1 f, Arbitrary1 g, Arbitrary a) => Arbitrary (Product f g a) where+ arbitrary = arbitrary1+ shrink = shrink1++instance (Arbitrary1 f, Arbitrary1 g) => Arbitrary1 (Compose f g) where+ liftArbitrary = fmap Compose . liftArbitrary . liftArbitrary+ liftShrink shr = map Compose . liftShrink (liftShrink shr) . getCompose+instance (Arbitrary1 f, Arbitrary1 g, Arbitrary a) => Arbitrary (Compose f g a) where+ arbitrary = arbitrary1+ shrink = shrink1 #endif -- Arbitrary instance for Const+instance Arbitrary2 Const where+ liftArbitrary2 arbA _ = fmap Const arbA+ liftShrink2 shrA _ = fmap Const . shrA . getConst+instance Arbitrary a => Arbitrary1 (Const a) where+ liftArbitrary = liftArbitrary2 arbitrary+ liftShrink = liftShrink2 shrink+-- Have to be defined explicitly, as Const is kind polymorphic instance Arbitrary a => Arbitrary (Const a b) where arbitrary = fmap Const arbitrary shrink = map Const . shrink . getConst +instance Arbitrary (m a) => Arbitrary (WrappedMonad m a) where+ arbitrary = WrapMonad <$> arbitrary+ shrink (WrapMonad a) = map WrapMonad (shrink a)++instance Arbitrary (a b c) => Arbitrary (WrappedArrow a b c) where+ arbitrary = WrapArrow <$> arbitrary+ shrink (WrapArrow a) = map WrapArrow (shrink a)+ -- Arbitrary instances for Monoid instance Arbitrary a => Arbitrary (Monoid.Dual a) where arbitrary = fmap Monoid.Dual arbitrary@@ -688,6 +928,17 @@ , all (>=0) xs' ] +instance Arbitrary QCGen where+ arbitrary = MkGen (\g _ -> g)++instance Arbitrary ExitCode where+ arbitrary = frequency [(1, return ExitSuccess), (3, liftM ExitFailure arbitrary)]++ shrink (ExitFailure x) = ExitSuccess : [ ExitFailure x' | x' <- shrink x ]+ shrink _ = []+++ -- ** Helper functions for implementing arbitrary -- | Generates an integral number. The number can be positive or negative@@ -759,12 +1010,46 @@ n <- choose (toInteger mn `max` (-k), toInteger mx `min` k) return (fromInteger n) +-- ** Generators for various kinds of character++-- | Generates any Unicode character (but not a surrogate)+arbitraryUnicodeChar :: Gen Char+arbitraryUnicodeChar =+ arbitraryBoundedEnum `suchThat` (not . isSurrogate)+ where+ isSurrogate c = generalCategory c == Surrogate++-- | Generates a random ASCII character (0-127).+arbitraryASCIIChar :: Gen Char+arbitraryASCIIChar = choose ('\0', '\127')++-- | Generates a printable Unicode character.+arbitraryPrintableChar :: Gen Char+arbitraryPrintableChar = arbitrary `suchThat` isPrint+ -- ** Helper functions for implementing shrink -- | Returns no shrinking alternatives. shrinkNothing :: a -> [a] shrinkNothing _ = [] +-- | Map a shrink function to another domain. This is handy if your data type+-- has special invariants, but is /almost/ isomorphic to some other type.+--+-- @+-- shrinkOrderedList :: (Ord a, Arbitrary a) => [a] -> [[a]]+-- shrinkOrderedList = shrinkMap sort id+--+-- shrinkSet :: (Ord a, Arbitrary a) => Set a -> Set [a]+-- shrinkSet = shrinkMap fromList toList+-- @+shrinkMap :: Arbitrary a => (a -> b) -> (b -> a) -> b -> [b]+shrinkMap f g = shrinkMapBy f g shrink++-- | Non-overloaded version of `shrinkMap`.+shrinkMapBy :: (a -> b) -> (b -> a) -> (a -> [a]) -> b -> [b]+shrinkMapBy f g shr = map f . shr . g+ -- | Shrink an integral number. shrinkIntegral :: Integral a => a -> [a] shrinkIntegral x =@@ -892,11 +1177,6 @@ coarbitrary [] = variant 0 coarbitrary (x:xs) = variant 1 . coarbitrary (x,xs) -#ifndef NO_NONEMPTY-instance CoArbitrary a => CoArbitrary (NonEmpty a) where- coarbitrary (x :| xs) = coarbitrary (x, xs)-#endif- instance (Integral a, CoArbitrary a) => CoArbitrary (Ratio a) where coarbitrary r = coarbitrary (numerator r,denominator r) @@ -943,11 +1223,6 @@ instance CoArbitrary Integer where coarbitrary = coarbitraryIntegral -#ifndef NO_NATURALS-instance CoArbitrary Natural where- coarbitrary = coarbitraryIntegral-#endif- instance CoArbitrary Int where coarbitrary = coarbitraryIntegral @@ -1084,7 +1359,7 @@ orderedList :: (Ord a, Arbitrary a) => Gen [a] orderedList = sort `fmap` arbitrary --- | Generate an infinite list.+-- | Generates an infinite list. infiniteList :: Arbitrary a => Gen [a] infiniteList = infiniteListOf arbitrary
Test/QuickCheck/Exception.hs view
@@ -56,7 +56,19 @@ tryEvaluate x = tryEvaluateIO (return x) tryEvaluateIO :: IO a -> IO (Either AnException a)-tryEvaluateIO m = E.try (m >>= E.evaluate)+tryEvaluateIO m = E.tryJust notAsync (m >>= E.evaluate)+ where+ notAsync :: E.SomeException -> Maybe AnException+#if MIN_VERSION_base(4,7,0)+ notAsync e = case E.fromException e of+ Just (E.SomeAsyncException _) -> Nothing+ Nothing -> Just e+#else+ notAsync e = case E.fromException e :: Maybe E.AsyncException of+ Just _ -> Nothing+ Nothing -> Just e+#endif+ --tryEvaluateIO m = Right `fmap` m evaluate :: a -> IO a
Test/QuickCheck/Function.hs view
@@ -1,13 +1,19 @@ {-# LANGUAGE TypeOperators, GADTs, CPP #-}-+#ifndef NO_SAFE_HASKELL+{-# LANGUAGE Safe #-}+#endif #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708-{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PatternSynonyms, ViewPatterns #-} #endif #ifndef NO_GENERICS {-# LANGUAGE DefaultSignatures, FlexibleContexts #-} #endif +#ifndef NO_POLYKINDS+{-# LANGUAGE PolyKinds #-}+#endif+ -- | Generation of random shrinkable, showable functions. -- See the paper \"Shrinking and showing functions\" by Koen Claessen. --@@ -28,7 +34,10 @@ -- See the @'Function' [a]@ instance for an example of the latter. module Test.QuickCheck.Function ( Fun(..)+ , applyFun , apply+ , applyFun2+ , applyFun3 , (:->) , Function(..) , functionMap@@ -38,6 +47,8 @@ , functionBoundedEnum #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708 , pattern Fn+ , pattern Fn2+ , pattern Fn3 #endif ) where@@ -51,16 +62,13 @@ import Data.Char import Data.Word import Data.List( intersperse )-import Data.Maybe( fromJust ) import Data.Ratio-import Control.Arrow( (&&&) ) import qualified Data.IntMap as IntMap import qualified Data.IntSet as IntSet import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.Sequence as Sequence import Data.Int-import Data.Word import Data.Complex import Data.Foldable(toList) @@ -68,14 +76,6 @@ import Data.Fixed #endif -#ifndef NO_NATURALS-import Numeric.Natural-#endif--#ifndef NO_NONEMPTY-import Data.List.NonEmpty(NonEmpty(..))-#endif- #ifndef NO_GENERICS import GHC.Generics hiding (C) #endif@@ -135,6 +135,12 @@ -------------------------------------------------------------------------- -- Function +-- | The class @Function a@ is used for random generation of showable+-- functions of type @a -> b@.+--+-- There is a default implementation for 'function', which you can use+-- if your type has structural equality. Otherwise, you can normally+-- use 'functionMap' or 'functionShow'. class Function a where function :: (a->b) -> (a:->b) #ifndef NO_GENERICS@@ -250,6 +256,9 @@ instance Function Int where function = functionIntegral +instance Function Word where+ function = functionIntegral+ instance Function Char where function = functionMap ord chr @@ -272,14 +281,6 @@ h (Left True) = EQ h (Right _) = GT -#ifndef NO_NONEMPTY-instance Function a => Function (NonEmpty a) where- function = functionMap g h- where- g (x :| xs) = (x, xs)- h (x, xs) = x :| xs-#endif- instance (Integral a, Function a) => Function (Ratio a) where function = functionMap g h where@@ -312,11 +313,6 @@ instance Function a => Function (Sequence.Seq a) where function = functionMap toList Sequence.fromList -#ifndef NO_NATURALS-instance Function Natural where- function = functionIntegral-#endif- instance Function Int8 where function = functionBoundedEnum @@ -449,26 +445,77 @@ -------------------------------------------------------------------------- -- the Fun modifier -data Fun a b = Fun (a :-> b, b, Bool) (a -> b)+-- | Generation of random shrinkable, showable functions.+--+-- To generate random values of type @'Fun' a b@,+-- you must have an instance @'Function' a@.+--+-- See also 'applyFun', and 'Fn' with GHC >= 7.8.+data Fun a b = Fun (a :-> b, b, Shrunk) (a -> b)+data Shrunk = Shrunk | NotShrunk deriving Eq #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708--- | A pattern for matching against the function only:+-- | A modifier for testing functions. -- -- > prop :: Fun String Integer -> Bool -- > prop (Fn f) = f "banana" == f "monkey" -- > || f "banana" == f "elephant"-pattern Fn f <- Fun _ f+#if __GLASGOW_HASKELL__ >= 800+pattern Fn :: (a -> b) -> Fun a b #endif+pattern Fn f <- (applyFun -> f) +-- | A modifier for testing binary functions.+--+-- > prop_zipWith :: Fun (Int, Bool) Char -> [Int] -> [Bool] -> Bool+-- > prop_zipWith (Fn2 f) xs ys = zipWith f xs ys == [ f x y | (x, y) <- zip xs ys]+#if __GLASGOW_HASKELL__ >= 800+pattern Fn2 :: (a -> b -> c) -> Fun (a, b) c+#endif+pattern Fn2 f <- (applyFun2 -> f)++-- | A modifier for testing ternary functions.+#if __GLASGOW_HASKELL__ >= 800+pattern Fn3 :: (a -> b -> c -> d) -> Fun (a, b, c) d+#endif+pattern Fn3 f <- (applyFun3 -> f)+#endif+ mkFun :: (a :-> b) -> b -> Fun a b-mkFun p d = Fun (p, d, False) (abstract p d)+mkFun p d = Fun (p, d, NotShrunk) (abstract p d) +-- | Alias to 'applyFun'. apply :: Fun a b -> (a -> b)-apply (Fun _ f) = f+apply = applyFun +-- | Extracts the value of a function.+--+-- 'Fn' is the pattern equivalent of this function.+--+-- > prop :: Fun String Integer -> Bool+-- > prop f = applyFun f "banana" == applyFun f "monkey"+-- > || applyFun f "banana" == applyFun f "elephant"+applyFun :: Fun a b -> (a -> b)+applyFun (Fun _ f) = f++-- | Extracts the value of a binary function.+--+-- 'Fn2' is the pattern equivalent of this function.+--+-- > prop_zipWith :: Fun (Int, Bool) Char -> [Int] -> [Bool] -> Bool+-- > prop_zipWith f xs ys = zipWith (applyFun2 f) xs ys == [ applyFun2 f x y | (x, y) <- zip xs ys]+--+applyFun2 :: Fun (a, b) c -> (a -> b -> c)+applyFun2 (Fun _ f) a b = f (a, b)++-- | Extracts the value of a ternary function. 'Fn3' is the+-- pattern equivalent of this function.+applyFun3 :: Fun (a, b, c) d -> (a -> b -> c -> d)+applyFun3 (Fun _ f) a b c = f (a, b, c)+ instance (Show a, Show b) => Show (Fun a b) where- show (Fun (_, _, False) _) = "<fun>"- show (Fun (p, d, True) _) = showFunction p (Just d)+ show (Fun (_, _, NotShrunk) _) = "<fun>"+ show (Fun (p, d, Shrunk) _) = showFunction p (Just d) instance (Function a, CoArbitrary a, Arbitrary b) => Arbitrary (Fun a b) where arbitrary =@@ -476,9 +523,9 @@ d <- arbitrary return (mkFun p d) - shrink (Fun (p, d, b) f) =+ shrink (Fun (p, d, s) f) = [ mkFun p' d' | (p', d') <- shrink (p, d) ] ++- [ Fun (p, d, True) f | not b ]+ [ Fun (p, d, Shrunk) f | s == NotShrunk ] -------------------------------------------------------------------------- -- the end.
Test/QuickCheck/Gen.hs view
@@ -10,37 +10,33 @@ import System.Random ( Random- , StdGen , random , randomR , split- , newStdGen ) import Control.Monad- ( liftM- , ap+ ( ap , replicateM , filterM ) import Control.Applicative- ( Applicative(..)- , (<$>)- )--import Control.Arrow- ( second- )+ ( Applicative(..) ) import Test.QuickCheck.Random import Data.List import Data.Ord+import Data.Maybe -------------------------------------------------------------------------- -- ** Generator type -- | A generator for values of type @a@.+--+-- The third-party package+-- <http://hackage.haskell.org/package/QuickCheck-GenT QuickCheck-GenT>+-- provides a monad transformer version of @GenT@. newtype Gen a = MkGen{ unGen :: QCGen -> Int -> a -- ^ Run the generator on a particular seed. -- If you just want to get a random value out, consider using 'generate'.@@ -60,9 +56,10 @@ MkGen m >>= k = MkGen (\r n ->- let (r1,r2) = split r- MkGen m' = k (m r1 n)- in m' r2 n+ case split r of+ (r1, r2) ->+ let MkGen m' = k (m r1 n)+ in m' r2 n ) --------------------------------------------------------------------------@@ -73,9 +70,35 @@ variant k (MkGen g) = MkGen (\r n -> g (variantQCGen k r) n) -- | Used to construct generators that depend on the size parameter.+--+-- For example, 'listOf', which uses the size parameter as an upper bound on+-- length of lists it generates, can be defined like this:+--+-- > listOf :: Gen a -> Gen [a]+-- > listOf gen = sized $ \n ->+-- > do k <- choose (0,n)+-- > vectorOf k gen+--+-- You can also do this using 'getSize'. sized :: (Int -> Gen a) -> Gen a sized f = MkGen (\r n -> let MkGen m = f n in m r n) +-- | Generates the size parameter. Used to construct generators that depend on+-- the size parameter.+--+-- For example, 'listOf', which uses the size parameter as an upper bound on+-- length of lists it generates, can be defined like this:+--+-- > listOf :: Gen a -> Gen [a]+-- > listOf gen = do+-- > n <- getSize+-- > k <- choose (0,n)+-- > vectorOf k gen+--+-- You can also do this using 'sized'.+getSize :: Gen Int+getSize = sized pure+ -- | Overrides the size parameter. Returns a generator which uses -- the given size instead of the runtime-size parameter. resize :: Int -> Gen a -> Gen a@@ -124,7 +147,14 @@ Just x -> return x Nothing -> sized (\n -> resize (n+1) (gen `suchThat` p)) +-- | Generates a value for which the given function returns a 'Just', and then+-- applies the function.+suchThatMap :: Gen a -> (a -> Maybe b) -> Gen b+gen `suchThatMap` f =+ fmap fromJust $ fmap f gen `suchThat` isJust+ -- | Tries to generate a value that satisfies a predicate.+-- If it fails to do so after enough attempts, returns @Nothing@. suchThatMaybe :: Gen a -> (a -> Bool) -> Gen (Maybe a) gen `suchThatMaybe` p = sized (try 0 . max 1) where
Test/QuickCheck/Gen/Unsafe.hs view
@@ -1,4 +1,7 @@ {-# LANGUAGE CPP #-}+#ifndef NO_SAFE_HASKELL+{-# LANGUAGE Safe #-}+#endif #ifndef NO_ST_MONAD {-# LANGUAGE Rank2Types #-} #endif
Test/QuickCheck/Modifiers.hs view
@@ -56,6 +56,9 @@ , Shrinking(..) , ShrinkState(..) #endif+ , ASCIIString(..)+ , UnicodeString(..)+ , PrintableString(..) ) where @@ -68,6 +71,7 @@ import Data.List ( sort )+import Data.Ix (Ix) -------------------------------------------------------------------------- -- | @Blind x@: as x, but x does not have to be in the 'Show' class.@@ -214,7 +218,7 @@ newtype Large a = Large {getLarge :: a} deriving ( Eq, Ord, Show, Read #ifndef NO_NEWTYPE_DERIVING- , Num, Integral, Real, Enum+ , Num, Integral, Real, Enum, Ix #endif ) @@ -231,7 +235,7 @@ newtype Small a = Small {getSmall :: a} deriving ( Eq, Ord, Show, Read #ifndef NO_NEWTYPE_DERIVING- , Num, Integral, Real, Enum+ , Num, Integral, Real, Enum, Ix #endif ) @@ -343,4 +347,32 @@ #endif /* NO_MULTI_PARAM_TYPE_CLASSES */ --------------------------------------------------------------------------+-- | @ASCIIString@: generates an ASCII string.+newtype ASCIIString = ASCIIString {getASCIIString :: String}+ deriving ( Eq, Ord, Show, Read )++instance Arbitrary ASCIIString where+ arbitrary = ASCIIString `fmap` listOf arbitraryASCIIChar+ shrink (ASCIIString xs) = ASCIIString `fmap` shrink xs++--------------------------------------------------------------------------+-- | @UnicodeString@: generates a unicode String.+-- The string will not contain surrogate pairs.+newtype UnicodeString = UnicodeString {getUnicodeString :: String}+ deriving ( Eq, Ord, Show, Read )++instance Arbitrary UnicodeString where+ arbitrary = UnicodeString `fmap` listOf arbitraryUnicodeChar+ shrink (UnicodeString xs) = UnicodeString `fmap` shrink xs++--------------------------------------------------------------------------+-- | @PrintableString@: generates a printable unicode String.+-- The string will not contain surrogate pairs.+newtype PrintableString = PrintableString {getPrintableString :: String}+ deriving ( Eq, Ord, Show, Read )++instance Arbitrary PrintableString where+ arbitrary = PrintableString `fmap` listOf arbitraryPrintableChar+ shrink (PrintableString xs) = PrintableString `fmap` shrink xs+ -- the end.
Test/QuickCheck/Monadic.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE CPP #-}+#ifndef NO_SAFE_HASKELL+#if !defined(NO_ST_MONAD) && !(MIN_VERSION_base(4,8,0))+{-# LANGUAGE Trustworthy #-}+#else+{-# LANGUAGE Safe #-}+#endif+#endif #ifndef NO_ST_MONAD {-# LANGUAGE Rank2Types #-} #endif@@ -83,6 +90,10 @@ import Control.Monad.Trans.Class #endif +#ifndef NO_MONADFAIL+import qualified Control.Monad.Fail as Fail+#endif+ -------------------------------------------------------------------------- -- type PropertyM @@ -95,18 +106,30 @@ newtype PropertyM m a = MkPropertyM { unPropertyM :: (a -> Gen (m Property)) -> Gen (m Property) } +bind :: PropertyM m a -> (a -> PropertyM m b) -> PropertyM m b+MkPropertyM m `bind` f = MkPropertyM (\k -> m (\a -> unPropertyM (f a) k))++fail_ :: Monad m => String -> PropertyM m a+fail_ s = stop (failed { reason = s })+ instance Functor (PropertyM m) where fmap f (MkPropertyM m) = MkPropertyM (\k -> m (k . f)) -instance Monad m => Applicative (PropertyM m) where- pure = return- (<*>) = liftM2 ($)+instance Applicative (PropertyM m) where+ pure x = MkPropertyM (\k -> k x)+ mf <*> mx =+ mf `bind` \f -> mx `bind` \x -> pure (f x) instance Monad m => Monad (PropertyM m) where- return x = MkPropertyM (\k -> k x)- MkPropertyM m >>= f = MkPropertyM (\k -> m (\a -> unPropertyM (f a) k))- fail s = stop (failed { reason = s })+ return = pure+ (>>=) = bind+ fail = fail_ +#ifndef NO_MONADFAIL+instance Monad m => Fail.MonadFail (PropertyM m) where+ fail = fail_+#endif+ #ifndef NO_TRANSFORMERS instance MonadTrans PropertyM where lift = run@@ -201,11 +224,11 @@ -- run functions -monadic :: Monad m => (m Property -> Property) -> PropertyM m a -> Property+monadic :: (Testable a, Monad m) => (m Property -> Property) -> PropertyM m a -> Property monadic runner m = property (fmap runner (monadic' m)) -monadic' :: Monad m => PropertyM m a -> Gen (m Property)-monadic' (MkPropertyM m) = m (const (return (return (property True))))+monadic' :: (Testable a, Monad m) => PropertyM m a -> Gen (m Property)+monadic' (MkPropertyM m) = m (\prop -> return (return (property prop))) -- | Runs the property monad for 'IO'-computations. --@@ -221,7 +244,7 @@ -- >>> quickCheck prop_cat -- +++ OK, passed 100 tests. ---monadicIO :: PropertyM IO a -> Property+monadicIO :: Testable a => PropertyM IO a -> Property monadicIO = monadic ioProperty #ifndef NO_ST_MONAD@@ -240,7 +263,7 @@ -- >>> quickCheck prop_sortST -- +++ OK, passed 100 tests. ---monadicST :: (forall s. PropertyM (ST s) a) -> Property+monadicST :: Testable a => (forall s. PropertyM (ST s) a) -> Property monadicST m = property (runSTGen (monadic' m)) runSTGen :: (forall s. Gen (ST s a)) -> Gen a
Test/QuickCheck/Poly.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-}-#ifndef NO_NEWTYPE_DERIVING-{-# LANGUAGE GeneralizedNewtypeDeriving #-}+#ifndef NO_SAFE_HASKELL+{-# LANGUAGE Safe #-} #endif -- | Types to help with testing polymorphic properties. --@@ -75,12 +75,28 @@ -- OrdA newtype OrdA = OrdA{ unOrdA :: Integer }- deriving ( Eq, Ord-#ifndef NO_NEWTYPE_DERIVING- , Num-#endif- )+ deriving ( Eq, Ord ) +liftOrdA+ :: (Integer -> Integer)+ -> OrdA -> OrdA+liftOrdA f (OrdA x) = OrdA (f x)++liftOrdA2+ :: (Integer -> Integer -> Integer)+ -> OrdA -> OrdA -> OrdA+liftOrdA2 f (OrdA x) (OrdA y) = OrdA (f x y)++instance Num OrdA where+ (+) = liftOrdA2 (+)+ (*) = liftOrdA2 (*)+ (-) = liftOrdA2 (-)+ negate = liftOrdA negate+ abs = liftOrdA abs+ signum = liftOrdA signum+ fromInteger = OrdA . fromInteger++ instance Show OrdA where showsPrec n (OrdA x) = showsPrec n x @@ -94,12 +110,27 @@ -- OrdB newtype OrdB = OrdB{ unOrdB :: Integer }- deriving ( Eq, Ord-#ifndef NO_NEWTYPE_DERIVING- , Num-#endif- )+ deriving ( Eq, Ord ) +liftOrdB+ :: (Integer -> Integer)+ -> OrdB -> OrdB+liftOrdB f (OrdB x) = OrdB (f x)++liftOrdB2+ :: (Integer -> Integer -> Integer)+ -> OrdB -> OrdB -> OrdB+liftOrdB2 f (OrdB x) (OrdB y) = OrdB (f x y)++instance Num OrdB where+ (+) = liftOrdB2 (+)+ (*) = liftOrdB2 (*)+ (-) = liftOrdB2 (-)+ negate = liftOrdB negate+ abs = liftOrdB abs+ signum = liftOrdB signum+ fromInteger = OrdB . fromInteger+ instance Show OrdB where showsPrec n (OrdB x) = showsPrec n x @@ -113,11 +144,26 @@ -- OrdC newtype OrdC = OrdC{ unOrdC :: Integer }- deriving ( Eq, Ord-#ifndef NO_NEWTYPE_DERIVING- , Num-#endif- )+ deriving ( Eq, Ord )++liftOrdC+ :: (Integer -> Integer)+ -> OrdC -> OrdC+liftOrdC f (OrdC x) = OrdC (f x)++liftOrdC2+ :: (Integer -> Integer -> Integer)+ -> OrdC -> OrdC -> OrdC+liftOrdC2 f (OrdC x) (OrdC y) = OrdC (f x y)++instance Num OrdC where+ (+) = liftOrdC2 (+)+ (*) = liftOrdC2 (*)+ (-) = liftOrdC2 (-)+ negate = liftOrdC negate+ abs = liftOrdC abs+ signum = liftOrdC signum+ fromInteger = OrdC . fromInteger instance Show OrdC where showsPrec n (OrdC x) = showsPrec n x
Test/QuickCheck/Property.hs view
@@ -11,7 +11,7 @@ import Test.QuickCheck.Gen import Test.QuickCheck.Gen.Unsafe import Test.QuickCheck.Arbitrary-import Test.QuickCheck.Text( showErr, isOneLine, putLine )+import Test.QuickCheck.Text( isOneLine, putLine ) import Test.QuickCheck.Exception import Test.QuickCheck.State hiding (labels) @@ -25,6 +25,9 @@ import Data.Map(Map) import qualified Data.Set as Set import Data.Set(Set)+#ifndef NO_DEEPSEQ+import Control.DeepSeq+#endif -------------------------------------------------------------------------- -- fixities@@ -69,7 +72,13 @@ -- | The type of properties. newtype Property = MkProperty { unProperty :: Gen Prop } --- | The class of things which can be tested, i.e. turned into a property.+-- | The class of properties, i.e., types which QuickCheck knows how to test.+-- Typically a property will be a function returning 'Bool' or 'Property'.+--+-- If a property does no quantification, i.e. has no+-- parameters and doesn't use 'forAll', it will only be tested once.+-- This may not be what you want if your property is an @IO Bool@.+-- You can change this behaviour using the 'again' combinator. class Testable prop where -- | Convert the thing to a property. property :: prop -> Property@@ -81,6 +90,14 @@ instance Testable Discard where property _ = property rejected +-- This instance is here to make it easier to turn IO () into a Property.+instance Testable () where+ property = property . liftUnit+ where+ -- N.B. the unit gets forced only inside 'property',+ -- so that we turn exceptions into test failures+ liftUnit () = succeeded+ instance Testable Bool where property = property . liftBool @@ -94,26 +111,22 @@ property mp = MkProperty $ do p <- mp; unProperty (again p) instance Testable Property where- property = property . unProperty+ property (MkProperty mp) = MkProperty $ do p <- mp; unProperty (property p) --- | Do I/O inside a property. This can obviously lead to unrepeatable--- testcases, so use with care.-{-# DEPRECATED morallyDubiousIOProperty "Use ioProperty instead" #-}+-- | Do I/O inside a property.+{-# DEPRECATED morallyDubiousIOProperty "Use 'ioProperty' instead" #-} morallyDubiousIOProperty :: Testable prop => IO prop -> Property-morallyDubiousIOProperty = ioProperty -- Silly names aren't all they're cracked up to be :)+morallyDubiousIOProperty = ioProperty --- | Do I/O inside a property. This can obviously lead to unrepeatable--- testcases, so use with care.------ For more advanced monadic testing you may want to look at--- "Test.QuickCheck.Monadic".+-- | Do I/O inside a property. ----- Note that if you use 'ioProperty' on a property of type @IO Bool@,--- or more generally a property that does no quantification, the property--- will only be executed once. To test the property repeatedly you must--- use the 'again' combinator.+-- Warning: any random values generated inside of the argument to @ioProperty@+-- will not currently be shrunk. For best results, generate all random values+-- before calling @ioProperty@. ioProperty :: Testable prop => IO prop -> Property-ioProperty = MkProperty . fmap (MkProp . ioRose . fmap unProp) . promote . fmap (unProperty . property)+ioProperty =+ MkProperty . fmap (MkProp . ioRose . fmap unProp) .+ promote . fmap (unProperty . noShrinking) instance (Arbitrary a, Show a, Testable prop) => Testable (a -> prop) where property f = forAllShrink arbitrary shrink f@@ -194,14 +207,16 @@ -- | The result of a single test. data Result = MkResult- { ok :: Maybe Bool -- ^ result of the test case; Nothing = discard- , expect :: Bool -- ^ indicates what the expected result of the property is- , reason :: String -- ^ a message indicating what went wrong- , theException :: Maybe AnException -- ^ the exception thrown, if any- , abort :: Bool -- ^ if True, the test should not be repeated- , labels :: Map String Int -- ^ all labels used by this property- , stamp :: Set String -- ^ the collected values for this test case- , callbacks :: [Callback] -- ^ the callbacks for this test case+ { ok :: Maybe Bool -- ^ result of the test case; Nothing = discard+ , expect :: Bool -- ^ indicates what the expected result of the property is+ , reason :: String -- ^ a message indicating what went wrong+ , theException :: Maybe AnException -- ^ the exception thrown, if any+ , abort :: Bool -- ^ if True, the test should not be repeated+ , maybeNumTests :: Maybe Int -- ^ stop after this many tests+ , labels :: Map String Int -- ^ all labels used by this property+ , stamp :: Set String -- ^ the collected labels for this test case+ , callbacks :: [Callback] -- ^ the callbacks for this test case+ , testCase :: [String] -- ^ the generated test case } exception :: String -> AnException -> Result@@ -226,14 +241,16 @@ where result = MkResult- { ok = undefined- , expect = True- , reason = ""- , theException = Nothing- , abort = True- , labels = Map.empty- , stamp = Set.empty- , callbacks = []+ { ok = undefined+ , expect = True+ , reason = ""+ , theException = Nothing+ , abort = True+ , maybeNumTests = Nothing+ , labels = Map.empty+ , stamp = Set.empty+ , callbacks = []+ , testCase = [] } --------------------------------------------------------------------------@@ -263,8 +280,8 @@ mapSize :: Testable prop => (Int -> Int) -> prop -> Property mapSize f p = MkProperty (sized ((`resize` unProperty (property p)) . f)) --- | Shrinks the argument to property if it fails. Shrinking is done--- automatically for most types. This is only needed when you want to+-- | Shrinks the argument to a property if it fails. Shrinking is done+-- automatically for most types. This function is only needed when you want to -- override the default behavior. shrinking :: Testable prop => (a -> [a]) -- ^ 'shrink'-like function.@@ -283,18 +300,27 @@ callback :: Testable prop => Callback -> prop -> Property callback cb = mapTotalResult (\res -> res{ callbacks = cb : callbacks res }) --- | Adds the given string to the counterexample.+-- | Adds the given string to the counterexample if the property fails. counterexample :: Testable prop => String -> prop -> Property counterexample s =- callback $ PostFinalFailure Counterexample $ \st _res -> do- res <- tryEvaluateIO (putLine (terminal st) s)+ mapTotalResult (\res -> res{ testCase = s:testCase res }) .+ callback (PostFinalFailure Counterexample $ \st _res -> do+ s <- showCounterexample s+ putLine (terminal st) s)++showCounterexample :: String -> IO String+showCounterexample s = do+ let force [] = return ()+ force (x:xs) = x `seq` force xs+ res <- tryEvaluateIO (force s)+ return $ case res of Left err ->- putLine (terminal st) (formatException "Exception thrown while printing test case" err)+ formatException "Exception thrown while showing test case" err Right () ->- return ()+ s --- | Adds the given string to the counterexample.+-- | Adds the given string to the counterexample if the property fails. {-# DEPRECATED printTestCase "Use counterexample instead" #-} printTestCase :: Testable prop => String -> prop -> Property printTestCase = counterexample@@ -321,7 +347,8 @@ verbose = mapResult (\res -> res { callbacks = newCallbacks (callbacks res) ++ callbacks res }) where newCallbacks cbs = PostTest Counterexample (\st res -> putLine (terminal st) (status res ++ ":")):- [ PostTest Counterexample f | PostFinalFailure Counterexample f <- cbs ]+ [ PostTest Counterexample f | PostFinalFailure Counterexample f <- cbs ] +++ [ PostTest Counterexample (\st res -> putLine (terminal st) "") ] status MkResult{ok = Just True} = "Passed" status MkResult{ok = Just False} = "Failed" status MkResult{ok = Nothing} = "Skipped (precondition false)"@@ -332,25 +359,79 @@ expectFailure = mapTotalResult (\res -> res{ expect = False }) -- | Modifies a property so that it only will be tested once.+-- Opposite of 'again'. once :: Testable prop => prop -> Property once = mapTotalResult (\res -> res{ abort = True }) --- | Undoes the effect of 'once'.+-- | Modifies a property so that it will be tested repeatedly.+-- Opposite of 'once'. again :: Testable prop => prop -> Property again = mapTotalResult (\res -> res{ abort = False }) +-- | Configures how many times a property will be tested.+--+-- For example,+--+-- > quickCheck (withMaxSuccess 1000 p)+--+-- will test @p@ up to 1000 times.+withMaxSuccess :: Testable prop => Int -> prop -> Property+withMaxSuccess n = n `seq` mapTotalResult (\res -> res{ maybeNumTests = Just n })+ -- | Attaches a label to a property. This is used for reporting -- test case distribution.+--+-- For example:+--+-- > prop_reverse_reverse :: [Int] -> Property+-- > prop_reverse_reverse xs =+-- > label ("length of input is " ++ show (length xs)) $+-- > reverse (reverse xs) === xs+--+-- >>> quickCheck prop_reverse_reverse+-- +++ OK, passed 100 tests:+-- 7% length of input is 7+-- 6% length of input is 3+-- 5% length of input is 4+-- 4% length of input is 6+-- ... label :: Testable prop => String -> prop -> Property label s = classify True s --- | Labels a property with a value:+-- | Attaches a label to a property. This is used for reporting+-- test case distribution. -- -- > collect x = label (show x)+--+-- For example:+--+-- > prop_reverse_reverse :: [Int] -> Property+-- > prop_reverse_reverse xs =+-- > collect (length xs) $+-- > reverse (reverse xs) === xs+--+-- >>> quickCheck prop_reverse_reverse+-- +++ OK, passed 100 tests:+-- 7% 7+-- 6% 3+-- 5% 4+-- 4% 6+-- ... collect :: (Show a, Testable prop) => a -> prop -> Property collect x = label (show x) --- | Conditionally labels test case.+-- | Records how many test cases satisfy a given condition.+--+-- For example:+--+-- > prop_sorted_sort :: [Int] -> Property+-- > prop_sorted_sort xs =+-- > sorted xs ==>+-- > classify (length xs > 1) "non-trivial" $+-- > sort xs === xs+--+-- >>> quickCheck prop_sorted_sort+-- +++ OK, passed 100 tests (22% non-trivial). classify :: Testable prop => Bool -- ^ @True@ if the test case should be labelled. -> String -- ^ Label.@@ -360,6 +441,17 @@ -- | Checks that at least the given proportion of /successful/ test -- cases belong to the given class. Discarded tests (i.e. ones -- with a false precondition) do not affect coverage.+--+-- For example:+--+-- > prop_sorted_sort :: [Int] -> Property+-- > prop_sorted_sort xs =+-- > sorted xs ==>+-- > cover (length xs > 1) 50 "non-trivial" $+-- > sort xs === xs+--+-- >>> quickCheck prop_sorted_sort+-- *** Insufficient coverage after 100 tests (only 24% non-trivial, not 50%). cover :: Testable prop => Bool -- ^ @True@ if the test case belongs to the class. -> Int -- ^ The required percentage (0-100) of test cases.@@ -385,16 +477,16 @@ -- the given number of microseconds. within :: Testable prop => Int -> prop -> Property within n = mapRoseResult f- -- We rely on the fact that the property will catch the timeout- -- exception and turn it into a failed test case. where f rose = ioRose $ do- let m `orError` x = fmap (fromMaybe (error x)) m+ let m `orError` x = fmap (fromMaybe x) m MkRose res roses <- timeout n (reduceRose rose) `orError`- "within: timeout exception not caught in Rose Result"+ return timeoutResult res' <- timeout n (protectResult (return res)) `orError`- "within: timeout exception not caught in Result"+ timeoutResult return (MkRose res' (map f roses))++ timeoutResult = failed { reason = "Timeout" } #ifdef NO_TIMEOUT timeout _ = fmap Just #endif@@ -498,12 +590,16 @@ -- The following three fields are not important because the -- test case has failed anyway abort = False,+ maybeNumTests = Nothing, labels = Map.empty, stamp = Set.empty, callbacks = callbacks result1 ++ [PostFinalFailure Counterexample $ \st _res -> putLine (terminal st) ""] ++- callbacks result2 }+ callbacks result2,+ testCase =+ testCase result1 +++ testCase result2 } Nothing -> result2 Nothing -> do result2 <- q@@ -523,6 +619,11 @@ x === y = counterexample (show x ++ " /= " ++ show y) (x == y) +#ifndef NO_DEEPSEQ+-- | Checks that a value is total, i.e., doesn't crash when evaluated.+total :: NFData a => a -> Property+total x = property (rnf x)+#endif -------------------------------------------------------------------------- -- the end.
Test/QuickCheck/Random.hs view
@@ -63,7 +63,7 @@ newtype QCGen = QCGen TheGen instance Show QCGen where- showsPrec n (QCGen g) = showsPrec n g+ showsPrec n (QCGen g) s = showsPrec n g "" ++ s instance Read QCGen where readsPrec n xs = [(QCGen g, ys) | (g, ys) <- readsPrec n xs]
Test/QuickCheck/State.hs view
@@ -3,7 +3,6 @@ import Test.QuickCheck.Text import Test.QuickCheck.Random-import qualified Data.Map as Map import Data.Map(Map) import Data.Set(Set) @@ -20,6 +19,7 @@ , maxDiscardedTests :: Int -- ^ maximum number of tests that can be discarded , computeSize :: Int -> Int -> Int -- ^ how to compute the size of test cases from -- #tests and #discarded tests+ , numTotMaxShrinks :: !Int -- ^ How many shrinks to try before giving up -- dynamic , numSuccessTests :: !Int -- ^ the current number of tests that have succeeded
Test/QuickCheck/Test.hs view
@@ -34,10 +34,15 @@ import Data.List ( sort+ , sortBy , group- , groupBy , intersperse )++import Data.Maybe(fromMaybe)+import Data.Ord(comparing)+import Text.Printf(printf)+ -------------------------------------------------------------------------- -- quickCheck @@ -53,13 +58,18 @@ -- If you want to store a test case permanently you should save -- the test case itself. , maxSuccess :: Int- -- ^ Maximum number of successful tests before succeeding+ -- ^ Maximum number of successful tests before succeeding. Testing stops+ -- at the first failure. If all tests are passing and you want to run more tests,+ -- increase this number. , maxDiscardRatio :: Int -- ^ Maximum number of discarded tests per successful test before giving up , maxSize :: Int -- ^ Size to use for the biggest test cases , chatty :: Bool -- ^ Whether to print anything+ , maxShrinks :: Int+ -- ^ Maximum number of shrinks to before giving up. Setting this to zero+ -- turns shrinking off. } deriving ( Show, Read ) @@ -68,38 +78,39 @@ -- | A successful test run = Success { numTests :: Int -- ^ Number of tests performed- , labels :: [(String,Int)] -- ^ Labels and frequencies found during all successful tests+ , labels :: [(String,Double)] -- ^ Labels and frequencies found during all successful tests , output :: String -- ^ Printed output } -- | Given up | GaveUp { numTests :: Int -- Number of tests performed- , labels :: [(String,Int)] -- Labels and frequencies found during all successful tests+ , labels :: [(String,Double)] -- Labels and frequencies found during all successful tests , output :: String -- Printed output } -- | A failed test run | Failure- { numTests :: Int -- Number of tests performed- , numShrinks :: Int -- ^ Number of successful shrinking steps performed- , numShrinkTries :: Int -- ^ Number of unsuccessful shrinking steps performed- , numShrinkFinal :: Int -- ^ Number of unsuccessful shrinking steps performed since last successful shrink- , usedSeed :: QCGen -- ^ What seed was used- , usedSize :: Int -- ^ What was the test size- , reason :: String -- ^ Why did the property fail- , theException :: Maybe AnException -- ^ The exception the property threw, if any- , labels :: [(String,Int)] -- Labels and frequencies found during all successful tests- , output :: String -- Printed output+ { numTests :: Int -- Number of tests performed+ , numShrinks :: Int -- ^ Number of successful shrinking steps performed+ , numShrinkTries :: Int -- ^ Number of unsuccessful shrinking steps performed+ , numShrinkFinal :: Int -- ^ Number of unsuccessful shrinking steps performed since last successful shrink+ , usedSeed :: QCGen -- ^ What seed was used+ , usedSize :: Int -- ^ What was the test size+ , reason :: String -- ^ Why did the property fail+ , theException :: Maybe AnException -- ^ The exception the property threw, if any+ , labels :: [(String,Double)] -- Labels and frequencies found during all successful tests+ , output :: String -- Printed output+ , failingTestCase :: [String] -- ^ The test case which provoked the failure } -- | A property that should have failed did not | NoExpectedFailure { numTests :: Int -- Number of tests performed- , labels :: [(String,Int)] -- Labels and frequencies found during all successful tests+ , labels :: [(String,Double)] -- Labels and frequencies found during all successful tests , output :: String -- Printed output } -- | The tests passed but a use of 'cover' had insufficient coverage | InsufficientCoverage { numTests :: Int -- Number of tests performed- , labels :: [(String,Int)] -- Labels and frequencies found during all successful tests+ , labels :: [(String,Double)] -- Labels and frequencies found during all successful tests , output :: String -- Printed output } deriving ( Show )@@ -117,10 +128,13 @@ , maxDiscardRatio = 10 , maxSize = 100 , chatty = True--- noShrinking flag?+ , maxShrinks = maxBound } -- | Tests a property and prints the results to 'stdout'.+--+-- By default up to 100 tests are performed, which may not be enough+-- to find all bugs. To run more tests, use 'withMaxSuccess'. quickCheck :: Testable prop => prop -> IO () quickCheck p = quickCheckWith stdArgs p @@ -144,6 +158,7 @@ , computeSize = case replay a of Nothing -> computeSize' Just (_,s) -> computeSize' `at0` s+ , numTotMaxShrinks = maxShrinks a , numSuccessTests = 0 , numDiscardedTests = 0 , numRecentlyDiscardedTests = 0@@ -206,7 +221,7 @@ ++ " tests (expected failure)" ) finished NoExpectedFailure- | insufficientCoverage st = do+ | not (null (insufficientlyCovered st)) = do putPart (terminal st) ( bold ("*** Insufficient coverage after ") ++ show (numSuccessTests st)@@ -264,20 +279,22 @@ | otherwise = x:xs case res of- MkResult{ok = Just True, stamp = stamp, expect = expect} -> -- successful test+ MkResult{ok = Just True, stamp = stamp, expect = expect, maybeNumTests = mnt} -> -- successful test do continue doneTesting st{ numSuccessTests = numSuccessTests st + 1 , numRecentlyDiscardedTests = 0+ , maxSuccessTests = fromMaybe (maxSuccessTests st) mnt , randomSeed = rnd2 , S.labels = Map.unionWith max (S.labels st) (P.labels res) , collected = stamp `cons` collected st , expectedFailure = expect } f - MkResult{ok = Nothing, expect = expect} -> -- discarded test+ MkResult{ok = Nothing, expect = expect, maybeNumTests = mnt} -> -- discarded test do continue giveUp st{ numDiscardedTests = numDiscardedTests st + 1 , numRecentlyDiscardedTests = numRecentlyDiscardedTests st + 1+ , maxSuccessTests = fromMaybe (maxSuccessTests st) mnt , randomSeed = rnd2 , S.labels = Map.unionWith max (S.labels st) (P.labels res) , expectedFailure = expect@@ -287,36 +304,40 @@ do if expect res then putPart (terminal st) (bold "*** Failed! ") else putPart (terminal st) "+++ OK, failed as expected. "- (numShrinks, totFailed, lastFailed) <- foundFailure st res ts+ (numShrinks, totFailed, lastFailed, res) <- foundFailure st res ts theOutput <- terminalOutput (terminal st) if not (expect res) then return Success{ labels = summary st, numTests = numSuccessTests st+1, output = theOutput }- else- return Failure{ usedSeed = randomSeed st -- correct! (this will be split first)- , usedSize = size- , numTests = numSuccessTests st+1- , numShrinks = numShrinks- , numShrinkTries = totFailed- , numShrinkFinal = lastFailed- , output = theOutput- , reason = P.reason res- , theException = P.theException res- , labels = summary st+ else do+ testCase <- mapM showCounterexample (P.testCase res)+ return Failure{ usedSeed = randomSeed st -- correct! (this will be split first)+ , usedSize = size+ , numTests = numSuccessTests st+1+ , numShrinks = numShrinks+ , numShrinkTries = totFailed+ , numShrinkFinal = lastFailed+ , output = theOutput+ , reason = P.reason res+ , theException = P.theException res+ , labels = summary st+ , failingTestCase = testCase } where (rnd1,rnd2) = split (randomSeed st) -summary :: State -> [(String,Int)]+summary :: State -> [(String, Double)] summary st = reverse- . sort- . map (\ss -> (head ss, (length ss * 100) `div` numSuccessTests st))+ . sortBy (comparing snd)+ . map (\ss -> (head ss, fromIntegral (length ss) * 100 / fromIntegral (numSuccessTests st))) . group . sort- $ [ concat (intersperse ", " (Set.toList s))+ $ [ concat (intersperse ", " s') | s <- collected st- , not (Set.null s)+ -- HACK: don't print out labels that were created by 'cover'.+ , let s' = [ t | t <- Set.toList s, Map.lookup t (S.labels st) == Just 0 ]+ , not (null s') ] success :: State -> IO ()@@ -329,48 +350,59 @@ ++ ")." ) cases -> do putLine (terminal st) ":"- sequence_ [ putLine (terminal st) pt | pt <- cases ]+ mapM_ (putLine $ terminal st) cases where- allLabels = reverse- . sort- . map (\ss -> (showP ((length ss * 100) `div` numSuccessTests st) ++ head ss))- . group- . sort- $ [ concat (intersperse ", " s')- | s <- collected st- , let s' = [ t | t <- Set.toList s, Map.lookup t (S.labels st) == Just 0 ]- , not (null s')- ]+ allLabels :: [String]+ allLabels = map (formatLabel (numSuccessTests st) True) (summary st) - covers = [ ("only " ++ show (labelPercentage l st) ++ "% " ++ l ++ ", not " ++ show reqP ++ "%")- | (l, reqP) <- Map.toList (S.labels st)- , labelPercentage l st < reqP- ]+ covers :: [String]+ covers = [ ("only " ++ formatLabel (numSuccessTests st) False (l, p) ++ ", not " ++ show reqP ++ "%")+ | (l, reqP, p) <- insufficientlyCovered st ] - showP p = (if p < 10 then " " else "") ++ show p ++ "% "+formatLabel :: Int -> Bool -> (String, Double) -> String+formatLabel n pad (x, p) = showP pad p ++ " " ++ x+ where+ showP :: Bool -> Double -> String+ showP pad p =+ (if pad && p < 10 then " " else "") +++ printf "%.*f" places p ++ "%" -labelPercentage :: String -> State -> Int-labelPercentage l st =+ -- Show no decimal places if <= 100 successful tests,+ -- one decimal place if <= 1000 successful tests,+ -- two decimal places if <= 10000 successful tests, and so on.+ places :: Integer+ places =+ ceiling (logBase 10 (fromIntegral n) - 2 :: Double) `max` 0++labelCount :: String -> State -> Int+labelCount l st = -- XXX in case of a disjunction, a label can occur several times, -- need to think what to do there- (100 * occur) `div` maxSuccessTests st- where- occur = length [ l' | l' <- concat (map Set.toList (collected st)), l == l' ]+ length [ l' | l' <- concat (map Set.toList (collected st)), l == l' ] -insufficientCoverage :: State -> Bool-insufficientCoverage st =- or [ labelPercentage l st < reqP | (l, reqP) <- Map.toList (S.labels st) ]+percentage :: Integral a => State -> a -> Double+percentage st n =+ fromIntegral n * 100 / fromIntegral (numSuccessTests st) +insufficientlyCovered :: State -> [(String, Int, Double)]+insufficientlyCovered st =+ [ (l, reqP, p)+ | (l, reqP) <- Map.toList (S.labels st),+ let p = percentage st (labelCount l st),+ p < fromIntegral reqP ]+ -------------------------------------------------------------------------- -- main shrinking loop -foundFailure :: State -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int)+foundFailure :: State -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int, P.Result) foundFailure st res ts = do localMin st{ numTryShrinks = 0 } res res ts -localMin :: State -> P.Result -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int)-localMin st MkResult{P.theException = Just e} lastRes _- | isInterrupt e = localMinFound st lastRes+localMin :: State -> P.Result -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int, P.Result)+-- Don't try to shrink for too long+localMin st res _ ts+ | numSuccessShrinks st + numTotTryShrinks st >= numTotMaxShrinks st =+ localMinFound st res localMin st res _ ts = do r <- tryEvaluateIO $ putTemp (terminal st)@@ -398,7 +430,7 @@ (exception "Exception while generating shrink-list" err) { callbacks = callbacks res } Right ts' -> localMin' st res ts' -localMin' :: State -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int)+localMin' :: State -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int, P.Result) localMin' st res [] = localMinFound st res localMin' st res (t:ts) = do -- CALLBACK before_test@@ -410,7 +442,7 @@ else localMin st{ numTryShrinks = numTryShrinks st + 1, numTotTryShrinks = numTotTryShrinks st + 1 } res res ts -localMinFound :: State -> P.Result -> IO (Int, Int, Int)+localMinFound :: State -> P.Result -> IO (Int, Int, Int, P.Result) localMinFound st res = do let report = concat [ "(after " ++ number (numSuccessTests st+1) "test",@@ -430,7 +462,7 @@ callbackPostFinalFailure st res -- NB no need to check if callbacks threw an exception because -- we are about to return to the user anyway- return (numSuccessShrinks st, numTotTryShrinks st - numTryShrinks st, numTryShrinks st)+ return (numSuccessShrinks st, numTotTryShrinks st - numTryShrinks st, numTryShrinks st, res) -------------------------------------------------------------------------- -- callbacks
Test/QuickCheck/Text.hs view
@@ -25,7 +25,6 @@ -------------------------------------------------------------------------- -- imports -import Control.Applicative import System.IO ( hFlush , hPutStr
changelog view
@@ -1,3 +1,71 @@+QuickCheck 2.10 (released 2017-06-15)+ * New combinators:+ - withMaxSuccess sets the maximum number of test cases for a property.+ - shrinkMap/shrinkMapBy are helpers for defining shrink functions.+ - total checks that a value is non-crashing.+ - suchThatMap is similar to 'suchThat'+ but takes a Maybe-returning function instead of a predicate.+ - getSize returns the current test case size.++ * Random strings and characters now include Unicode characters by+ default. To generate only ASCII characters, use the new+ ASCIIString modifier or arbitraryASCIIChar generator.+ The following modifiers and generators also control the+ kind of strings generated: UnicodeString, PrintableString,+ arbitraryUnicodeChar, arbitraryPrintableChar.++ * QuickCheck no longer catches asynchronous exceptions, which+ means that pressing ctrl-C will now cancel testing without+ printing a counterexample. If you are debugging an infinite loop,+ please use the 'timeout' combinator or 'verboseCheck' instead.+ ('timeout' is better as it allows the counterexample to be+ shrunk.)++ * Much of Test.QuickCheck.Function (showable random functions)+ is now exported from Test.QuickCheck.+ - Test.QuickCheck.Function now defines functions and+ pattern synonyms which simplify testing functions of+ more than one argument: apply2, apply3, Fn2, Fn3.++ * New typeclasses Arbitrary1 and Arbitrary2 which lift Arbitrary+ to unary/binary type constructors, like in Data.Functor.Classes.++ * Some Arbitrary instances have been removed: NonEmpty, Natural.+ This is because they resulted in a lot of extra dependencies.+ You can now find them in the quickcheck-instances package.+ Alternatively, use the NonEmptyList and NonNegative modifiers.++ * New Arbitrary instances for the following types: Proxy, ExitCode,+ WrappedMonad, WrappedArrow, QCGen, and the types in+ Foreign.C.Types and Data.Functor.{Product,Compose}.+ Also a Function instance for Word.++ * The functions in Test.QuickCheck.Monadic which take an argument+ of type PropertyM m a now expect that 'a' to be Testable, and test it.+ To reduce breakage from this, () is now an instance of Testable which+ always succeeds.+ - PropertyM now has a MonadFail instance on recent GHCs.+ Furthermore, the constraints on some instances were loosened.++ * Miscellaneous API changes:+ - Result now returns the counterexample as a list of strings.+ See the "failingTestCase" field.+ - Args now has a `maxShrinks` argument, the maximum number of+ shrinks to try before giving up shrinking.+ - The 'labels' field of Result now encodes frequencies as Doubles+ rather than Ints.++ * Bugfixes:+ - 'Test.QuickCheck.Function', 'Test.QuickCheck.Poly', and+ 'Test.QuickCheck.Monadic' are now Safe modules.+ - Result.theException and Result.reason were taken from+ the pre-shrunk counterexample, not the shrunk one.+ - The Testable Property instance improperly used 'again'.+ - Gen.>>= is strict in the result of split, fixing a space leak.+ - within now gives a better error message on timeout++ * Some more examples and links have been added to the documentation.+ QuickCheck 2.9.2 (released 2016-09-15) * Fix a bug where some properties were only being tested once * Make shrinking of floating-point values less aggressive
examples/Heap.hs view
@@ -5,8 +5,6 @@ -- imports import Test.QuickCheck-import Test.QuickCheck.Text-import Test.QuickCheck.All import Data.List ( sort
+ examples/Heap_Program.hs view
@@ -0,0 +1,197 @@+{-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}+module Main where++--------------------------------------------------------------------------+-- imports++import Test.QuickCheck+import Test.QuickCheck.Poly++import Data.List+ ( sort+ , (\\)+ )++import Control.Monad+ ( liftM+ , liftM2+ )++--------------------------------------------------------------------------+-- skew heaps++data Heap a+ = Node a (Heap a) (Heap a)+ | Nil+ deriving ( Eq, Ord, Show )++empty :: Heap a+empty = Nil++isEmpty :: Heap a -> Bool+isEmpty Nil = True+isEmpty _ = False++unit :: a -> Heap a+unit x = Node x empty empty++size :: Heap a -> Int+size Nil = 0+size (Node _ h1 h2) = 1 + size h1 + size h2++insert :: Ord a => a -> Heap a -> Heap a+insert x h = unit x `merge` h++removeMin :: Ord a => Heap a -> Maybe (a, Heap a)+removeMin Nil = Nothing+removeMin (Node x h1 h2) = Just (x, h1 `merge` h2)++merge :: Ord a => Heap a -> Heap a -> Heap a+h1 `merge` Nil = h1+Nil `merge` h2 = h2+h1@(Node x h11 h12) `merge` h2@(Node y h21 h22)+ | x <= y = Node x (h12 `merge` h2) h11+ | otherwise = Node y (h22 `merge` h1) h21++fromList :: Ord a => [a] -> Heap a+fromList xs = merging [ unit x | x <- xs ]+ where+ merging [] = empty+ merging [h] = h+ merging hs = merging (sweep hs)++ sweep [] = []+ sweep [h] = [h]+ sweep (h1:h2:hs) = (h1 `merge` h2) : sweep hs++toList :: Heap a -> [a]+toList h = toList' [h]+ where+ toList' [] = []+ toList' (Nil : hs) = toList' hs+ toList' (Node x h1 h2 : hs) = x : toList' (h1:h2:hs)++toSortedList :: Ord a => Heap a -> [a]+toSortedList Nil = []+toSortedList (Node x h1 h2) = x : toList (h1 `merge` h2)++--------------------------------------------------------------------------+-- heap programs++data HeapP a+ = Empty+ | Unit a+ | Insert a (HeapP a)+ | SafeRemoveMin (HeapP a)+ | Merge (HeapP a) (HeapP a)+ | FromList [a]+ deriving (Show)++heap :: Ord a => HeapP a -> Heap a+heap Empty = empty+heap (Unit x) = unit x+heap (Insert x p) = insert x (heap p)+heap (SafeRemoveMin p) = case removeMin (heap p) of+ Nothing -> empty -- arbitrary choice+ Just (_,h) -> h+heap (Merge p q) = heap p `merge` heap q+heap (FromList xs) = fromList xs++instance Arbitrary a => Arbitrary (HeapP a) where+ arbitrary = sized arbHeapP+ where+ arbHeapP s =+ frequency+ [ (1, do return Empty)+ , (1, do x <- arbitrary+ return (Unit x))+ , (s, do x <- arbitrary+ p <- arbHeapP s1+ return (Insert x p))+ , (s, do p <- arbHeapP s1+ return (SafeRemoveMin p))+ , (s, do p <- arbHeapP s2+ q <- arbHeapP s2+ return (Merge p q))+ , (1, do xs <- arbitrary+ return (FromList xs))+ ]+ where+ s1 = s-1+ s2 = s`div`2+++ shrink (Unit x) = [ Unit x' | x' <- shrink x ]+ shrink (FromList xs) = [ Unit x | x <- xs ]+ ++ [ FromList xs' | xs' <- shrink xs ]+ shrink (Insert x p) = [ p ]+ ++ [ Insert x p' | p' <- shrink p ]+ ++ [ Insert x' p | x' <- shrink x ]+ shrink (SafeRemoveMin p) = [ p ]+ ++ [ SafeRemoveMin p' | p' <- shrink p ]+ shrink (Merge p q) = [ p, q ]+ ++ [ Merge p' q | p' <- shrink p ]+ ++ [ Merge p q' | q' <- shrink q ]+ shrink _ = []++data HeapPP a = HeapPP (HeapP a) (Heap a)+ deriving (Show)++instance (Ord a, Arbitrary a) => Arbitrary (HeapPP a) where+ arbitrary =+ do p <- arbitrary+ return (HeapPP p (heap p))++ shrink (HeapPP p _) =+ [ HeapPP p' (heap p') | p' <- shrink p ]++--------------------------------------------------------------------------+-- properties++(==?) :: Heap OrdA -> [OrdA] -> Bool+h ==? xs = sort (toList h) == sort xs++prop_Empty =+ empty ==? []++prop_IsEmpty (HeapPP _ h) =+ isEmpty h == null (toList h)++prop_Unit x =+ unit x ==? [x]++prop_Size (HeapPP _ h) =+ size h == length (toList h)++prop_Insert x (HeapPP _ h) =+ insert x h ==? (x : toList h)++prop_RemoveMin (HeapPP _ h) =+ cover (size h > 1) 80 "non-trivial" $+ case removeMin h of+ Nothing -> h ==? []+ Just (x,h') -> x == minimum (toList h) && h' ==? (toList h \\ [x])++prop_Merge (HeapPP _ h1) (HeapPP _ h2) =+ (h1 `merge` h2) ==? (toList h1 ++ toList h2)++prop_FromList xs =+ fromList xs ==? xs++prop_ToSortedList (HeapPP _ h) =+ h ==? xs && xs == sort xs+ where+ xs = toSortedList h++--------------------------------------------------------------------------+-- main++return []+main = $(quickCheckAll)++--------------------------------------------------------------------------+-- the end.++-- toSortedList (Node x h1 h2) = x : toSortedList (h1 `merge` h2)++
+ examples/Heap_ProgramAlgebraic.hs view
@@ -0,0 +1,254 @@+{-# LANGUAGE ScopedTypeVariables, TemplateHaskell, GADTs #-}+module Main where++--------------------------------------------------------------------------+-- imports++import Test.QuickCheck+import Test.QuickCheck.Poly++import Data.List+ ( sort+ , nub+ , (\\)+ )++import Data.Maybe+ ( fromJust+ )++import Control.Monad+ ( liftM+ , liftM2+ )++--------------------------------------------------------------------------+-- skew heaps++data Heap a+ = Node a (Heap a) (Heap a)+ | Nil+ deriving ( Eq, Ord, Show )++empty :: Heap a+empty = Nil++isEmpty :: Heap a -> Bool+isEmpty Nil = True+isEmpty _ = False++unit :: a -> Heap a+unit x = Node x empty empty++size :: Heap a -> Int+size Nil = 0+size (Node _ h1 h2) = 1 + size h1 + size h2++insert :: Ord a => a -> Heap a -> Heap a+insert x h = unit x `merge` h++removeMin :: Ord a => Heap a -> Maybe (a, Heap a)+removeMin Nil = Nothing+removeMin (Node x h1 h2) = Just (x, h1 `merge` h2)++merge :: Ord a => Heap a -> Heap a -> Heap a+h1 `merge` Nil = h1+Nil `merge` h2 = h2+h1@(Node x h11 h12) `merge` h2@(Node y h21 h22)+ | x <= y = Node x (h12 `merge` h2) h11+ | otherwise = Node y (h22 `merge` h1) h21++fromList :: Ord a => [a] -> Heap a+fromList xs = merging [ unit x | x <- xs ] []+ where+ merging [] [] = empty+ merging [p] [] = p+ merging (p:q:ps) qs = merging ps ((p`merge`q):qs)+ merging ps qs = merging (ps ++ reverse qs) []++toList :: Heap a -> [a]+toList h = toList' [h]+ where+ toList' [] = []+ toList' (Nil : hs) = toList' hs+ toList' (Node x h1 h2 : hs) = x : toList' (h1:h2:hs)++toSortedList :: Ord a => Heap a -> [a]+toSortedList Nil = []+toSortedList (Node x h1 h2) = x : toSortedList (h1 `merge` h2)++--------------------------------------------------------------------------+-- heap programs++data HeapP a+ = Empty+ | Unit a+ | Insert a (HeapP a)+ | SafeRemoveMin (HeapP a)+ | Merge (HeapP a) (HeapP a)+ | FromList [a]+ deriving (Show)++safeRemoveMin :: Ord a => Heap a -> Heap a+safeRemoveMin h = case removeMin h of+ Nothing -> empty -- arbitrary choice+ Just (_,h) -> h++heap :: Ord a => HeapP a -> Heap a+heap Empty = empty+heap (Unit x) = unit x+heap (Insert x p) = insert x (heap p)+heap (SafeRemoveMin p) = safeRemoveMin (heap p)+heap (Merge p q) = heap p `merge` heap q+heap (FromList xs) = fromList xs++instance (Ord a, Arbitrary a) => Arbitrary (HeapP a) where+ arbitrary = sized arbHeapP+ where+ arbHeapP s =+ frequency+ [ (1, do return Empty)+ , (1, do x <- arbitrary+ return (Unit x))+ , (s, do x <- arbitrary+ p <- arbHeapP s1+ return (Insert x p))+ , (s, do p <- arbHeapP s1+ return (SafeRemoveMin p))+ , (s, do p <- arbHeapP s2+ q <- arbHeapP s2+ return (Merge p q))+ , (1, do xs <- arbitrary+ return (FromList xs))+ ]+ where+ s1 = s-1+ s2 = s`div`2+++ shrink Empty = []+ shrink (Unit x) = [ Unit x' | x' <- shrink x ]+ shrink (FromList xs) = [ Unit x | x <- xs ]+ ++ [ FromList xs' | xs' <- shrink xs ]+ shrink p =+ [ FromList (toList (heap p)) ] +++ case p of+ Insert x p -> [ p ]+ ++ [ Insert x p' | p' <- shrink p ]+ ++ [ Insert x' p | x' <- shrink x ]+ SafeRemoveMin p -> [ p ]+ ++ [ SafeRemoveMin p' | p' <- shrink p ]+ Merge p q -> [ p, q ]+ ++ [ Merge p' q | p' <- shrink p ]+ ++ [ Merge p q' | q' <- shrink q ]++data HeapPP a = HeapPP (HeapP a) (Heap a)+ deriving (Show)++instance (Ord a, Arbitrary a) => Arbitrary (HeapPP a) where+ arbitrary =+ do p <- arbitrary+ return (HeapPP p (heap p))++ shrink (HeapPP p _) =+ [ HeapPP p' (heap p') | p' <- shrink p ]++--------------------------------------------------------------------------+-- properties++data Context a where+ Context :: Eq b => (Heap a -> b) -> Context a++instance (Ord a, Arbitrary a) => Arbitrary (Context a) where+ arbitrary =+ do f <- sized arbContext+ let vec h = (size h, toSortedList h, isEmpty h)+ return (Context (vec . f))+ where+ arbContext s =+ frequency+ [ (1, do return id)+ , (s, do x <- arbitrary+ f <- arbContext (s-1)+ return (insert x . f))+ , (s, do f <- arbContext (s-1)+ return (safeRemoveMin . f))+ , (s, do HeapPP _ h <- arbitrary+ f <- arbContext (s`div`2)+ elements [ (h `merge`) . f, (`merge` h) . f ])+ ]++instance Show (Context a) where+ show _ = "*"++(=~) :: Heap Char -> Heap Char -> Property+--h1 =~ h2 = sort (toList h1) == sort (toList h2)+--h1 =~ h2 = property (nub (sort (toList h1)) == nub (sort (toList h2))) -- bug!+h1 =~ h2 = property (\(Context c) -> c h1 == c h2)++{-+The normal form is:++ insert x1 (insert x2 (... empty)...)++where x1 <= x2 <= ...+-}++-- heap creating operations++prop_Unit x =+ unit x =~ insert x empty++prop_RemoveMin_Empty =+ removeMin (empty :: Heap OrdA) == Nothing++prop_RemoveMin_Insert1 x =+ removeMin (insert x empty :: Heap OrdA) == Just (x, empty)++prop_RemoveMin_Insert2 x y (HeapPP _ h) =+ removeMin (insert x (insert y h)) ==~+ (insert (max x y) `maph` removeMin (insert (min x y) h))+ where+ f `maph` Just (x,h) = Just (x, f h)+ f `maph` Nothing = Nothing++ Nothing ==~ Nothing = property True+ Just (x,h1) ==~ Just (y,h2) = x==y .&&. h1 =~ h2++prop_InsertSwap x y (HeapPP _ h) =+ insert x (insert y h) =~ insert y (insert x h)++prop_MergeInsertLeft x (HeapPP _ h1) (HeapPP _ h2) =+ (insert x h1 `merge` h2) =~ insert x (h1 `merge` h2)++prop_MergeInsertRight x (HeapPP _ h1) (HeapPP _ h2) =+ (h1 `merge` insert x h2) =~ insert x (h1 `merge` h2)++-- heap observing operations++prop_Size_Empty =+ size empty == 0++prop_Size_Insert x (HeapPP _ (h :: Heap OrdA)) =+ size (insert x h) == 1 + size h++prop_ToList_Empty =+ toList empty == ([] :: [OrdA])++prop_ToList_Insert x (HeapPP _ (h :: Heap OrdA)) =+ sort (toList (insert x h)) == sort (x : toList h)++prop_ToSortedList (HeapPP _ (h :: Heap OrdA)) =+ toSortedList h == sort (toList h)++--------------------------------------------------------------------------+-- main++return []+main = $(quickCheckAll)++--------------------------------------------------------------------------+-- the end.+++
+ examples/Lambda.hs view
@@ -0,0 +1,363 @@+{-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}+module Main where++--------------------------------------------------------------------------+-- imports++import Test.QuickCheck++import Control.Monad+ ( liftM+ , liftM2+ )++import Data.Char+ ( toUpper+ )++import Data.Set (Set)+import qualified Data.Set as Set++--------------------------------------------------------------------------+-- types for lambda expressions++-- variables++newtype Var = MkVar String+ deriving ( Eq, Ord )++instance Show Var where+ show (MkVar s) = s++varList :: [Var]+varList = [ MkVar s+ | let vs = [ c:v | v <- "" : vs, c <- ['a'..'z'] ]+ , s <- vs+ ]++instance Arbitrary Var where+ arbitrary = growingElements [ MkVar [c] | c <- ['a'..'z'] ]++-- constants++newtype Con = MkCon String+ deriving ( Eq, Ord )++instance Show Con where+ show (MkCon s) = s++instance Arbitrary Con where+ arbitrary = growingElements [ MkCon [c] | c <- ['A'..'Z'] ]++-- expressions++data Exp+ = Lam Var Exp+ | App Exp Exp+ | Var Var+ | Con Con+ deriving ( Eq, Ord )++instance Show Exp where+ showsPrec n (Lam x t) = showParen (n>0) (showString "\\" . shows x . showString "." . shows t)+ showsPrec n (App s t) = showParen (n>1) (showsPrec 1 s . showString " " . showsPrec 2 t)+ showsPrec _ (Var x) = shows x+ showsPrec _ (Con c) = shows c++instance Arbitrary Exp where+ arbitrary = sized arbExp+ where+ arbExp n =+ frequency $+ [ (2, liftM Var arbitrary)+ , (1, liftM Con arbitrary)+ ] +++ concat+ [ [ (5, liftM2 Lam arbitrary arbExp1)+ , (5, liftM2 App arbExp2 arbExp2)+ ]+ | n > 0+ ]+ where+ arbExp1 = arbExp (n-1)+ arbExp2 = arbExp (n `div` 2)++ shrink (Lam x a) = [ a ]+ ++ [ Lam x a' | a' <- shrink a ]+ shrink (App a b) = [ a, b ]+ ++ [ ab+ | Lam x a' <- [a]+ , let ab = subst x b a'+ , length (show ab) < length (show (App a b))+ ]+ ++ [ App a' b | a' <- shrink a ]+ ++ [ App a b' | b' <- shrink b ]+ shrink (Var x) = [Con (MkCon (map toUpper (show x)))]+ shrink _ = []++--------------------------------------------------------------------------+-- functions for lambda expressions++free :: Exp -> Set Var+free (Lam x a) = Set.delete x (free a)+free (App a b) = free a `Set.union` free b+free (Var x) = Set.singleton x+free (Con _) = Set.empty++subst :: Var -> Exp -> Exp -> Exp+subst x c (Var y) | x == y = c+subst x b (Lam y a) | x /= y = Lam y (subst x b a)+subst x c (App a b) = App (subst x c a) (subst x c b)+subst x c a = a++fresh :: Var -> Set Var -> Var+fresh x ys = head (filter (`Set.notMember` ys) (x:varList))++rename :: Var -> Var -> Exp -> Exp+rename x y a | x == y = a+ | otherwise = subst x (Var y) a++-- different bugs:+--subst x b (Lam y a) | x /= y = Lam y (subst x b a) -- bug 1+--subst x b (Lam y a) | x /= y = Lam y' (subst x b (rename y y' a)) where y':_ = (y:varList) \\ free b -- bug 2+--subst x b (Lam y a) | x /= y = Lam y' (subst x b (rename y y' a)) where y' = (y:varList) \\ (x:free b) -- bug 3+--subst x b (Lam y a) | x /= y = Lam y' (subst x b (rename y y' a)) where y' = fresh y (x:free b) -- bug 4+--subst x c (Lam y a) | x /= y = Lam y' (subst x c (rename y y' a)) where y' = fresh y (x `insert` delete y (free a) `union` free c)++--------------------------------------------------------------------------+-- properties for substitutions++showResult :: (Show a, Testable prop) => a -> (a -> prop) -> Property+showResult x f =+ whenFail (putStrLn ("Result: " ++ show x)) $+ f x++prop_SubstFreeNoVarCapture a x b =+ showResult (subst x b a) $ \subst_x_b_a ->+ x `Set.member` free_a ==>+ free subst_x_b_a == (Set.delete x free_a `Set.union` free b)+ where+ free_a = free a++prop_SubstNotFreeSame a x b =+ showResult (subst x b a) $ \subst_x_b_a ->+ x `Set.notMember` free a ==>+ subst_x_b_a == a++prop_SubstNotFreeSameVars a x b =+ showResult (subst x b a) $ \subst_x_b_a ->+ x `Set.notMember` free a ==>+ free subst_x_b_a == free a++main1 =+ do quickCheck prop_SubstFreeNoVarCapture+ quickCheck prop_SubstNotFreeSame+ quickCheck prop_SubstNotFreeSameVars++--expectFailure $+++++++++--------------------------------------------------------------------------+-- eval++eval :: Exp -> Exp+eval (Var x) = error "eval: free variable"+eval (App a b) =+ case eval a of+ Lam x a' -> eval (subst x b a')+ a' -> App a' (eval b)+eval a = a++--------------------------------------------------------------------------+-- closed lambda expressions++newtype ClosedExp = Closed Exp deriving ( Show )++instance Arbitrary ClosedExp where+ arbitrary = Closed `fmap` sized (arbExp [])+ where+ arbExp xs n =+ frequency $+ [ (8, liftM Var (elements xs))+ | not (null xs)+ ] +++ [ (2, liftM Con arbitrary)+ ] +++ [ (20, do x <- arbitrary+ t <- arbExp (x:xs) n'+ return (Lam x t))+ | n > 0 || null xs+ ] +++ [ (20, liftM2 App (arbExp xs n2) (arbExp xs n2))+ | n > 0+ ]+ where+ n' = n-1+ n2 = n `div` 2++ shrink (Closed a) =+ [ Closed a' | a' <- shrink a, Set.null (free a') ]++--------------------------------------------------------------------------+-- properties for closed lambda expressions++isValue :: Exp -> Bool+isValue (Var _) = False+isValue (App (Lam _ _) _) = False+isValue (App a b) = isValue a && isValue b+isValue _ = True++prop_ClosedExpIsClosed (Closed a) =+ Set.null (free a)++prop_EvalProducesValue (Closed a) =+ within 1000 $+ isValue (eval a)++main2 =+ do quickCheck prop_ClosedExpIsClosed+ quickCheck prop_EvalProducesValue++-- expectFailure $++--------------------------------------------------------------------------+-- main++main =+ do main1+ main2++--------------------------------------------------------------------------+-- the end.++{-+instance Arbitrary Exp where+ arbitrary = sized (arbExp [])+ where++ arbitrary = repair [] `fmap` sized arbExp+ where+ arbExp n =+ frequency $+ [ (1, liftM Var arbitrary)+ ] ++ concat+ [ [ (3, liftM2 Lam arbitrary (arbExp n'))+ , (4, liftM2 App (arbExp n2) (arbExp n2))+ ]+ | n > 0+ ]+ where+ n' = n-1+ n2 = n `div` 2++ repair xs (Var x)+ | x `elem` xs = Var x+ | null xs = Lam x (Var x)+ | otherwise = Var (xs !! (ord (last (show x)) `mod` length xs))+ repair xs (App a b) = App (repair xs a) (repair xs b)+ repair xs (Lam x a) = Lam x (repair (x:xs) a)++ -- lots of clever shrinking added+ shrinkRec (Lam x a) = [ a | x `notElem` free a ]+ shrinkRec (App a b) = [ a, b ]+ ++ [ red+ | Lam x a' <- [a]+ , let red = subst x b a'+ , length (show red) < length (show (App a b))+ ]+ shrinkRec (Var x) = [Con (MkCon (map toUpper (show x)))]+ shrinkRec _ = []++-- types++data Type+ = Base Con+ | Type :-> Type+ deriving ( Eq, Show )++instance Arbitrary Type where+ arbitrary = sized arbType+ where+ arbType n =+ frequency $+ [ (1, liftM Base arbitrary)+ ] +++ [ (4, liftM2 (:->) arbType2 arbType2)+ | n > 0+ ]+ where+ arbType2 = arbType (n `div` 2)++newtype WellTypedExp = WellTyped Exp+ deriving ( Eq, Show )++arbExpWithType n env t =+ frequency $+ [ (2, liftM Var (elements xs))+ | let xs = [ x | (x,t') <- env, t == t' ]+ , not (null xs)+ ] +++ [ (1, return (Con b))+ | Base b <- [t]+ ] +++ [ (if n > 0 then 5 else 1+ , do x <- arbitrary+ b <- arbExpWithType n1 ((x,ta):[ xt | xt <- env, fst xt /= x ]) tb+ return (Lam x b))+ | ta :-> tb <- [t]+ ] +++ [ (5, do tb <- arbitrary+ a <- arbExpWithType n2 env (tb :-> t)+ b <- arbExpWithType n2 env tb+ return (App a b))+ | n > 0+ ]+ where+ n1 = n-1+ n2 = n `div` 2++instance Arbitrary WellTypedExp where+ arbitrary =+ do t <- arbitrary+ e <- sized (\n -> arbExpWithType n [] t)+ return (WellTyped e)++ shrink _ = []++newtype OpenExp = Open Exp+ deriving ( Eq, Show )++instance Arbitrary OpenExp where+ arbitrary = Open `fmap` sized arbExp+ where+ arbExp n =+ frequency $+ [ (2, liftM Var arbitrary)+ , (1, liftM Con arbitrary)+ ] +++ concat+ [ [ (5, liftM2 Lam arbitrary arbExp1)+ , (5, liftM2 App arbExp2 arbExp2)+ ]+ | n > 0+ ]+ where+ arbExp1 = arbExp (n-1)+ arbExp2 = arbExp (n `div` 2)++ shrink (Open a) = map Open (shrink a)++prop_EvalProducesValueWT (WellTyped a) =+ isValue (eval a)++-}++x = MkVar "x"+y = MkVar "y"+
+ examples/Merge.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}+module Main where++--------------------------------------------------------------------------+-- imports++import Test.QuickCheck++import Data.List+ ( sort+ )++--------------------------------------------------------------------------+-- merge sort++msort :: Ord a => [a] -> [a]+msort xs = merging [ [x] | x <- xs ]++merging :: Ord a => [[a]] -> [a]+merging [] = []+merging [xs] = xs+merging xss = merging (sweep xss)++sweep :: Ord a => [[a]] -> [[a]]+sweep [] = []+sweep [xs] = [xs]+sweep (xs:ys:xss) = merge xs ys : sweep xss++merge :: Ord a => [a] -> [a] -> [a]+merge xs [] = xs+merge [] ys = ys+merge (x:xs) (y:ys)+ | x <= y = x : merge xs (y:ys)+ | otherwise = y : merge (x:xs) ys++--------------------------------------------------------------------------+-- example properties++ordered :: Ord a => [a] -> Bool+ordered [] = True+ordered [x] = True+ordered (x:y:xs) = x <= y && ordered (y:xs)++prop_Merge xs (ys :: [Int]) =+ ordered xs && ordered ys ==>+ collect (length xs + length ys) $+ ordered (xs `merge` ys)++-- collect (sort [length xs, length ys]) $++++++++++++++++++++--------------------------------------------------------------------------+-- quantificiation++--prop_Merge (Ordered xs) (Ordered (ys :: [Int])) =+-- ordered (xs `merge` ys)++++++++++++++-- classify (length xs `min` length ys >= 5) "not trivial" $+-- cover (length xs `min` length ys >= 5) 70 "not trivial" $++{-+ shrink (Ordered xs) =+ [ Ordered xs'+ | xs' <- shrink xs+ , ordered xs'+ ]+-}++--------------------------------------------------------------------------+-- merging++prop_Merging (xss :: [OrderedList Int]) =+ ordered (merging [ xs | Ordered xs <- xss ])++++++++-- mapSize (`div` 2) $ \(xss :: [OrderedList Int]) ->++return []+main = $quickCheckAll++--------------------------------------------------------------------------+-- the end.
+ examples/Set.hs view
@@ -0,0 +1,213 @@+{-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}+module Main where++--------------------------------------------------------------------------+-- imports++import Test.QuickCheck++import Text.Show.Functions+import Data.List+ ( sort+ , group+ , nub+ , (\\)+ )++import Control.Monad+ ( liftM+ , liftM2+ )++import Data.Maybe++--import Text.Show.Functions++--------------------------------------------------------------------------+-- binary search trees++data Set a+ = Node a (Set a) (Set a)+ | Empty+ deriving ( Eq, Ord, Show )++empty :: Set a+empty = Empty++isEmpty :: Set a -> Bool+isEmpty Empty = True+isEmpty _ = False++unit :: a -> Set a+unit x = Node x empty empty++size :: Set a -> Int+size Empty = 0+size (Node _ s1 s2) = 1 + size s1 + size s2++insert :: Ord a => a -> Set a -> Set a+insert x s = s `union` unit x++merge :: Set a -> Set a -> Set a+s `merge` Empty = s+s `merge` Node x Empty s2 = Node x s s2+s `merge` Node x (Node y s11 s12) s2 = Node y s (Node x (s11 `merge` s12) s2)++delete :: Ord a => a -> Set a -> Set a+delete x Empty = Empty+delete x (Node x' s1 s2) =+ case x `compare` x' of+ LT -> Node x' (delete x s1) s2+ EQ -> s1 `merge` s2+ GT -> Node x' s1 (delete x s2)++union :: Ord a => Set a -> Set a -> Set a+{-+s1 `union` Empty = s1+Empty `union` s2 = s2+s1@(Node x s11 s12) `union` s2@(Node y s21 s22) =+ case x `compare` y of+ LT -> Node x s11 (s12 `union` Node y Empty s22) `union` s21+ EQ -> Node x (s11 `union` s21) (s12 `union` s22)+ --GT -> s11 `union` Node y s21 (Node x Empty s12 `union` s22)+ GT -> Node x (s11 `union` Node y s21 Empty) s12 `union` s22 +-}+s1 `union` Empty = s1+Empty `union` s2 = s2+Node x s11 s12 `union` s2 = Node x (s11 `union` s21) (s12 `union` s22)+ where+ (s21,s22) = split x s2++split :: Ord a => a -> Set a -> (Set a, Set a)+split x Empty = (Empty, Empty)+split x (Node y s1 s2) =+ case x `compare` y of+ LT -> (s11, Node y s12 s2)+ EQ -> (s1, s2)+ GT -> (Node y s1 s21, s22)+ where+ (s11,s12) = split x s1+ (s21,s22) = split x s2+ +mapp :: (a -> b) -> Set a -> Set b+mapp f Empty = Empty+mapp f (Node x s1 s2) = Node (f x) (mapp f s1) (mapp f s2)++fromList :: Ord a => [a] -> Set a+--fromList xs = build [ (empty,x) | x <- sort xs ]+fromList xs = build [ (empty,head x) | x <- group (sort xs) ]+ where+ build [] = empty+ build [(s,x)] = attach x s+ build sxs = build (sweep sxs)++ sweep [] = []+ sweep [sx] = [sx]+ sweep ((s1,x1):(s2,x2):sxs) = (Node x1 s1 s2,x2) : sweep sxs++ attach x Empty = unit x+ attach x (Node y s1 s2) = Node y s1 (attach x s2)++toList :: Set a -> [a]+toList s = toSortedList s++toSortedList :: Set a -> [a]+toSortedList s = toList' s []+ where+ toList' Empty xs = xs+ toList' (Node x s1 s2) xs = toList' s1 (x : toList' s2 xs)++--------------------------------------------------------------------------+-- generators++instance (Ord a, Arbitrary a) => Arbitrary (Set a) where+ arbitrary = sized (arbSet Nothing Nothing)+ where+ arbSet mx my n =+ frequency $+ [ (1, return Empty) ] +++ [ (7, do mz <- arbitrary `suchThatMaybe` (isOK mx my)+ case mz of+ Nothing -> return Empty+ Just z -> liftM2 (Node z) (arbSet mx mz n2)+ (arbSet mz my n2)+ where n2 = n `div` 2)+ | n > 0+ ]++ isOK mx my z =+ maybe True (<z) mx && maybe True (z<) my++ shrink Empty = []+ shrink t@(Node x s1 s2) = [ s1, s2 ]+ ++ [ t' | x' <- shrink x, let t' = Node x' s1 s2, invariant t' ]++-- instance (Ord a, ShrinkSub a) => ShrinkSub (Set a)++--------------------------------------------------------------------------+-- properties++(.<) :: Ord a => Set a -> a -> Bool+Empty .< x = True+Node y _ s .< x = y < x && s .< x++(<.) :: Ord a => a -> Set a -> Bool+x <. Empty = True+x <. Node y _ s = x < y && x <. s++(==?) :: Ord a => Set a -> [a] -> Bool+s ==? xs = invariant s && sort (toList s) == nub (sort xs)++invariant :: Ord a => Set a -> Bool+invariant Empty = True+invariant (Node x s1 s2) = s1 .< x && x <. s2 && invariant s1 && invariant s2++prop_Invariant (s :: Set Int) =+ invariant s++prop_Empty =+ empty ==? ([] :: [Int])++prop_Unit (x :: Int) =+ unit x ==? [x]++prop_Size (s :: Set Int) =+ cover (size s >= 15) 60 "large" $+ size s == length (toList s)++prop_Insert x (s :: Set Int) =+ insert x s ==? (x : toList s)++prop_Delete x (s :: Set Int) =+ delete x s ==? (toList s \\ [x])++prop_Union s1 (s2 :: Set Int) =+ (s1 `union` s2) ==? (toList s1 ++ toList s2)++prop_Mapp (f :: Int -> Int) (s :: Set Int) =+ expectFailure $+ whenFail (putStrLn ("Fun: " ++ show [ (x,f x) | x <- toList s])) $+ mapp f s ==? map f (toList s)++prop_FromList (xs :: [Int]) =+ fromList xs ==? xs++prop_ToSortedList (s :: Set Int) =+ s ==? xs && xs == sort xs+ where+ xs = toSortedList s+ +-- whenFail (putStrLn ("Result: " ++ show (fromList xs))) $++prop_FromList' (xs :: [Int]) =+ shrinking shrink xs $ \xs' ->+ fromList xs ==? xs++--------------------------------------------------------------------------+-- main++return []+main = $quickCheckAll++--------------------------------------------------------------------------+-- the end.
+ examples/Simple.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}+module Main where++--------------------------------------------------------------------------+-- imports++import Test.QuickCheck++--------------------------------------------------------------------------+-- example 1++allEqual x y z = x == y && y == z+allEqual' x y z = 2*x == y + z++prop_SimonThompson x y (z :: Int) =+ allEqual x y z == allEqual' x y z++--------------------------------------------------------------------------+-- example 2++prop_ReverseReverse :: Eq a => [a] -> Bool+prop_ReverseReverse xs =+ reverse (reverse xs) == xs++prop_Reverse xs =+ reverse xs == xs++--------------------------------------------------------------------------+-- example 3++prop_Error (x,y) =+ 2*x <= 5*y++--------------------------------------------------------------------------+-- main++return []+prop_conj = counterexample "Simon Thompson" $(monomorphic 'prop_SimonThompson) .&&.+ counterexample "reverse" $(monomorphic 'prop_Reverse)+prop_disj = counterexample "reverse" $(monomorphic 'prop_Reverse) .||.+ counterexample "Simon Thompson" $(monomorphic 'prop_SimonThompson)+return []+main = $quickCheckAll++--------------------------------------------------------------------------+-- the end.
tests/Generators.hs view
@@ -142,5 +142,17 @@ prop_reachesBound_Word32 = reachesBound :: Word32 -> Property prop_reachesBound_Word64 = reachesBound :: Word64 -> Property +-- Bad shrink: infinite list+--+-- remove unexpectedFailure in prop_B1, shrinking should not loop forever.+data B1 = B1 Int deriving (Eq, Show)++instance Arbitrary B1 where+ arbitrary = fmap B1 arbitrary+ shrink x = x : shrink x++prop_B1 :: B1 -> Property+prop_B1 (B1 n) = expectFailure $ n === n + 1+ return []-main = $quickCheckAll >>= print+main = $forAllProperties (quickCheckWithResult stdArgs { maxShrinks = 10000 }) >>= print