Skip to content

Commit c5e015f

Browse files
authored
Merge pull request #1095 from metosin/multi-keyword-dispatch-gen
Multi keyword dispatch gen
2 parents 41f33c9 + df62939 commit c5e015f

File tree

3 files changed

+51
-8
lines changed

3 files changed

+51
-8
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Malli is in well matured [alpha](README.md#alpha).
1818

1919
* Fix ClojureScript [arithmetic warning](https://github.com/metosin/malli/issues/1093)
2020
* Distribute `:merge` over `:multi` [#1086](https://github.com/metosin/malli/pull/1086), see [documentation](README.md#distributive-schemas)
21+
* allow `m/-proxy-schema` child to be a `delay` [#1090](https://github.com/metosin/malli/pull/1090)
22+
* `:multi` with keyword `:dispatch` accumulates data to generated values [#1095](https://github.com/metosin/malli/pull/1095)
2123
* allow `m/-proxy-schema` child to be a `delay`
2224
* Fix `malli.dev.pretty` throws when explaining errors in nested maps [#1094](https://github.com/metosin/malli/issues/1096)
2325
* `json-transformer` decodes 123.0 into 123 for schemas like `:int`, `pos-int?` etc. [#986](https://github.com/metosin/malli/issues/986)

src/malli/generator.cljc

+15-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
[clojure.test.check.rose-tree :as rose]
1010
[malli.core :as m]
1111
[malli.registry :as mr]
12+
[malli.util :as mu]
1213
[malli.impl.util :refer [-last -merge]]
1314
#?(:clj [borkdude.dynaload :as dynaload])))
1415

@@ -163,10 +164,21 @@
163164
(gen-one-of gs)
164165
(-never-gen options)))
165166

167+
(defn- -merge-keyword-dispatch-map-into-entries [schema]
168+
(let [dispatch (-> schema m/properties :dispatch)]
169+
(cond-> schema
170+
(keyword? dispatch)
171+
(mu/transform-entries
172+
#(map (fn [[k :as e]]
173+
(cond-> e
174+
(not= ::m/default k)
175+
(update 2 mu/merge [:map [dispatch [:= nil k]]]))) %)
176+
(m/options schema)))))
177+
166178
(defn -multi-gen [schema options]
167-
(if-some [gs (not-empty
168-
(into [] (keep #(-not-unreachable (generator (last %) options)))
169-
(m/entries schema options)))]
179+
(if-some [gs (->> (m/entries (-merge-keyword-dispatch-map-into-entries schema) options)
180+
(into [] (keep #(-not-unreachable (generator (last %) options))))
181+
(not-empty))]
170182
(gen-one-of gs)
171183
(-never-gen options)))
172184

test/malli/generator_test.cljc

+34-5
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
:symbol
5050
:qualified-keyword
5151
:qualified-symbol]]
52-
(is (every? (partial m/validate schema) (mg/sample schema {:size 1000})))))
52+
(is (every? (m/validator schema) (mg/sample schema {:size 1000})))))
5353

5454
(testing "double properties"
5555
(let [infinity? #(or (= % ##Inf)
@@ -165,16 +165,16 @@
165165
(testing "recursion"
166166
(let [schema [:schema {:registry {::cons [:maybe [:tuple int? [:ref ::cons]]]}}
167167
::cons]]
168-
(is (every? (partial m/validate schema) (mg/sample schema {:size 100})))))
168+
(is (every? (m/validator schema) (mg/sample schema {:size 100})))))
169169
(testing "mutual recursion"
170170
(let [schema [:schema
171171
{:registry {::ping [:maybe [:tuple [:= "ping"] [:ref ::pong]]]
172172
::pong [:maybe [:tuple [:= "pong"] [:ref ::ping]]]}}
173173
::ping]]
174-
(is (every? (partial m/validate schema) (mg/sample schema {:size 100})))))
174+
(is (every? (m/validator schema) (mg/sample schema {:size 100})))))
175175
(testing "recursion limiting"
176176
(are [schema]
177-
(every? (partial m/validate schema) (mg/sample schema {:size 100}))
177+
(every? (m/validator schema) (mg/sample schema {:size 100}))
178178

179179
[:schema {:registry {::rec [:maybe [:ref ::rec]]}} ::rec]
180180
[:schema {:registry {::rec [:map [:rec {:optional true} [:ref ::rec]]]}} ::rec]
@@ -369,7 +369,7 @@
369369
[:map [:x int?] [:y int?]]
370370
[:x]]]
371371
:let [schema (m/schema schema {:registry registry})]]
372-
(is (every? (partial m/validate schema) (mg/sample schema {:size 1000}))))))
372+
(is (every? (m/validator schema) (mg/sample schema {:size 1000}))))))
373373

374374
#?(:clj
375375
(deftest function-schema-test
@@ -1098,3 +1098,32 @@
10981098
(deftest double-with-long-min-test
10991099
(is (m/validate :double (shrink [:double {:min 3}])))
11001100
(is (= 3.0 (shrink [:double {:min 3}]))))
1101+
1102+
(deftest multi-keyword-dispatch-test
1103+
(testing "keyword dispatch value accumulates to generated value"
1104+
(let [schema [:multi {:dispatch :type}
1105+
["duck" :map]
1106+
["boss" :map]]]
1107+
(is (every? #{{:type "duck"} {:type "boss"}} (mg/sample schema)))
1108+
(is (every? (m/validator schema) (mg/sample schema)))))
1109+
1110+
(testing "non keyword doesn't accumulate data"
1111+
(let [schema [:multi {:dispatch (fn [x] (:type x))}
1112+
["duck" :map]
1113+
["boss" :map]]]
1114+
(is (every? #{{}} (mg/sample schema)))
1115+
(is (not (every? (m/validator schema) (mg/sample schema))))))
1116+
1117+
(testing "::m/default works too"
1118+
(let [schema [:multi {:dispatch :type}
1119+
["duck" :map]
1120+
[::m/default [:= "boss"]]]]
1121+
(is (every? #{{:type "duck"} "boss"} (mg/sample schema)))
1122+
(is (every? (m/validator schema) (mg/sample schema)))))
1123+
1124+
(testing "works with nil & {} too"
1125+
(let [schema [:multi {:dispatch :type}
1126+
[nil :map]
1127+
[{} :map]]]
1128+
(is (every? #{{:type nil} {:type {}}} (mg/sample schema)))
1129+
(is (every? (m/validator schema) (mg/sample schema))))))

0 commit comments

Comments
 (0)