packages feed

QuickCheck 2.14.2 → 2.14.3

raw patch · 16 files changed

+352/−50 lines, 16 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary GHC.Integer.Type.Integer
- Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary GHC.Integer.Type.Integer
- Test.QuickCheck.Function: instance Test.QuickCheck.Function.Function GHC.Integer.Type.Integer
+ Test.QuickCheck: discardAfter :: Testable prop => Int -> prop -> Property
+ Test.QuickCheck: shrinkBoundedEnum :: (Bounded a, Enum a, Eq a) => a -> [a]
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary GHC.IO.Handle.Types.Newline
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary GHC.IO.Handle.Types.NewlineMode
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary GHC.Num.Integer.Integer
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary GHC.IO.Handle.Types.Newline
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary GHC.IO.Handle.Types.NewlineMode
+ Test.QuickCheck.Arbitrary: instance Test.QuickCheck.Arbitrary.CoArbitrary GHC.Num.Integer.Integer
+ Test.QuickCheck.Arbitrary: shrinkBoundedEnum :: (Bounded a, Enum a, Eq a) => a -> [a]
+ Test.QuickCheck.Function: functionElements :: Eq a => [a] -> (a -> b) -> a :-> b
+ Test.QuickCheck.Function: instance Test.QuickCheck.Function.Function GHC.IO.Handle.Types.Newline
+ Test.QuickCheck.Function: instance Test.QuickCheck.Function.Function GHC.IO.Handle.Types.NewlineMode
+ Test.QuickCheck.Function: instance Test.QuickCheck.Function.Function GHC.Num.Integer.Integer
+ Test.QuickCheck.Gen: genDouble :: Gen Double
+ Test.QuickCheck.Gen: genFloat :: Gen Float
+ Test.QuickCheck.Monadic: assertWith :: Monad m => Bool -> String -> PropertyM m ()

Files

