The following examples assume you have the following namespace alias:
(require '[clojure.test.check.generators :as gen])
For the most part, these are in order of simplest to most complex. They also skip over some of the built-in, basic generators.
(def five-through-nine (gen/choose 5 9))
(gen/sample five-through-nine)
;; => (6 5 9 5 7 7 6 9 7 9)
(def languages (gen/elements ["clojure" "haskell" "erlang" "scala" "python"]))
(gen/sample languages)
;; => ("clojure" "scala" "clojure" "haskell" "clojure" "erlang" "erlang"
;; => "erlang" "haskell" "python")
(def int-or-nil (gen/one-of [gen/int (gen/return nil)]))
(gen/sample int-or-nil)
;; => (nil 0 -2 nil nil 3 nil nil 4 2)
(def mostly-ints (gen/frequency [[9 gen/int] [1 (gen/return nil)]]))
(gen/sample mostly-ints)
;; => (0 -1 nil 0 -2 0 6 -6 8 7)
(def even-and-positive (gen/fmap #(* 2 %) gen/pos-int))
(gen/sample even-and-positive 20)
;; => (0 0 2 0 8 6 4 12 4 18 10 0 8 2 16 16 6 4 10 4)
;; generate exponents with gen/s-pos-int (strictly positive integers),
;; and then apply the function to them
(def powers-of-two (gen/fmap #(int (Math/pow 2 %)) gen/s-pos-int))
(gen/sample powers-of-two)
;; => (2 2 8 16 16 64 16 2 4 4)
;; apply the sort function to each generated vector
(def sorted-vec (gen/fmap sort (gen/vector gen/int)))
(gen/sample sorted-vec)
;; => (() (-1) (-2 -2) (-1 2 3) (-1 2 4) (-3 2 3 3 4) (1)
;; => (-4 0 1 3 4 6) (-5 -4 -1 0 2 8) (1))
(def int-and-boolean (gen/tuple gen/int gen/boolean))
(gen/sample int-and-boolean)
;; => ([0 false] [0 true] [0 true] [3 true] [-3 false]
;; => [0 true] [4 true] [0 true] [-2 true] [-9 false])
(def anything-but-five (gen/such-that #(not= % 5) gen/int))
(gen/sample anything-but-five)
;; => (0 0 -2 1 -3 1 -4 7 -1 6)
It's important to note that such-that
should only be used for predicates that
are very likely to match. For example, you should not use such-that
to
filter out random vectors that are not sorted, as is this is exceedingly
unlikely to happen randomly. If you want sorted vectors, just sort them using
gen/fmap
and sort
.
(def vector-and-elem (gen/bind (gen/not-empty (gen/vector gen/int))
#(gen/tuple (gen/return %) (gen/elements %))))
(gen/sample vector-and-elem)
;; =>([[-1] -1]
;; => [[0] 0]
;; => [[-1 -1] -1]
;; => [[2 0 -2] 2]
;; => [[0 1 1] 0]
;; => [[-2 -3 -1 1] -1]
;; => [[-1 2 -5] -5]
;; => [[5 -7 -3 7] 5]
;; => [[-1 2 2] 2]
;; => [[-8 7 -3 -2 -6] -3])
gen/bind
and gen/fmap
are similar: they're both binary functions that take
a generator and a function as arguments (though their argument order is
reversed). They differ in what the provided function's return value should be.
The function provided to gen/fmap
should return a value. We saw that
earlier when we used gen/fmap
to sort a vector. sort
returns a normal
value. The function provided to gen/bind
should return a generator. Notice
how above we're providing a function that returns a gen/tuple
generator? The
decision of which to use depends on whether you want to simply transform the
value of a generator (sort it, multiply it by two, etc.), or create an
entirely new generator out of it.
Go back to the intro.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close