|
135 | 135 | ([e a] `(expect ~e ~a nil true ~e))
|
136 | 136 | ([e a msg] `(expect ~e ~a ~msg true ~e))
|
137 | 137 | ([e a msg ex? e']
|
138 |
| - (let [msg' (str/join |
139 |
| - "\n" |
140 |
| - (cond-> [] |
141 |
| - msg |
142 |
| - (conj msg) |
143 |
| - (when-not (= e e')) |
144 |
| - (conj |
145 |
| - (str " within: " |
146 |
| - (pr-str (if (and (sequential? e') (= 'expect (first e'))) |
147 |
| - e' |
148 |
| - (list 'expect e' a)))))))] |
149 |
| - (cond |
150 |
| - (and (sequential? a) (= 'from-each (first a))) |
151 |
| - (let [[_ bindings & body] a] |
152 |
| - (if (= 1 (count body)) |
153 |
| - `(doseq ~bindings |
154 |
| - (expect ~e ~(first body) ~msg ~ex? ~e)) |
155 |
| - `(doseq ~bindings |
156 |
| - (expect ~e (do ~@body) ~msg ~ex? ~e)))) |
157 |
| - |
158 |
| - (and (sequential? a) (= 'in (first a))) |
159 |
| - (let [form `(~'expect ~e ~a ~msg)] |
160 |
| - `(let [a# ~(second a)] |
161 |
| - (cond (or (sequential? a#) (set? a#)) |
162 |
| - (let [all-reports# (atom nil)] |
163 |
| - (with-redefs [t/do-report (all-report all-reports#)] |
164 |
| - (doseq [~'x a#] |
165 |
| - ;; TODO: really want x evaluated here! (not sure about msg) |
166 |
| - (expect ~'x ~e nil ~ex? ~form))) |
167 |
| - (if (contains? @all-reports# :pass) |
168 |
| - ;; report all the passes (and no failures or errors) |
169 |
| - (doseq [r# (:pass @all-reports#)] (t/do-report r#)) |
170 |
| - (do |
171 |
| - ;; report all the errors and all the failures |
172 |
| - (doseq [r# (:error @all-reports#)] (t/do-report r#)) |
173 |
| - (doseq [r# (:fail @all-reports#)] (t/do-report r#))))) |
174 |
| - (map? a#) |
175 |
| - (let [e# ~e] |
176 |
| - (expect e# (select-keys a# (keys e#)) ~msg ~ex? ~form)) |
177 |
| - :else |
178 |
| - (throw (IllegalArgumentException. "'in' requires map or sequence"))))) |
179 |
| - |
180 |
| - (and (sequential? e) (= 'more (first e))) |
181 |
| - (let [es (mapv (fn [e] `(expect ~e ~a ~msg ~ex? ~e')) (rest e))] |
182 |
| - `(do ~@es)) |
183 |
| - |
184 |
| - (and (sequential? e) (= 'more-> (first e))) |
185 |
| - (let [es (mapv (fn [[e a->]] |
186 |
| - (if (and (sequential? a->) |
187 |
| - (symbol? (first a->)) |
188 |
| - (let [s (name (first a->))] |
189 |
| - (or (str/ends-with? s "->") |
190 |
| - (str/ends-with? s "->>")))) |
191 |
| - `(expect ~e (~(first a->) (? ~a) ~@(rest a->)) ~msg false ~e') |
192 |
| - `(expect ~e (-> (? ~a) ~a->) ~msg false ~e'))) |
193 |
| - (partition 2 (rest e)))] |
194 |
| - `(do ~@es)) |
195 |
| - |
196 |
| - (and (sequential? e) (= 'more-of (first e))) |
197 |
| - (let [es (mapv (fn [[e a]] `(expect ~e ~a ~msg ~ex? ~e')) |
198 |
| - (partition 2 (rest (rest e))))] |
199 |
| - `(let [~(second e) ~a] ~@es)) |
200 |
| - |
201 |
| - (and ex? (symbol? e) (resolve e) (class? (resolve e))) |
202 |
| - (if msg' |
203 |
| - (if (isa? (resolve e) Throwable) |
204 |
| - `(t/is (~'thrown? ~e ~a) ~msg') |
205 |
| - `(t/is (~'instance? ~e ~a) ~msg')) |
206 |
| - (if (isa? (resolve e) Throwable) |
207 |
| - `(t/is (~'thrown? ~e ~a)) |
208 |
| - `(t/is (~'instance? ~e ~a)))) |
209 |
| - |
210 |
| - (isa? (type e) java.util.regex.Pattern) |
211 |
| - (if msg' |
212 |
| - `(t/is (re-find ~e ~a) ~msg') |
213 |
| - `(t/is (re-find ~e ~a))) |
214 |
| - |
215 |
| - :else |
216 |
| - (if msg' |
217 |
| - `(t/is (~'=? ~e ~a) ~msg') |
218 |
| - `(t/is (~'=? ~e ~a))))))) |
| 138 | + (let [within (if (and (sequential? e') (= 'expect (first e'))) |
| 139 | + `(pr-str '~e') |
| 140 | + `(pr-str (list '~'expect '~e' '~a))) |
| 141 | + msg' `(str/join |
| 142 | + "\n" |
| 143 | + (cond-> [] |
| 144 | + ~msg |
| 145 | + (conj ~msg) |
| 146 | + ~(not= e e') |
| 147 | + (conj (str " within: " ~within))))] |
| 148 | + (cond |
| 149 | + (and (sequential? a) (= 'from-each (first a))) |
| 150 | + (let [[_ bindings & body] a] |
| 151 | + (if (= 1 (count body)) |
| 152 | + `(doseq ~bindings |
| 153 | + (expect ~e ~(first body) ~msg ~ex? ~e)) |
| 154 | + `(doseq ~bindings |
| 155 | + (expect ~e (do ~@body) ~msg ~ex? ~e)))) |
| 156 | + |
| 157 | + (and (sequential? a) (= 'in (first a))) |
| 158 | + (let [form `(~'expect ~e ~a)] |
| 159 | + `(let [a# ~(second a) |
| 160 | + not-in# (str '~e " not found in " a#) |
| 161 | + msg# (if (seq ~msg') (str ~msg' "\n" not-in#) not-in#)] |
| 162 | + (cond (or (sequential? a#) (set? a#)) |
| 163 | + (let [all-reports# (atom nil) |
| 164 | + one-report# (atom nil)] |
| 165 | + ;; we accumulate any and all failures and errors but we |
| 166 | + ;; only accumulate passes if each sequential expectation |
| 167 | + ;; fully passes (i.e., no failures or errors) |
| 168 | + (with-redefs [t/do-report (all-report one-report#)] |
| 169 | + (doseq [a'# a#] |
| 170 | + (expect ~e a'# msg# ~ex? ~form) |
| 171 | + (if (or (contains? @one-report# :error) |
| 172 | + (contains? @one-report# :fail)) |
| 173 | + (do |
| 174 | + (when (contains? @one-report# :fail) |
| 175 | + (swap! all-reports# |
| 176 | + update :fail into (:fail @one-report#))) |
| 177 | + (when (contains? @one-report# :error) |
| 178 | + (swap! all-reports# |
| 179 | + update :error into (:error @one-report#)))) |
| 180 | + (when (contains? @one-report# :pass) |
| 181 | + (swap! all-reports# |
| 182 | + update :pass into (:pass @one-report#)))) |
| 183 | + (reset! one-report# nil))) |
| 184 | + |
| 185 | + (if (contains? @all-reports# :pass) |
| 186 | + ;; report all the passes (and no failures or errors) |
| 187 | + (doseq [r# (:pass @all-reports#)] (t/do-report r#)) |
| 188 | + (do |
| 189 | + (when-let [r# (first (:error @all-reports#))] |
| 190 | + (t/do-report r#)) |
| 191 | + (when-let [r# (first (:fail @all-reports#))] |
| 192 | + (t/do-report r#))))) |
| 193 | + (map? a#) |
| 194 | + (let [e# ~e] |
| 195 | + (expect e# (select-keys a# (keys e#)) ~msg ~ex? ~form)) |
| 196 | + :else |
| 197 | + (throw (IllegalArgumentException. "'in' requires map or sequence"))))) |
| 198 | + |
| 199 | + (and (sequential? e) (= 'more (first e))) |
| 200 | + (let [es (mapv (fn [e] `(expect ~e ~a ~msg ~ex? ~e')) (rest e))] |
| 201 | + `(do ~@es)) |
| 202 | + |
| 203 | + (and (sequential? e) (= 'more-> (first e))) |
| 204 | + (let [es (mapv (fn [[e a->]] |
| 205 | + (if (and (sequential? a->) |
| 206 | + (symbol? (first a->)) |
| 207 | + (let [s (name (first a->))] |
| 208 | + (or (str/ends-with? s "->") |
| 209 | + (str/ends-with? s "->>")))) |
| 210 | + `(expect ~e (~(first a->) (? ~a) ~@(rest a->)) ~msg false ~e') |
| 211 | + `(expect ~e (-> (? ~a) ~a->) ~msg false ~e'))) |
| 212 | + (partition 2 (rest e)))] |
| 213 | + `(do ~@es)) |
| 214 | + |
| 215 | + (and (sequential? e) (= 'more-of (first e))) |
| 216 | + (let [es (mapv (fn [[e a]] `(expect ~e ~a ~msg ~ex? ~e')) |
| 217 | + (partition 2 (rest (rest e))))] |
| 218 | + `(let [~(second e) ~a] ~@es)) |
| 219 | + |
| 220 | + (and ex? (symbol? e) (resolve e) (class? (resolve e))) |
| 221 | + (if (seq `~msg') |
| 222 | + (if (isa? (resolve e) Throwable) |
| 223 | + `(t/is (~'thrown? ~e ~a) ~msg') |
| 224 | + `(t/is (~'instance? ~e ~a) ~msg')) |
| 225 | + (if (isa? (resolve e) Throwable) |
| 226 | + `(t/is (~'thrown? ~e ~a)) |
| 227 | + `(t/is (~'instance? ~e ~a)))) |
| 228 | + |
| 229 | + (isa? (type e) java.util.regex.Pattern) |
| 230 | + (if (seq `~msg') |
| 231 | + `(t/is (re-find ~e ~a) ~msg') |
| 232 | + `(t/is (re-find ~e ~a))) |
| 233 | + |
| 234 | + :else |
| 235 | + (if (seq `~msg') |
| 236 | + `(t/is (~'=? ~e ~a) ~msg') |
| 237 | + `(t/is (~'=? ~e ~a))))))) |
219 | 238 |
|
220 | 239 | (comment
|
221 | 240 | (macroexpand '(expect (more-> 1 :a 2 :b 3 (-> :c :d)) {:a 1 :b 2 :c {:d 4}}))
|
|
0 commit comments