How do I generate random keys for test.check?

I'm using test.check to generate a hashmap. I want one key to be a random numeric keywords This is what I tried

(gen/hash-map
  :16 gen/nat
  :1041 gen/string
  (keyword (str gen/nat)) gen/string)

This works fine for the first two keys, but gen/sample returns a function for the last key instead of a value. An output from gen/sample {:16 1, :1041 "»", :clojure.test.check.generators.Generator@3daf97b7 "u"}


Here is an example using gen/bind

user> (require '[clojure.test.check.generators :as gen])
nil
user> (gen/sample (gen/bind gen/nat
                            #(gen/hash-map
                              :16 gen/nat
                              :1041 gen/string
                              (keyword (str %)) gen/string)))
({:16 0, :1041 "", :0 ""}
 {:16 1, :1041 "—", :1 "Õ"}
 {:16 1, :1041 "~", :2 "{"}
 {:16 0, :1041 "", :0 ""}
 {:16 1, :1041 "}", :2 "š¤#"}
 {:16 4, :1041 "", :4 "ÂêÃ"}
 {:16 6, :1041 "¯¾ùPêà", :1 "xaÝ$"}
 {:16 1, :1041 "", :4 "ž"}
 {:16 7, :1041 "", :3 "Ù¡"}
 {:16 3, :1041 "‚«¤s", :5 "ƶoÒA“"})
user> 

And here is one using gen/fmap

user> (gen/sample (gen/fmap (fn [[m n s]] (assoc m (keyword (str n)) s))
                            (gen/tuple (gen/hash-map
                                        :16 gen/nat
                                        :1041 gen/string)
                                       gen/nat gen/string)))
({:16 0, :1041 "", :0 ""}
 {:16 0, :1041 "", :1 "Ô"}
 {:16 2, :1041 "`", :0 "V²"}
 {:16 1, :1041 "X", :2 "b"}
 {:16 3, :1041 "JÓ", :2 ""}
 {:16 2, :1041 "", :2 ""}
 {:16 2, :1041 "", :2 "×kîj"}
 {:16 0, :1041 "", :0 ""}
 {:16 5, :1041 "ÎÖ", :0 ":üv-`"}
 {:16 8, :1041 "¬KéÎêo\r", :4 "ÆÌ"})
user> 

In such cases, you have to use either gen/fmap or gen/bind. Both of them allow you to manipulate the output of a generator. If you want to return a generator, then use gen/bind. If you want to return a value, then use gen/fmap. Both gen/fmap and gen/bind take two arguments, one of which is a generator, and the other argument is a function that takes the value generated by the first as its input and returns either a generator (for gen/bind) or a value (for gen/fmap).


You'll need to use clojure.test.check.generators/fmap to apply your functions (str, keyword) to your generator.