1{-# LANGUAGE CPP #-} 2#ifndef NO_ST_MONAD 3{-# LANGUAGE Rank2Types #-} 4#endif 5-- | Test case generation. 6-- 7-- __Note__: the contents of this module (except for the definition of 8-- 'Gen') are re-exported by "Test.QuickCheck". You probably do not 9-- need to import it directly. 10module Test.QuickCheck.Gen where 11 12-------------------------------------------------------------------------- 13-- imports 14 15import System.Random 16 ( Random 17 , random 18 , randomR 19 , split 20 ) 21 22import Control.Monad 23 ( ap 24 , replicateM 25 , filterM 26 ) 27 28import Control.Monad.Fix 29 ( MonadFix(..) ) 30 31import Control.Applicative 32 ( Applicative(..) ) 33 34import Test.QuickCheck.Random 35import Data.List 36import Data.Ord 37import Data.Maybe 38#ifndef NO_SPLITMIX 39import System.Random.SplitMix(bitmaskWithRejection64', SMGen, nextInteger) 40#endif 41import Data.Word 42import Data.Int 43import Data.Bits 44import Control.Applicative 45 46-------------------------------------------------------------------------- 47-- ** Generator type 48 49-- | A generator for values of type @a@. 50-- 51-- The third-party packages 52-- <http://hackage.haskell.org/package/QuickCheck-GenT QuickCheck-GenT> 53-- and 54-- <http://hackage.haskell.org/package/quickcheck-transformer quickcheck-transformer> 55-- provide monad transformer versions of @Gen@. 56newtype Gen a = MkGen{ 57 unGen :: QCGen -> Int -> a -- ^ Run the generator on a particular seed. 58 -- If you just want to get a random value out, consider using 'generate'. 59 } 60 61instance Functor Gen where 62 fmap f (MkGen h) = 63 MkGen (\r n -> f (h r n)) 64 65instance Applicative Gen where 66 pure x = 67 MkGen (\_ _ -> x) 68 (<*>) = ap 69 70#ifndef NO_EXTRA_METHODS_IN_APPLICATIVE 71 -- We don't need to split the seed for these. 72 _ *> m = m 73 m <* _ = m 74#endif 75 76instance Monad Gen where 77 return = pure 78 79 MkGen m >>= k = 80 MkGen (\r n -> 81 case split r of 82 (r1, r2) -> 83 let MkGen m' = k (m r1 n) 84 in m' r2 n 85 ) 86 87 (>>) = (*>) 88 89instance MonadFix Gen where 90 mfix f = 91 MkGen $ \r n -> 92 let a = unGen (f a) r n 93 in a 94 95-------------------------------------------------------------------------- 96-- ** Primitive generator combinators 97 98-- | Modifies a generator using an integer seed. 99variant :: Integral n => n -> Gen a -> Gen a 100variant k (MkGen g) = MkGen (\r n -> g (integerVariant (toInteger k) $! r) n) 101 102-- | Used to construct generators that depend on the size parameter. 103-- 104-- For example, 'listOf', which uses the size parameter as an upper bound on 105-- length of lists it generates, can be defined like this: 106-- 107-- > listOf :: Gen a -> Gen [a] 108-- > listOf gen = sized $ \n -> 109-- > do k <- choose (0,n) 110-- > vectorOf k gen 111-- 112-- You can also do this using 'getSize'. 113sized :: (Int -> Gen a) -> Gen a 114sized f = MkGen (\r n -> let MkGen m = f n in m r n) 115 116-- | Returns the size parameter. Used to construct generators that depend on 117-- the size parameter. 118-- 119-- For example, 'listOf', which uses the size parameter as an upper bound on 120-- length of lists it generates, can be defined like this: 121-- 122-- > listOf :: Gen a -> Gen [a] 123-- > listOf gen = do 124-- > n <- getSize 125-- > k <- choose (0,n) 126-- > vectorOf k gen 127-- 128-- You can also do this using 'sized'. 129getSize :: Gen Int 130getSize = sized pure 131 132-- | Overrides the size parameter. Returns a generator which uses 133-- the given size instead of the runtime-size parameter. 134resize :: Int -> Gen a -> Gen a 135resize n _ | n < 0 = error "Test.QuickCheck.resize: negative size" 136resize n (MkGen g) = MkGen (\r _ -> g r n) 137 138-- | Adjust the size parameter, by transforming it with the given 139-- function. 140scale :: (Int -> Int) -> Gen a -> Gen a 141scale f g = sized (\n -> resize (f n) g) 142 143-- | Generates a random element in the given inclusive range. 144-- For integral and enumerated types, the specialised variants of 145-- 'choose' below run much quicker. 146choose :: Random a => (a,a) -> Gen a 147choose rng = MkGen (\r _ -> let (x,_) = randomR rng r in x) 148 149-- | Generates a random element over the natural range of `a`. 150chooseAny :: Random a => Gen a 151chooseAny = MkGen (\r _ -> let (x,_) = random r in x) 152 153-- | A fast implementation of 'choose' for enumerated types. 154chooseEnum :: Enum a => (a, a) -> Gen a 155chooseEnum (lo, hi) = 156 fmap toEnum (chooseInt (fromEnum lo, fromEnum hi)) 157 158-- | A fast implementation of 'choose' for 'Int'. 159chooseInt :: (Int, Int) -> Gen Int 160chooseInt = chooseBoundedIntegral 161 162-- Note about INLINEABLE: we specialise chooseBoundedIntegral 163-- for each concrete type, so that all the bounds checks get 164-- simplified away. 165{-# INLINEABLE chooseBoundedIntegral #-} 166-- | A fast implementation of 'choose' for bounded integral types. 167chooseBoundedIntegral :: (Bounded a, Integral a) => (a, a) -> Gen a 168chooseBoundedIntegral (lo, hi) 169#ifndef NO_SPLITMIX 170 | toInteger mn >= toInteger (minBound :: Int64) && 171 toInteger mx <= toInteger (maxBound :: Int64) = 172 fmap fromIntegral (chooseInt64 (fromIntegral lo, fromIntegral hi)) 173 | toInteger mn >= toInteger (minBound :: Word64) && 174 toInteger mx <= toInteger (maxBound :: Word64) = 175 fmap fromIntegral (chooseWord64 (fromIntegral lo, fromIntegral hi)) 176#endif 177 | otherwise = 178 fmap fromInteger (chooseInteger (toInteger lo, toInteger hi)) 179#ifndef NO_SPLITMIX 180 where 181 mn = minBound `asTypeOf` lo 182 mx = maxBound `asTypeOf` hi 183#endif 184 185-- | A fast implementation of 'choose' for 'Integer'. 186chooseInteger :: (Integer, Integer) -> Gen Integer 187#ifdef NO_SPLITMIX 188chooseInteger = choose 189#else 190chooseInteger (lo, hi) 191 | lo >= toInteger (minBound :: Int64) && lo <= toInteger (maxBound :: Int64) && 192 hi >= toInteger (minBound :: Int64) && hi <= toInteger (maxBound :: Int64) = 193 fmap toInteger (chooseInt64 (fromInteger lo, fromInteger hi)) 194 | lo >= toInteger (minBound :: Word64) && lo <= toInteger (maxBound :: Word64) && 195 hi >= toInteger (minBound :: Word64) && hi <= toInteger (maxBound :: Word64) = 196 fmap toInteger (chooseWord64 (fromInteger lo, fromInteger hi)) 197 | otherwise = MkGen $ \(QCGen g) _ -> fst (nextInteger lo hi g) 198 199chooseWord64 :: (Word64, Word64) -> Gen Word64 200chooseWord64 (lo, hi) 201 | lo <= hi = chooseWord64' (lo, hi) 202 | otherwise = chooseWord64' (hi, lo) 203 where 204 chooseWord64' :: (Word64, Word64) -> Gen Word64 205 chooseWord64' (lo, hi) = 206 fmap (+ lo) (chooseUpTo (hi - lo)) 207 208chooseInt64 :: (Int64, Int64) -> Gen Int64 209chooseInt64 (lo, hi) 210 | lo <= hi = chooseInt64' (lo, hi) 211 | otherwise = chooseInt64' (hi, lo) 212 where 213 chooseInt64' :: (Int64, Int64) -> Gen Int64 214 chooseInt64' (lo, hi) = do 215 w <- chooseUpTo (fromIntegral hi - fromIntegral lo) 216 return (fromIntegral (w + fromIntegral lo)) 217 218chooseUpTo :: Word64 -> Gen Word64 219chooseUpTo n = 220 MkGen $ \(QCGen g) _ -> 221 fst (bitmaskWithRejection64' n g) 222#endif 223 224-- | Run a generator. The size passed to the generator is always 30; 225-- if you want another size then you should explicitly use 'resize'. 226generate :: Gen a -> IO a 227generate (MkGen g) = 228 do r <- newQCGen 229 return (g r 30) 230 231-- | Generates some example values. 232sample' :: Gen a -> IO [a] 233sample' g = 234 generate (sequence [ resize n g | n <- [0,2..20] ]) 235 236-- | Generates some example values and prints them to 'stdout'. 237sample :: Show a => Gen a -> IO () 238sample g = 239 do cases <- sample' g 240 mapM_ print cases 241 242-------------------------------------------------------------------------- 243-- ** Common generator combinators 244 245-- | Generates a value that satisfies a predicate. 246suchThat :: Gen a -> (a -> Bool) -> Gen a 247gen `suchThat` p = 248 do mx <- gen `suchThatMaybe` p 249 case mx of 250 Just x -> return x 251 Nothing -> sized (\n -> resize (n+1) (gen `suchThat` p)) 252 253-- | Generates a value for which the given function returns a 'Just', and then 254-- applies the function. 255suchThatMap :: Gen a -> (a -> Maybe b) -> Gen b 256gen `suchThatMap` f = 257 fmap fromJust $ fmap f gen `suchThat` isJust 258 259-- | Tries to generate a value that satisfies a predicate. 260-- If it fails to do so after enough attempts, returns @Nothing@. 261suchThatMaybe :: Gen a -> (a -> Bool) -> Gen (Maybe a) 262gen `suchThatMaybe` p = sized (\n -> try n (2*n)) 263 where 264 try m n 265 | m > n = return Nothing 266 | otherwise = do 267 x <- resize m gen 268 if p x then return (Just x) else try (m+1) n 269 270-- | Randomly uses one of the given generators. The input list 271-- must be non-empty. 272oneof :: [Gen a] -> Gen a 273oneof [] = error "QuickCheck.oneof used with empty list" 274oneof gs = chooseInt (0,length gs - 1) >>= (gs !!) 275 276-- | Chooses one of the given generators, with a weighted random distribution. 277-- The input list must be non-empty. 278frequency :: [(Int, Gen a)] -> Gen a 279frequency [] = error "QuickCheck.frequency used with empty list" 280frequency xs 281 | any (< 0) (map fst xs) = 282 error "QuickCheck.frequency: negative weight" 283 | all (== 0) (map fst xs) = 284 error "QuickCheck.frequency: all weights were zero" 285frequency xs0 = chooseInt (1, tot) >>= (`pick` xs0) 286 where 287 tot = sum (map fst xs0) 288 289 pick n ((k,x):xs) 290 | n <= k = x 291 | otherwise = pick (n-k) xs 292 pick _ _ = error "QuickCheck.pick used with empty list" 293 294-- | Generates one of the given values. The input list must be non-empty. 295elements :: [a] -> Gen a 296elements [] = error "QuickCheck.elements used with empty list" 297elements xs = (xs !!) `fmap` chooseInt (0, length xs - 1) 298 299-- | Generates a random subsequence of the given list. 300sublistOf :: [a] -> Gen [a] 301sublistOf xs = filterM (\_ -> chooseEnum (False, True)) xs 302 303-- | Generates a random permutation of the given list. 304shuffle :: [a] -> Gen [a] 305shuffle xs = do 306 ns <- vectorOf (length xs) (chooseInt (minBound :: Int, maxBound)) 307 return (map snd (sortBy (comparing fst) (zip ns xs))) 308 309-- | Takes a list of elements of increasing size, and chooses 310-- among an initial segment of the list. The size of this initial 311-- segment increases with the size parameter. 312-- The input list must be non-empty. 313growingElements :: [a] -> Gen a 314growingElements [] = error "QuickCheck.growingElements used with empty list" 315growingElements xs = sized $ \n -> elements (take (1 `max` size n) xs) 316 where 317 k = length xs 318 mx = 100 319 log' = round . log . toDouble 320 size n = (log' n + 1) * k `div` log' mx 321 toDouble = fromIntegral :: Int -> Double 322 323{- WAS: 324growingElements xs = sized $ \n -> elements (take (1 `max` (n * k `div` 100)) xs) 325 where 326 k = length xs 327-} 328 329-- | Generates a list of random length. The maximum length depends on the 330-- size parameter. 331listOf :: Gen a -> Gen [a] 332listOf gen = sized $ \n -> 333 do k <- chooseInt (0,n) 334 vectorOf k gen 335 336-- | Generates a non-empty list of random length. The maximum length 337-- depends on the size parameter. 338listOf1 :: Gen a -> Gen [a] 339listOf1 gen = sized $ \n -> 340 do k <- chooseInt (1,1 `max` n) 341 vectorOf k gen 342 343-- | Generates a list of the given length. 344vectorOf :: Int -> Gen a -> Gen [a] 345vectorOf = replicateM 346 347-- | Generates an infinite list. 348infiniteListOf :: Gen a -> Gen [a] 349infiniteListOf gen = sequence (repeat gen) 350 351-------------------------------------------------------------------------- 352-- the end. 353