/
malli_tests.clj
115 lines (97 loc) · 6.76 KB
/
malli_tests.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
(ns muotti.malli-tests
(:require [clojure.test :refer :all]
[malli.core :as malli]
[muotti.core :as muotti]
[muotti.malli :as mm]
[clojure.tools.logging :as log])
(:import (java.time Instant)))
(defn ^:private create-transformer
[config]
(let [muotti-xformer (muotti/->transformer config)
malli-xformer (mm/transformer muotti-xformer)]
malli-xformer))
(defn ^:private assert-decoding
([label transformer malli-schema data expected]
(testing label
(is (= (malli/decode malli-schema data transformer) expected))))
([label transformer malli-schema data expected reg]
(testing label
(is (= (malli/decode malli-schema data reg transformer) expected)))))
(defn ^:private assert-validation
[label malli-schema data expected]
(testing label
(is (= (malli/validate malli-schema data) expected))))
(deftest malli-schema-support
(let [tf (create-transformer mm/malli-config)]
(testing "malli.core/type-schemas"
(assert-decoding "[:string -> :int]" tf :int "123" 123)
(assert-decoding "[:string -> :int] fails for decimal-like strings" tf :int "123.4" nil)
(assert-decoding "[:string -> :double]" tf :double "123.4" 123.4)
(assert-decoding "[:string -> :double] works for integer-like strings" tf :double "123" 123.0)
(assert-decoding "[:string -> :boolean]" tf :boolean "true" true)
(assert-decoding "[:string -> :boolean]" tf :boolean "false" false)
(assert-decoding "[:string -> :boolean] is nil for 'stuff'" tf :boolean "stuff" nil)
(assert-decoding "[:string -> :boolean] is nil for ''" tf :boolean "" nil)
(assert-decoding "[:string -> :keyword]" tf :keyword "abc" :abc)
(assert-decoding "[:string -> :keyword] allows creating visually confusing keywords" tf :keyword ":keyword" (keyword ":keyword")) ; TODO: This might be a bug
(assert-decoding "[:string -> :symbol]" tf :symbol "icon" 'icon)
(assert-decoding "[:string -> :uuid]" tf :uuid "55f7b535-d87a-4635-ae46-a882291e4ae2" #uuid "55f7b535-d87a-4635-ae46-a882291e4ae2")
(assert-decoding "[:int -> :string]" tf [:string] 1 "1")
(assert-decoding "[:int -> :double]" tf [:double] 1 1.0)
(assert-decoding "[:double -> :string]" tf :string 45.67 "45.67")
(assert-decoding "[:boolean -> :string] converts true" tf :string true "true")
(assert-decoding "[:boolean -> :string] converts false" tf :string false "false")
(assert-decoding "[:boolean -> :string] nil is nil" tf :string nil nil)
(assert-decoding "[:keyword -> :string]" tf :string :locknload "locknload")
(assert-decoding "[:keyword -> :symbol]" tf :symbol :abloy 'abloy)
(assert-decoding "[:qualified-keyword -> :string]" tf :string :lock/load "lock/load")
(assert-decoding "[:symbol -> :string]" tf :string 'assa "assa")
(assert-decoding "[:qualified-symbol -> :string]" tf :string 'fifty/sixty "fifty/sixty")
(assert-decoding "[:uuid -> :string]" tf :string #uuid "479d9c47-64d6-4709-968d-c7d48aaf49a2" "479d9c47-64d6-4709-968d-c7d48aaf49a2")
; NOTES:
; - :any is identity, so no tests at all for it
; - :nil may be overridden by :muotti/default, so no specific tests for it
)
; TODO: Verify all these work as expected
(testing "malli.core/base-schemas"
; :and, :or, :orn, :not, :map, :map-of, :vector, :sequential, :set, :enum, :maybe, :tuple, :multi, :re, :fn, :ref, :=>, :function and :schema
(assert-decoding ":string -> [:or :int :boolean] -> :int" tf [:or :int :boolean] "123" 123)
(assert-decoding ":string -> [:or :int :boolean] -> :boolean" tf [:or :int :boolean] "true" true)
(assert-decoding ":string -> [:or :int :boolean] -> nil" tf [:or :int :boolean] :remu :remu)
(assert-decoding ":int -> [:and :int pos?] -> what" tf [:and :int pos?] 123 123)
(assert-decoding ":int -> [:and :int pos?] -> what" tf [:and :int pos?] "456" 456)
(assert-decoding ":int -> [:and :int pos?] -> what" tf [:and pos? :int] -789 nil)
(assert-decoding ":int -> [:and :int pos?] -> what" tf [:and pos? :int] 789 789))
(testing "malli.core/predicate-schemas"
(let [muotti-registry (mm/extension-types-registry malli/default-registry)
with-registry (fn [schema] (malli/schema schema {:registry muotti-registry}))]
(testing "numeric predicates"
(testing "extended predicates"
(assert-validation "[instance? {:type java.time.Instant}]" (with-registry [instance? {:class Instant}]) (Instant/now) true))
(testing "extended types"
(assert-validation "::big-int" (with-registry ::mm/big-int) 999999999999999999999N true)
(assert-validation "::big-integer" (with-registry ::mm/big-integer) (BigInteger. "999999999999999999999") true)
(assert-validation "::big-decimal" (with-registry ::mm/big-decimal) 99999999999999999999.9M true)
(assert-validation "::big-decimal" (with-registry ::mm/big-decimal) (BigDecimal. "99999999999999999999.9") true)
(assert-decoding "[:string -> ::big-integer]" tf (with-registry ::mm/big-integer) "999999999999999999999" 999999999999999999999N))
(testing "type test predicates"
(assert-decoding "[:string -> int?]" tf (with-registry int?) "123" 123)
(assert-decoding "[:string -> pos?]" tf (with-registry pos?) "123" 123.0)
(assert-decoding "[:string -> rational?]" tf (with-registry rational?) "2/3" (/ 2 3)))))
; any?, some?, number?, integer?, int?, pos-int?, neg-int?, nat-int?, pos?, neg?, float?, double?,
; boolean?, string?, ident?, simple-ident?, qualified-ident?, keyword?, simple-keyword?, qualified-keyword?,
; symbol?, simple-symbol?, qualified-symbol?, uuid?, uri?, decimal?, inst?, seqable?, indexed?, map?, vector?,
; list?, seq?, char?, set?, nil?, false?, true?, zero?, rational?, coll?, empty?, associative?, sequential?,
; ratio?, bytes?, ifn? and fn?
)))
(deftest default-values
(let [tf (create-transformer mm/malli-config)]
(testing "provided default value is used for nil inputs"
(assert-decoding "nil -> [:string {:muotti/default \"hello\"] -> hello" tf [:string {:muotti/default "hello"}] nil "hello"))))
(deftest override-types
(let [tf (create-transformer {:transformations {[:override/source :string] {:transformer (constantly "overridden from")}
[:string :override/target] {:transformer (constantly "overridden to")}}})]
(testing "source type can be overridden"
(assert-decoding ":override/source -> :string" tf [:string {:muotti/source :override/source}] "value" "overridden from"))
(testing "target type can be overridden"
(assert-decoding ":string -> :override/target" tf [:string {:muotti/target :override/target}] "value" "overridden to"))))