Welcome! Please see the About page for a little more info on how this works.

0 votes
in Spec by
Generator override doesn't work as expected on multi-specs.
Code below illustrates the problem.

{code:none}
(s/def ::obj-type #{:a :b})

(s/def ::base-obj (s/keys :req [::obj-type]))

(defmulti obj-type ::obj-type)
(defmethod obj-type :a [_]
  ::base-obj)
(defmethod obj-type :b [_]
  ::base-obj)

(s/def ::obj (s/multi-spec obj-type ::obj-type))


{code:none}
(gen/sample (s/gen ::obj {::obj-type #(gen/return :a)}))

In the example above the dispatch-fn *::obj-type* for the multimethod is given a generator override.
It is expected to return only colls of *{::obj-type :a}*
Actually it will also return *{::obj-type :b}*.  
That is a generator cannot be used to constrain the set of dispatch-keys to sample from.

h2. Current method:
In the case of a multimethod a generator is constructed for every possible dispatch value.
One is then chosen randomly without paying any attention to overrides for the dispatch-fn(key).

h2. Patched method:
Commit available [here|https://github.com/bonega/spec.alpha/commit/9cb42478b52eac275d496ec29669e2bf4b3e8e1f]
Patched version constructs generators for dispatch values exactly as original.
After that a check is made to see if there exists an override for the dispatch-fn.
If so a gen/bind is done using the override generator.
The bind function generates a value from the override generator.
That value is then used to lookup and return the correct multimethod generator.

[Test case|https://pastebin.com/62ZT5Zfc]

6 Answers

0 votes
by

Comment made by: bonega

Patch provided for issue.

0 votes
by

Comment made by: alexmiller

Can you move the code for the problem into the description and explain the problem and the change?

0 votes
by
_Comment made by: andreas@aldb.se_

I can't figure out how to edit the description...

description:
In the case of a multimethod a generator is constructed for every possible dispatch value.
One is then choosen randomly without paying any attention to overrides for the dispatch-fn(key).

commit: https://github.com/bonega/spec.alpha/commit/9cb42478b52eac275d496ec29669e2bf4b3e8e1f
My patch hopefully fixes that by checking if there exists an override for the dispatch-fn.
If so a gen/bind is done to the override generator and the result is used to lookup the correct multimethod generator.

Test case: https://pastebin.com/62ZT5Zfc
The test is expected to pass.
Basically I want to generate ::obj with an overriding generator like `(gen/generate (s/gen ::obj {::obj-type #(gen/return :a)}))`.
Expected result should always be `{::obj-type :a}`.
Previously :b was possible as output even though an override was specified.
0 votes
by

Comment made by: alexmiller

I've given you edit right for the ticket so you can make the updates...

0 votes
by

Comment made by: andreas@aldb.se

I have updated the description.
Let me know if anything is unclear.

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-2311 (reported by andreas@aldb.se)
...