Skip to content

Commit 3c10854

Browse files
committed
port destructuring tests
1 parent b132dd7 commit 3c10854

1 file changed

Lines changed: 220 additions & 1 deletion

File tree

src/test/cljs/cljs/destructuring_test.cljs

Lines changed: 220 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
(ns cljs.destructuring-test
1010
(:refer-clojure :exclude [iter])
11-
(:require [cljs.test :refer-macros [deftest testing is]]
11+
(:require [cljs.test :refer-macros [deftest testing is are]]
1212
[clojure.string :as s]
1313
[clojure.set :as set]))
1414

@@ -224,6 +224,225 @@
224224
(= m3 (seq-to-map-for-destructuring (list :a 1 :b 2 {:a 0})))
225225
(= a4 nil)))))
226226

227+
(deftest keys-bang
228+
(let [sample-map {:a 1 :b 2}]
229+
(testing ":keys! happy path, binds and throws when key missing"
230+
(is (= 1 (let [{:keys! [a b]} sample-map] a)))
231+
(is (thrown? js/Error (let [{:keys! [a b]} {:a 1}] a))))
232+
(testing ":keys! with & bind and don't bind"
233+
(is (= 1 (let [{:keys! [a & :b]} sample-map] a)))
234+
(is (thrown? js/Error (let [{:keys! [a & :b]} {:a 1}] a))))
235+
(testing "nested maps with :keys! &"
236+
(let [sample-map {:a 1 :b {:a 2 :b 3 :c 4 :d 42}}
237+
{a :a {aa :a :as m :keys! [b c & :d]} :b} sample-map]
238+
(is (= m (:b sample-map)))
239+
(is (= a 1))
240+
(is (= aa 2))
241+
(is (= b 3))
242+
(is (= c 4))
243+
(is (thrown? js/Error (let [{a :a {aa :a :as m :keys! [b c & :d :e]} :b} sample-map] a)))
244+
(is (thrown? js/Error (let [{a :a {aa :a :as m :keys! [b c & :d]} :b} (update sample-map :b dissoc :c)] a)))))
245+
(testing "a broad range of qualified names/declarators with :keys! &"
246+
(let [sample-map {:foo/a 1 :b 2 :foo/c 3}
247+
{:keys! [foo/a & :b]} sample-map
248+
{:keys! [b & :foo/c]} sample-map
249+
sample-map2 {:foo/aa 1 :bb 2 :foo/cc 3}
250+
{:foo/keys! [aa & :foo/cc]} sample-map2]
251+
(is (= a 1))
252+
(is (= b 2))
253+
(is (thrown? js/Error (let [{:keys! [b & :foo/c]} (dissoc sample-map :b)] b)))
254+
(is (thrown? js/Error (let [{:keys! [b & :foo/c]} (dissoc sample-map :foo/c)] b)))
255+
(is (= 1 (let [{:foo/keys! [aa & :bb]} sample-map2] aa)))
256+
(is (= aa 1))
257+
(is (= 1 (let [{:keys! [::a & ::b]} {::a 1 , ::b 2}] a)))))
258+
(testing "that right of & is unbound (compile-time errors)"
259+
(is (thrown? js/Error (eval '(let [{:keys! [a & :b]} sample-map] b))))
260+
(is (thrown? js/Error (eval '(let [{a :a {aa :a :as m :keys [b c & :e]} :b} sample-map] e))))
261+
(is (thrown? js/Error (eval '(let [{:keys! [foo/a & :foo/c]} sample-map] c))))
262+
(let [sample-map2 {:foo/aa 1 :bb 2 :foo/cc 3}]
263+
(is (thrown? js/Error (eval '(let [{:foo/keys! [foo/aa & :foo/cc]} sample-map2] cc))))))))
264+
265+
(deftest syms-bang
266+
(let [sample-map '{a 1 b 2}]
267+
(testing ":syms! happy path, binds and throws when key missing"
268+
(is (= 1 (let [{:syms! [a b]} sample-map] a)))
269+
(is (thrown? js/Error (let [{:syms! [a b]} {:a 1}] a))))
270+
(testing ":syms! with & bind and don't bind"
271+
(is (= 1 (let [{:syms! [a & 'b]} sample-map] a)))
272+
(is (thrown? js/Error (let [{:syms! [a & 'b]} {:a 1}] a))))
273+
(testing "nested maps with :syms! &"
274+
(let [sample-map '{a 1 b {a 2 b 3 c 4 d 42}}
275+
{a 'a {aa 'a :as m :syms! [b c & 'd]} 'b} sample-map]
276+
(is (= m ('b sample-map)))
277+
(is (= a 1))
278+
(is (= aa 2))
279+
(is (= b 3))
280+
(is (= c 4))
281+
(is (thrown? js/Error (let [{a 'a {aa :a :as m :syms! [b c & 'd 'e]} 'b} sample-map] a)))
282+
(is (thrown? js/Error (let [{a 'a {aa :a :as m :syms! [b c & 'd]} 'b} (update sample-map 'b dissoc 'c)] a)))))
283+
(testing "a broad range of qualified names/declarators with :syms! &"
284+
(let [sample-map '{foo/a 1 b 2 foo/c 3}
285+
{:syms! [foo/a & 'b]} sample-map
286+
{:syms! [b & 'foo/c]} sample-map
287+
sample-map2 '{foo/aa 1 bb 2 foo/cc 3}
288+
{:foo/syms! [aa & 'foo/cc]} sample-map2]
289+
(is (= a 1))
290+
(is (= b 2))
291+
(is (thrown? js/Error (let [{:syms! [b & 'foo/c]} (dissoc sample-map 'b)] b)))
292+
(is (thrown? js/Error (let [{:syms! [b & 'foo/c]} (dissoc sample-map 'foo/c)] b)))
293+
(is (= aa 1))
294+
(is (= 1 (let [{:foo/syms! [aa & 'bb]} sample-map2] aa)))))
295+
(testing "that right of & is unbound (compile-time errors)"
296+
(is (thrown? js/Error (eval '(let [{:syms! [a & 'b]} sample-map] b))))
297+
(is (thrown? js/Error (eval '(let [{a a {aa a :as m :syms [b c & 'e]} :b} sample-map] e))))
298+
(is (thrown? js/Error (eval '(let [{:syms! [foo/a & 'foo/c]} sample-map] c))))
299+
(let [sample-map2 '{foo/aa 1 bb 2 foo/cc 3}]
300+
(is (thrown? js/Error (eval '(let [{:foo/syms! [foo/aa & 'foo/cc]} sample-map2] cc))))))))
301+
302+
(deftest strs-bang
303+
(let [sample-map {"a" 1 "b" 2}]
304+
(testing ":strs! happy path, binds and throws when key missing"
305+
(is (= 1 (let [{:strs! [a b]} sample-map] a)))
306+
(is (thrown? js/Error (let [{:strs! [a b]} {:a 1}] a))))
307+
(testing ":strs! with & bind and don't bind"
308+
(is (= 1 (let [{:strs! [a & "b"]} sample-map] a)))
309+
(is (thrown? js/Error (let [{:strs! [a & "b"]} {:a 1}] a))))
310+
(testing "nested maps with :strs! &"
311+
(let [sample-map {"a" 1 "b" {"a" 2 "b" 3 "c" 4 "d" 42}}
312+
{a "a" {aa "a" :as m :strs! [b c & "d"]} "b"} sample-map]
313+
(is (= m (get sample-map "b")))
314+
(is (= a 1))
315+
(is (= aa 2))
316+
(is (= b 3))
317+
(is (= c 4))
318+
(is (thrown? js/Error (let [{a "a" {aa "a" :as m :strs! [b c & "d" "e"]} "b"} sample-map] a)))
319+
(is (thrown? js/Error (let [{a "a" {aa "a" :as m :strs! [b c & "d"]} "b"} (update sample-map "b" dissoc "c")] a)))))
320+
(testing "that right of & is unbound (compile-time errors)"
321+
(is (thrown? js/Error (eval '(let [{:strs! [a & "b"]} sample-map] b))))
322+
(is (thrown? js/Error (eval '(let [{a "a" {aa "a" :as m :keys [b c & "e"]} "b"} sample-map] e)))))))
323+
324+
(deftest select-directive
325+
(let [m {:a 1 :b 2 :c 3 :d 4
326+
'sa 10 'sb 20 'sc 30 'sd 40
327+
"stra" 100 "strb" 200 "strc" 300 "strd" 400
328+
:foo/x 1000 :foo/y 2000 :foo/z 3000
329+
::x 10000 ::y 20000 ::z 30000
330+
:nested {:aa 1 'saa 10 "straa" 100}}
331+
332+
{:keys [a b & :c :z]
333+
:keys! [d]
334+
:select keys-sel} m
335+
336+
{:syms [sa sb & 'sc 'sz]
337+
:syms! [sd]
338+
:select syms-sel} m
339+
340+
{:strs [stra strb & "strc" "strz"]
341+
:strs! [strd]
342+
:select strs-sel} m
343+
344+
{:foo/keys [x & :y :zz]
345+
:foo/keys! [z]
346+
:select qkeys-sel} m
347+
348+
{::keys [x & :y :zz]
349+
::keys! [z]
350+
:select aqkeys-sel} m
351+
352+
{{aa :aa saa 'saa
353+
:select nest-sel} :nested
354+
aqx ::x
355+
:select tl-sel} m
356+
357+
{:keys! [a b & :c]
358+
:keys [d & :z]
359+
:or {}
360+
:select or-sel} m
361+
362+
{:keys [a b c d]
363+
:syms [sa sb sc sd]
364+
:strs [stra strb strc strd]
365+
:foo/keys! [x y z]
366+
::keys [x y z]
367+
nest :nested
368+
:as mm
369+
:select sel-mm} m]
370+
(are [expected result] (= expected result)
371+
keys-sel {:a 1 :b 2 :c 3 :d 4}
372+
syms-sel '{sa 10 sb 20 sc 30 sd 40}
373+
strs-sel {"stra" 100 "strb" 200 "strc" 300 "strd" 400}
374+
qkeys-sel {:foo/x 1000 :foo/z 3000}
375+
aqkeys-sel {::x 10000 ::z 30000}
376+
nest-sel '{:aa 1, saa 10}
377+
tl-sel '{:nested {:aa 1, saa 10} ::x 10000}
378+
or-sel {:a 1 :b 2 :c 3 :d 4}
379+
sel-mm mm))
380+
(testing "base cases"
381+
(is (nil? (let [{{a :a} :n :select s} nil] s))
382+
"if you haven't supplied a map, select won't make one for no reason")
383+
384+
(testing "you get what you supplied if nothing else"
385+
(is (= {} (let [{{a :a} :n :select s} {}] s)))
386+
(is (= {:n nil} (let [{{a :a} :n :select s} {:n nil}] s)))
387+
(is (= {:n {}} (let [{{a :a} :n :select s} {:n {}}] s))))
388+
389+
(testing "defaults can turn nothing into something"
390+
(is (= {:n {:a 42}} (let [{{a :a :or {a 42}} :n :select s} nil] s)))
391+
(is (= {:n {:a 42}} (let [{{a :a :or {a 42}} :n :select s} {:n nil}] s))))))
392+
393+
(deftest select-or-defaults
394+
(let [sample-map {:a 1, :b 2, :c {:aa 10 :bb 20},
395+
'd 4 'e 5 'f {'dd 40 'ee 50},
396+
"g" 6 "h" 7 "i" {"gg" 60 "hh" 70},}]
397+
(testing "happy path"
398+
(testing ":defaults"
399+
(is (empty? (let [{:defaults d :or {}} {}] d)))
400+
(is (thrown? js/Error (eval '(let [{:defaults d :or {:a 1}} {}] d))))
401+
(is (= {:a 1} (let [{:keys [a] :defaults d :or {:a 1}} {}] d)))
402+
(is (= {:a 1} (let [{:keys [a] :defaults d :or {a 1}} {}] d)))
403+
(is (= {:a 1, 'b 2, "c" 3} (let [{b 'b, c "c", :keys [a] :defaults d :or {:a 1, 'b 2, "c" 3}} {}] d))))
404+
405+
(testing ":keys + :select + :or + defaults"
406+
(let [{:keys [a b z & :c :d] {:keys! [aa & :bb]} :c
407+
:or {:d 42, z :or-z}
408+
:select m
409+
:defaults dfs} sample-map]
410+
(is (= 1 a))
411+
(is (= 2 b))
412+
(is (= 10 aa))
413+
(is (= {:z :or-z, :c {:aa 10, :bb 20}, :b 2, :d 42, :a 1} m))
414+
(is (= {:d 42, :z :or-z} dfs))))
415+
416+
(testing ":syms + :select + :or + defaults"
417+
(let [{:syms [d e z & 'd 'f] {:syms! [dd & 'ee]} 'f
418+
:or {'d 42, z :or-z}
419+
:select m
420+
:defaults dfs} sample-map]
421+
(is (= 4 d))
422+
(is (= 5 e))
423+
(is (= 40 dd))
424+
(is (= '{f {dd 40, ee 50}, e 5, d 4, z :or-z} m))
425+
(is (= '{d 42, z :or-z} dfs))))
426+
427+
(testing ":strs + :select + :or + defaults"
428+
(let [{:strs [g h z & "d" "i"] {:strs! [gg & "hh"]} "i"
429+
:or {"d" 42, z :or-z}
430+
:select m
431+
:defaults dfs} sample-map]
432+
(is (= 6 g))
433+
(is (= 7 h))
434+
(is (= 60 gg))
435+
(is (= {"d" 42, "z" :or-z, "i" {"gg" 60, "hh" 70}, "g" 6, "h" 7} m))
436+
(is (= {"d" 42, "z" :or-z} dfs))))
437+
438+
(testing "mixed things after &"
439+
(is (= 1 (let [{:keys [a & 'b]} {:a 1}] a)))
440+
(is (= 1 (let [{:keys! [a & 'b "c"]} {:a 1, 'b 2, "c" 3}] a))))
441+
442+
(testing "known compile-time errors"
443+
(is (thrown? js/Error (eval '(let [{:keys [a] :defaults d :or {:a 1, a 1}} {}] d))))
444+
(is (thrown? js/Error (eval '(let [{:defaults d} {}] d))))))))
445+
227446
(comment
228447

229448
(cljs.test/run-tests)

0 commit comments

Comments
 (0)