Codebase list test-check-clojure / e946781
clojure_test_check_test.{[clj cljs] -> cljc} Nicolas Berger authored 8 years ago Gary Fredericks committed 8 years ago
3 changed file(s) with 645 addition(s) and 1175 deletion(s). Raw diff Collapse all Expand all
+0
-620
src/test/clojure/clojure/test/check/test.clj less more
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.test
10 (:use clojure.test)
11 (:require [clojure.test.check :as tc]
12 [clojure.test.check.generators :as gen]
13 [clojure.test.check.properties :as prop]
14 [clojure.test.check.rose-tree :as rose]
15 [clojure.test.check.random :as random]
16 [clojure.test.check.clojure-test :as ct :refer (defspec)]
17 [clojure.edn :as edn]))
18
19 (deftest generators-are-generators
20 (testing "generator? returns true when called with a generator"
21 (is (gen/generator? gen/int))
22 (is (gen/generator? (gen/vector gen/int)))
23 (is (gen/generator? (gen/return 5)))))
24
25 (deftest values-are-not-generators
26 (testing "generator? returns false when called with a value"
27 (is (not (gen/generator? 5)))
28 (is (not (gen/generator? int)))
29 (is (not (gen/generator? [1 2 3])))))
30
31 ;; plus and 0 form a monoid
32 ;; ---------------------------------------------------------------------------
33
34 (defn passes-monoid-properties
35 [a b c]
36 (and (= (+ 0 a) a)
37 (= (+ a 0) a)
38 (= (+ a (+ b c)) (+ (+ a b) c))))
39
40 (deftest plus-and-0-are-a-monoid
41 (testing "+ and 0 form a monoid"
42 (is (let [p (prop/for-all* [gen/int gen/int gen/int] passes-monoid-properties)]
43 (:result
44 (tc/quick-check 1000 p)))))
45 (testing "with ratios as well"
46 (is (let [p (prop/for-all* [gen/ratio gen/ratio gen/ratio] passes-monoid-properties)]
47 (:result
48 (tc/quick-check 1000 p))))))
49
50 ;; reverse
51 ;; ---------------------------------------------------------------------------
52
53 (defn reverse-equal?-helper
54 [l]
55 (let [r (vec (reverse l))]
56 (and (= (count l) (count r))
57 (= (seq l) (rseq r)))))
58
59 (deftest reverse-equal?
60 (testing "For all vectors L, reverse(reverse(L)) == L"
61 (is (let [p (prop/for-all* [(gen/vector gen/int)] reverse-equal?-helper)]
62 (:result (tc/quick-check 1000 p))))))
63
64 ;; failing reverse
65 ;; ---------------------------------------------------------------------------
66
67 (deftest bad-reverse-test
68 (testing "For all vectors L, L == reverse(L). Not true"
69 (is (false?
70 (let [p (prop/for-all* [(gen/vector gen/int)] #(= (reverse %) %))]
71 (:result (tc/quick-check 1000 p)))))))
72
73 ;; failing element remove
74 ;; ---------------------------------------------------------------------------
75
76 (defn first-is-gone
77 [l]
78 (not (some #{(first l)} (vec (rest l)))))
79
80 (deftest bad-remove
81 (testing "For all vectors L, if we remove the first element E, E should not
82 longer be in the list. (This is a false assumption)"
83 (is (false?
84 (let [p (prop/for-all* [(gen/vector gen/int)] first-is-gone)]
85 (:result (tc/quick-check 1000 p)))))))
86
87 ;; exceptions shrink and return as result
88 ;; ---------------------------------------------------------------------------
89
90 (def exception (Exception. "I get caught"))
91
92 (defn exception-thrower
93 [& args]
94 (throw exception))
95
96 (deftest exceptions-are-caught
97 (testing "Exceptions during testing are caught. They're also shrunk as long
98 as they continue to throw."
99 (is (= [exception [0]]
100 (let [result
101 (tc/quick-check
102 1000 (prop/for-all* [gen/int] exception-thrower))]
103 [(:result result) (get-in result [:shrunk :smallest])])))))
104
105 ;; Count and concat work as expected
106 ;; ---------------------------------------------------------------------------
107
108 (defn concat-counts-correct
109 [a b]
110 (= (count (concat a b))
111 (+ (count a) (count b))))
112
113 (deftest count-and-concat
114 (testing "For all vectors A and B:
115 length(A + B) == length(A) + length(B)"
116 (is (:result
117 (let [p (prop/for-all* [(gen/vector gen/int)
118 (gen/vector gen/int)] concat-counts-correct)]
119 (tc/quick-check 1000 p))))))
120
121 ;; Interpose (Count)
122 ;; ---------------------------------------------------------------------------
123
124 (defn interpose-twice-the-length ;; (or one less)
125 [v]
126 (let [interpose-count (count (interpose :i v))
127 original-count (count v)]
128 (or
129 (= (* 2 original-count) interpose-count)
130 (= (dec (* 2 original-count)) interpose-count))))
131
132
133 (deftest interpose-creates-sequence-twice-the-length
134 (testing
135 "Interposing a collection with a value makes its count
136 twice the original collection, or ones less."
137 (is (:result
138 (tc/quick-check 1000 (prop/for-all [v (gen/vector gen/int)] (interpose-twice-the-length v)))))))
139
140 ;; Lists and vectors are equivalent with seq abstraction
141 ;; ---------------------------------------------------------------------------
142
143 (defn list-vector-round-trip-equiv
144 [a]
145 ;; NOTE: can't use `(into '() ...)` here because that
146 ;; puts the list in reverse order. clojure.test.check found that bug
147 ;; pretty quickly...
148 (= a (apply list (vec a))))
149
150 (deftest list-and-vector-round-trip
151 (testing
152 ""
153 (is (:result
154 (tc/quick-check
155 1000 (prop/for-all*
156 [(gen/list gen/int)] list-vector-round-trip-equiv))))))
157
158 ;; keyword->string->keyword roundtrip
159 ;; ---------------------------------------------------------------------------
160
161 (def keyword->string->keyword (comp keyword clojure.string/join rest str))
162
163 (defn keyword-string-roundtrip-equiv
164 [k]
165 (= k (keyword->string->keyword k)))
166
167 (deftest keyword-string-roundtrip
168 (testing
169 "For all keywords, turning them into a string and back is equivalent
170 to the original string (save for the `:` bit)"
171 (is (:result
172 (tc/quick-check 1000 (prop/for-all*
173 [gen/keyword] keyword-string-roundtrip-equiv)
174 :max-size 25)))))
175
176 ;; Boolean and/or
177 ;; ---------------------------------------------------------------------------
178
179 (deftest boolean-or
180 (testing
181 "`or` with true and anything else should be true"
182 (is (:result (tc/quick-check
183 1000 (prop/for-all*
184 [gen/boolean] #(or % true)))))))
185
186 (deftest boolean-and
187 (testing
188 "`and` with false and anything else should be false"
189 (is (:result (tc/quick-check
190 1000 (prop/for-all*
191 [gen/boolean] #(not (and % false))))))))
192
193 ;; Sorting
194 ;; ---------------------------------------------------------------------------
195
196 (defn elements-are-in-order-after-sorting
197 [v]
198 (every? identity (map <= (partition 2 1 (sort v)))))
199
200 (deftest sorting
201 (testing
202 "For all vectors V, sorted(V) should have the elements in order"
203 (is (:result
204 (tc/quick-check
205 1000
206 (prop/for-all*
207 [(gen/vector gen/int)] elements-are-in-order-after-sorting))))))
208
209 ;; Constant generators
210 ;; ---------------------------------------------------------------------------
211
212 ;; A constant generator always returns its created value
213 (defspec constant-generators 100
214 (prop/for-all [a (gen/return 42)]
215 (print "")
216 (= a 42)))
217
218 (deftest constant-generators-dont-shrink
219 (testing
220 "Generators created with `gen/return` should not shrink"
221 (is (= [42]
222 (let [result (tc/quick-check 100
223 (prop/for-all
224 [a (gen/return 42)]
225 false))]
226 (-> result :shrunk :smallest))))))
227
228 ;; Tests are deterministic
229 ;; ---------------------------------------------------------------------------
230
231 (defn vector-elements-are-unique
232 [v]
233 (== (count v) (count (distinct v))))
234
235 (defn unique-test
236 [seed]
237 (tc/quick-check 1000
238 (prop/for-all*
239 [(gen/vector gen/int)] vector-elements-are-unique)
240 :seed seed))
241
242 (defn equiv-runs
243 [seed]
244 (= (unique-test seed) (unique-test seed)))
245
246 (deftest tests-are-deterministic
247 (testing "If two runs are started with the same seed, they should
248 return the same results."
249 (is (:result
250 (tc/quick-check 1000 (prop/for-all* [gen/int] equiv-runs))))))
251
252 ;; Generating basic generators
253 ;; --------------------------------------------------------------------------
254 (deftest generators-test
255 (let [t (fn [generator pred]
256 (is (:result (tc/quick-check 100
257 (prop/for-all [x generator]
258 (pred x))))))]
259
260 (testing "keyword" (t gen/keyword keyword?))
261 (testing "ratio" (t gen/ratio (some-fn ratio? integer?)))
262 (testing "byte" (t gen/byte #(instance? Byte %)))
263 (testing "bytes" (t gen/bytes #(instance? (Class/forName "[B") %)))
264
265 (testing "char" (t gen/char char?))
266 (testing "char-ascii" (t gen/char-ascii char?))
267 (testing "char-alphanumeric" (t gen/char-alphanumeric char?))
268 (testing "string" (t gen/string string?))
269 (testing "string-ascii" (t gen/string-ascii string?))
270 (testing "string-alphanumeric" (t gen/string-alphanumeric string?))
271
272 (testing "vector" (t (gen/vector gen/int) vector?))
273 (testing "list" (t (gen/list gen/int) list?))
274 (testing "map" (t (gen/map gen/int gen/int) map?))
275 ))
276
277 ;; Generating proper matrices
278 ;; ---------------------------------------------------------------------------
279
280 (defn proper-matrix?
281 "Check if provided nested vectors form a proper matrix — that is, all nested
282 vectors have the same length"
283 [mtx]
284 (let [first-size (count (first mtx))]
285 (every? (partial = first-size) (map count (rest mtx)))))
286
287 (deftest proper-matrix-test
288 (testing
289 "can generate proper matrices"
290 (is (:result (tc/quick-check
291 100 (prop/for-all
292 [mtx (gen/vector (gen/vector gen/int 3) 3)]
293 (proper-matrix? mtx)))))))
294
295 (def bounds-and-vector
296 (gen/bind (gen/tuple gen/s-pos-int gen/s-pos-int)
297 (fn [[a b]]
298 (let [minimum (min a b)
299 maximum (max a b)]
300 (gen/tuple (gen/return [minimum maximum])
301 (gen/vector gen/int minimum maximum))))))
302
303 (deftest proper-vector-test
304 (testing
305 "can generate vectors with sizes in a provided range"
306 (is (:result (tc/quick-check
307 100 (prop/for-all
308 [b-and-v bounds-and-vector]
309 (let [[[minimum maximum] v] b-and-v
310 c (count v)]
311 (and (<= c maximum)
312 (>= c minimum)))))))))
313
314 ;; Tuples and Pairs retain their count during shrinking
315 ;; ---------------------------------------------------------------------------
316
317 (defn n-int-generators
318 [n]
319 (vec (repeat n gen/int)))
320
321 (def tuples
322 [(apply gen/tuple (n-int-generators 1))
323 (apply gen/tuple (n-int-generators 2))
324 (apply gen/tuple (n-int-generators 3))
325 (apply gen/tuple (n-int-generators 4))
326 (apply gen/tuple (n-int-generators 5))
327 (apply gen/tuple (n-int-generators 6))])
328
329 (defn get-tuple-gen
330 [index]
331 (nth tuples (dec index)))
332
333 (defn inner-tuple-property
334 [size]
335 (prop/for-all [t (get-tuple-gen size)]
336 false))
337
338 (defspec tuples-retain-size-during-shrinking 1000
339 (prop/for-all [index (gen/choose 1 6)]
340 (let [result (tc/quick-check
341 100 (inner-tuple-property index))]
342 (= index (count (-> result
343 :shrunk :smallest first))))))
344
345 ;; Bind works
346 ;; ---------------------------------------------------------------------------
347
348 (def nat-vec
349 (gen/such-that not-empty
350 (gen/vector gen/nat)))
351
352 (def vec-and-elem
353 (gen/bind nat-vec
354 (fn [v]
355 (gen/tuple (gen/elements v) (gen/return v)))))
356
357 (defspec element-is-in-vec 100
358 (prop/for-all [[element coll] vec-and-elem]
359 (some #{element} coll)))
360
361 ;; fmap is respected during shrinking
362 ;; ---------------------------------------------------------------------------
363
364 (def plus-fifty
365 (gen/fmap (partial + 50) gen/nat))
366
367 (deftest f-map-respected-during-shrinking
368 (testing
369 "Generators created fmap should have that function applied
370 during shrinking"
371 (is (= [50]
372 (let [result (tc/quick-check 100
373 (prop/for-all
374 [a plus-fifty]
375 false))]
376 (-> result :shrunk :smallest))))))
377
378 ;; gen/int returns an integer when size is a double; regression for TCHECK-73
379 ;; ---------------------------------------------------------------------------
380
381 (def gen-double
382 (gen/fmap (fn [[x y]] (double (+ x (/ y 10))))
383 (gen/tuple gen/pos-int (gen/choose 0 9))))
384
385 (defspec gen-int-with-double-size 1000
386 (prop/for-all [size gen-double]
387 (integer? (gen/generate gen/int size))))
388
389 ;; recursive-gen doesn't change ints to doubles; regression for TCHECK-73
390 ;; ---------------------------------------------------------------------------
391
392 (defspec recursive-generator-test 100
393 (let [btree* (fn [g] (gen/hash-map
394 :value gen/int
395 :left g
396 :right g))
397 btree (gen/recursive-gen btree* (gen/return nil))
398 valid? (fn valid? [tree]
399 (and (integer? (:value tree))
400 (or (nil? (:left tree))
401 (valid? (:left tree)))
402 (or (nil? (:right tree))
403 (valid? (:right tree)))))]
404 (prop/for-all [t btree] (valid? t))))
405
406 (deftest calc-long-increasing
407 ;; access internal gen/calc-long function for testing
408 (are [low high] (apply < (map #(@#'gen/calc-long % low high) (range 0.0 0.9999 0.111)))
409 ;; low and high should not be too close, 100 is a reasonable spread
410 (- Long/MAX_VALUE 100) Long/MAX_VALUE
411 Long/MIN_VALUE (+ Long/MIN_VALUE 100)
412 Long/MIN_VALUE 0
413 0 100
414 -100 0
415 0 Long/MAX_VALUE
416 Long/MIN_VALUE Long/MAX_VALUE))
417
418 ;; edn rountrips
419 ;; ---------------------------------------------------------------------------
420
421 (defn edn-roundtrip?
422 [value]
423 (= value (-> value prn-str edn/read-string)))
424
425 (defspec edn-roundtrips 50
426 (prop/for-all [a gen/any]
427 (edn-roundtrip? a)))
428
429 ;; not-empty works
430 ;; ---------------------------------------------------------------------------
431
432 (defspec not-empty-works 100
433 (prop/for-all [v (gen/not-empty (gen/vector gen/boolean))]
434 (not-empty v)))
435
436 ;; no-shrink works
437 ;; ---------------------------------------------------------------------------
438
439 (defn run-no-shrink
440 [i]
441 (tc/quick-check 100
442 (prop/for-all [coll (gen/vector gen/nat)]
443 (some #{i} coll))))
444
445 (defspec no-shrink-works 100
446 (prop/for-all [i gen/nat]
447 (let [result (run-no-shrink i)]
448 (if (:result result)
449 true
450 (= (:fail result)
451 (-> result :shrunk :smallest))))))
452
453 ;; elements works with a variety of input
454 ;; ---------------------------------------------------------------------------
455
456 (deftest elements-with-empty
457 (is (thrown? AssertionError (gen/elements ()))))
458
459 (defspec elements-with-a-set 100
460 (prop/for-all [num (gen/elements #{9 10 11 12})]
461 (<= 9 num 12)))
462
463
464 ;; choose respects bounds during shrinking
465 ;; ---------------------------------------------------------------------------
466
467 (def range-gen
468 (gen/fmap (fn [[a b]]
469 [(min a b) (max a b)])
470 (gen/tuple gen/int gen/int)))
471
472 (defspec choose-respects-bounds-during-shrinking 100
473 (prop/for-all [[mini maxi] range-gen
474 random-seed gen/nat
475 size gen/nat]
476 (let [tree (gen/call-gen
477 (gen/choose mini maxi)
478 (random/make-random random-seed)
479 size)]
480 (every?
481 #(and (<= mini %) (>= maxi %))
482 (rose/seq tree)))))
483
484
485 ;; rand-range copes with full range of longs as bounds
486 ;; ---------------------------------------------------------------------------
487
488 (deftest rand-range-copes-with-full-range-of-longs
489 (let [[low high] (reduce
490 (fn [[low high :as margins] x]
491 (cond
492 (< x low) [x high]
493 (> x high) [low x]
494 :else margins))
495 [Long/MAX_VALUE Long/MIN_VALUE]
496 ; choose uses rand-range directly, reasonable proxy for its
497 ; guarantees
498 (take 1e6 (gen/sample-seq (gen/choose Long/MIN_VALUE Long/MAX_VALUE))))]
499 (is (< low high))
500 (is (< low Integer/MIN_VALUE))
501 (is (> high Integer/MAX_VALUE))))
502
503 ;; rand-range yields values inclusive of both lower & upper bounds provided to it
504 ;; further, that generators that use rand-range use its full range of values
505 ;; ---------------------------------------------------------------------------
506
507 (deftest rand-range-uses-inclusive-bounds
508 (let [bounds [5 7]
509 rand-range (fn [r] (apply #'gen/rand-range r bounds))]
510 (loop [trials 0
511 bounds (set bounds)
512 r (random/make-random)]
513 (cond
514 (== trials 10000)
515 (is nil (str "rand-range didn't return both of its bounds after 10000 trials; "
516 "it is possible for this to fail without there being a problem, "
517 "but we should be able to rely upon probability to not bother us "
518 "too frequently."))
519 (empty? bounds) (is true)
520 :else (let [[r1 r2] (random/split r)]
521 (recur (inc trials) (disj bounds (rand-range r1)) r2))))))
522
523 (deftest elements-generates-all-provided-values
524 (let [options [:a 42 'c/d "foo"]]
525 (is (->> (reductions
526 disj
527 (set options)
528 (gen/sample-seq (gen/elements options)))
529 (take 10000)
530 (some empty?))
531 (str "elements didn't return all of its candidate values after 10000 trials; "
532 "it is possible for this to fail without there being a problem, "
533 "but we should be able to rely upon probability to not bother us "
534 "too frequently."))))
535
536 ;; shuffling a vector generates a permutation of that vector
537 ;; ---------------------------------------------------------------------------
538
539 (def original-vector-and-permutation
540 (gen/bind (gen/vector gen/int)
541 #(gen/tuple (gen/return %) (gen/shuffle %))))
542
543 (defspec shuffled-vector-is-a-permutation-of-original 100
544 (prop/for-all [[coll permutation] original-vector-and-permutation]
545 (= (sort coll) (sort permutation))))
546
547 ;; vector can generate large vectors; regression for TCHECK-49
548 ;; ---------------------------------------------------------------------------
549
550 (deftest large-vector-test
551 (is (= 100000
552 (count (first (gen/sample
553 (gen/vector gen/nat 100000)
554 1))))))
555
556 ;; scale controls growth rate of generators
557 ;; ---------------------------------------------------------------------------
558
559 (deftest scale-test
560 (let [g (gen/scale (partial min 10) gen/pos-int) ;; should limit size to 10
561 samples (gen/sample g 1000)]
562 (is (every? (partial >= 11) samples))
563 (is (some (partial = 10) samples))))
564
565 ;; generator dev helpers
566 ;; ---------------------------------------------------------------------------
567
568 (deftest generate-test
569 (is (string? (gen/generate gen/string)))
570 (is (string? (gen/generate gen/string 42))))
571
572 ;; defspec macro
573 ;; ---------------------------------------------------------------------------
574
575 (defspec run-only-once 1 (prop/for-all* [gen/int] (constantly true)))
576
577 (defspec run-default-times (prop/for-all* [gen/int] (constantly true)))
578
579 (defspec run-with-map1 {:num-tests 1} (prop/for-all* [gen/int] (constantly true)))
580
581 (defspec run-with-map {:num-tests 1
582 :seed 1}
583 (prop/for-all [a gen/int]
584 (= a 0)))
585
586 (def my-defspec-options {:num-tests 1 :seed 1})
587
588 (defspec run-with-symbolic-options my-defspec-options
589 (prop/for-all [a gen/int]
590 (= a 0)))
591
592 (defspec run-with-no-options
593 (prop/for-all [a gen/int]
594 (integer? a)))
595
596 (defspec run-float-time 1e3
597 (prop/for-all [a gen/int]
598 (integer? a)))
599
600 ;; TCHECK-77 Regression
601 ;; ---------------------------------------------------------------------------
602
603 (deftest choose-distribution-sanity-check
604 (testing
605 "Should not get the same random value more than 90% of the time"
606 ;; This is a probabilistic test; the odds of a false-positive
607 ;; failure for the ranges with two elements should be roughly 1 in
608 ;; 10^162 (and even rarer for larger ranges), so it will never
609 ;; ever happen.
610 (are [low high] (let [xs (gen/sample (gen/choose low high) 1000)
611 count-of-most-frequent (apply max (vals (frequencies xs)))]
612 (< count-of-most-frequent 900))
613 (dec Long/MAX_VALUE) Long/MAX_VALUE
614 Long/MIN_VALUE (inc Long/MIN_VALUE)
615 Long/MIN_VALUE 0
616 0 1
617 -1 0
618 0 Long/MAX_VALUE
619 Long/MIN_VALUE Long/MAX_VALUE)))
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.test
10 #?(:clj (:use clojure.test))
11 (:require #?(:cljs
12 [cljs.test :as test :refer-macros [deftest testing is]])
13 [clojure.test.check :as tc]
14 [clojure.test.check.generators :as gen]
15 [clojure.test.check.properties :as prop #?@(:cljs [:include-macros true])]
16 [clojure.test.check.rose-tree :as rose]
17 [clojure.test.check.random :as random]
18 [clojure.test.check.clojure-test :as ct #?(:clj :refer :cljs :refer-macros) (defspec)]
19 #?(:clj [clojure.edn :as edn]
20 :cljs [cljs.reader :as edn])))
21
22 (deftest generators-are-generators
23 (testing "generator? returns true when called with a generator"
24 (is (gen/generator? gen/int))
25 (is (gen/generator? (gen/vector gen/int)))
26 (is (gen/generator? (gen/return 5)))))
27
28 (deftest values-are-not-generators
29 (testing "generator? returns false when called with a value"
30 (is (not (gen/generator? 5)))
31 (is (not (gen/generator? int)))
32 (is (not (gen/generator? [1 2 3])))))
33
34 ;; plus and 0 form a monoid
35 ;; ---------------------------------------------------------------------------
36
37 (defn passes-monoid-properties
38 [a b c]
39 (and (= (+ 0 a) a)
40 (= (+ a 0) a)
41 (= (+ a (+ b c)) (+ (+ a b) c))))
42
43 (deftest plus-and-0-are-a-monoid
44 (testing "+ and 0 form a monoid"
45 (is (let [p (prop/for-all* [gen/int gen/int gen/int] passes-monoid-properties)]
46 (:result
47 (tc/quick-check 1000 p)))))
48 #?(:clj
49 (testing "with ratios as well"
50 (is (let [p (prop/for-all* [gen/ratio gen/ratio gen/ratio] passes-monoid-properties)]
51 (:result
52 (tc/quick-check 1000 p)))))
53
54 ;; NOTE: no ratios in ClojureScript - David
55 ))
56
57 ;; reverse
58 ;; ---------------------------------------------------------------------------
59
60 (defn reverse-equal?-helper
61 [l]
62 (let [r (vec (reverse l))]
63 (and (= (count l) (count r))
64 (= (seq l) (rseq r)))))
65
66 (deftest reverse-equal?
67 (testing "For all vectors L, reverse(reverse(L)) == L"
68 (is (let [p (prop/for-all* [(gen/vector gen/int)] reverse-equal?-helper)]
69 (:result (tc/quick-check 1000 p))))))
70
71 ;; failing reverse
72 ;; ---------------------------------------------------------------------------
73
74 (deftest bad-reverse-test
75 (testing "For all vectors L, L == reverse(L). Not true"
76 (is (false?
77 (let [p (prop/for-all* [(gen/vector gen/int)] #(= (reverse %) %))]
78 (:result (tc/quick-check 1000 p)))))))
79
80 ;; failing element remove
81 ;; ---------------------------------------------------------------------------
82
83 (defn first-is-gone
84 [l]
85 (not (some #{(first l)} (vec (rest l)))))
86
87 (deftest bad-remove
88 (testing "For all vectors L, if we remove the first element E, E should not
89 longer be in the list. (This is a false assumption)"
90 (is (false?
91 (let [p (prop/for-all* [(gen/vector gen/int)] first-is-gone)]
92 (:result (tc/quick-check 1000 p)))))))
93
94 ;; exceptions shrink and return as result
95 ;; ---------------------------------------------------------------------------
96
97 (def exception (#?(:clj Exception. :cljs js/Error.) "I get caught"))
98
99 (defn exception-thrower
100 [& args]
101 (throw exception))
102
103 (deftest exceptions-are-caught
104 (testing "Exceptions during testing are caught. They're also shrunk as long
105 as they continue to throw."
106 (is (= [exception [0]]
107 (let [result
108 (tc/quick-check
109 1000 (prop/for-all* [gen/int] exception-thrower))]
110 [(:result result) (get-in result [:shrunk :smallest])])))))
111
112 ;; Count and concat work as expected
113 ;; ---------------------------------------------------------------------------
114
115 (defn concat-counts-correct
116 [a b]
117 (= (count (concat a b))
118 (+ (count a) (count b))))
119
120 (deftest count-and-concat
121 (testing "For all vectors A and B:
122 length(A + B) == length(A) + length(B)"
123 (is (:result
124 (let [p (prop/for-all* [(gen/vector gen/int)
125 (gen/vector gen/int)] concat-counts-correct)]
126 (tc/quick-check 1000 p))))))
127
128 ;; Interpose (Count)
129 ;; ---------------------------------------------------------------------------
130
131 (defn interpose-twice-the-length ;; (or one less)
132 [v]
133 (let [interpose-count (count (interpose :i v))
134 original-count (count v)]
135 (or
136 (= (* 2 original-count) interpose-count)
137 (= (dec (* 2 original-count)) interpose-count))))
138
139
140 (deftest interpose-creates-sequence-twice-the-length
141 (testing
142 "Interposing a collection with a value makes its count
143 twice the original collection, or ones less."
144 (is (:result
145 (tc/quick-check 1000 (prop/for-all [v (gen/vector gen/int)] (interpose-twice-the-length v)))))))
146
147 ;; Lists and vectors are equivalent with seq abstraction
148 ;; ---------------------------------------------------------------------------
149
150 (defn list-vector-round-trip-equiv
151 [a]
152 ;; NOTE: can't use `(into '() ...)` here because that
153 ;; puts the list in reverse order. clojure.test.check found that bug
154 ;; pretty quickly...
155 (= a (apply list (vec a))))
156
157 (deftest list-and-vector-round-trip
158 (testing
159 ""
160 (is (:result
161 (tc/quick-check
162 1000 (prop/for-all*
163 [(gen/list gen/int)] list-vector-round-trip-equiv))))))
164
165 ;; keyword->string->keyword roundtrip
166 ;; ---------------------------------------------------------------------------
167
168 (def keyword->string->keyword
169 (comp keyword name))
170
171 (defn keyword-string-roundtrip-equiv
172 [k]
173 (= k (keyword->string->keyword k)))
174
175 ;; NOTE cljs: this is one of the slowest due to how keywords are constructed
176 ;; drop N to 100 - David
177 (deftest keyword-string-roundtrip
178 (testing
179 "For all keywords, turning them into a string and back is equivalent
180 to the original string (save for the `:` bit)"
181 (is (:result
182 (let [n #?(:clj 1000 :cljs 100)]
183 (tc/quick-check n (prop/for-all*
184 [gen/keyword] keyword-string-roundtrip-equiv)
185 :max-size 25))))))
186
187 ;; Boolean and/or
188 ;; ---------------------------------------------------------------------------
189
190 (deftest boolean-or
191 (testing
192 "`or` with true and anything else should be true"
193 (is (:result (tc/quick-check
194 1000 (prop/for-all*
195 [gen/boolean] #(or % true)))))))
196
197 (deftest boolean-and
198 (testing
199 "`and` with false and anything else should be false"
200 (is (:result (tc/quick-check
201 1000 (prop/for-all*
202 [gen/boolean] #(not (and % false))))))))
203
204 ;; Sorting
205 ;; ---------------------------------------------------------------------------
206
207 (defn elements-are-in-order-after-sorting
208 [v]
209 (every? identity (map <= (partition 2 1 (sort v)))))
210
211 (deftest sorting
212 (testing
213 "For all vectors V, sorted(V) should have the elements in order"
214 (is (:result
215 (tc/quick-check
216 1000
217 (prop/for-all*
218 [(gen/vector gen/int)] elements-are-in-order-after-sorting))))))
219
220 ;; Constant generators
221 ;; ---------------------------------------------------------------------------
222
223 ;; A constant generator always returns its created value
224 (defspec constant-generators 100
225 (prop/for-all [a (gen/return 42)]
226 (print "")
227 (= a 42)))
228
229 (deftest constant-generators-dont-shrink
230 (testing
231 "Generators created with `gen/return` should not shrink"
232 (is (= [42]
233 (let [result (tc/quick-check 100
234 (prop/for-all
235 [a (gen/return 42)]
236 false))]
237 (-> result :shrunk :smallest))))))
238
239 ;; Tests are deterministic
240 ;; ---------------------------------------------------------------------------
241
242 (defn vector-elements-are-unique
243 [v]
244 (== (count v) (count (distinct v))))
245
246 (defn unique-test
247 [seed]
248 (tc/quick-check 1000
249 (prop/for-all*
250 [(gen/vector gen/int)] vector-elements-are-unique)
251 :seed seed))
252
253 (defn equiv-runs
254 [seed]
255 (= (unique-test seed) (unique-test seed)))
256
257 (deftest tests-are-deterministic
258 (testing "If two runs are started with the same seed, they should
259 return the same results."
260 (is (:result
261 (tc/quick-check 1000 (prop/for-all* [gen/int] equiv-runs))))))
262
263 ;; Generating basic generators
264 ;; --------------------------------------------------------------------------
265 (deftest generators-test
266 (let [t (fn [generator pred]
267 (is (:result (tc/quick-check 100
268 (prop/for-all [x generator]
269 (pred x))))))
270 is-char-fn #?(:clj char? :cljs string?)]
271
272 (testing "keyword" (t gen/keyword keyword?))
273
274 ;; No ratio in cljs
275 #?@(:clj [
276 (testing "ratio" (t gen/ratio (some-fn ratio? integer?)))
277 (testing "byte" (t gen/byte #(instance? Byte %)))
278 (testing "bytes" (t gen/bytes #(instance? (Class/forName "[B") %)))])
279
280
281 (testing "char" (t gen/char is-char-fn))
282 (testing "char-ascii" (t gen/char-ascii is-char-fn))
283 (testing "char-alphanumeric" (t gen/char-alphanumeric is-char-fn))
284 (testing "string" (t gen/string string?))
285 (testing "string-ascii" (t gen/string-ascii string?))
286 (testing "string-alphanumeric" (t gen/string-alphanumeric string?))
287
288 (testing "vector" (t (gen/vector gen/int) vector?))
289 (testing "list" (t (gen/list gen/int) list?))
290 (testing "map" (t (gen/map gen/int gen/int) map?))
291 ))
292
293 ;; Generating proper matrices
294 ;; ---------------------------------------------------------------------------
295
296 (defn proper-matrix?
297 "Check if provided nested vectors form a proper matrix — that is, all nested
298 vectors have the same length"
299 [mtx]
300 (let [first-size (count (first mtx))]
301 (every? (partial = first-size) (map count (rest mtx)))))
302
303 (deftest proper-matrix-test
304 (testing
305 "can generate proper matrices"
306 (is (:result (tc/quick-check
307 100 (prop/for-all
308 [mtx (gen/vector (gen/vector gen/int 3) 3)]
309 (proper-matrix? mtx)))))))
310
311 (def bounds-and-vector
312 (gen/bind (gen/tuple gen/s-pos-int gen/s-pos-int)
313 (fn [[a b]]
314 (let [minimum (min a b)
315 maximum (max a b)]
316 (gen/tuple (gen/return [minimum maximum])
317 (gen/vector gen/int minimum maximum))))))
318
319 (deftest proper-vector-test
320 (testing
321 "can generate vectors with sizes in a provided range"
322 (is (:result (tc/quick-check
323 100 (prop/for-all
324 [b-and-v bounds-and-vector]
325 (let [[[minimum maximum] v] b-and-v
326 c (count v)]
327 (and (<= c maximum)
328 (>= c minimum)))))))))
329
330 ;; Tuples and Pairs retain their count during shrinking
331 ;; ---------------------------------------------------------------------------
332
333 (defn n-int-generators
334 [n]
335 (vec (repeat n gen/int)))
336
337 (def tuples
338 [(apply gen/tuple (n-int-generators 1))
339 (apply gen/tuple (n-int-generators 2))
340 (apply gen/tuple (n-int-generators 3))
341 (apply gen/tuple (n-int-generators 4))
342 (apply gen/tuple (n-int-generators 5))
343 (apply gen/tuple (n-int-generators 6))])
344
345 (defn get-tuple-gen
346 [index]
347 (nth tuples (dec index)))
348
349 (defn inner-tuple-property
350 [size]
351 (prop/for-all [t (get-tuple-gen size)]
352 false))
353
354 (defspec tuples-retain-size-during-shrinking 1000
355 (prop/for-all [index (gen/choose 1 6)]
356 (let [result (tc/quick-check
357 100 (inner-tuple-property index))]
358 (= index (count (-> result
359 :shrunk :smallest first))))))
360
361 ;; Bind works
362 ;; ---------------------------------------------------------------------------
363
364 (def nat-vec
365 (gen/such-that not-empty
366 (gen/vector gen/nat)))
367
368 (def vec-and-elem
369 (gen/bind nat-vec
370 (fn [v]
371 (gen/tuple (gen/elements v) (gen/return v)))))
372
373 (defspec element-is-in-vec 100
374 (prop/for-all [[element coll] vec-and-elem]
375 (some #{element} coll)))
376
377 ;; fmap is respected during shrinking
378 ;; ---------------------------------------------------------------------------
379
380 (def plus-fifty
381 (gen/fmap (partial + 50) gen/nat))
382
383 (deftest f-map-respected-during-shrinking
384 (testing
385 "Generators created fmap should have that function applied
386 during shrinking"
387 (is (= [50]
388 (let [result (tc/quick-check 100
389 (prop/for-all
390 [a plus-fifty]
391 false))]
392 (-> result :shrunk :smallest))))))
393
394 ;; gen/int returns an integer when size is a double; regression for TCHECK-73
395 ;; ---------------------------------------------------------------------------
396
397 (def gen-double
398 (gen/fmap (fn [[x y]] (double (+ x (/ y 10))))
399 (gen/tuple gen/pos-int (gen/choose 0 9))))
400
401 (defspec gen-int-with-double-size 1000
402 (prop/for-all [size gen-double]
403 (integer? (gen/generate gen/int size))))
404
405 ;; recursive-gen doesn't change ints to doubles; regression for TCHECK-73
406 ;; ---------------------------------------------------------------------------
407
408 (defspec recursive-generator-test 100
409 (let [btree* (fn [g] (gen/hash-map
410 :value gen/int
411 :left g
412 :right g))
413 btree (gen/recursive-gen btree* (gen/return nil))
414 valid? (fn valid? [tree]
415 (and (integer? (:value tree))
416 (or (nil? (:left tree))
417 (valid? (:left tree)))
418 (or (nil? (:right tree))
419 (valid? (:right tree)))))]
420 (prop/for-all [t btree] (valid? t))))
421
422 ;; NOTE cljs: adjust for JS numerics - NB
423
424 #?(:clj
425 (deftest calc-long-increasing
426 ;; access internal gen/calc-long function for testing
427 (are [low high] (apply < (map #(@#'gen/calc-long % low high) (range 0.0 0.9999 0.111)))
428 ;; low and high should not be too close, 100 is a reasonable spread
429 (- Long/MAX_VALUE 100) Long/MAX_VALUE
430 Long/MIN_VALUE (+ Long/MIN_VALUE 100)
431 Long/MIN_VALUE 0
432 0 100
433 -100 0
434 0 Long/MAX_VALUE
435 Long/MIN_VALUE Long/MAX_VALUE)))
436
437 ;; edn rountrips
438 ;; ---------------------------------------------------------------------------
439
440 (defn edn-roundtrip?
441 [value]
442 (= value (-> value prn-str edn/read-string)))
443
444 (defspec edn-roundtrips 50
445 (prop/for-all [a gen/any]
446 (edn-roundtrip? a)))
447
448 ;; not-empty works
449 ;; ---------------------------------------------------------------------------
450
451 (defspec not-empty-works 100
452 (prop/for-all [v (gen/not-empty (gen/vector gen/boolean))]
453 (not-empty v)))
454
455 ;; no-shrink works
456 ;; ---------------------------------------------------------------------------
457
458 (defn run-no-shrink
459 [i]
460 (tc/quick-check 100
461 (prop/for-all [coll (gen/vector gen/nat)]
462 (some #{i} coll))))
463
464 (defspec no-shrink-works 100
465 (prop/for-all [i gen/nat]
466 (let [result (run-no-shrink i)]
467 (if (:result result)
468 true
469 (= (:fail result)
470 (-> result :shrunk :smallest))))))
471
472 ;; elements works with a variety of input
473 ;; ---------------------------------------------------------------------------
474
475 (deftest elements-with-empty
476 (is (thrown? #?(:clj AssertionError :cljs js/Error)
477 (gen/elements ()))))
478
479 (defspec elements-with-a-set 100
480 (prop/for-all [num (gen/elements #{9 10 11 12})]
481 (<= 9 num 12)))
482
483
484 ;; choose respects bounds during shrinking
485 ;; ---------------------------------------------------------------------------
486
487 (def range-gen
488 (gen/fmap (fn [[a b]]
489 [(min a b) (max a b)])
490 (gen/tuple gen/int gen/int)))
491
492 (defspec choose-respects-bounds-during-shrinking 100
493 (prop/for-all [[mini maxi] range-gen
494 random-seed gen/nat
495 size gen/nat]
496 (let [tree (gen/call-gen
497 (gen/choose mini maxi)
498 (random/make-random random-seed)
499 size)]
500 (every?
501 #(and (<= mini %) (>= maxi %))
502 (rose/seq tree)))))
503
504
505 ;; rand-range copes with full range of longs as bounds
506 ;; ---------------------------------------------------------------------------
507
508 ;; NOTE cljs: need to adjust for JS numerics - David
509
510 #?(:clj
511 (deftest rand-range-copes-with-full-range-of-longs
512 (let [[low high] (reduce
513 (fn [[low high :as margins] x]
514 (cond
515 (< x low) [x high]
516 (> x high) [low x]
517 :else margins))
518 [Long/MAX_VALUE Long/MIN_VALUE]
519 ; choose uses rand-range directly, reasonable proxy for its
520 ; guarantees
521 (take 1e6 (gen/sample-seq (gen/choose Long/MIN_VALUE Long/MAX_VALUE))))]
522 (is (< low high))
523 (is (< low Integer/MIN_VALUE))
524 (is (> high Integer/MAX_VALUE)))))
525
526 ;; rand-range yields values inclusive of both lower & upper bounds provided to it
527 ;; further, that generators that use rand-range use its full range of values
528 ;; ---------------------------------------------------------------------------
529
530 (deftest rand-range-uses-inclusive-bounds
531 (let [bounds [5 7]
532 rand-range (fn [r] (apply #'gen/rand-range r bounds))]
533 (loop [trials 0
534 bounds (set bounds)
535 r (random/make-random)]
536 (cond
537 (== trials 10000)
538 (is nil (str "rand-range didn't return both of its bounds after 10000 trials; "
539 "it is possible for this to fail without there being a problem, "
540 "but we should be able to rely upon probability to not bother us "
541 "too frequently."))
542 (empty? bounds) (is true)
543 :else (let [[r1 r2] (random/split r)]
544 (recur (inc trials) (disj bounds (rand-range r1)) r2))))))
545
546 (deftest elements-generates-all-provided-values
547 (let [options [:a 42 'c/d "foo"]]
548 (is (->> (reductions
549 disj
550 (set options)
551 (gen/sample-seq (gen/elements options)))
552 (take 10000)
553 (some empty?))
554 (str "elements didn't return all of its candidate values after 10000 trials; "
555 "it is possible for this to fail without there being a problem, "
556 "but we should be able to rely upon probability to not bother us "
557 "too frequently."))))
558
559 ;; shuffling a vector generates a permutation of that vector
560 ;; ---------------------------------------------------------------------------
561
562 (def original-vector-and-permutation
563 (gen/bind (gen/vector gen/int)
564 #(gen/tuple (gen/return %) (gen/shuffle %))))
565
566 (defspec shuffled-vector-is-a-permutation-of-original 100
567 (prop/for-all [[coll permutation] original-vector-and-permutation]
568 (= (sort coll) (sort permutation))))
569
570 ;; vector can generate large vectors; regression for TCHECK-49
571 ;; ---------------------------------------------------------------------------
572
573 (deftest large-vector-test
574 (is (= 100000
575 (count (first (gen/sample
576 (gen/vector gen/nat 100000)
577 1))))))
578
579 ;; scale controls growth rate of generators
580 ;; ---------------------------------------------------------------------------
581
582 (deftest scale-test
583 (let [g (gen/scale (partial min 10) gen/pos-int) ;; should limit size to 10
584 samples (gen/sample g 1000)]
585 (is (every? (partial >= 11) samples))
586 (is (some (partial = 10) samples))))
587
588 ;; generator dev helpers
589 ;; ---------------------------------------------------------------------------
590
591 (deftest generate-test
592 (is (string? (gen/generate gen/string)))
593 (is (string? (gen/generate gen/string 42))))
594
595 ;; defspec macro
596 ;; ---------------------------------------------------------------------------
597
598 (defspec run-only-once 1 (prop/for-all* [gen/int] (constantly true)))
599
600 (defspec run-default-times (prop/for-all* [gen/int] (constantly true)))
601
602 (defspec run-with-map1 {:num-tests 1} (prop/for-all* [gen/int] (constantly true)))
603
604 (defspec run-with-map {:num-tests 1
605 :seed 1}
606 (prop/for-all [a gen/int]
607 (= a 0)))
608
609 (def my-defspec-options {:num-tests 1 :seed 1})
610
611 (defspec run-with-symbolic-options my-defspec-options
612 (prop/for-all [a gen/int]
613 (= a 0)))
614
615 (defspec run-with-no-options
616 (prop/for-all [a gen/int]
617 (integer? a)))
618
619 (defspec run-float-time 1e3
620 (prop/for-all [a gen/int]
621 (integer? a)))
622
623 ;; TCHECK-77 Regression
624 ;; ---------------------------------------------------------------------------
625
626 ;; Note cljs: need to adjust for JS numerics - NB
627 #?(:clj
628 (deftest choose-distribution-sanity-check
629 (testing
630 "Should not get the same random value more than 90% of the time"
631 ;; This is a probabilistic test; the odds of a false-positive
632 ;; failure for the ranges with two elements should be roughly 1 in
633 ;; 10^162 (and even rarer for larger ranges), so it will never
634 ;; ever happen.
635 (are [low high] (let [xs (gen/sample (gen/choose low high) 1000)
636 count-of-most-frequent (apply max (vals (frequencies xs)))]
637 (< count-of-most-frequent 900))
638 (dec Long/MAX_VALUE) Long/MAX_VALUE
639 Long/MIN_VALUE (inc Long/MIN_VALUE)
640 Long/MIN_VALUE 0
641 0 1
642 -1 0
643 0 Long/MAX_VALUE
644 Long/MIN_VALUE Long/MAX_VALUE))))
+0
-555
src/test/clojure/clojure/test/check/test.cljs less more
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)))