Move cljs tests to src/test/clojure
This way the tests will still run under cljs when they get to
be converted to .cljc
Nicolas Berger authored 8 years ago
Gary Fredericks committed 8 years ago
20 | 20 | :cljsbuild |
21 | 21 | {:builds |
22 | 22 | [{:id "node-dev" |
23 | :source-paths ["src/main/clojure" "src/test/cljs" | |
23 | :source-paths ["src/main/clojure" "src/test/clojure" | |
24 | 24 | "src/target/cljs/node"] |
25 | 25 | :notify-command ["node" "resources/run.js"] |
26 | 26 | :compiler {:optimizations :none |
30 | 30 | :output-dir "target/cljs/node_dev/out" |
31 | 31 | :source-map true}} |
32 | 32 | {:id "browser-dev" |
33 | :source-paths ["src/main/clojure" "src/test/cljs" | |
33 | :source-paths ["src/main/clojure" "src/test/clojure" | |
34 | 34 | "src/target/cljs/browser"] |
35 | 35 | :compiler {:optimizations :none |
36 | 36 | :static-fns true |
38 | 38 | :output-dir "target/cljs/browser_dev/out" |
39 | 39 | :source-map true}} |
40 | 40 | {:id "node-adv" |
41 | :source-paths ["src/main/clojure" "src/test/cljs" | |
41 | :source-paths ["src/main/clojure" "src/test/clojure" | |
42 | 42 | "src/target/cljs/node"] |
43 | 43 | :notify-command ["node" "target/cljs/node_adv/tests.js"] |
44 | 44 | :compiler {:optimizations :advanced |
47 | 47 | :output-to "target/cljs/node_adv/tests.js" |
48 | 48 | :output-dir "target/cljs/node_adv/out"}} |
49 | 49 | {:id "browser-adv" |
50 | :source-paths ["src/main/clojure" "src/test/cljs" | |
50 | :source-paths ["src/main/clojure" "src/test/clojure" | |
51 | 51 | "src/target/cljs/browser"] |
52 | 52 | :compiler {:optimizations :advanced |
53 | 53 | :pretty-print false |
0 | ; Copyright (c) Rich Hickey, Reid Draper, and contributors. | |
1 | ; All rights reserved. | |
2 | ; The use and distribution terms for this software are covered by the | |
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
4 | ; which can be found in the file epl-v10.html at the root of this distribution. | |
5 | ; By using this software in any fashion, you are agreeing to be bound by | |
6 | ; the terms of this license. | |
7 | ; You must not remove this notice, or any other, from this software. | |
8 | ||
9 | (ns clojure.test.check.clojure-test-test | |
10 | (:require [cljs.test :as test :refer [test-var] :refer-macros [is]] | |
11 | [clojure.test.check.generators :as gen] | |
12 | [clojure.test.check.properties :as prop :include-macros true] | |
13 | [clojure.test.check.clojure-test :as ct :refer-macros [defspec]] | |
14 | [cljs.reader :refer [read-string]])) | |
15 | ||
16 | (defspec default-trial-counts | |
17 | (prop/for-all* [gen/int] (constantly true))) | |
18 | ||
19 | (defspec trial-counts 5000 | |
20 | (prop/for-all* [gen/int] (constantly true))) | |
21 | ||
22 | ;; NOTE: No Thread/sleep in JS - David | |
23 | ;; (defspec long-running-spec 1000 | |
24 | ;; (prop/for-all* [] #(do (Thread/sleep 1) true))) | |
25 | ||
26 | (defn- vector-elements-are-unique* | |
27 | [v] | |
28 | (== (count v) (count (distinct v)))) | |
29 | ||
30 | (def ^:private vector-elements-are-unique | |
31 | (prop/for-all* | |
32 | [(gen/vector gen/int)] | |
33 | vector-elements-are-unique*)) | |
34 | ||
35 | (defspec this-is-supposed-to-fail 100 vector-elements-are-unique) | |
36 | ||
37 | (defn- capture-test-var | |
38 | [v] | |
39 | (doto (with-out-str (test-var v)) | |
40 | print)) | |
41 | ||
42 | (defn test-ns-hook | |
43 | [] | |
44 | (let [out-str (capture-test-var #'default-trial-counts) | |
45 | num-tests (-> out-str | |
46 | read-string | |
47 | :num-tests)] | |
48 | (is (= num-tests ct/*default-test-count*))) | |
49 | ||
50 | (is (-> (capture-test-var #'trial-counts) | |
51 | read-string | |
52 | (select-keys [:test-var :result :num-tests]) | |
53 | (= {:test-var "trial-counts", :result true, :num-tests 5000}))) | |
54 | ||
55 | (binding [ct/*report-trials* true] | |
56 | (let [output (capture-test-var #'trial-counts)] | |
57 | (is (re-matches #"\.{5}[\s\S]+" output)))) | |
58 | ||
59 | ;; NOTE: No Thread/sleep in JS - David | |
60 | ;; (binding [ct/*report-trials* ct/trial-report-periodic | |
61 | ;; ct/*trial-report-period* 500] | |
62 | ;; (is (re-seq | |
63 | ;; #"(Passing trial \d{3} / 1000 for .+\n)+" | |
64 | ;; (capture-test-var #'long-running-spec)))) | |
65 | ||
66 | (let [[report-counters report-str] | |
67 | (binding [ct/*report-shrinking* true] | |
68 | ;; need to keep the failure of this-is-supposed-to-fail from | |
69 | ;; affecting the clojure.test.check test run | |
70 | (let [restore-env (test/get-current-env) | |
71 | _ (test/set-env! (test/empty-env)) | |
72 | report-str (capture-test-var #'this-is-supposed-to-fail) | |
73 | env (test/get-current-env)] | |
74 | (test/set-env! restore-env) | |
75 | [(:report-counters env) report-str]))] | |
76 | (is (== 1 (:fail report-counters))) | |
77 | (is (re-seq | |
78 | #"Shrinking vector-elements-are-unique starting with parameters \[\[[\s\S]+" | |
79 | report-str)))) | |
80 |
0 | (ns clojure.test.check.random-test | |
1 | "Testing that the cljs impl matches the clojure impl." | |
2 | (:require [cljs.test :refer-macros [deftest is]] | |
3 | [clojure.test.check.random :as random])) | |
4 | ||
5 | (deftest longs-test | |
6 | ||
7 | ;; comparing with this code run on clj-jvm: | |
8 | (comment | |
9 | (-> 42 | |
10 | (random/make-java-util-splittable-random) | |
11 | (random/split-n 17) | |
12 | (->> (mapcat random/split) | |
13 | (map random/rand-long) | |
14 | (reduce bit-xor)) | |
15 | (str)) | |
16 | => | |
17 | "5298131359241775269") | |
18 | ||
19 | (is (= "5298131359241775269" | |
20 | (-> 42 | |
21 | (random/make-java-util-splittable-random) | |
22 | (random/split-n 17) | |
23 | (->> (mapcat random/split) | |
24 | (map random/rand-long) | |
25 | (reduce #(.xor %1 %2))) | |
26 | (str))))) | |
27 | ||
28 | (deftest doubles-test | |
29 | ||
30 | ;; comparing with this code run on clj-jvm: | |
31 | (comment | |
32 | ||
33 | (-> -42 | |
34 | (random/make-java-util-splittable-random) | |
35 | (random/split-n 17) | |
36 | (->> (mapcat random/split) | |
37 | (map random/rand-double) | |
38 | (reduce +)) | |
39 | (str)) | |
40 | => | |
41 | "17.39141655134964") | |
42 | ||
43 | (is (= "17.39141655134964" | |
44 | (-> -42 | |
45 | (random/make-java-util-splittable-random) | |
46 | (random/split-n 17) | |
47 | (->> (mapcat random/split) | |
48 | (map random/rand-double) | |
49 | (reduce +)) | |
50 | (str))))) | |
51 | ||
52 | (deftest auto-seeding-test | |
53 | (is (distinct? (random/rand-double (random/make-random)) | |
54 | (random/rand-double (random/make-random)) | |
55 | (random/rand-double (random/make-random)) | |
56 | (random/rand-double (random/make-random))) | |
57 | "Each call to make-random should return a different RNG.")) |
0 | ; Copyright (c) Rich Hickey, Reid Draper, and contributors. | |
1 | ; All rights reserved. | |
2 | ; The use and distribution terms for this software are covered by the | |
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
4 | ; which can be found in the file epl-v10.html at the root of this distribution. | |
5 | ; By using this software in any fashion, you are agreeing to be bound by | |
6 | ; the terms of this license. | |
7 | ; You must not remove this notice, or any other, from this software. | |
8 | ||
9 | (ns clojure.test.check.rose-tree-test | |
10 | (:require [cljs.test :as test :include-macros true] | |
11 | [clojure.test.check :as tc] | |
12 | [clojure.test.check.generators :as gen] | |
13 | [clojure.test.check.properties :as prop :include-macros true] | |
14 | [clojure.test.check.rose-tree :as rose] | |
15 | [clojure.test.check.clojure-test :as ct :refer-macros [defspec]])) | |
16 | ||
17 | (defn depth-one-children | |
18 | [rose] | |
19 | (into [] (map rose/root (rose/children rose)))) | |
20 | ||
21 | (defn depth-one-and-two-children | |
22 | [rose] | |
23 | (let [the-children (rose/children rose)] | |
24 | (into [] | |
25 | (concat | |
26 | (map rose/root the-children) | |
27 | (map rose/root (mapcat rose/children the-children)))))) | |
28 | ||
29 | (defspec test-collapse-rose | |
30 | 100 | |
31 | (prop/for-all [i gen/int] | |
32 | (let [tree (gen/int-rose-tree i)] | |
33 | (= (depth-one-and-two-children tree) | |
34 | (depth-one-children (rose/collapse tree)))))) |
0 | (ns clojure.test.check.test | |
1 | (:require [cljs.test :as test :refer-macros [deftest testing is]] | |
2 | [clojure.test.check :as tc] | |
3 | [clojure.test.check.generators :as gen] | |
4 | [clojure.test.check.properties :as prop :include-macros true] | |
5 | [clojure.test.check.random :as random] | |
6 | [clojure.test.check.rose-tree :as rose] | |
7 | [clojure.test.check.clojure-test :as ct :refer-macros [defspec]] | |
8 | [cljs.reader :as edn])) | |
9 | ||
10 | (deftest generators-are-generators | |
11 | (testing "generator? returns true when called with a generator" | |
12 | (is (gen/generator? gen/int)) | |
13 | (is (gen/generator? (gen/vector gen/int))) | |
14 | (is (gen/generator? (gen/return 5))))) | |
15 | ||
16 | ||
17 | (deftest values-are-not-generators | |
18 | (testing "generator? returns false when called with a value" | |
19 | (is (not (gen/generator? 5))) | |
20 | (is (not (gen/generator? int))) | |
21 | (is (not (gen/generator? [1 2 3]))))) | |
22 | ||
23 | ;; plus and 0 form a monoid | |
24 | ;; --------------------------------------------------------------------------- | |
25 | ||
26 | (defn passes-monoid-properties | |
27 | [a b c] | |
28 | (and | |
29 | (= (+ 0 a) a) | |
30 | (= (+ a 0) a) | |
31 | (= (+ a (+ b c)) (+ (+ a b) c)))) | |
32 | ||
33 | (deftest plus-and-0-are-a-monoid | |
34 | (testing "+ and 0 form a monoid" | |
35 | (is | |
36 | (let [p (prop/for-all* [gen/int gen/int gen/int] | |
37 | passes-monoid-properties)] | |
38 | (:result (tc/quick-check 1000 p))))) | |
39 | ;; NOTE: no ratios in ClojureScript - David | |
40 | ;; (testing "with ratios as well" | |
41 | ;; (is | |
42 | ;; (let [p (prop/for-all* [gen/ratio gen/ratio gen/ratio] | |
43 | ;; passes-monoid-properties)] | |
44 | ;; (:result (tc/quick-check 1000 p))))) | |
45 | ) | |
46 | ||
47 | ;; reverse | |
48 | ;; --------------------------------------------------------------------------- | |
49 | ||
50 | (defn reverse-equal?-helper | |
51 | [l] | |
52 | (let [r (vec (reverse l))] | |
53 | (and (= (count l) (count r)) | |
54 | (= (seq l) (rseq r))))) | |
55 | ||
56 | (deftest reverse-equal? | |
57 | (testing "For all vectors L, reverse(reverse(L)) == L" | |
58 | (is (let [p (prop/for-all* [(gen/vector gen/int)] reverse-equal?-helper)] | |
59 | (:result (tc/quick-check 1000 p)))))) | |
60 | ||
61 | ;; failing reverse | |
62 | ;; --------------------------------------------------------------------------- | |
63 | ||
64 | (deftest bad-reverse-test | |
65 | (testing "For all vectors L, L == reverse(L). Not true" | |
66 | (is (false? | |
67 | (let [p (prop/for-all* [(gen/vector gen/int)] #(= (reverse %) %))] | |
68 | (:result (tc/quick-check 1000 p))))))) | |
69 | ||
70 | ;; failing element remove | |
71 | ;; --------------------------------------------------------------------------- | |
72 | ||
73 | (defn first-is-gone | |
74 | [l] | |
75 | (not (some #{(first l)} (vec (rest l))))) | |
76 | ||
77 | (deftest bad-remove | |
78 | (testing "For all vectors L, if we remove the first element E, E should not | |
79 | longer be in the list. (This is a false assumption)" | |
80 | (is (false? | |
81 | (let [p (prop/for-all* [(gen/vector gen/int)] first-is-gone)] | |
82 | (:result (tc/quick-check 1000 p))))))) | |
83 | ||
84 | ;; exceptions shrink and return as result | |
85 | ;; --------------------------------------------------------------------------- | |
86 | ||
87 | (def exception (js/Error. "I get caught")) | |
88 | ||
89 | (defn exception-thrower | |
90 | [& args] | |
91 | (throw exception)) | |
92 | ||
93 | (deftest exceptions-are-caught | |
94 | (testing "Exceptions during testing are caught. They're also shrunk as long | |
95 | as they continue to throw." | |
96 | (is (= [exception [0]] | |
97 | (let [result | |
98 | (tc/quick-check | |
99 | 1000 (prop/for-all* [gen/int] exception-thrower))] | |
100 | [(:result result) (get-in result [:shrunk :smallest])]))))) | |
101 | ||
102 | ;; Count and concat work as expected | |
103 | ;; --------------------------------------------------------------------------- | |
104 | ||
105 | (defn concat-counts-correct | |
106 | [a b] | |
107 | (= (count (concat a b)) | |
108 | (+ (count a) (count b)))) | |
109 | ||
110 | (deftest count-and-concat | |
111 | (testing "For all vectors A and B: | |
112 | length(A + B) == length(A) + length(B)" | |
113 | (is (:result | |
114 | (let [p (prop/for-all* [(gen/vector gen/int) | |
115 | (gen/vector gen/int)] concat-counts-correct)] | |
116 | (tc/quick-check 1000 p)))))) | |
117 | ||
118 | ;; Interpose (Count) | |
119 | ;; --------------------------------------------------------------------------- | |
120 | ||
121 | (defn interpose-twice-the-length ;; (or one less) | |
122 | [v] | |
123 | (let [interpose-count (count (interpose :i v)) | |
124 | original-count (count v)] | |
125 | (or | |
126 | (= (* 2 original-count) interpose-count) | |
127 | (= (dec (* 2 original-count)) interpose-count)))) | |
128 | ||
129 | ||
130 | (deftest interpose-creates-sequence-twice-the-length | |
131 | (testing | |
132 | "Interposing a collection with a value makes its count | |
133 | twice the original collection, or ones less." | |
134 | (is (:result | |
135 | (tc/quick-check 1000 (prop/for-all [v (gen/vector gen/int)] (interpose-twice-the-length v))))))) | |
136 | ||
137 | ;; Lists and vectors are equivalent with seq abstraction | |
138 | ;; --------------------------------------------------------------------------- | |
139 | ||
140 | (defn list-vector-round-trip-equiv | |
141 | [a] | |
142 | ;; NOTE: can't use `(into '() ...)` here because that | |
143 | ;; puts the list in reverse order. clojure.test.check found that bug | |
144 | ;; pretty quickly... | |
145 | (= a (apply list (vec a)))) | |
146 | ||
147 | (deftest list-and-vector-round-trip | |
148 | (testing | |
149 | "" | |
150 | (is (:result | |
151 | (tc/quick-check | |
152 | 1000 (prop/for-all* | |
153 | [(gen/list gen/int)] list-vector-round-trip-equiv)))))) | |
154 | ||
155 | ;; keyword->string->keyword roundtrip | |
156 | ;; --------------------------------------------------------------------------- | |
157 | ||
158 | (defn keyword-string-roundtrip-equiv | |
159 | [k] | |
160 | (= k (keyword (name k)))) | |
161 | ||
162 | ;; NOTE: this is one of the slowest due to how keywords are constructed | |
163 | ;; drop N to 200 - David | |
164 | (deftest keyword-string-roundtrip | |
165 | (testing | |
166 | "For all keywords, turning them into a string and back is equivalent | |
167 | to the original string (save for the `:` bit)" | |
168 | (is (:result | |
169 | (tc/quick-check 100 (prop/for-all* | |
170 | [gen/keyword] keyword-string-roundtrip-equiv) | |
171 | :max-size 25))))) | |
172 | ||
173 | ;; Boolean and/or | |
174 | ;; --------------------------------------------------------------------------- | |
175 | ||
176 | (deftest boolean-or | |
177 | (testing | |
178 | "`or` with true and anything else should be true" | |
179 | (is (:result (tc/quick-check | |
180 | 1000 (prop/for-all* | |
181 | [gen/boolean] #(or % true))))))) | |
182 | ||
183 | (deftest boolean-and | |
184 | (testing | |
185 | "`and` with false and anything else should be false" | |
186 | (is (:result (tc/quick-check | |
187 | 1000 (prop/for-all* | |
188 | [gen/boolean] #(not (and % false)))))))) | |
189 | ||
190 | ;; Sorting | |
191 | ;; --------------------------------------------------------------------------- | |
192 | ||
193 | (defn elements-are-in-order-after-sorting | |
194 | [v] | |
195 | (every? identity (map <= (partition 2 1 (sort v))))) | |
196 | ||
197 | (deftest sorting | |
198 | (testing | |
199 | "For all vectors V, sorted(V) should have the elements in order" | |
200 | (is (:result | |
201 | (tc/quick-check | |
202 | 1000 | |
203 | (prop/for-all* | |
204 | [(gen/vector gen/int)] elements-are-in-order-after-sorting)))))) | |
205 | ||
206 | ;; Constant generators | |
207 | ;; --------------------------------------------------------------------------- | |
208 | ||
209 | ;; A constant generator always returns its created value | |
210 | (defspec constant-generators 100 | |
211 | (prop/for-all [a (gen/return 42)] | |
212 | (print "") | |
213 | (= a 42))) | |
214 | ||
215 | (deftest constant-generators-dont-shrink | |
216 | (testing "Generators created with `gen/return` should not shrink" | |
217 | (is (= [42] | |
218 | (let [result (tc/quick-check 100 | |
219 | (prop/for-all | |
220 | [a (gen/return 42)] | |
221 | false))] | |
222 | (-> result :shrunk :smallest)))))) | |
223 | ||
224 | ;; Tests are deterministic | |
225 | ;; --------------------------------------------------------------------------- | |
226 | ||
227 | (defn vector-elements-are-unique | |
228 | [v] | |
229 | (== (count v) (count (distinct v)))) | |
230 | ||
231 | (defn unique-test | |
232 | [seed] | |
233 | (tc/quick-check 1000 | |
234 | (prop/for-all* | |
235 | [(gen/vector gen/int)] vector-elements-are-unique) | |
236 | :seed seed)) | |
237 | ||
238 | (defn equiv-runs | |
239 | [seed] | |
240 | (= (unique-test seed) (unique-test seed))) | |
241 | ||
242 | (deftest tests-are-deterministic | |
243 | (testing "If two runs are started with the same seed, they should | |
244 | return the same results." | |
245 | (is (:result | |
246 | (tc/quick-check 1000 (prop/for-all* [gen/int] equiv-runs)))))) | |
247 | ||
248 | ;; Generating basic generators | |
249 | ;; -------------------------------------------------------------------------- | |
250 | ||
251 | (deftest generators-test | |
252 | (let [t (fn [generator pred] | |
253 | (is (:result (tc/quick-check 100 | |
254 | (prop/for-all [x generator] | |
255 | (pred x))))))] | |
256 | ||
257 | (testing "keyword" (t gen/keyword keyword?)) | |
258 | ;; (testing "ratio" (t gen/ratio clojure.lang.Ratio)) | |
259 | ;; (testing "byte" (t gen/byte Byte)) | |
260 | ;; (testing "bytes" (t gen/bytes (Class/forName "[B"))) | |
261 | ||
262 | (testing "char" (t gen/char string?)) | |
263 | (testing "char-ascii" (t gen/char-ascii string?)) | |
264 | (testing "char-alphanumeric" (t gen/char-alphanumeric string?)) | |
265 | (testing "string" (t gen/string string?)) | |
266 | (testing "string-ascii" (t gen/string-ascii string?)) | |
267 | (testing "string-alphanumeric" (t gen/string-alphanumeric string?)) | |
268 | ||
269 | (testing "vector" (t (gen/vector gen/int) vector?)) | |
270 | (testing "list" (t (gen/list gen/int) list?)) | |
271 | (testing "map" (t (gen/map gen/int gen/int) map?)) | |
272 | )) | |
273 | ||
274 | ;; Generating proper matrices | |
275 | ;; --------------------------------------------------------------------------- | |
276 | ||
277 | (defn proper-matrix? | |
278 | "Check if provided nested vectors form a proper matrix — that is, all nested | |
279 | vectors have the same length" | |
280 | [mtx] | |
281 | (let [first-size (count (first mtx))] | |
282 | (every? (partial = first-size) (map count (rest mtx))))) | |
283 | ||
284 | (deftest proper-matrix-test | |
285 | (testing | |
286 | "can generate proper matrices" | |
287 | (is (:result (tc/quick-check | |
288 | 100 (prop/for-all | |
289 | [mtx (gen/vector (gen/vector gen/int 3) 3)] | |
290 | (proper-matrix? mtx))))))) | |
291 | ||
292 | (def bounds-and-vector | |
293 | (gen/bind (gen/tuple gen/s-pos-int gen/s-pos-int) | |
294 | (fn [[a b]] | |
295 | (let [minimum (min a b) | |
296 | maximum (max a b)] | |
297 | (gen/tuple (gen/return [minimum maximum]) | |
298 | (gen/vector gen/int minimum maximum)))))) | |
299 | ||
300 | (deftest proper-vector-test | |
301 | (testing | |
302 | "can generate vectors with sizes in a provided range" | |
303 | (is (:result (tc/quick-check | |
304 | 100 (prop/for-all | |
305 | [b-and-v bounds-and-vector] | |
306 | (let [[[minimum maximum] v] b-and-v | |
307 | c (count v)] | |
308 | (and (<= c maximum) | |
309 | (>= c minimum))))))))) | |
310 | ||
311 | ;; Tuples and Pairs retain their count during shrinking | |
312 | ;; --------------------------------------------------------------------------- | |
313 | ||
314 | (defn n-int-generators | |
315 | [n] | |
316 | (vec (repeat n gen/int))) | |
317 | ||
318 | (def tuples | |
319 | [(apply gen/tuple (n-int-generators 1)) | |
320 | (apply gen/tuple (n-int-generators 2)) | |
321 | (apply gen/tuple (n-int-generators 3)) | |
322 | (apply gen/tuple (n-int-generators 4)) | |
323 | (apply gen/tuple (n-int-generators 5)) | |
324 | (apply gen/tuple (n-int-generators 6))]) | |
325 | ||
326 | (defn get-tuple-gen | |
327 | [index] | |
328 | (nth tuples (dec index))) | |
329 | ||
330 | (defn inner-tuple-property | |
331 | [size] | |
332 | (prop/for-all [t (get-tuple-gen size)] | |
333 | false)) | |
334 | ||
335 | (defspec tuples-retain-size-during-shrinking 1000 | |
336 | (prop/for-all [index (gen/choose 1 6)] | |
337 | (let [result (tc/quick-check | |
338 | 100 (inner-tuple-property index))] | |
339 | (= index (count (-> result | |
340 | :shrunk :smallest first)))))) | |
341 | ||
342 | ;; Bind works | |
343 | ;; --------------------------------------------------------------------------- | |
344 | ||
345 | (def nat-vec | |
346 | (gen/such-that not-empty | |
347 | (gen/vector gen/nat))) | |
348 | ||
349 | (def vec-and-elem | |
350 | (gen/bind nat-vec | |
351 | (fn [v] | |
352 | (gen/tuple (gen/elements v) (gen/return v))))) | |
353 | ||
354 | (defspec element-is-in-vec 100 | |
355 | (prop/for-all [[element coll] vec-and-elem] | |
356 | (some #{element} coll))) | |
357 | ||
358 | ;; fmap is respected during shrinking | |
359 | ;; --------------------------------------------------------------------------- | |
360 | ||
361 | (def plus-fifty | |
362 | (gen/fmap (partial + 50) gen/nat)) | |
363 | ||
364 | (deftest f-map-respected-during-shrinking | |
365 | (testing | |
366 | "Generators created fmap should have that function applied | |
367 | during shrinking" | |
368 | (is (= [50] | |
369 | (let [result (tc/quick-check 100 | |
370 | (prop/for-all | |
371 | [a plus-fifty] | |
372 | false))] | |
373 | (-> result :shrunk :smallest)))))) | |
374 | ||
375 | ;; edn rountrips | |
376 | ;; --------------------------------------------------------------------------- | |
377 | ||
378 | ;; TODO: EDN round trips sometimes fail - David | |
379 | ||
380 | (defn edn-roundtrip? | |
381 | [value] | |
382 | (= value (-> value prn-str edn/read-string))) | |
383 | ||
384 | (defspec edn-roundtrips 50 | |
385 | (prop/for-all [a gen/any] | |
386 | (edn-roundtrip? a))) | |
387 | ||
388 | ;; not-empty works | |
389 | ;; --------------------------------------------------------------------------- | |
390 | ||
391 | (defspec not-empty-works 100 | |
392 | (prop/for-all [v (gen/not-empty (gen/vector gen/boolean))] | |
393 | (not-empty v))) | |
394 | ||
395 | ;; no-shrink works | |
396 | ;; --------------------------------------------------------------------------- | |
397 | ||
398 | (defn run-no-shrink | |
399 | [i] | |
400 | (tc/quick-check 100 | |
401 | (prop/for-all [coll (gen/vector gen/nat)] | |
402 | (some #{i} coll)))) | |
403 | ||
404 | (defspec no-shrink-works 100 | |
405 | (prop/for-all [i gen/nat] | |
406 | (let [result (run-no-shrink i)] | |
407 | (if (:result result) | |
408 | true | |
409 | (= (:fail result) | |
410 | (-> result :shrunk :smallest)))))) | |
411 | ||
412 | ;; elements works with a variety of input | |
413 | ;; --------------------------------------------------------------------------- | |
414 | ||
415 | (deftest elements-with-empty | |
416 | (is (thrown? js/Error (gen/elements ())))) | |
417 | ||
418 | (defspec elements-with-a-set 100 | |
419 | (prop/for-all [num (gen/elements #{9 10 11 12})] | |
420 | (<= 9 num 12))) | |
421 | ||
422 | ||
423 | ;; choose respects bounds during shrinking | |
424 | ;; --------------------------------------------------------------------------- | |
425 | ||
426 | (def range-gen | |
427 | (gen/fmap (fn [[a b]] | |
428 | [(min a b) (max a b)]) | |
429 | (gen/tuple gen/int gen/int))) | |
430 | ||
431 | (defspec choose-respects-bounds-during-shrinking 100 | |
432 | (prop/for-all [[mini maxi] range-gen | |
433 | random-seed gen/nat | |
434 | size gen/nat] | |
435 | (let [tree (gen/call-gen | |
436 | (gen/choose mini maxi) | |
437 | (random/make-random random-seed) | |
438 | size)] | |
439 | (every? | |
440 | #(and (<= mini %) (>= maxi %)) | |
441 | (rose/seq tree))))) | |
442 | ||
443 | ;; rand-range copes with full range of longs as bounds | |
444 | ;; --------------------------------------------------------------------------- | |
445 | ||
446 | ;; NOTE: need to adjust for JS numerics - David | |
447 | ||
448 | ;; (deftest rand-range-copes-with-full-range-of-longs | |
449 | ;; (let [[low high] (reduce | |
450 | ;; (fn [[low high :as margins] x] | |
451 | ;; (cond | |
452 | ;; (< x low) [x high] | |
453 | ;; (> x high) [low x] | |
454 | ;; :else margins)) | |
455 | ;; [Long/MAX_VALUE Long/MIN_VALUE] | |
456 | ;; ; choose uses rand-range directly, reasonable proxy for its | |
457 | ;; ; guarantees | |
458 | ;; (take 1e6 (gen/sample-seq (gen/choose Long/MIN_VALUE Long/MAX_VALUE))))] | |
459 | ;; (is (< low high)) | |
460 | ;; (is (< low Integer/MIN_VALUE)) | |
461 | ;; (is (> high Integer/MAX_VALUE)))) | |
462 | ||
463 | ;; rand-range yields values inclusive of both lower & upper bounds provided to it | |
464 | ;; further, that generators that use rand-range use its full range of values | |
465 | ;; --------------------------------------------------------------------------- | |
466 | ||
467 | (deftest rand-range-uses-inclusive-bounds | |
468 | (let [bounds [5 7] | |
469 | rand-range (fn [r] (apply gen/rand-range r bounds))] | |
470 | (loop [trials 0 | |
471 | bounds (set bounds) | |
472 | r (random/make-random)] | |
473 | (cond | |
474 | (== trials 10000) | |
475 | (is nil (str "rand-range didn't return both of its bounds after 10000 trials; " | |
476 | "it is possible for this to fail without there being a problem, " | |
477 | "but we should be able to rely upon probability to not bother us " | |
478 | "too frequently.")) | |
479 | (empty? bounds) (is true) | |
480 | :else (let [[r1 r2] (random/split r)] | |
481 | (recur (inc trials) (disj bounds (rand-range r1)) r2)))))) | |
482 | ||
483 | (deftest elements-generates-all-provided-values | |
484 | (let [options [:a 42 'c/d "foo"]] | |
485 | (is (->> (reductions | |
486 | disj | |
487 | (set options) | |
488 | (gen/sample-seq (gen/elements options))) | |
489 | (take 10000) | |
490 | (some empty?)) | |
491 | (str "elements didn't return all of its candidate values after 10000 trials; " | |
492 | "it is possible for this to fail without there being a problem, " | |
493 | "but we should be able to rely upon probability to not bother us " | |
494 | "too frequently.")))) | |
495 | ||
496 | ;; shuffling a vector generates a permutation of that vector | |
497 | ;; --------------------------------------------------------------------------- | |
498 | ||
499 | (def original-vector-and-permutation | |
500 | (gen/bind (gen/vector gen/int) | |
501 | #(gen/tuple (gen/return %) (gen/shuffle %)))) | |
502 | ||
503 | (defspec shuffled-vector-is-a-permutation-of-original 100 | |
504 | (prop/for-all [[coll permutation] original-vector-and-permutation] | |
505 | (= (sort coll) (sort permutation)))) | |
506 | ||
507 | ;; vector can generate large vectors; regression for TCHECK-49 | |
508 | ;; --------------------------------------------------------------------------- | |
509 | ||
510 | (deftest large-vector-test | |
511 | (is (= 100000 | |
512 | (count (first (gen/sample | |
513 | (gen/vector gen/nat 100000) | |
514 | 1)))))) | |
515 | ||
516 | ;; scale controls growth rate of generators | |
517 | ;; --------------------------------------------------------------------------- | |
518 | ||
519 | (deftest scale-test | |
520 | (let [g (gen/scale (partial min 10) gen/pos-int) ;; should limit size to 10 | |
521 | samples (gen/sample g 1000)] | |
522 | (is (every? (partial >= 11) samples)) | |
523 | (is (some (partial = 10) samples)))) | |
524 | ||
525 | ;; generator dev helpers | |
526 | ;; --------------------------------------------------------------------------- | |
527 | ||
528 | (deftest generate-test | |
529 | (is (string? (gen/generate gen/string))) | |
530 | (is (string? (gen/generate gen/string 42)))) | |
531 | ||
532 | ;; defspec macro | |
533 | ;; --------------------------------------------------------------------------- | |
534 | ||
535 | (defspec run-only-once 1 (prop/for-all* [gen/int] (constantly true))) | |
536 | ||
537 | (defspec run-default-times (prop/for-all* [gen/int] (constantly true))) | |
538 | ||
539 | (defspec run-with-map1 {:num-tests 1} (prop/for-all* [gen/int] (constantly true))) | |
540 | ||
541 | (defspec run-with-map {:num-tests 1 | |
542 | :seed 1} | |
543 | (prop/for-all [a gen/int] | |
544 | (= a 0))) | |
545 | ||
546 | (def my-defspec-options {:num-tests 1 :seed 1}) | |
547 | ||
548 | (defspec run-with-symbolic-options my-defspec-options | |
549 | (prop/for-all [a gen/int] | |
550 | (= a 0))) | |
551 | ||
552 | (defspec run-with-no-options | |
553 | (prop/for-all [a gen/int] | |
554 | (integer? a))) |
0 | ; Copyright (c) Rich Hickey, Reid Draper, and contributors. | |
1 | ; All rights reserved. | |
2 | ; The use and distribution terms for this software are covered by the | |
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
4 | ; which can be found in the file epl-v10.html at the root of this distribution. | |
5 | ; By using this software in any fashion, you are agreeing to be bound by | |
6 | ; the terms of this license. | |
7 | ; You must not remove this notice, or any other, from this software. | |
8 | ||
9 | (ns clojure.test.check.clojure-test-test | |
10 | (:require [cljs.test :as test :refer [test-var] :refer-macros [is]] | |
11 | [clojure.test.check.generators :as gen] | |
12 | [clojure.test.check.properties :as prop :include-macros true] | |
13 | [clojure.test.check.clojure-test :as ct :refer-macros [defspec]] | |
14 | [cljs.reader :refer [read-string]])) | |
15 | ||
16 | (defspec default-trial-counts | |
17 | (prop/for-all* [gen/int] (constantly true))) | |
18 | ||
19 | (defspec trial-counts 5000 | |
20 | (prop/for-all* [gen/int] (constantly true))) | |
21 | ||
22 | ;; NOTE: No Thread/sleep in JS - David | |
23 | ;; (defspec long-running-spec 1000 | |
24 | ;; (prop/for-all* [] #(do (Thread/sleep 1) true))) | |
25 | ||
26 | (defn- vector-elements-are-unique* | |
27 | [v] | |
28 | (== (count v) (count (distinct v)))) | |
29 | ||
30 | (def ^:private vector-elements-are-unique | |
31 | (prop/for-all* | |
32 | [(gen/vector gen/int)] | |
33 | vector-elements-are-unique*)) | |
34 | ||
35 | (defspec this-is-supposed-to-fail 100 vector-elements-are-unique) | |
36 | ||
37 | (defn- capture-test-var | |
38 | [v] | |
39 | (doto (with-out-str (test-var v)) | |
40 | print)) | |
41 | ||
42 | (defn test-ns-hook | |
43 | [] | |
44 | (let [out-str (capture-test-var #'default-trial-counts) | |
45 | num-tests (-> out-str | |
46 | read-string | |
47 | :num-tests)] | |
48 | (is (= num-tests ct/*default-test-count*))) | |
49 | ||
50 | (is (-> (capture-test-var #'trial-counts) | |
51 | read-string | |
52 | (select-keys [:test-var :result :num-tests]) | |
53 | (= {:test-var "trial-counts", :result true, :num-tests 5000}))) | |
54 | ||
55 | (binding [ct/*report-trials* true] | |
56 | (let [output (capture-test-var #'trial-counts)] | |
57 | (is (re-matches #"\.{5}[\s\S]+" output)))) | |
58 | ||
59 | ;; NOTE: No Thread/sleep in JS - David | |
60 | ;; (binding [ct/*report-trials* ct/trial-report-periodic | |
61 | ;; ct/*trial-report-period* 500] | |
62 | ;; (is (re-seq | |
63 | ;; #"(Passing trial \d{3} / 1000 for .+\n)+" | |
64 | ;; (capture-test-var #'long-running-spec)))) | |
65 | ||
66 | (let [[report-counters report-str] | |
67 | (binding [ct/*report-shrinking* true] | |
68 | ;; need to keep the failure of this-is-supposed-to-fail from | |
69 | ;; affecting the clojure.test.check test run | |
70 | (let [restore-env (test/get-current-env) | |
71 | _ (test/set-env! (test/empty-env)) | |
72 | report-str (capture-test-var #'this-is-supposed-to-fail) | |
73 | env (test/get-current-env)] | |
74 | (test/set-env! restore-env) | |
75 | [(:report-counters env) report-str]))] | |
76 | (is (== 1 (:fail report-counters))) | |
77 | (is (re-seq | |
78 | #"Shrinking vector-elements-are-unique starting with parameters \[\[[\s\S]+" | |
79 | report-str)))) | |
80 |
0 | (ns clojure.test.check.random-test | |
1 | "Testing that the cljs impl matches the clojure impl." | |
2 | (:require [cljs.test :refer-macros [deftest is]] | |
3 | [clojure.test.check.random :as random])) | |
4 | ||
5 | (deftest longs-test | |
6 | ||
7 | ;; comparing with this code run on clj-jvm: | |
8 | (comment | |
9 | (-> 42 | |
10 | (random/make-java-util-splittable-random) | |
11 | (random/split-n 17) | |
12 | (->> (mapcat random/split) | |
13 | (map random/rand-long) | |
14 | (reduce bit-xor)) | |
15 | (str)) | |
16 | => | |
17 | "5298131359241775269") | |
18 | ||
19 | (is (= "5298131359241775269" | |
20 | (-> 42 | |
21 | (random/make-java-util-splittable-random) | |
22 | (random/split-n 17) | |
23 | (->> (mapcat random/split) | |
24 | (map random/rand-long) | |
25 | (reduce #(.xor %1 %2))) | |
26 | (str))))) | |
27 | ||
28 | (deftest doubles-test | |
29 | ||
30 | ;; comparing with this code run on clj-jvm: | |
31 | (comment | |
32 | ||
33 | (-> -42 | |
34 | (random/make-java-util-splittable-random) | |
35 | (random/split-n 17) | |
36 | (->> (mapcat random/split) | |
37 | (map random/rand-double) | |
38 | (reduce +)) | |
39 | (str)) | |
40 | => | |
41 | "17.39141655134964") | |
42 | ||
43 | (is (= "17.39141655134964" | |
44 | (-> -42 | |
45 | (random/make-java-util-splittable-random) | |
46 | (random/split-n 17) | |
47 | (->> (mapcat random/split) | |
48 | (map random/rand-double) | |
49 | (reduce +)) | |
50 | (str))))) | |
51 | ||
52 | (deftest auto-seeding-test | |
53 | (is (distinct? (random/rand-double (random/make-random)) | |
54 | (random/rand-double (random/make-random)) | |
55 | (random/rand-double (random/make-random)) | |
56 | (random/rand-double (random/make-random))) | |
57 | "Each call to make-random should return a different RNG.")) |
0 | ; Copyright (c) Rich Hickey, Reid Draper, and contributors. | |
1 | ; All rights reserved. | |
2 | ; The use and distribution terms for this software are covered by the | |
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
4 | ; which can be found in the file epl-v10.html at the root of this distribution. | |
5 | ; By using this software in any fashion, you are agreeing to be bound by | |
6 | ; the terms of this license. | |
7 | ; You must not remove this notice, or any other, from this software. | |
8 | ||
9 | (ns clojure.test.check.rose-tree-test | |
10 | (:require [cljs.test :as test :include-macros true] | |
11 | [clojure.test.check :as tc] | |
12 | [clojure.test.check.generators :as gen] | |
13 | [clojure.test.check.properties :as prop :include-macros true] | |
14 | [clojure.test.check.rose-tree :as rose] | |
15 | [clojure.test.check.clojure-test :as ct :refer-macros [defspec]])) | |
16 | ||
17 | (defn depth-one-children | |
18 | [rose] | |
19 | (into [] (map rose/root (rose/children rose)))) | |
20 | ||
21 | (defn depth-one-and-two-children | |
22 | [rose] | |
23 | (let [the-children (rose/children rose)] | |
24 | (into [] | |
25 | (concat | |
26 | (map rose/root the-children) | |
27 | (map rose/root (mapcat rose/children the-children)))))) | |
28 | ||
29 | (defspec test-collapse-rose | |
30 | 100 | |
31 | (prop/for-all [i gen/int] | |
32 | (let [tree (gen/int-rose-tree i)] | |
33 | (= (depth-one-and-two-children tree) | |
34 | (depth-one-children (rose/collapse tree)))))) |
0 | (ns clojure.test.check.test | |
1 | (:require [cljs.test :as test :refer-macros [deftest testing is]] | |
2 | [clojure.test.check :as tc] | |
3 | [clojure.test.check.generators :as gen] | |
4 | [clojure.test.check.properties :as prop :include-macros true] | |
5 | [clojure.test.check.random :as random] | |
6 | [clojure.test.check.rose-tree :as rose] | |
7 | [clojure.test.check.clojure-test :as ct :refer-macros [defspec]] | |
8 | [cljs.reader :as edn])) | |
9 | ||
10 | (deftest generators-are-generators | |
11 | (testing "generator? returns true when called with a generator" | |
12 | (is (gen/generator? gen/int)) | |
13 | (is (gen/generator? (gen/vector gen/int))) | |
14 | (is (gen/generator? (gen/return 5))))) | |
15 | ||
16 | ||
17 | (deftest values-are-not-generators | |
18 | (testing "generator? returns false when called with a value" | |
19 | (is (not (gen/generator? 5))) | |
20 | (is (not (gen/generator? int))) | |
21 | (is (not (gen/generator? [1 2 3]))))) | |
22 | ||
23 | ;; plus and 0 form a monoid | |
24 | ;; --------------------------------------------------------------------------- | |
25 | ||
26 | (defn passes-monoid-properties | |
27 | [a b c] | |
28 | (and | |
29 | (= (+ 0 a) a) | |
30 | (= (+ a 0) a) | |
31 | (= (+ a (+ b c)) (+ (+ a b) c)))) | |
32 | ||
33 | (deftest plus-and-0-are-a-monoid | |
34 | (testing "+ and 0 form a monoid" | |
35 | (is | |
36 | (let [p (prop/for-all* [gen/int gen/int gen/int] | |
37 | passes-monoid-properties)] | |
38 | (:result (tc/quick-check 1000 p))))) | |
39 | ;; NOTE: no ratios in ClojureScript - David | |
40 | ;; (testing "with ratios as well" | |
41 | ;; (is | |
42 | ;; (let [p (prop/for-all* [gen/ratio gen/ratio gen/ratio] | |
43 | ;; passes-monoid-properties)] | |
44 | ;; (:result (tc/quick-check 1000 p))))) | |
45 | ) | |
46 | ||
47 | ;; reverse | |
48 | ;; --------------------------------------------------------------------------- | |
49 | ||
50 | (defn reverse-equal?-helper | |
51 | [l] | |
52 | (let [r (vec (reverse l))] | |
53 | (and (= (count l) (count r)) | |
54 | (= (seq l) (rseq r))))) | |
55 | ||
56 | (deftest reverse-equal? | |
57 | (testing "For all vectors L, reverse(reverse(L)) == L" | |
58 | (is (let [p (prop/for-all* [(gen/vector gen/int)] reverse-equal?-helper)] | |
59 | (:result (tc/quick-check 1000 p)))))) | |
60 | ||
61 | ;; failing reverse | |
62 | ;; --------------------------------------------------------------------------- | |
63 | ||
64 | (deftest bad-reverse-test | |
65 | (testing "For all vectors L, L == reverse(L). Not true" | |
66 | (is (false? | |
67 | (let [p (prop/for-all* [(gen/vector gen/int)] #(= (reverse %) %))] | |
68 | (:result (tc/quick-check 1000 p))))))) | |
69 | ||
70 | ;; failing element remove | |
71 | ;; --------------------------------------------------------------------------- | |
72 | ||
73 | (defn first-is-gone | |
74 | [l] | |
75 | (not (some #{(first l)} (vec (rest l))))) | |
76 | ||
77 | (deftest bad-remove | |
78 | (testing "For all vectors L, if we remove the first element E, E should not | |
79 | longer be in the list. (This is a false assumption)" | |
80 | (is (false? | |
81 | (let [p (prop/for-all* [(gen/vector gen/int)] first-is-gone)] | |
82 | (:result (tc/quick-check 1000 p))))))) | |
83 | ||
84 | ;; exceptions shrink and return as result | |
85 | ;; --------------------------------------------------------------------------- | |
86 | ||
87 | (def exception (js/Error. "I get caught")) | |
88 | ||
89 | (defn exception-thrower | |
90 | [& args] | |
91 | (throw exception)) | |
92 | ||
93 | (deftest exceptions-are-caught | |
94 | (testing "Exceptions during testing are caught. They're also shrunk as long | |
95 | as they continue to throw." | |
96 | (is (= [exception [0]] | |
97 | (let [result | |
98 | (tc/quick-check | |
99 | 1000 (prop/for-all* [gen/int] exception-thrower))] | |
100 | [(:result result) (get-in result [:shrunk :smallest])]))))) | |
101 | ||
102 | ;; Count and concat work as expected | |
103 | ;; --------------------------------------------------------------------------- | |
104 | ||
105 | (defn concat-counts-correct | |
106 | [a b] | |
107 | (= (count (concat a b)) | |
108 | (+ (count a) (count b)))) | |
109 | ||
110 | (deftest count-and-concat | |
111 | (testing "For all vectors A and B: | |
112 | length(A + B) == length(A) + length(B)" | |
113 | (is (:result | |
114 | (let [p (prop/for-all* [(gen/vector gen/int) | |
115 | (gen/vector gen/int)] concat-counts-correct)] | |
116 | (tc/quick-check 1000 p)))))) | |
117 | ||
118 | ;; Interpose (Count) | |
119 | ;; --------------------------------------------------------------------------- | |
120 | ||
121 | (defn interpose-twice-the-length ;; (or one less) | |
122 | [v] | |
123 | (let [interpose-count (count (interpose :i v)) | |
124 | original-count (count v)] | |
125 | (or | |
126 | (= (* 2 original-count) interpose-count) | |
127 | (= (dec (* 2 original-count)) interpose-count)))) | |
128 | ||
129 | ||
130 | (deftest interpose-creates-sequence-twice-the-length | |
131 | (testing | |
132 | "Interposing a collection with a value makes its count | |
133 | twice the original collection, or ones less." | |
134 | (is (:result | |
135 | (tc/quick-check 1000 (prop/for-all [v (gen/vector gen/int)] (interpose-twice-the-length v))))))) | |
136 | ||
137 | ;; Lists and vectors are equivalent with seq abstraction | |
138 | ;; --------------------------------------------------------------------------- | |
139 | ||
140 | (defn list-vector-round-trip-equiv | |
141 | [a] | |
142 | ;; NOTE: can't use `(into '() ...)` here because that | |
143 | ;; puts the list in reverse order. clojure.test.check found that bug | |
144 | ;; pretty quickly... | |
145 | (= a (apply list (vec a)))) | |
146 | ||
147 | (deftest list-and-vector-round-trip | |
148 | (testing | |
149 | "" | |
150 | (is (:result | |
151 | (tc/quick-check | |
152 | 1000 (prop/for-all* | |
153 | [(gen/list gen/int)] list-vector-round-trip-equiv)))))) | |
154 | ||
155 | ;; keyword->string->keyword roundtrip | |
156 | ;; --------------------------------------------------------------------------- | |
157 | ||
158 | (defn keyword-string-roundtrip-equiv | |
159 | [k] | |
160 | (= k (keyword (name k)))) | |
161 | ||
162 | ;; NOTE: this is one of the slowest due to how keywords are constructed | |
163 | ;; drop N to 200 - David | |
164 | (deftest keyword-string-roundtrip | |
165 | (testing | |
166 | "For all keywords, turning them into a string and back is equivalent | |
167 | to the original string (save for the `:` bit)" | |
168 | (is (:result | |
169 | (tc/quick-check 100 (prop/for-all* | |
170 | [gen/keyword] keyword-string-roundtrip-equiv) | |
171 | :max-size 25))))) | |
172 | ||
173 | ;; Boolean and/or | |
174 | ;; --------------------------------------------------------------------------- | |
175 | ||
176 | (deftest boolean-or | |
177 | (testing | |
178 | "`or` with true and anything else should be true" | |
179 | (is (:result (tc/quick-check | |
180 | 1000 (prop/for-all* | |
181 | [gen/boolean] #(or % true))))))) | |
182 | ||
183 | (deftest boolean-and | |
184 | (testing | |
185 | "`and` with false and anything else should be false" | |
186 | (is (:result (tc/quick-check | |
187 | 1000 (prop/for-all* | |
188 | [gen/boolean] #(not (and % false)))))))) | |
189 | ||
190 | ;; Sorting | |
191 | ;; --------------------------------------------------------------------------- | |
192 | ||
193 | (defn elements-are-in-order-after-sorting | |
194 | [v] | |
195 | (every? identity (map <= (partition 2 1 (sort v))))) | |
196 | ||
197 | (deftest sorting | |
198 | (testing | |
199 | "For all vectors V, sorted(V) should have the elements in order" | |
200 | (is (:result | |
201 | (tc/quick-check | |
202 | 1000 | |
203 | (prop/for-all* | |
204 | [(gen/vector gen/int)] elements-are-in-order-after-sorting)))))) | |
205 | ||
206 | ;; Constant generators | |
207 | ;; --------------------------------------------------------------------------- | |
208 | ||
209 | ;; A constant generator always returns its created value | |
210 | (defspec constant-generators 100 | |
211 | (prop/for-all [a (gen/return 42)] | |
212 | (print "") | |
213 | (= a 42))) | |
214 | ||
215 | (deftest constant-generators-dont-shrink | |
216 | (testing "Generators created with `gen/return` should not shrink" | |
217 | (is (= [42] | |
218 | (let [result (tc/quick-check 100 | |
219 | (prop/for-all | |
220 | [a (gen/return 42)] | |
221 | false))] | |
222 | (-> result :shrunk :smallest)))))) | |
223 | ||
224 | ;; Tests are deterministic | |
225 | ;; --------------------------------------------------------------------------- | |
226 | ||
227 | (defn vector-elements-are-unique | |
228 | [v] | |
229 | (== (count v) (count (distinct v)))) | |
230 | ||
231 | (defn unique-test | |
232 | [seed] | |
233 | (tc/quick-check 1000 | |
234 | (prop/for-all* | |
235 | [(gen/vector gen/int)] vector-elements-are-unique) | |
236 | :seed seed)) | |
237 | ||
238 | (defn equiv-runs | |
239 | [seed] | |
240 | (= (unique-test seed) (unique-test seed))) | |
241 | ||
242 | (deftest tests-are-deterministic | |
243 | (testing "If two runs are started with the same seed, they should | |
244 | return the same results." | |
245 | (is (:result | |
246 | (tc/quick-check 1000 (prop/for-all* [gen/int] equiv-runs)))))) | |
247 | ||
248 | ;; Generating basic generators | |
249 | ;; -------------------------------------------------------------------------- | |
250 | ||
251 | (deftest generators-test | |
252 | (let [t (fn [generator pred] | |
253 | (is (:result (tc/quick-check 100 | |
254 | (prop/for-all [x generator] | |
255 | (pred x))))))] | |
256 | ||
257 | (testing "keyword" (t gen/keyword keyword?)) | |
258 | ;; (testing "ratio" (t gen/ratio clojure.lang.Ratio)) | |
259 | ;; (testing "byte" (t gen/byte Byte)) | |
260 | ;; (testing "bytes" (t gen/bytes (Class/forName "[B"))) | |
261 | ||
262 | (testing "char" (t gen/char string?)) | |
263 | (testing "char-ascii" (t gen/char-ascii string?)) | |
264 | (testing "char-alphanumeric" (t gen/char-alphanumeric string?)) | |
265 | (testing "string" (t gen/string string?)) | |
266 | (testing "string-ascii" (t gen/string-ascii string?)) | |
267 | (testing "string-alphanumeric" (t gen/string-alphanumeric string?)) | |
268 | ||
269 | (testing "vector" (t (gen/vector gen/int) vector?)) | |
270 | (testing "list" (t (gen/list gen/int) list?)) | |
271 | (testing "map" (t (gen/map gen/int gen/int) map?)) | |
272 | )) | |
273 | ||
274 | ;; Generating proper matrices | |
275 | ;; --------------------------------------------------------------------------- | |
276 | ||
277 | (defn proper-matrix? | |
278 | "Check if provided nested vectors form a proper matrix — that is, all nested | |
279 | vectors have the same length" | |
280 | [mtx] | |
281 | (let [first-size (count (first mtx))] | |
282 | (every? (partial = first-size) (map count (rest mtx))))) | |
283 | ||
284 | (deftest proper-matrix-test | |
285 | (testing | |
286 | "can generate proper matrices" | |
287 | (is (:result (tc/quick-check | |
288 | 100 (prop/for-all | |
289 | [mtx (gen/vector (gen/vector gen/int 3) 3)] | |
290 | (proper-matrix? mtx))))))) | |
291 | ||
292 | (def bounds-and-vector | |
293 | (gen/bind (gen/tuple gen/s-pos-int gen/s-pos-int) | |
294 | (fn [[a b]] | |
295 | (let [minimum (min a b) | |
296 | maximum (max a b)] | |
297 | (gen/tuple (gen/return [minimum maximum]) | |
298 | (gen/vector gen/int minimum maximum)))))) | |
299 | ||
300 | (deftest proper-vector-test | |
301 | (testing | |
302 | "can generate vectors with sizes in a provided range" | |
303 | (is (:result (tc/quick-check | |
304 | 100 (prop/for-all | |
305 | [b-and-v bounds-and-vector] | |
306 | (let [[[minimum maximum] v] b-and-v | |
307 | c (count v)] | |
308 | (and (<= c maximum) | |
309 | (>= c minimum))))))))) | |
310 | ||
311 | ;; Tuples and Pairs retain their count during shrinking | |
312 | ;; --------------------------------------------------------------------------- | |
313 | ||
314 | (defn n-int-generators | |
315 | [n] | |
316 | (vec (repeat n gen/int))) | |
317 | ||
318 | (def tuples | |
319 | [(apply gen/tuple (n-int-generators 1)) | |
320 | (apply gen/tuple (n-int-generators 2)) | |
321 | (apply gen/tuple (n-int-generators 3)) | |
322 | (apply gen/tuple (n-int-generators 4)) | |
323 | (apply gen/tuple (n-int-generators 5)) | |
324 | (apply gen/tuple (n-int-generators 6))]) | |
325 | ||
326 | (defn get-tuple-gen | |
327 | [index] | |
328 | (nth tuples (dec index))) | |
329 | ||
330 | (defn inner-tuple-property | |
331 | [size] | |
332 | (prop/for-all [t (get-tuple-gen size)] | |
333 | false)) | |
334 | ||
335 | (defspec tuples-retain-size-during-shrinking 1000 | |
336 | (prop/for-all [index (gen/choose 1 6)] | |
337 | (let [result (tc/quick-check | |
338 | 100 (inner-tuple-property index))] | |
339 | (= index (count (-> result | |
340 | :shrunk :smallest first)))))) | |
341 | ||
342 | ;; Bind works | |
343 | ;; --------------------------------------------------------------------------- | |
344 | ||
345 | (def nat-vec | |
346 | (gen/such-that not-empty | |
347 | (gen/vector gen/nat))) | |
348 | ||
349 | (def vec-and-elem | |
350 | (gen/bind nat-vec | |
351 | (fn [v] | |
352 | (gen/tuple (gen/elements v) (gen/return v))))) | |
353 | ||
354 | (defspec element-is-in-vec 100 | |
355 | (prop/for-all [[element coll] vec-and-elem] | |
356 | (some #{element} coll))) | |
357 | ||
358 | ;; fmap is respected during shrinking | |
359 | ;; --------------------------------------------------------------------------- | |
360 | ||
361 | (def plus-fifty | |
362 | (gen/fmap (partial + 50) gen/nat)) | |
363 | ||
364 | (deftest f-map-respected-during-shrinking | |
365 | (testing | |
366 | "Generators created fmap should have that function applied | |
367 | during shrinking" | |
368 | (is (= [50] | |
369 | (let [result (tc/quick-check 100 | |
370 | (prop/for-all | |
371 | [a plus-fifty] | |
372 | false))] | |
373 | (-> result :shrunk :smallest)))))) | |
374 | ||
375 | ;; edn rountrips | |
376 | ;; --------------------------------------------------------------------------- | |
377 | ||
378 | ;; TODO: EDN round trips sometimes fail - David | |
379 | ||
380 | (defn edn-roundtrip? | |
381 | [value] | |
382 | (= value (-> value prn-str edn/read-string))) | |
383 | ||
384 | (defspec edn-roundtrips 50 | |
385 | (prop/for-all [a gen/any] | |
386 | (edn-roundtrip? a))) | |
387 | ||
388 | ;; not-empty works | |
389 | ;; --------------------------------------------------------------------------- | |
390 | ||
391 | (defspec not-empty-works 100 | |
392 | (prop/for-all [v (gen/not-empty (gen/vector gen/boolean))] | |
393 | (not-empty v))) | |
394 | ||
395 | ;; no-shrink works | |
396 | ;; --------------------------------------------------------------------------- | |
397 | ||
398 | (defn run-no-shrink | |
399 | [i] | |
400 | (tc/quick-check 100 | |
401 | (prop/for-all [coll (gen/vector gen/nat)] | |
402 | (some #{i} coll)))) | |
403 | ||
404 | (defspec no-shrink-works 100 | |
405 | (prop/for-all [i gen/nat] | |
406 | (let [result (run-no-shrink i)] | |
407 | (if (:result result) | |
408 | true | |
409 | (= (:fail result) | |
410 | (-> result :shrunk :smallest)))))) | |
411 | ||
412 | ;; elements works with a variety of input | |
413 | ;; --------------------------------------------------------------------------- | |
414 | ||
415 | (deftest elements-with-empty | |
416 | (is (thrown? js/Error (gen/elements ())))) | |
417 | ||
418 | (defspec elements-with-a-set 100 | |
419 | (prop/for-all [num (gen/elements #{9 10 11 12})] | |
420 | (<= 9 num 12))) | |
421 | ||
422 | ||
423 | ;; choose respects bounds during shrinking | |
424 | ;; --------------------------------------------------------------------------- | |
425 | ||
426 | (def range-gen | |
427 | (gen/fmap (fn [[a b]] | |
428 | [(min a b) (max a b)]) | |
429 | (gen/tuple gen/int gen/int))) | |
430 | ||
431 | (defspec choose-respects-bounds-during-shrinking 100 | |
432 | (prop/for-all [[mini maxi] range-gen | |
433 | random-seed gen/nat | |
434 | size gen/nat] | |
435 | (let [tree (gen/call-gen | |
436 | (gen/choose mini maxi) | |
437 | (random/make-random random-seed) | |
438 | size)] | |
439 | (every? | |
440 | #(and (<= mini %) (>= maxi %)) | |
441 | (rose/seq tree))))) | |
442 | ||
443 | ;; rand-range copes with full range of longs as bounds | |
444 | ;; --------------------------------------------------------------------------- | |
445 | ||
446 | ;; NOTE: need to adjust for JS numerics - David | |
447 | ||
448 | ;; (deftest rand-range-copes-with-full-range-of-longs | |
449 | ;; (let [[low high] (reduce | |
450 | ;; (fn [[low high :as margins] x] | |
451 | ;; (cond | |
452 | ;; (< x low) [x high] | |
453 | ;; (> x high) [low x] | |
454 | ;; :else margins)) | |
455 | ;; [Long/MAX_VALUE Long/MIN_VALUE] | |
456 | ;; ; choose uses rand-range directly, reasonable proxy for its | |
457 | ;; ; guarantees | |
458 | ;; (take 1e6 (gen/sample-seq (gen/choose Long/MIN_VALUE Long/MAX_VALUE))))] | |
459 | ;; (is (< low high)) | |
460 | ;; (is (< low Integer/MIN_VALUE)) | |
461 | ;; (is (> high Integer/MAX_VALUE)))) | |
462 | ||
463 | ;; rand-range yields values inclusive of both lower & upper bounds provided to it | |
464 | ;; further, that generators that use rand-range use its full range of values | |
465 | ;; --------------------------------------------------------------------------- | |
466 | ||
467 | (deftest rand-range-uses-inclusive-bounds | |
468 | (let [bounds [5 7] | |
469 | rand-range (fn [r] (apply gen/rand-range r bounds))] | |
470 | (loop [trials 0 | |
471 | bounds (set bounds) | |
472 | r (random/make-random)] | |
473 | (cond | |
474 | (== trials 10000) | |
475 | (is nil (str "rand-range didn't return both of its bounds after 10000 trials; " | |
476 | "it is possible for this to fail without there being a problem, " | |
477 | "but we should be able to rely upon probability to not bother us " | |
478 | "too frequently.")) | |
479 | (empty? bounds) (is true) | |
480 | :else (let [[r1 r2] (random/split r)] | |
481 | (recur (inc trials) (disj bounds (rand-range r1)) r2)))))) | |
482 | ||
483 | (deftest elements-generates-all-provided-values | |
484 | (let [options [:a 42 'c/d "foo"]] | |
485 | (is (->> (reductions | |
486 | disj | |
487 | (set options) | |
488 | (gen/sample-seq (gen/elements options))) | |
489 | (take 10000) | |
490 | (some empty?)) | |
491 | (str "elements didn't return all of its candidate values after 10000 trials; " | |
492 | "it is possible for this to fail without there being a problem, " | |
493 | "but we should be able to rely upon probability to not bother us " | |
494 | "too frequently.")))) | |
495 | ||
496 | ;; shuffling a vector generates a permutation of that vector | |
497 | ;; --------------------------------------------------------------------------- | |
498 | ||
499 | (def original-vector-and-permutation | |
500 | (gen/bind (gen/vector gen/int) | |
501 | #(gen/tuple (gen/return %) (gen/shuffle %)))) | |
502 | ||
503 | (defspec shuffled-vector-is-a-permutation-of-original 100 | |
504 | (prop/for-all [[coll permutation] original-vector-and-permutation] | |
505 | (= (sort coll) (sort permutation)))) | |
506 | ||
507 | ;; vector can generate large vectors; regression for TCHECK-49 | |
508 | ;; --------------------------------------------------------------------------- | |
509 | ||
510 | (deftest large-vector-test | |
511 | (is (= 100000 | |
512 | (count (first (gen/sample | |
513 | (gen/vector gen/nat 100000) | |
514 | 1)))))) | |
515 | ||
516 | ;; scale controls growth rate of generators | |
517 | ;; --------------------------------------------------------------------------- | |
518 | ||
519 | (deftest scale-test | |
520 | (let [g (gen/scale (partial min 10) gen/pos-int) ;; should limit size to 10 | |
521 | samples (gen/sample g 1000)] | |
522 | (is (every? (partial >= 11) samples)) | |
523 | (is (some (partial = 10) samples)))) | |
524 | ||
525 | ;; generator dev helpers | |
526 | ;; --------------------------------------------------------------------------- | |
527 | ||
528 | (deftest generate-test | |
529 | (is (string? (gen/generate gen/string))) | |
530 | (is (string? (gen/generate gen/string 42)))) | |
531 | ||
532 | ;; defspec macro | |
533 | ;; --------------------------------------------------------------------------- | |
534 | ||
535 | (defspec run-only-once 1 (prop/for-all* [gen/int] (constantly true))) | |
536 | ||
537 | (defspec run-default-times (prop/for-all* [gen/int] (constantly true))) | |
538 | ||
539 | (defspec run-with-map1 {:num-tests 1} (prop/for-all* [gen/int] (constantly true))) | |
540 | ||
541 | (defspec run-with-map {:num-tests 1 | |
542 | :seed 1} | |
543 | (prop/for-all [a gen/int] | |
544 | (= a 0))) | |
545 | ||
546 | (def my-defspec-options {:num-tests 1 :seed 1}) | |
547 | ||
548 | (defspec run-with-symbolic-options my-defspec-options | |
549 | (prop/for-all [a gen/int] | |
550 | (= a 0))) | |
551 | ||
552 | (defspec run-with-no-options | |
553 | (prop/for-all [a gen/int] | |
554 | (integer? a))) |