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

0 votes
ago in Spec by
(gen/let [x (s/gen (s/keys :opt [::a]))
          y (s/gen (s/keys :opt [::a]) {::a ???})])

If x generates without ::a, I'd also like to generate y without ::a. I can't presently see a way to express that.

1 Answer

0 votes
ago by
edited ago by

Given that you're using gen/let, why not just this?

(gen/let [x (s/gen (s/keys :opt [::a]))
          y (s/gen (s/keys :opt [::a]))]
  {:x x
   :y (cond-> y (not (contains? x ::a)) (dissoc ::a))})

Alternatively:

(gen/let [x (s/gen (s/keys :opt [::a]))
          y (s/gen (cond-> (s/keys :opt [::a])
                     (not (contains? x ::a))
                     (s/and #(not (contains? % ::a)))))]
  {:x x
   :y y})
ago by
I didn't mention that I'd put the y spec in an `(s/def ::y (s/keys ...))` in my question which might have made this clearer.

I want the behaviour of spec which detects  that anything it generates is valid according to the spec. If the definition of `::y` ever changed to `(s/def ::y (s/keys :req [::a]))` and I'd blocked `::a` from generating within `::y` then I'd like it to refuse to generate `::y`.
ago by
So, in more generally, `::y` is "something", `::x` is "can have `::a`", and the combined generation must make `y` valid but in some way congruent with `x`. Pretty sure the only reasonable way is to change the `y` generator based on the value of `x`. I've updated my answer.
Welcome to Clojure Q&A, where you can ask questions and receive answers from members of the Clojure community.
...