Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #50 from mourjo/master
Add bounded recursive generator.
  • Loading branch information
gfredericks committed Apr 18, 2018
2 parents 55864d2 + 2840191 commit 71a7775
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/com/gfredericks/test/chuck/generators.cljc
Expand Up @@ -321,3 +321,68 @@
(gen/tuple (gen/elements offset-fns)
(gen/large-integer* {:min offset-min
:max offset-max})))))

(defn- bounded-recursive-helper
[container-gen-fn scalar-gen scalar-size max-breadth curr-height]
(if (neg? curr-height)
(gen/resize scalar-size scalar-gen)
(gen/resize max-breadth
(container-gen-fn
(bounded-recursive-helper container-gen-fn
scalar-gen
scalar-size
max-breadth
(dec curr-height))))))


(defn bounded-recursive-gen
"Same as gen/recursive-gen but allows a bound on both breadth and height.
Height = Number of levels of nesting. Eg:
level of nesting = 0: [15 -4]
level of nesting = 1: [[5 1 -3 -10 -18] [17]]
Breadth = Number of elements in a level (number of elements in each vector,
in the above eg).
Example 1: Breadth=2, Height=10
This means that no vector will contain more than 2 elements.
and there will be at most 10 levels of nested vectors.
(last (gen/sample (bounded-recursive-gen gen/vector
gen/int
2 10) 20))
=> [[[[[] []]
[[[[[[[[-11 1] []]]] [[[[3 10] []]] []]] []] []]
[[[[[[[16 10] []]] []] []] [[] []]] [[[[]]] []]]]]
[[[[]] []]]]]
Example 2: Breadth=10, Height=2 (Opposite of ex 1)
This means that no vector will contain more than 10 elements.
and there will be atmost 2 levels of nested vectors.
(last (gen/sample (bounded-recursive-gen gen/vector
gen/int
10 2) 20))
=> [[[11 5 3 8 15 -19 -12 -2] [7 3 -12 -11 0 -10 19 -19 -1] [16 -15 19 1]]
[[6 -18 -14 -10 -7 -5 5]
[7 10 -5]
[-19 -5 3 -15 15 17 -18]
[16 -15 10 -7]
[14 3 5 9 -2 8 -7 11]
[-5 17 -19 5 -9 7]
[11 -1 -4 5]
[-2 13 -16 -4]
[-3 -12 -1]
[4 15]]]
There are atmost 2 nested levels, and no vector contains more than 10
elements."
[container-gen-fn scalar-gen max-breadth max-height]
(assert (gen/generator? scalar-gen)
"Second arg to recursive-gen must be a generator")
(gen/sized
(fn [size]
(gen/bind
(gen/choose 1 5)
(fn [decay-factor]
(bounded-recursive-helper container-gen-fn
scalar-gen
size
(min max-breadth (Math/pow size (/ 1 decay-factor)))
(min max-height (Math/pow size (/ 1 (inc decay-factor))))))))))
19 changes: 19 additions & 0 deletions test/com/gfredericks/test/chuck/generators_test.cljc
Expand Up @@ -127,3 +127,22 @@
(ct/within? (ct/date-time 2000)
(ct/date-time 2009)
dt)))

(defn valid-bounded-rec-struct?
[breadth height coll]
(if (not-any? coll? coll)
(and (<= (count coll) breadth)
(or (zero? height) (pos? height)))
(and (<= (count coll) breadth)
(every? identity (map (partial valid-bounded-rec-struct?
breadth
(dec height))
coll)))))

(defspec bounded-recursive-gen-spec 100
(prop/for-all
[bounded-rec (gen'/bounded-recursive-gen gen/vector
gen/int
10
5)]
(valid-bounded-rec-struct? 10 5 bounded-rec)))

0 comments on commit 71a7775

Please sign in to comment.