|
| 1 | +(ns clojure.core-test.sort-by |
| 2 | + (:require [clojure.test :as t :refer [deftest testing is are]] |
| 3 | + [clojure.core-test.portability #?(:cljs :refer-macros :default :refer) [when-var-exists]])) |
| 4 | + |
| 5 | +(when-var-exists sort-by |
| 6 | + ;; Data for simple tests |
| 7 | + (def simple-vec-maps [{:a 2 :b 9} |
| 8 | + {:a 1 :b 10} |
| 9 | + {:a 4 :b 7} |
| 10 | + {:a 3 :b 8}]) |
| 11 | + |
| 12 | + ;; Data for stable sorting |
| 13 | + (def stable-data [{:a 1 :b 11} |
| 14 | + {:a 1 :b 21} |
| 15 | + {:a 1 :b 39} |
| 16 | + {:a 1 :b 2} |
| 17 | + {:a 4 :b 5} |
| 18 | + {:a 2 :b 101} |
| 19 | + {:a 2 :b 71} |
| 20 | + {:a 2 :b 28} |
| 21 | + {:a 2 :b 99} |
| 22 | + {:a 4 :b 210} |
| 23 | + {:a 3 :b 113} |
| 24 | + {:a 3 :b 412} |
| 25 | + {:a 3 :b 135} |
| 26 | + {:a 3 :b 314} |
| 27 | + {:a 4 :b 215}]) |
| 28 | + |
| 29 | + (deftest test-sort-by |
| 30 | + (testing "sort-by artity-2" |
| 31 | + (testing "key-fn is `identity`" |
| 32 | + (are [expected x] (= expected (sort x) (sort-by identity x)) |
| 33 | + ;; cases from `sort` tests, since (sort ...) = (sort-by identity ...) |
| 34 | + '() nil |
| 35 | + '(1 2 3 4) [3 1 2 4] |
| 36 | + '(nil 2 3 4) [3 nil 2 4] |
| 37 | + '(1 2 3 4) '(3 1 2 4) |
| 38 | + '(1 2 3 4) #{3 1 2 4} |
| 39 | + '([:a 1] [:b 2] [:c 3]) {:c 3 :b 2 :a 1} |
| 40 | + '([1] [2] [3] [4]) [[3] [1] [2] [4]] |
| 41 | + '("a" "b" "c" "d") ["b" "a" "c" "d"] |
| 42 | + '(\c \e \j \l \o \r \u) "clojure")) |
| 43 | + (testing "key-fn is keyword" |
| 44 | + (is (= (seq [{:a 4 :b 7} |
| 45 | + {:a 3 :b 8} |
| 46 | + {:a 2 :b 9} |
| 47 | + {:a 1 :b 10}]) |
| 48 | + (sort-by :b simple-vec-maps))) |
| 49 | + (is (= (seq [{:a 1 :b 10} |
| 50 | + {:a 2 :b 9} |
| 51 | + {:a 3 :b 8} |
| 52 | + {:a 4 :b 7}]) |
| 53 | + (sort-by :a simple-vec-maps))) |
| 54 | + ;; test more complex key-fn and stability of sort-by |
| 55 | + ;; :a + :b = 11 for all elements of simple-vec-maps |
| 56 | + (is (= (seq simple-vec-maps) |
| 57 | + (sort-by #(+ (:a %) (:b %)) simple-vec-maps))) |
| 58 | + ;; If the key-fn returns the same value all the time we also |
| 59 | + ;; expect no change. For instance, when the key-fn returns |
| 60 | + ;; `nil` constantly because we use the wrong keyword or we |
| 61 | + ;; navigate the structure of the element incorrectly. |
| 62 | + (is (= (seq simple-vec-maps) |
| 63 | + (sort-by :c simple-vec-maps))))) |
| 64 | + |
| 65 | + (testing "sort-by artity-3" |
| 66 | + ;; Use `compare` |
| 67 | + (is (= (seq [{:a 1 :b 10} |
| 68 | + {:a 2 :b 9} |
| 69 | + {:a 3 :b 8} |
| 70 | + {:a 4 :b 7}]) |
| 71 | + (sort-by :a compare simple-vec-maps))) |
| 72 | + ;; Reverse `compare` |
| 73 | + (is (= (seq [{:a 4 :b 7} |
| 74 | + {:a 3 :b 8} |
| 75 | + {:a 2 :b 9} |
| 76 | + {:a 1 :b 10}]) |
| 77 | + (sort-by :a #(compare %2 %1) simple-vec-maps))) |
| 78 | + (is (= (seq [{:a 1 :b 10} |
| 79 | + {:a 2 :b 9} |
| 80 | + {:a 3 :b 8} |
| 81 | + {:a 4 :b 7}]) |
| 82 | + (sort-by :a < simple-vec-maps))) |
| 83 | + (is (= (seq [{:a 4 :b 7} |
| 84 | + {:a 3 :b 8} |
| 85 | + {:a 2 :b 9} |
| 86 | + {:a 1 :b 10}]) |
| 87 | + (sort-by :a > simple-vec-maps))) |
| 88 | + |
| 89 | + ;; Use `compare` |
| 90 | + (is (= (seq [{:a 4 :b 7} |
| 91 | + {:a 3 :b 8} |
| 92 | + {:a 2 :b 9} |
| 93 | + {:a 1 :b 10}]) |
| 94 | + (sort-by :b compare simple-vec-maps))) |
| 95 | + ;; Reverse `compare` |
| 96 | + (is (= (seq [{:a 1 :b 10} |
| 97 | + {:a 2 :b 9} |
| 98 | + {:a 3 :b 8} |
| 99 | + {:a 4 :b 7}]) |
| 100 | + (sort-by :b #(compare %2 %1) simple-vec-maps))) |
| 101 | + (is (= (seq [{:a 4 :b 7} |
| 102 | + {:a 3 :b 8} |
| 103 | + {:a 2 :b 9} |
| 104 | + {:a 1 :b 10}]) |
| 105 | + (sort-by :b < simple-vec-maps))) |
| 106 | + (is (= (seq [{:a 1 :b 10} |
| 107 | + {:a 2 :b 9} |
| 108 | + {:a 3 :b 8} |
| 109 | + {:a 4 :b 7}]) |
| 110 | + (sort-by :b > simple-vec-maps)))) |
| 111 | + |
| 112 | + (testing "negative cases" |
| 113 | + ;; key-fn is not a fn |
| 114 | + (is (thrown? #?(:cljs :default, :default Exception) (sort-by nil simple-vec-maps))) |
| 115 | + (is (thrown? #?(:cljs :default, :default Exception) (sort-by [] simple-vec-maps))) |
| 116 | + ;; comparator is not a fn |
| 117 | + (is (thrown? #?(:cljs :default, :default Exception) (sort-by :a nil simple-vec-maps))) |
| 118 | + (is (thrown? #?(:cljs :default, :default Exception) (sort-by :a [] simple-vec-maps))) |
| 119 | + ;; collection is not a collection |
| 120 | + (is (thrown? #?(:cljs :default, :default Exception) (sort-by :a 1))) |
| 121 | + (is (thrown? #?(:cljs :default, :default Exception) (sort-by :a true)))) |
| 122 | + |
| 123 | + (testing "stable sort" |
| 124 | + ;; sort first by :b and then by :a results in runs of :a in |
| 125 | + ;; order with all the :b's associated with a given :a being in |
| 126 | + ;; order |
| 127 | + (is (= (seq [{:a 1, :b 2} |
| 128 | + {:a 1, :b 11} |
| 129 | + {:a 1, :b 21} |
| 130 | + {:a 1, :b 39} |
| 131 | + {:a 2, :b 28} |
| 132 | + {:a 2, :b 71} |
| 133 | + {:a 2, :b 99} |
| 134 | + {:a 2, :b 101} |
| 135 | + {:a 3, :b 113} |
| 136 | + {:a 3, :b 135} |
| 137 | + {:a 3, :b 314} |
| 138 | + {:a 3, :b 412} |
| 139 | + {:a 4, :b 5} |
| 140 | + {:a 4, :b 210} |
| 141 | + {:a 4, :b 215}]) |
| 142 | + (->> stable-data |
| 143 | + (sort-by :b) |
| 144 | + (sort-by :a))))))) |
0 commit comments