gfredericks / test.chuck

A utility library for test.check
Eclipse Public License 1.0
215 stars 26 forks source link

Add sub-map function. #10

Closed firesofmay closed 9 years ago

firesofmay commented 9 years ago

Useful in generating varying sized map instead of always, generating fixed map.

gfredericks commented 9 years ago

I'm a bit confused as to the stated use case here; doesn't test.check's gen/map already generate variable sized maps?

I can imagine it being useful in other situations though, but I think I'd prefer a function that takes a concrete map rather than a map generator, unless there's a compelling reason to have it the way it is?

I think of it as parallel to the gen'/subsequence generator which takes a concrete collection, not a generator of a collection.

firesofmay commented 9 years ago

@gfredericks
Thanks for your feedback. I'll try to explain my usecase with an example. I need to test an endpoint which takes a user-data. User-data is a map of 4 keys and each key has a certain kind of value, for example :level is a natural number but username is a non-empty string etc.

For the first time device sends all data as create-user step. After that the user can update some/all data at any time.

Here's an example user generator:

(def user-gen
  (gen/hash-map
         :level gen/nat
         :name (gen/such-that not-empty gen/string-alphanumeric)
         :user (gen/elements ["paid" "free" "premium"])
         :device-type (gen/elements ["ios" "android" "windows"])))

And here's our create request for the first time user:

(first (gen/sample user-gen))
=> {:device-type "android", :user "free", :name "gR1", :level 0}

And now we would like to simulate update request:

(first (gen/sample (sub-map user-gen)))
=> {:user "free", :device-type "ios"}

Note that in this same data can be sent multiple times, which is okay in my case (in some cases that may not be acceptable but I am not covering it)

I don't think gen/map allows me to do the same thing, does it? Can I say what key can have what kinds of values?

And the reason why I thought of sub-map taking a generator and not a map, is I thought of it simply taking the generator and generating the subset of that map directly.

And if someone has only a map, they can simply pass it as (gen/return my-map).

If you think there is a better way to do this, or passing a concrete map makes more sense let me know i'll make the appropriate change.

Will update the test accordingly as well.

gfredericks commented 9 years ago

I think the use case makes sense. It occurred to me that this could also be done as a variant of gen'/map->hash-map (or gen/hash-map), where the argument is keys and generators for values. The main advantage there is that you avoid generating/shrinking the values for the keys you don't use.

Not sure I mind either way between that and a function that takes a concrete map, but I definitely like either better than a function that takes a generator. I think higher-order-generators are worth avoiding when possible.

Thanks for the addition!

firesofmay commented 9 years ago

I've pushed the changes. Let me know if it's okay. Thanks.

firesofmay commented 9 years ago

Made the changes. (I am not sure if you get notified for new patch set hence adding a comment here)

gfredericks commented 9 years ago

Looks great, thanks again!

gfredericks commented 9 years ago

Released in 0.1.21