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

+1 vote
in Spec by

The example below shows that you can get generated values out of an s/merge using mult-specs that don't make sense with the intended spec.

Looking at the implementation of the generator for s/merge each arg to s/merge gets generated individually, but it would be nice if they instead flowed through from right to left so things like multi-specs wouldn’t choose randomly from their dispatches.

  (s/def :ent/id string?)

  (defmulti ent-multi-id :ent/id)
  (defmethod ent-multi-id :default [_] (s/keys))

  (defn maybe-retag-fn [retag-k]
    (fn [gen-v dispatch-tag]
      (if (= dispatch-tag :default)
        (assoc gen-v retag-k dispatch-tag))))

  (s/def ::ent (s/merge (s/multi-spec ent-multi-id (maybe-retag-fn :ent/id))
                        (s/keys :req [:ent/id])))

  (gen/sample (s/gen ::ent) 5)
  ;; => ({:ent/id ""} {:ent/id "w"} {:ent/id ""} {:ent/id "66"} {:ent/id "63v"})

  (s/def :foo/id string?)

  (defmethod ent-multi-id "foo" [_]
    (s/keys :req [:foo/id]))

  (gen/sample (s/gen ::ent) 5)
  ;; => ({:foo/id "", :ent/id ""} {:foo/id "6", :ent/id "f"} {:foo/id "A", :ent/id "W"} {:foo/id "L", :ent/id "nd"} {:ent/id "H"})

Please log in or register to answer this question.