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