Hey Mayank! What you've done here might appear to work, but it will get you into trouble when test.check starts to shrink your inputs. When test.check runs your generators it relies you you using it as your only source of randomness, and so your use of `rand-int` will cause some problems.
The trick is to use the `bind` function to make a generator which depends on the value of another generator (in this case, to capture the generated map so you can call rand-subset with the correct set of keys): (defn rand-subset "Given a collection coll it'll generate a random subset." [coll] (gen/fmap (fn [i] (combo/nth-subset coll i)) (gen/choose 0 (dec (combo/count-subsets coll))))) (defn gen-varying-map "Given a generator which generates a map, it'll randomly select keys from it thus making it varying-sized map. Note: It can return empty maps as well." [map-gen] (gen/bind map-gen (fn [map] (gen/fmap (fn [keyseq] (select-keys map keyseq)) (rand-subset (keys map)))))) (gen/sample (gen-varying-map (gen/hash-map "user" (gen/such-that not-empty gen/string-alpha-numeric) "level" gen/nat "timezone" gen/pos-int))) => ({"user" "e", "level" 0} {"level" 1} {"user" "M1"} {"timezone" 2} {"user" "2", "level" 2, "timezone" 0} {"timezone" 3} {"user" "W", "level" 5, "timezone" 0} {"timezone" 5} {} {}) This output appears the same as yours, but it will produce predictable shrink trees, and thus will shrink more effectively. Carlo On 26 July 2015 at 07:10, Mayank Jain <firesof...@gmail.com> wrote: > Hi, > > I would like to generate variable sized map using test.check i.e. > given any generator which generates a map, it should randomly select-keys > from it. > > Here's what I've come up with so far: > > >> (ns proj.util > (:require [clojure.test.check.generators :as gen] > [clojure.math.combinatorics :as combo])) > > (defn rand-subset > "Given a collection coll, > it'll generate a random subset." > [coll] > (->> coll > combo/count-subsets > rand-int > (combo/nth-subset coll))) > > (defn gen-varying-map > "Given a generator which generates a map, > it'll randomly select keys from it thus making it > varying-sized map. > Note: It can return empty maps as well." > [map-gen] > (gen/fmap (fn [m] > (let [ks (rand-subset (keys m))] > (select-keys m ks))) > map-gen)) > > Here's an example output, > (gen/sample (gen-varying-map (gen/hash-map > "user" (gen/such-that not-empty > > gen/string-alphanumeric) > "level" gen/nat > "timezone" gen/pos-int))) > => > ({"user" "1"} > {"user" "l8", "level" 0, "timezone" 1} > {"level" 1} > {"user" "oA", "timezone" 0} > {"level" 2, "timezone" 1} > {"level" 5} > {"user" "8aP", "level" 5, "timezone" 6} > {"user" "035rqi", "level" 7} > {"timezone" 4} > {"timezone" 2}) > > My question is, is this the right way? Or is there a better way to do it? > > Thanks :) > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.