Search code examples
testingclojuregeneratorquickcheck

How to generate random elements depending on previous elements using Quickcheck?


I'm using QuickCheck to do generative testing in Clojure.

However I don't know it well and often I end up doing convoluted things. One thing that I need to do quite often is something like that:

  • generate a first prime number from a list of prime-numbers (so far so good)
  • generate a second prime number which is smaller than the first one
  • generate a third prime number which is smaller than the first one

However I have no idea as to how to do that cleanly using QuickCheck.

Here's an even simpler, silly, example which doesn't work:

(prop/for-all [a (gen/choose 1 10)
               b (gen/such-that #(= a %) (gen/choose 1 10))]
                (= a b))

It doesn't work because a cannot be resolved (prop/for-all isn't like a let statement).

So how can I generate the three primes, with the condition that the two latter ones are inferior to the first one?


Solution

  • In test.check we can use gen/bind as the bind operator in the generator monad, so we can use this to make generators which depend on other generators.

    For example, to generate pairs [a b] where we must have (>= a b) we can use this generator:

    (def pair-gen (gen/bind (gen/choose 1 10)
                            (fn [a]
                              (gen/bind (gen/choose 1 a)
                                        (fn [b]
                                          (gen/return [a b]))))))
    

    To satisfy ourselves:

    (c/quick-check 10000
                   (prop/for-all [[a b] pair-gen]
                     (>= a b)))
    

    gen/bind takes a generator g and a function f. It generates a value from g, let's call it x. gen/bind then returns the value of (f x), which must be a new generator. gen/return is a generator which only generates its argument (so above I used it to return the pairs).