diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 8b1f04798..1863b71f9 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -1513,12 +1513,12 @@ (let [find (finder (reduce-kv (fn [acc k s] (assoc acc k (-validator s))) {} @dispatch-map))] (fn [x] (if-let [validator (find (dispatch x))] (validator x) false)))) (-explainer [this path] - (let [find (finder (reduce (fn [acc [k s]] (assoc acc k (-explainer s (conj path k)))) {} (-entries this))) - ->path (if (keyword? dispatch) #(conj % dispatch) identity)] + (let [find (finder (reduce (fn [acc [k s]] (assoc acc k (-explainer s (conj path k)))) {} (-entries this)))] (fn [x in acc] (if-let [explainer (find (dispatch x))] (explainer x in acc) - (conj acc (miu/-error (->path path) (->path in) this x ::invalid-dispatch-value)))))) + (let [->path (if (and (map? x) (keyword? dispatch)) #(conj % dispatch) identity)] + (conj acc (miu/-error (->path path) (->path in) this x ::invalid-dispatch-value))))))) (-parser [_] (let [parse (fn [k s] (let [p (-parser s)] (fn [x] (miu/-map-valid #(miu/-tagged k %) (p x))))) find (finder (reduce-kv (fn [acc k s] (assoc acc k (parse k s))) {} @dispatch-map))] diff --git a/test/malli/core_test.cljc b/test/malli/core_test.cljc index fbb634e30..489d7ef6e 100644 --- a/test/malli/core_test.cljc +++ b/test/malli/core_test.cljc @@ -116,6 +116,8 @@ (m/walk [:map {:registry {::age [:and int? [:> 18]]}} [:age ::age]] (m/schema-walker identity))))) +(defrecord SomeRecord []) + (deftest validation-test (testing "coercion" @@ -1024,19 +1026,26 @@ [:human [:map [:type keyword?] [:name string?] [:address [:map [:country keyword?]]]]]] valid1 {:type :sized, :size 10} valid2 {:type :human :name "inkeri", :address {:country :PO}} + valid3 (map->SomeRecord {:type :sized, :size 10}) invalid1 {:type :sized, :size "size"} invalid2 {:type :human :namez "inkeri"} - invalid3 {:type :worm}] + invalid3 {:type :worm} + invalid4 [] + invalid5 "xxx" + invalid6 (map->SomeRecord {:type :record})] (is (true? (m/validate schema valid1))) (is (true? (m/validate schema valid2))) + (is (true? (m/validate schema valid3))) (is (false? (m/validate schema invalid1))) (is (false? (m/validate schema invalid2))) (is (false? (m/validate schema invalid3))) - (is (false? (m/validate schema "not-a-map"))) + (is (false? (m/validate schema invalid4))) + (is (false? (m/validate schema invalid5))) (is (nil? (m/explain schema valid1))) (is (nil? (m/explain schema valid2))) + (is (nil? (m/explain schema valid3))) (is (results= {:schema schema, :value {:type :sized, :size "size"}, @@ -1066,18 +1075,51 @@ :type :malli.core/invalid-dispatch-value}]} (m/explain schema invalid3))) + (is (results= {:schema schema, + :value [] + :errors [{:path [] + :in [] + :schema schema + :value [] + :type :malli.core/invalid-dispatch-value}]} + (m/explain schema invalid4))) + + (is (results= {:schema schema, + :value "xxx" + :errors [{:path [] + :in [] + :schema schema + :value "xxx" + :type :malli.core/invalid-dispatch-value}]} + (m/explain schema invalid5))) + + (is (results= {:schema schema, + :value invalid6 + :errors [{:path [:type] + :in [:type] + :schema schema + :value invalid6 + :type :malli.core/invalid-dispatch-value}]} + (m/explain schema invalid6))) + (is (= (miu/-tagged :sized valid1) (m/parse schema valid1))) (is (= (miu/-tagged :human valid2) (m/parse schema valid2))) + (is (= (miu/-tagged :sized valid3) (m/parse schema valid3))) (is (= ::m/invalid (m/parse schema invalid1))) (is (= ::m/invalid (m/parse schema invalid2))) (is (= ::m/invalid (m/parse schema invalid3))) - (is (= ::m/invalid (m/parse schema "not-a-map"))) + (is (= ::m/invalid (m/parse schema invalid4))) + (is (= ::m/invalid (m/parse schema invalid5))) + (is (= ::m/invalid (m/parse schema invalid6))) (is (= valid1 (m/unparse schema (m/parse schema valid1)))) (is (= valid2 (m/unparse schema (m/parse schema valid2)))) + (is (= valid3 (m/unparse schema (m/parse schema valid3)))) (is (= ::m/invalid (m/unparse schema invalid1))) (is (= ::m/invalid (m/unparse schema invalid2))) (is (= ::m/invalid (m/unparse schema invalid3))) - (is (= ::m/invalid (m/unparse schema "not-a-map"))) + (is (= ::m/invalid (m/unparse schema invalid4))) + (is (= ::m/invalid (m/unparse schema invalid5))) + (is (= ::m/invalid (m/unparse schema invalid6))) (is (= {:type :sized, :size 10} (m/decode schema {:type "sized", :size "10"} mt/string-transformer))) diff --git a/test/malli/error_test.cljc b/test/malli/error_test.cljc index 64cb503dc..7198a63a9 100644 --- a/test/malli/error_test.cljc +++ b/test/malli/error_test.cljc @@ -440,6 +440,8 @@ (is (= ["should be an ifn"] (me/humanize (m/explain ifn? 123))))) +(defrecord Horror []) + (deftest multi-error-test (let [schema [:multi {:dispatch :type} ["plus" [:map [:value int?]]] @@ -454,6 +456,19 @@ (-> schema (m/explain {:type "minuz"}) (me/with-spell-checking) + (me/humanize))))) + + (testing "explain works even when dispatch is a keyword but value is not a map" + (is (= ["invalid dispatch value"] + (-> (m/schema [:multi {:dispatch :x} + [:y [:map [:x :keyword]]]]) + (m/explain []) + (me/humanize)))) + + (is (= {:x ["invalid dispatch value"]} + (-> (m/schema [:multi {:dispatch :x} + [:y [:map [:x :keyword]]]]) + (m/explain (map->Horror {:foo :bar})) (me/humanize)))))) (deftest explain-sequential @@ -604,8 +619,6 @@ :f [1 2 3 4]}) (me/humanize))))) -(defrecord Horror []) - (deftest robust-humanize-form (let [f (fn [s] [:fn {:error/message s} (constantly false)]) => ::irrelevant] @@ -651,7 +664,7 @@ [:and [:sequential :int] (f "1") (f "2")] [1 2] => ["1" "2"]))) (deftest multi-humanize-test-428 - (is (= {:user {:type ["invalid dispatch value"]}} + (is (= {:user ["invalid dispatch value"]} (-> (m/explain [:map [:user [:multi {:dispatch :type}]]] {:user nil}) (me/humanize)))))