Skip to content

Commit

Permalink
Merge pull request #1095 from metosin/multi-keyword-dispatch-gen
Browse files Browse the repository at this point in the history
Multi keyword dispatch gen
  • Loading branch information
ikitommi authored Aug 28, 2024
2 parents 41f33c9 + df62939 commit c5e015f
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Malli is in well matured [alpha](README.md#alpha).

* Fix ClojureScript [arithmetic warning](https://github.com/metosin/malli/issues/1093)
* Distribute `:merge` over `:multi` [#1086](https://github.com/metosin/malli/pull/1086), see [documentation](README.md#distributive-schemas)
* allow `m/-proxy-schema` child to be a `delay` [#1090](https://github.com/metosin/malli/pull/1090)
* `:multi` with keyword `:dispatch` accumulates data to generated values [#1095](https://github.com/metosin/malli/pull/1095)
* allow `m/-proxy-schema` child to be a `delay`
* Fix `malli.dev.pretty` throws when explaining errors in nested maps [#1094](https://github.com/metosin/malli/issues/1096)
* `json-transformer` decodes 123.0 into 123 for schemas like `:int`, `pos-int?` etc. [#986](https://github.com/metosin/malli/issues/986)
Expand Down
18 changes: 15 additions & 3 deletions src/malli/generator.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
[clojure.test.check.rose-tree :as rose]
[malli.core :as m]
[malli.registry :as mr]
[malli.util :as mu]
[malli.impl.util :refer [-last -merge]]
#?(:clj [borkdude.dynaload :as dynaload])))

Expand Down Expand Up @@ -163,10 +164,21 @@
(gen-one-of gs)
(-never-gen options)))

(defn- -merge-keyword-dispatch-map-into-entries [schema]
(let [dispatch (-> schema m/properties :dispatch)]
(cond-> schema
(keyword? dispatch)
(mu/transform-entries
#(map (fn [[k :as e]]
(cond-> e
(not= ::m/default k)
(update 2 mu/merge [:map [dispatch [:= nil k]]]))) %)
(m/options schema)))))

(defn -multi-gen [schema options]
(if-some [gs (not-empty
(into [] (keep #(-not-unreachable (generator (last %) options)))
(m/entries schema options)))]
(if-some [gs (->> (m/entries (-merge-keyword-dispatch-map-into-entries schema) options)
(into [] (keep #(-not-unreachable (generator (last %) options))))
(not-empty))]
(gen-one-of gs)
(-never-gen options)))

Expand Down
39 changes: 34 additions & 5 deletions test/malli/generator_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
:symbol
:qualified-keyword
:qualified-symbol]]
(is (every? (partial m/validate schema) (mg/sample schema {:size 1000})))))
(is (every? (m/validator schema) (mg/sample schema {:size 1000})))))

(testing "double properties"
(let [infinity? #(or (= % ##Inf)
Expand Down Expand Up @@ -165,16 +165,16 @@
(testing "recursion"
(let [schema [:schema {:registry {::cons [:maybe [:tuple int? [:ref ::cons]]]}}
::cons]]
(is (every? (partial m/validate schema) (mg/sample schema {:size 100})))))
(is (every? (m/validator schema) (mg/sample schema {:size 100})))))
(testing "mutual recursion"
(let [schema [:schema
{:registry {::ping [:maybe [:tuple [:= "ping"] [:ref ::pong]]]
::pong [:maybe [:tuple [:= "pong"] [:ref ::ping]]]}}
::ping]]
(is (every? (partial m/validate schema) (mg/sample schema {:size 100})))))
(is (every? (m/validator schema) (mg/sample schema {:size 100})))))
(testing "recursion limiting"
(are [schema]
(every? (partial m/validate schema) (mg/sample schema {:size 100}))
(every? (m/validator schema) (mg/sample schema {:size 100}))

[:schema {:registry {::rec [:maybe [:ref ::rec]]}} ::rec]
[:schema {:registry {::rec [:map [:rec {:optional true} [:ref ::rec]]]}} ::rec]
Expand Down Expand Up @@ -369,7 +369,7 @@
[:map [:x int?] [:y int?]]
[:x]]]
:let [schema (m/schema schema {:registry registry})]]
(is (every? (partial m/validate schema) (mg/sample schema {:size 1000}))))))
(is (every? (m/validator schema) (mg/sample schema {:size 1000}))))))

#?(:clj
(deftest function-schema-test
Expand Down Expand Up @@ -1098,3 +1098,32 @@
(deftest double-with-long-min-test
(is (m/validate :double (shrink [:double {:min 3}])))
(is (= 3.0 (shrink [:double {:min 3}]))))

(deftest multi-keyword-dispatch-test
(testing "keyword dispatch value accumulates to generated value"
(let [schema [:multi {:dispatch :type}
["duck" :map]
["boss" :map]]]
(is (every? #{{:type "duck"} {:type "boss"}} (mg/sample schema)))
(is (every? (m/validator schema) (mg/sample schema)))))

(testing "non keyword doesn't accumulate data"
(let [schema [:multi {:dispatch (fn [x] (:type x))}
["duck" :map]
["boss" :map]]]
(is (every? #{{}} (mg/sample schema)))
(is (not (every? (m/validator schema) (mg/sample schema))))))

(testing "::m/default works too"
(let [schema [:multi {:dispatch :type}
["duck" :map]
[::m/default [:= "boss"]]]]
(is (every? #{{:type "duck"} "boss"} (mg/sample schema)))
(is (every? (m/validator schema) (mg/sample schema)))))

(testing "works with nil & {} too"
(let [schema [:multi {:dispatch :type}
[nil :map]
[{} :map]]]
(is (every? #{{:type nil} {:type {}}} (mg/sample schema)))
(is (every? (m/validator schema) (mg/sample schema))))))

0 comments on commit c5e015f

Please sign in to comment.