Newer
Older
(def divider-heavy "================================================================================")
(def divider-light "--------------------------------------------------------------------------------")
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# no reason to use a dynamic binding here since it's global anyway (?)
(def toplevel :private @[])
(defn group [description thunk]
(with-dyns [:children @[]
:before nil
:before-each nil
:after nil
:after-each nil]
(thunk)
(array/push toplevel {:type 'group
:description description
:children (dyn :children)
:before (dyn :before)
:before-each (dyn :before-each)
:after (dyn :after)
:after-each (dyn :after-each)})))
(defn before [thunk]
(setdyn :before thunk))
(defn before-each [thunk]
(setdyn :before-each thunk))
(defn after [thunk]
(setdyn :after thunk))
(defn after-each [thunk]
(setdyn :after-each thunk))
(defn test [description thunk]
(array/push (dyn :children) {:type 'test
:description description
:thunk thunk}))
(defn execute-toplevel []
(map (fn [group]
# TODO: catch errors in hooks?
(when-let [before (group :before)]
(before))
(def child-results
(map (fn [child]
(when-let [before-each (group :before-each)]
(before-each))
(match child
{:type 'test :thunk thunk :description desc}
(try
(do
((test :thunk))
(printf "* %s ✅" (test :description))
{:type 'test :test test :passed true})
([err]
(printf "* %s ❌" (test :description))
{:type 'test :test test :passed false :error err}))
# TODO: :type 'group
)
(when-let [after-each (group :after-each)]
(after-each)))
(group :children)))
(when-let [after (group :after)]
(after))
{:type 'group :group group :children child-results})
toplevel))
(defn run-tests []
(def results (execute-toplevel))
(print divider-heavy)
(report results)
(let
# TODO: do better
[is-repl (and (= "janet" (path/basename (dyn *executable*)))
(all (fn [arg] (not= ".janet" (path/ext arg))) (dyn *args*)))
some-failed (some (fn [res] (not (res :passed))) results)]
(when (and some-failed (not is-repl))
(os/exit 1))))
(defn- report "Default reporter" [results]
(print "FAILURES:")
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# TODO: recursion
(def failure-results
(reduce
(fn [acc group-result]
(if-let [failed-children (filter (fn [res] (not (res :passed)))
(group-result :children))
failed-group-result (merge group-result
{:children failed-children})]
(array/push acc failed-group-result)
acc))
(array/new)
results))
(defn get-spaces [n]
(string (splice (g/to-array (g/take 10 (g/cycle [" "])))))
(->> [" "]
(generators/cycle)
(generators/take 10)
(generators/to-array)
(splice)
(string)))
(defn print-failure-results [result depth]
(def indent (get-spaces (* 2 depth)))
(match result
{:type 'group :group {:description desc} :children child-results}
(do
(print indent desc)
(loop [child-result :in child-results]
(print-failure-results child-result (+ 1 depth))))
{:type 'test :test {:description desc} :error err}
(do
(print indent desc)
(print err)
(print))))
(loop [result :in failure-results]
(print-failure-result result 0))
(print divider-heavy)
(print "SUMMARY:")
(print divider-light)
(let [num-total (length results)
num-passed (sum (map (fn [res] (if (res :passed) 1 0)) results))
num-failed (- num-total num-passed)]
(printf "Total: %i" num-total)
(printf "Passing: %i" num-passed)
(printf "Failed: %i" num-failed))
(print divider-heavy))
(defn reset "Clear defined tests" []
(set tests @[]))