clojure_test_check.{[clj cljs] -> cljc}
Nicolas Berger authored 8 years ago
Gary Fredericks committed 8 years ago
8 | 8 | |
9 | 9 | (ns clojure.test.check.clojure-test |
10 | 10 | (:require #?(:clj [clojure.test :as ct] |
11 | :cljs [cljs.test :as ct :include-macros true]))) | |
12 | ||
13 | (defn exception-like? [v] | |
14 | (instance? #?(:clj Throwable :cljs js/Error) v)) | |
11 | :cljs [cljs.test :as ct :include-macros true]) | |
12 | [clojure.test.check.impl :refer [get-current-time-millis | |
13 | exception-like?]])) | |
15 | 14 | |
16 | 15 | (defn assert-check |
17 | 16 | [{:keys [result] :as m}] |
92 | 91 | |
93 | 92 | (def ^:private last-trial-report (atom 0)) |
94 | 93 | |
95 | (defn get-current-time-millis [] | |
96 | #?(:clj (System/currentTimeMillis) | |
97 | :cljs (.valueOf (js/Date.)))) | |
98 | ||
99 | 94 | (let [begin-test-var-method (get-method ct/report #?(:clj :begin-test-var |
100 | 95 | :cljs [::ct/default :begin-test-var]))] |
101 | 96 | (defmethod ct/report #?(:clj :begin-test-var |
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.impl) | |
10 | ||
11 | (defn exception-like? [v] | |
12 | (instance? #?(:clj Throwable :cljs js/Error) v)) | |
13 | ||
14 | (defn get-current-time-millis [] | |
15 | #?(:clj (System/currentTimeMillis) | |
16 | :cljs (.valueOf (js/Date.)))) |
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 | |
10 | (:require [clojure.test.check.generators :as gen] | |
11 | [clojure.test.check.clojure-test :as ct] | |
12 | [clojure.test.check.random :as random] | |
13 | [clojure.test.check.rose-tree :as rose])) | |
14 | ||
15 | (declare shrink-loop failure) | |
16 | ||
17 | (defn- make-rng | |
18 | [seed] | |
19 | (if seed | |
20 | [seed (random/make-random seed)] | |
21 | (let [non-nil-seed (System/currentTimeMillis)] | |
22 | [non-nil-seed (random/make-random non-nil-seed)]))) | |
23 | ||
24 | (defn- complete | |
25 | [property num-trials seed] | |
26 | (ct/report-trial property num-trials num-trials) | |
27 | {:result true :num-tests num-trials :seed seed}) | |
28 | ||
29 | (defn- not-falsey-or-exception? | |
30 | "True if the value is not falsy or an exception" | |
31 | [value] | |
32 | (and value (not (instance? Throwable value)))) | |
33 | ||
34 | (defn quick-check | |
35 | "Tests `property` `num-tests` times. | |
36 | Takes optional keys `:seed` and `:max-size`. The seed parameter | |
37 | can be used to re-run previous tests, as the seed used is returned | |
38 | after a test is run. The max-size can be used to control the 'size' | |
39 | of generated values. The size will start at 0, and grow up to | |
40 | max-size, as the number of tests increases. Generators will use | |
41 | the size parameter to bound their growth. This prevents, for example, | |
42 | generating a five-thousand element vector on the very first test. | |
43 | ||
44 | Examples: | |
45 | ||
46 | (def p (for-all [a gen/pos-int] (> (* a a) a))) | |
47 | (quick-check 100 p) | |
48 | " | |
49 | [num-tests property & {:keys [seed max-size] :or {max-size 200}}] | |
50 | (let [[created-seed rng] (make-rng seed) | |
51 | size-seq (gen/make-size-range-seq max-size)] | |
52 | (loop [so-far 0 | |
53 | size-seq size-seq | |
54 | rstate rng] | |
55 | (if (== so-far num-tests) | |
56 | (complete property num-tests created-seed) | |
57 | (let [[size & rest-size-seq] size-seq | |
58 | [r1 r2] (random/split rstate) | |
59 | result-map-rose (gen/call-gen property r1 size) | |
60 | result-map (rose/root result-map-rose) | |
61 | result (:result result-map) | |
62 | args (:args result-map)] | |
63 | (if (not-falsey-or-exception? result) | |
64 | (do | |
65 | (ct/report-trial property so-far num-tests) | |
66 | (recur (inc so-far) rest-size-seq r2)) | |
67 | (failure property result-map-rose so-far size created-seed))))))) | |
68 | ||
69 | (defn- smallest-shrink | |
70 | [total-nodes-visited depth smallest] | |
71 | {:total-nodes-visited total-nodes-visited | |
72 | :depth depth | |
73 | :result (:result smallest) | |
74 | :smallest (:args smallest)}) | |
75 | ||
76 | (defn- shrink-loop | |
77 | "Shrinking a value produces a sequence of smaller values of the same type. | |
78 | Each of these values can then be shrunk. Think of this as a tree. We do a | |
79 | modified depth-first search of the tree: | |
80 | ||
81 | Do a non-exhaustive search for a deeper (than the root) failing example. | |
82 | Additional rules added to depth-first search: | |
83 | * If a node passes the property, you may continue searching at this depth, | |
84 | but not backtrack | |
85 | * If a node fails the property, search its children | |
86 | The value returned is the left-most failing example at the depth where a | |
87 | passing example was found." | |
88 | [rose-tree] | |
89 | (let [shrinks-this-depth (rose/children rose-tree)] | |
90 | (loop [nodes shrinks-this-depth | |
91 | current-smallest (rose/root rose-tree) | |
92 | total-nodes-visited 0 | |
93 | depth 0] | |
94 | (if (empty? nodes) | |
95 | (smallest-shrink total-nodes-visited depth current-smallest) | |
96 | (let [[head & tail] nodes | |
97 | result (:result (rose/root head))] | |
98 | (if (not-falsey-or-exception? result) | |
99 | ;; this node passed the test, so now try testing its right-siblings | |
100 | (recur tail current-smallest (inc total-nodes-visited) depth) | |
101 | ;; this node failed the test, so check if it has children, | |
102 | ;; if so, traverse down them. If not, save this as the best example | |
103 | ;; seen now and then look at the right-siblings | |
104 | ;; children | |
105 | (if-let [children (seq (rose/children head))] | |
106 | (recur children (rose/root head) (inc total-nodes-visited) (inc depth)) | |
107 | (recur tail (rose/root head) (inc total-nodes-visited) depth)))))))) | |
108 | ||
109 | (defn- failure | |
110 | [property failing-rose-tree trial-number size seed] | |
111 | (let [root (rose/root failing-rose-tree) | |
112 | result (:result root) | |
113 | failing-args (:args root)] | |
114 | ||
115 | (ct/report-failure property result trial-number failing-args) | |
116 | ||
117 | {:result result | |
118 | :seed seed | |
119 | :failing-size size | |
120 | :num-tests (inc trial-number) | |
121 | :fail (vec failing-args) | |
122 | :shrunk (shrink-loop failing-rose-tree)})) |
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 | |
10 | (:require [clojure.test.check.generators :as gen] | |
11 | [clojure.test.check.clojure-test :as ct] | |
12 | [clojure.test.check.random :as random] | |
13 | [clojure.test.check.rose-tree :as rose] | |
14 | [clojure.test.check.impl :refer [get-current-time-millis | |
15 | exception-like?]])) | |
16 | ||
17 | (declare shrink-loop failure) | |
18 | ||
19 | (defn- make-rng | |
20 | [seed] | |
21 | (if seed | |
22 | [seed (random/make-random seed)] | |
23 | (let [non-nil-seed (get-current-time-millis)] | |
24 | [non-nil-seed (random/make-random non-nil-seed)]))) | |
25 | ||
26 | (defn- complete | |
27 | [property num-trials seed] | |
28 | (ct/report-trial property num-trials num-trials) | |
29 | {:result true :num-tests num-trials :seed seed}) | |
30 | ||
31 | (defn- not-falsey-or-exception? | |
32 | "True if the value is not falsy or an exception" | |
33 | [value] | |
34 | (and value (not (exception-like? value)))) | |
35 | ||
36 | (defn quick-check | |
37 | "Tests `property` `num-tests` times. | |
38 | Takes optional keys `:seed` and `:max-size`. The seed parameter | |
39 | can be used to re-run previous tests, as the seed used is returned | |
40 | after a test is run. The max-size can be used to control the 'size' | |
41 | of generated values. The size will start at 0, and grow up to | |
42 | max-size, as the number of tests increases. Generators will use | |
43 | the size parameter to bound their growth. This prevents, for example, | |
44 | generating a five-thousand element vector on the very first test. | |
45 | ||
46 | Examples: | |
47 | ||
48 | (def p (for-all [a gen/pos-int] (> (* a a) a))) | |
49 | (quick-check 100 p) | |
50 | " | |
51 | [num-tests property & {:keys [seed max-size] :or {max-size 200}}] | |
52 | (let [[created-seed rng] (make-rng seed) | |
53 | size-seq (gen/make-size-range-seq max-size)] | |
54 | (loop [so-far 0 | |
55 | size-seq size-seq | |
56 | rstate rng] | |
57 | (if (== so-far num-tests) | |
58 | (complete property num-tests created-seed) | |
59 | (let [[size & rest-size-seq] size-seq | |
60 | [r1 r2] (random/split rstate) | |
61 | result-map-rose (gen/call-gen property r1 size) | |
62 | result-map (rose/root result-map-rose) | |
63 | result (:result result-map) | |
64 | args (:args result-map)] | |
65 | (if (not-falsey-or-exception? result) | |
66 | (do | |
67 | (ct/report-trial property so-far num-tests) | |
68 | (recur (inc so-far) rest-size-seq r2)) | |
69 | (failure property result-map-rose so-far size created-seed))))))) | |
70 | ||
71 | (defn- smallest-shrink | |
72 | [total-nodes-visited depth smallest] | |
73 | {:total-nodes-visited total-nodes-visited | |
74 | :depth depth | |
75 | :result (:result smallest) | |
76 | :smallest (:args smallest)}) | |
77 | ||
78 | (defn- shrink-loop | |
79 | "Shrinking a value produces a sequence of smaller values of the same type. | |
80 | Each of these values can then be shrunk. Think of this as a tree. We do a | |
81 | modified depth-first search of the tree: | |
82 | ||
83 | Do a non-exhaustive search for a deeper (than the root) failing example. | |
84 | Additional rules added to depth-first search: | |
85 | * If a node passes the property, you may continue searching at this depth, | |
86 | but not backtrack | |
87 | * If a node fails the property, search its children | |
88 | The value returned is the left-most failing example at the depth where a | |
89 | passing example was found." | |
90 | [rose-tree] | |
91 | (let [shrinks-this-depth (rose/children rose-tree)] | |
92 | (loop [nodes shrinks-this-depth | |
93 | current-smallest (rose/root rose-tree) | |
94 | total-nodes-visited 0 | |
95 | depth 0] | |
96 | (if (empty? nodes) | |
97 | (smallest-shrink total-nodes-visited depth current-smallest) | |
98 | (let [[head & tail] nodes | |
99 | result (:result (rose/root head))] | |
100 | (if (not-falsey-or-exception? result) | |
101 | ;; this node passed the test, so now try testing its right-siblings | |
102 | (recur tail current-smallest (inc total-nodes-visited) depth) | |
103 | ;; this node failed the test, so check if it has children, | |
104 | ;; if so, traverse down them. If not, save this as the best example | |
105 | ;; seen now and then look at the right-siblings | |
106 | ;; children | |
107 | (if-let [children (seq (rose/children head))] | |
108 | (recur children (rose/root head) (inc total-nodes-visited) (inc depth)) | |
109 | (recur tail (rose/root head) (inc total-nodes-visited) depth)))))))) | |
110 | ||
111 | (defn- failure | |
112 | [property failing-rose-tree trial-number size seed] | |
113 | (let [root (rose/root failing-rose-tree) | |
114 | result (:result root) | |
115 | failing-args (:args root)] | |
116 | ||
117 | (ct/report-failure property result trial-number failing-args) | |
118 | ||
119 | {:result result | |
120 | :seed seed | |
121 | :failing-size size | |
122 | :num-tests (inc trial-number) | |
123 | :fail (vec failing-args) | |
124 | :shrunk (shrink-loop failing-rose-tree)})) |
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 | |
10 | (:require [clojure.test.check.generators :as gen] | |
11 | [clojure.test.check.clojure-test :as ct] | |
12 | [clojure.test.check.random :as random] | |
13 | [clojure.test.check.rose-tree :as rose])) | |
14 | ||
15 | (declare shrink-loop failure) | |
16 | ||
17 | (defn- make-rng | |
18 | [seed] | |
19 | (if seed | |
20 | [seed (random/make-random seed)] | |
21 | (let [non-nil-seed (.valueOf (js/Date.))] | |
22 | [non-nil-seed (random/make-random non-nil-seed)]))) | |
23 | ||
24 | (defn- complete | |
25 | [property num-trials seed] | |
26 | (ct/report-trial property num-trials num-trials) | |
27 | {:result true :num-tests num-trials :seed seed}) | |
28 | ||
29 | (defn- not-falsey-or-exception? | |
30 | "True if the value is not falsy or an exception" | |
31 | [value] | |
32 | (and value (not (instance? js/Error value)))) | |
33 | ||
34 | (defn quick-check | |
35 | "Tests `property` `num-tests` times. | |
36 | Takes optional keys `:seed` and `:max-size`. The seed parameter | |
37 | can be used to re-run previous tests, as the seed used is returned | |
38 | after a test is run. The max-size can be used to control the 'size' | |
39 | of generated values. The size will start at 0, and grow up to | |
40 | max-size, as the number of tests increases. Generators will use | |
41 | the size parameter to bound their growth. This prevents, for example, | |
42 | generating a five-thousand element vector on the very first test. | |
43 | ||
44 | Examples: | |
45 | ||
46 | (def p (for-all [a gen/pos-int] (> (* a a) a))) | |
47 | (quick-check 100 p) | |
48 | " | |
49 | [num-tests property & {:keys [seed max-size] :or {max-size 200}}] | |
50 | (let [[created-seed rng] (make-rng seed) | |
51 | size-seq (gen/make-size-range-seq max-size)] | |
52 | (loop [so-far 0 | |
53 | size-seq size-seq | |
54 | rstate rng] | |
55 | (if (== so-far num-tests) | |
56 | (complete property num-tests created-seed) | |
57 | (let [[size & rest-size-seq] size-seq | |
58 | [r1 r2] (random/split rstate) | |
59 | result-map-rose (gen/call-gen property r1 size) | |
60 | result-map (rose/root result-map-rose) | |
61 | result (:result result-map) | |
62 | args (:args result-map)] | |
63 | (if (not-falsey-or-exception? result) | |
64 | (do | |
65 | (ct/report-trial property so-far num-tests) | |
66 | (recur (inc so-far) rest-size-seq r2)) | |
67 | (failure property result-map-rose so-far size created-seed))))))) | |
68 | ||
69 | (defn- smallest-shrink | |
70 | [total-nodes-visited depth smallest] | |
71 | {:total-nodes-visited total-nodes-visited | |
72 | :depth depth | |
73 | :result (:result smallest) | |
74 | :smallest (:args smallest)}) | |
75 | ||
76 | (defn- shrink-loop | |
77 | "Shrinking a value produces a sequence of smaller values of the same type. | |
78 | Each of these values can then be shrunk. Think of this as a tree. We do a | |
79 | modified depth-first search of the tree: | |
80 | ||
81 | Do a non-exhaustive search for a deeper (than the root) failing example. | |
82 | Additional rules added to depth-first search: | |
83 | * If a node passes the property, you may continue searching at this depth, | |
84 | but not backtrack | |
85 | * If a node fails the property, search its children | |
86 | The value returned is the left-most failing example at the depth where a | |
87 | passing example was found." | |
88 | [rose-tree] | |
89 | (let [shrinks-this-depth (rose/children rose-tree)] | |
90 | (loop [nodes shrinks-this-depth | |
91 | current-smallest (rose/root rose-tree) | |
92 | total-nodes-visited 0 | |
93 | depth 0] | |
94 | (if (empty? nodes) | |
95 | (smallest-shrink total-nodes-visited depth current-smallest) | |
96 | (let [[head & tail] nodes | |
97 | result (:result (rose/root head))] | |
98 | (if (not-falsey-or-exception? result) | |
99 | ;; this node passed the test, so now try testing its right-siblings | |
100 | (recur tail current-smallest (inc total-nodes-visited) depth) | |
101 | ;; this node failed the test, so check if it has children, | |
102 | ;; if so, traverse down them. If not, save this as the best example | |
103 | ;; seen now and then look at the right-siblings | |
104 | ;; children | |
105 | (let [children (rose/children head)] | |
106 | (if (empty? children) | |
107 | (recur tail (rose/root head) (inc total-nodes-visited) depth) | |
108 | (recur children (rose/root head) (inc total-nodes-visited) (inc depth)))))))))) | |
109 | ||
110 | (defn- failure | |
111 | [property failing-rose-tree trial-number size seed] | |
112 | (let [root (rose/root failing-rose-tree) | |
113 | result (:result root) | |
114 | failing-args (:args root)] | |
115 | ||
116 | (ct/report-failure property result trial-number failing-args) | |
117 | ||
118 | {:result result | |
119 | :seed seed | |
120 | :failing-size size | |
121 | :num-tests (inc trial-number) | |
122 | :fail (vec failing-args) | |
123 | :shrunk (shrink-loop failing-rose-tree)})) |