QuickCheck.cabal view
@@ -1,5 +1,5 @@ Name: QuickCheck-Version: 2.14.2+Version: 2.14.3 Cabal-Version: >= 1.10 Build-type: Simple License: BSD3@@ -57,15 +57,17 @@ source-repository this   type:     git   location: https://github.com/nick8325/quickcheck-  tag:      2.14.2+  tag:      2.14.3  flag templateHaskell   Description: Build Test.QuickCheck.All, which uses Template Haskell.   Default: True+  Manual: True  flag old-random   Description: Build against a pre-1.2.0 version of the random package.   Default: False+  Manual: False  library   Hs-source-dirs: src@@ -114,7 +116,10 @@    if impl(ghc) && flag(templateHaskell)     Build-depends: template-haskell >= 2.4-    Other-Extensions: TemplateHaskell+    if impl(ghc >=8.0)+      Other-Extensions: TemplateHaskellQuotes+    else+      Other-Extensions: TemplateHaskell     Exposed-Modules: Test.QuickCheck.All   else     cpp-options: -DNO_TEMPLATE_HASKELL
README view
@@ -1,8 +1,6 @@ This is QuickCheck 2, a library for random testing of program properties. -Install it in the usual way:--$ cabal install+Add `QuickCheck` to your package dependencies to use it in tests or REPL.  The quickcheck-instances [1] companion package provides instances for types in Haskell Platform packages at the cost of additional dependencies.
changelog view
@@ -1,3 +1,16 @@+QuickCheck 2.14.3 (released 2023-05-31)+	* Add shrinkBoundedEnum (thanks to Jonathan Knowles)+	* Add discardAfter for discarding tests on timeout (thanks to Justus Sagemüller)+	* Add assertWith for monadic testing (thanks to KtorZ)+	* Add functionElements to Test.QuickCheck.Function (thanks to Oleg Grenrus)+	* Add Arbitrary instance for Newline (thanks to Daniel Bramucci)+	* Improve Arbitrary instances for Float and Double (thanks to Oleg Grenrus)+	* Improve arbitrarySizedFractional (thanks to Bodigrim)+	* Fix shrinkRealFrac and shrinkDecimal, which were broken+	* Speed up printing of progress messages (thanks to Bodigrim)+	* Add COMPLETE pragmas for Fn and family (thanks to ilkecan)+	* Make templateHaskell flag manual (thanks to Oleg Grenrus)+ QuickCheck 2.14.2 (released 2020-11-14) 	* Add Arbitrary instances for Tree (thanks to Oleg Grenrus) 	* GHC 9.0 compatibility (thanks to Vilem-Benjamin Liepelt)
src/Test/QuickCheck.hs view
@@ -81,6 +81,7 @@   , shrinkMapBy   , shrinkIntegral   , shrinkRealFrac+  , shrinkBoundedEnum   , shrinkDecimal      -- ** Lifting of 'Arbitrary' to unary and binary type constructors@@ -269,6 +270,7 @@   , noShrinking   , withMaxSuccess   , within+  , discardAfter   , once   , again   , mapSize
src/Test/QuickCheck/All.hs view
@@ -1,4 +1,9 @@-{-# LANGUAGE TemplateHaskell, Rank2Types, CPP #-}+{-# LANGUAGE Rank2Types, CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# LANGUAGE TemplateHaskellQuotes #-}+#else+{-# LANGUAGE TemplateHaskell #-}+#endif #ifndef NO_SAFE_HASKELL {-# LANGUAGE Trustworthy #-} #endif@@ -24,7 +29,7 @@ import Test.QuickCheck.Property hiding (Result) import Test.QuickCheck.Test import Data.Char-import Data.List+import Data.List (isPrefixOf, nubBy) import Control.Monad  import qualified System.IO as S@@ -44,7 +49,7 @@ -- property, the same scoping problems pop up as in 'quickCheckAll': -- see the note there about @return []@. polyQuickCheck :: Name -> ExpQ-polyQuickCheck x = [| quickCheck $(monomorphic x) |]+polyQuickCheck x = [| quickCheck |] `appE` monomorphic x  -- | Test a polymorphic property, defaulting all type variables to 'Integer'. -- This is just a convenience function that combines 'verboseCheck' and 'monomorphic'.@@ -53,7 +58,7 @@ -- property, the same scoping problems pop up as in 'quickCheckAll': -- see the note there about @return []@. polyVerboseCheck :: Name -> ExpQ-polyVerboseCheck x = [| verboseCheck $(monomorphic x) |]+polyVerboseCheck x = [| verboseCheck |] `appE` monomorphic x  type Error = forall a. String -> a @@ -132,7 +137,7 @@ -- 'forAllProperties' has the same issue with scoping as 'quickCheckAll': -- see the note there about @return []@. forAllProperties :: Q Exp -- :: (Property -> IO Result) -> IO Bool-forAllProperties = [| runQuickCheckAll $allProperties |]+forAllProperties = [| runQuickCheckAll |] `appE` allProperties  -- | List all properties in the current module. --@@ -155,10 +160,15 @@       quickCheckOne :: (Int, String) -> Q [Exp]       quickCheckOne (l, x) = do         exists <- (warning x >> return False) `recover` (reify (mkName x) >> return True)-        if exists then sequence [ [| ($(stringE $ x ++ " from " ++ filename ++ ":" ++ show l),-                                     property $(monomorphic (mkName x))) |] ]+        if exists+         then sequence+          [ tupE+            [ stringE $ x ++ " from " ++ filename ++ ":" ++ show l+            , [| property |] `appE` monomorphic (mkName x)+            ]+          ]          else return []-  [| $(fmap (ListE . concat) (mapM quickCheckOne idents)) :: [(String, Property)] |]+  fmap (ListE . concat) (mapM quickCheckOne idents) `sigE` [t| [(String, Property)] |]  readUTF8File name = S.openFile name S.ReadMode >>=                     set_utf8_io_enc >>=@@ -195,7 +205,7 @@ -- of the module, which means that the later call to 'quickCheckAll' -- can see everything that was defined before the @return []@. Yikes! quickCheckAll :: Q Exp-quickCheckAll = [| $(forAllProperties) quickCheckResult |]+quickCheckAll = forAllProperties `appE` [| quickCheckResult |]  -- | Test all properties in the current module. -- This is just a convenience function that combines 'quickCheckAll' and 'verbose'.@@ -203,7 +213,7 @@ -- 'verboseCheckAll' has the same issue with scoping as 'quickCheckAll': -- see the note there about @return []@. verboseCheckAll :: Q Exp-verboseCheckAll = [| $(forAllProperties) verboseCheckResult |]+verboseCheckAll = forAllProperties `appE` [| verboseCheckResult |]  runQuickCheckAll :: [(String, Property)] -> (Property -> IO Result) -> IO Bool runQuickCheckAll ps qc =
src/Test/QuickCheck/Arbitrary.hs view
@@ -68,6 +68,7 @@   , shrinkMapBy              -- :: (a -> b) -> (b -> a) -> (a -> [a]) -> b -> [b]   , shrinkIntegral           -- :: Integral a => a -> [a]   , shrinkRealFrac           -- :: RealFrac a => a -> [a]+  , shrinkBoundedEnum        -- :: (Bounded a, Enum a) => a -> [a]   , shrinkDecimal            -- :: RealFrac a => a -> [a]   -- ** Helper functions for implementing coarbitrary   , coarbitraryIntegral      -- :: Integral a => a -> Gen b -> Gen b@@ -137,6 +138,15 @@  import Data.Version (Version (..)) +#if defined(MIN_VERSION_base)+#if MIN_VERSION_base(4,2,0)+import System.IO+  ( Newline(..)+  , NewlineMode(..)+  )+#endif+#endif+ import Control.Monad   ( liftM   , liftM2@@ -684,11 +694,55 @@                 )  instance Arbitrary Float where-  arbitrary = arbitrarySizedFractional+  arbitrary = oneof+    -- generate 0..1 numbers with full precision+    [ genFloat+    -- generate integral numbers+    , fromIntegral <$> (arbitrary :: Gen Int)+    -- generate fractions with small denominators+    , smallDenominators+    -- uniform -size..size with with denominators ~ size+    , uniform+    -- and uniform -size..size with higher precision+    , arbitrarySizedFractional+    ]+    where+      smallDenominators = sized $ \n -> do+        i <- chooseInt (0, n)+        pure (fromRational (streamNth i rationalUniverse))++      uniform = sized $ \n -> do+        let n' = toInteger n+        b <- chooseInteger (1, max 1 n')+        a <- chooseInteger ((-n') * b, n' * b)+        return (fromRational (a % b))+   shrink    = shrinkDecimal  instance Arbitrary Double where-  arbitrary = arbitrarySizedFractional+  arbitrary = oneof+    -- generate 0..1 numbers with full precision+    [ genDouble+    -- generate integral numbers+    , fromIntegral <$> (arbitrary :: Gen Int)+    -- generate fractions with small denominators+    , smallDenominators+    -- uniform -size..size with with denominators ~ size+    , uniform+    -- and uniform -size..size with higher precision+    , arbitrarySizedFractional+    ]+    where+      smallDenominators = sized $ \n -> do+        i <- chooseInt (0, n)+        pure (fromRational (streamNth i rationalUniverse))++      uniform = sized $ \n -> do+        let n' = toInteger n+        b <- chooseInteger (1, max 1 n')+        a <- chooseInteger ((-n') * b, n' * b)+        return (fromRational (a % b))+   shrink    = shrinkDecimal  instance Arbitrary CChar where@@ -987,8 +1041,26 @@   shrink (ExitFailure x) = ExitSuccess : [ ExitFailure x' | x' <- shrink x ]   shrink _        = [] +#if defined(MIN_VERSION_base)+#if MIN_VERSION_base(4,2,0)+instance Arbitrary Newline where+  arbitrary = elements [LF, CRLF] +  -- The behavior of code for LF is generally simpler than for CRLF+  -- See the documentation for this type, which states that Haskell+  -- Internally always assumes newlines are \n and this type represents+  -- how to translate that to and from the outside world, where LF means+  -- no translation.+  shrink LF = []+  shrink CRLF = [LF] +instance Arbitrary NewlineMode where+  arbitrary = NewlineMode <$> arbitrary <*> arbitrary++  shrink (NewlineMode inNL outNL) = [NewlineMode inNL' outNL' | (inNL', outNL') <- shrink (inNL, outNL)]+#endif+#endif+ -- ** Helper functions for implementing arbitrary  -- | Apply a binary function to random arguments.@@ -1024,17 +1096,14 @@ inBounds :: Integral a => (Int -> a) -> Gen Int -> Gen a inBounds fi g = fmap fi (g `suchThat` (\x -> toInteger x == toInteger (fi x))) --- | Generates a fractional number. The number can be positive or negative+-- | Uniformly generates a fractional number. The number can be positive or negative -- and its maximum absolute value depends on the size parameter. arbitrarySizedFractional :: Fractional a => Gen a arbitrarySizedFractional =-  sized $ \n ->-    let n' = toInteger n in-      do b <- chooseInteger (1, precision)-         a <- chooseInteger ((-n') * b, n' * b)-         return (fromRational (a % b))- where-  precision = 9999999999999 :: Integer+  sized $ \n -> do+    denom <- chooseInt (1, max 1 n)+    numer <- chooseInt (-n*denom, n*denom)+    pure $ fromIntegral numer / fromIntegral denom  -- Useful for getting at minBound and maxBound without having to -- fiddle around with asTypeOf.@@ -1119,7 +1188,7 @@ -- shrinkOrderedList :: (Ord a, Arbitrary a) => [a] -> [[a]] -- shrinkOrderedList = shrinkMap sort id ----- shrinkSet :: (Ord a, Arbitrary a) => Set a -> Set [a]+-- shrinkSet :: (Ord a, Arbitrary a) => Set a -> [Set a] -- shrinkSet = shrinkMap fromList toList -- @ shrinkMap :: Arbitrary a => (a -> b) -> (b -> a) -> b -> [b]@@ -1147,14 +1216,42 @@             (True,  False) -> a + b < 0             (False, True)  -> a + b > 0 +-- | Shrink an element of a bounded enumeration.+--+-- === __Example__+--+-- @+-- data MyEnum = E0 | E1 | E2 | E3 | E4 | E5 | E6 | E7 | E8 | E9+--    deriving (Bounded, Enum, Eq, Ord, Show)+-- @+--+-- >>> shrinkBoundedEnum E9+-- [E0,E5,E7,E8]+--+-- >>> shrinkBoundedEnum E5+-- [E0,E3,E4]+--+-- >>> shrinkBoundedEnum E0+-- []+--+shrinkBoundedEnum :: (Bounded a, Enum a, Eq a) => a -> [a]+shrinkBoundedEnum a+  | a == minBound =+    []+  | otherwise =+    toEnum <$> filter (>= minBoundInt) (shrinkIntegral $ fromEnum a)+  where+    minBoundInt :: Int+    minBoundInt = fromEnum (minBound `asTypeOf` a)+ -- | Shrink a fraction, preferring numbers with smaller -- numerators or denominators. See also 'shrinkDecimal'. shrinkRealFrac :: RealFrac a => a -> [a] shrinkRealFrac x-  | not (x == x)  = 0 : take 10 (iterate (*2) 0) -- NaN-  | not (2*x+1>x) = 0 : takeWhile (<x) (iterate (*2) 0) -- infinity+  | not (x == x)  = 0 : takeWhile (< 1000) numbers -- NaN+  | x > 0 && not (2*x+1>x) = 0 : takeWhile (<x) numbers -- infinity   | x < 0 = negate x:map negate (shrinkRealFrac (negate x))-  | otherwise =+  | otherwise = -- x is finite and >= 0     -- To ensure termination     filter (\y -> abs y < abs x) $       -- Try shrinking to an integer first@@ -1168,14 +1265,16 @@   where     num = numerator (toRational x)     denom = denominator (toRational x)+    numbers = iterate (*2) 1  -- | Shrink a real number, preferring numbers with shorter -- decimal representations. See also 'shrinkRealFrac'. shrinkDecimal :: RealFrac a => a -> [a] shrinkDecimal x-  | not (x == x)  = 0 : take 10 (iterate (*2) 0)        -- NaN-  | not (2*abs x+1>abs x) = 0 : takeWhile (<x) (iterate (*2) 0) -- infinity-  | otherwise =+  | not (x == x)  = 0 : takeWhile (< 1000) numbers -- NaN+  | not (2*abs x+1>abs x) = 0 : takeWhile (<x) numbers -- infinity+  | x < 0 = negate x:map negate (shrinkDecimal (negate x))+  | otherwise = -- x is finite and >= 0     -- e.g. shrink pi =     --   shrink 3 ++ map (/ 10) (shrink 31) ++     --   map (/ 100) (shrink 314) + ...,@@ -1187,6 +1286,9 @@       n <- m:shrink m,       let y = fromRational (fromInteger n / precision),       abs y < abs x ]+  where+    -- 1, 2, 3, ..., 10, 20, 30, ..., 100, 200, 300, etc.+    numbers = concat $ iterate (map (*10)) (map fromInteger [1..9])  -------------------------------------------------------------------------- -- ** CoArbitrary@@ -1447,6 +1549,17 @@ instance CoArbitrary Version where   coarbitrary (Version a b) = coarbitrary (a, b) +#if defined(MIN_VERSION_base)+#if MIN_VERSION_base(4,2,0)+instance CoArbitrary Newline where+  coarbitrary LF = variant 0+  coarbitrary CRLF = variant 1++instance CoArbitrary NewlineMode where+  coarbitrary (NewlineMode inNL outNL) = coarbitrary inNL . coarbitrary outNL+#endif+#endif+ -- ** Helpers for implementing coarbitrary  -- | A 'coarbitrary' implementation for integral numbers.@@ -1481,6 +1594,42 @@ -- | Generates an infinite list. infiniteList :: Arbitrary a => Gen [a] infiniteList = infiniteListOf arbitrary+++--------------------------------------------------------------------------+-- ** Rational helper++infixr 5 :<+data Stream a = !a :< Stream a++streamNth :: Int -> Stream a -> a+streamNth n (x :< xs) | n <= 0    = x+                      | otherwise = streamNth (n - 1) xs++-- We read into this stream only with ~size argument,+-- so it's ok to have it as CAF.+--+rationalUniverse :: Stream Rational+rationalUniverse = 0 :< 1 :< (-1) :< go leftSideStream+  where+    go (x :< xs) =+      let nx = -x+          rx = recip x+          nrx = -rx+      in nx `seq` rx `seq` nrx `seq` (x :< rx :< nx :< nrx :< go xs)++-- All the rational numbers on the left side of the Calkin-Wilf tree,+-- in breadth-first order.+leftSideStream :: Stream Rational+leftSideStream = (1 % 2) :< go leftSideStream+  where+    go (x :< xs) =+        lChild `seq` rChild `seq`+        (lChild :< rChild :< go xs)+      where+        nd = numerator x + denominator x+        lChild = numerator x % nd+        rChild = nd % denominator x  -------------------------------------------------------------------------- -- the end.
src/Test/QuickCheck/Exception.hs view
@@ -5,6 +5,9 @@  {-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE CPP #-}+#ifndef NO_SAFE_HASKELL+{-# LANGUAGE Safe #-}+#endif module Test.QuickCheck.Exception where  #if !defined(__GLASGOW_HASKELL__) || (__GLASGOW_HASKELL__ < 700)
src/Test/QuickCheck/Features.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE CPP #-}+#ifndef NO_SAFE_HASKELL+{-# LANGUAGE Safe #-}+#endif {-# OPTIONS_HADDOCK hide #-} module Test.QuickCheck.Features where @@ -9,7 +13,7 @@ import Test.QuickCheck.Text import qualified Data.Set as Set import Data.Set(Set)-import Data.List+import Data.List (intersperse) import Data.IORef import Data.Maybe 
src/Test/QuickCheck/Function.hs view
@@ -48,6 +48,7 @@   , functionIntegral   , functionRealFrac   , functionBoundedEnum+  , functionElements   , functionVoid   , functionMapWith   , functionEitherWith@@ -83,6 +84,15 @@ import Data.Functor.Identity import qualified Data.Monoid as Monoid +#if defined(MIN_VERSION_base)+#if MIN_VERSION_base(4,2,0)+import System.IO+  ( Newline(..)+  , NewlineMode(..)+  )+#endif+#endif+ #ifndef NO_FIXED import Data.Fixed #endif@@ -165,8 +175,12 @@ -- Use only for small types (i.e. not integers): creates -- the list @['minBound'..'maxBound']@! functionBoundedEnum :: (Eq a, Bounded a, Enum a) => (a->b) -> (a:->b)-functionBoundedEnum f = Table [(x,f x) | x <- [minBound..maxBound]]+functionBoundedEnum = functionElements [minBound..maxBound] +-- | Provides a 'Function' instance for small finite types.+functionElements :: Eq a => [a] ->  (a->b) -> (a:->b)+functionElements xs f = Table [(x,f x) | x <- xs]+ -- | Provides a 'Function' instance for types with 'RealFrac'. functionRealFrac :: RealFrac a => (a->b) -> (a:->b) functionRealFrac = functionMap toRational fromRational@@ -367,6 +381,25 @@ instance Function Word64 where   function = functionIntegral +#if defined(MIN_VERSION_base)+#if MIN_VERSION_base(4,2,0)+instance Function Newline where+  function = functionMap g h+    where+      g LF = False+      g CRLF = True++      h False = LF+      h True = CRLF++instance Function NewlineMode where+  function = functionMap g h+    where+      g (NewlineMode inNL outNL) = (inNL,outNL)+      h (inNL,outNL) = NewlineMode inNL outNL+#endif+#endif+ -- instances for Data.Monoid newtypes  instance Function a => Function (Monoid.Dual a) where@@ -525,6 +558,9 @@ pattern Fn :: (a -> b) -> Fun a b #endif pattern Fn f <- (applyFun -> f)+#if __GLASGOW_HASKELL__ >= 802+{-# COMPLETE Fn #-}+#endif  -- | A modifier for testing binary functions. --@@ -534,12 +570,18 @@ pattern Fn2 :: (a -> b -> c) -> Fun (a, b) c #endif pattern Fn2 f <- (applyFun2 -> f)+#if __GLASGOW_HASKELL__ >= 802+{-# COMPLETE Fn2 #-}+#endif  -- | 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)+#if __GLASGOW_HASKELL__ >= 802+{-# COMPLETE Fn3 #-}+#endif #endif  mkFun :: (a :-> b) -> b -> Fun a b
src/Test/QuickCheck/Gen.hs view
@@ -2,6 +2,9 @@ #ifndef NO_ST_MONAD {-# LANGUAGE Rank2Types #-} #endif+#ifndef NO_SAFE_HASKELL+{-# LANGUAGE Safe #-}+#endif -- | Test case generation. -- -- __Note__: the contents of this module (except for the definition of@@ -32,11 +35,11 @@   ( Applicative(..) )  import Test.QuickCheck.Random-import Data.List+import Data.List (sortBy) import Data.Ord import Data.Maybe #ifndef NO_SPLITMIX-import System.Random.SplitMix(bitmaskWithRejection64', SMGen, nextInteger)+import System.Random.SplitMix(bitmaskWithRejection64', nextInteger, nextDouble, nextFloat, SMGen) #endif import Data.Word import Data.Int@@ -238,6 +241,23 @@ sample g =   do cases <- sample' g      mapM_ print cases++--------------------------------------------------------------------------+-- ** Floating point++-- | Generate 'Double' in 0..1 range+genDouble :: Gen Double++-- | Generate 'Float' in 0..1 range+genFloat :: Gen Float++#ifndef NO_SPLITMIX+genDouble = MkGen $ \(QCGen g) _ -> fst (nextDouble g)+genFloat  = MkGen $ \(QCGen g) _ -> fst (nextFloat g)+#else+genDouble = choose (0,1)+genFloat  = choose (0,1)+#endif  -------------------------------------------------------------------------- -- ** Common generator combinators
src/Test/QuickCheck/Monadic.hs view
@@ -56,6 +56,7 @@   -- * Monadic specification combinators   , run   , assert+  , assertWith   , pre   , wp   , pick@@ -149,6 +150,28 @@ assert :: Monad m => Bool -> PropertyM m () assert True  = return () assert False = fail "Assertion failed"++-- | Like 'assert' but allows caller to specify an explicit message to show on failure.+--+-- __Example:__+--+-- @+-- do+--   assertWith True  "My first predicate."+--   assertWith False "My other predicate."+--   ...+-- @+--+-- @+-- Assertion failed (after 2 tests):+--     Passed: My first predicate+--     Failed: My other predicate+-- @+assertWith :: Monad m => Bool -> String -> PropertyM m ()+assertWith condition msg = do+    let prefix = if condition then "Passed: " else "Failed: "+    monitor $ counterexample $ prefix ++ msg+    assert condition  -- should think about strictness/exceptions here -- | Tests preconditions. Unlike 'assert' this does not cause the
src/Test/QuickCheck/Property.hs view
@@ -217,12 +217,12 @@   fmap f (MkRose x rs) = MkRose (f x) [ fmap f r | r <- rs ]  instance Applicative Rose where-  pure = return+  pure x = MkRose x []   -- f must be total   (<*>) = liftM2 ($)  instance Monad Rose where-  return x = MkRose x []+  return = pure   -- k must be total   m >>= k  = joinRose (fmap k m) @@ -778,7 +778,20 @@ -- -- Bad: @prop_foo a b c = ...; main = quickCheck (within 1000000 prop_foo)@ within :: Testable prop => Int -> prop -> Property-within n = mapRoseResult f+within n = onTimeout+   (failed { reason = "Timeout of " ++ show n ++ " microseconds exceeded." })+   n++-- | Discards the test case if it does not complete within the given+-- number of microseconds. This can be useful when testing algorithms+-- that have pathological cases where they run extremely slowly.+discardAfter :: Testable prop => Int -> prop -> Property+discardAfter n = onTimeout+   (rejected { reason = "Timeout of " ++ show n ++ " microseconds exceeded." })+   n++onTimeout :: Testable prop => Result -> Int -> prop -> Property+onTimeout timeoutResult n = mapRoseResult f   where     f rose = ioRose $ do       let m `orError` x = fmap (fromMaybe x) m@@ -787,11 +800,11 @@       res' <- timeout n (protectResult (return res)) `orError`         timeoutResult       return (MkRose res' (map f roses))--    timeoutResult = failed { reason = "Timeout of " ++ show n ++ " microseconds exceeded." } #ifdef NO_TIMEOUT     timeout _ = fmap Just #endif++  -- | Explicit universal quantification: uses an explicitly given -- test case generator.
src/Test/QuickCheck/State.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE CPP #-}+#ifndef NO_SAFE_HASKELL+{-# LANGUAGE Safe #-}+#endif {-# OPTIONS_HADDOCK hide #-} -- | QuickCheck's internal state. Internal QuickCheck module. module Test.QuickCheck.State where
src/Test/QuickCheck/Text.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE CPP #-}+#ifndef NO_SAFE_HASKELL+{-# LANGUAGE Safe #-}+#endif {-# OPTIONS_HADDOCK hide #-} -- | Terminal control and text helper functions. Internal QuickCheck module. module Test.QuickCheck.Text@@ -43,7 +47,7 @@   )  import Data.IORef-import Data.List+import Data.List (intersperse, transpose) import Text.Printf import Test.QuickCheck.Exception @@ -222,11 +226,11 @@ putLine tm s = putPart tm (s ++ "\n")  putTemp tm@(MkTerminal _ tmp _ err) s =-  do n <- readIORef tmp-     err $-       replicate n ' ' ++ replicate n '\b' ++-       s ++ [ '\b' | _ <- s ]-     writeIORef tmp (length s)+  do oldLen <- readIORef tmp+     let newLen = length s+         maxLen = max newLen oldLen+     err $ s ++ replicate (maxLen - newLen) ' ' ++ replicate maxLen '\b'+     writeIORef tmp newLen  -------------------------------------------------------------------------- -- the end.
tests/Generators.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE TemplateHaskell, GeneralizedNewtypeDeriving, Rank2Types, NoMonomorphismRestriction #-} import Test.QuickCheck import Test.QuickCheck.Gen.Unsafe-import Data.List+import Data.List (inits, sort, nub) import Data.Int import Data.Word import Data.Version@@ -203,6 +203,18 @@  prop_B1 :: B1 -> Property prop_B1 (B1 n) = expectFailure $ n === n + 1++-- Double properties:++-- We occasionaly generate duplicates.+prop_double_duplicate_list :: [Double] -> Property+prop_double_duplicate_list xs = expectFailure $ nub xs === xs where+  sorted = sort xs++-- And enough numbers to show basic IEEE pit falls.+prop_double_assoc :: Double -> Double -> Double -> Property+prop_double_assoc x y z = expectFailure $ x + (y + z) === (x + y) + z+  return [] main = do True <- $forAllProperties (quickCheckWithResult stdArgs { maxShrinks = 10000 }); return ()
tests/Split.hs view
@@ -1,6 +1,6 @@ import Test.QuickCheck import Test.QuickCheck.Random-import Data.List+import Data.List (group, isPrefixOf, sort)  -- This type allows us to run integerVariant and get a list of bits out. newtype Splits = Splits { unSplits :: [Bool] } deriving (Eq, Ord, Show)