-
Notifications
You must be signed in to change notification settings - Fork 34
/
test.janet
156 lines (139 loc) · 4.54 KB
/
test.janet
1
2
3
4
5
6
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
82
83
84
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# Helper code for running tests
(var num-tests-passed 0)
(var num-tests-run 0)
(var suite-num 0)
(var start-time 0)
(def- tests-passed-ref (get (dyn 'num-tests-passed) :ref))
(def- tests-run-ref (get (dyn 'num-tests-run) :ref))
(defmacro assert
"Overrides the default assert with some nice error handling."
[x &opt e]
(default e (string/format "%j" (dyn :macro-form)))
(def xx (gensym))
~(do
(++ (',tests-run-ref 0))
(def ,xx ,x)
(if ,xx (++ (',tests-passed-ref 0)))
(as-macro ,unless ,xx
(if (os/isatty)
(,prin "\e[31m✘\e[0m ")
(,prin "[FAIL] "))
(,print ,e))
,xx))
(defmacro assert-not
"Invert assert."
[x &opt e]
~(as-macro ,assert (,not ,x) ,e))
(defmacro assert-error
"Test passes if forms error."
[msg & forms]
(def errsym (gensym))
~(as-macro ,assert (,= ',errsym (as-macro ,try (do ,;forms) ([_] ',errsym))) ,msg))
(defmacro assert-no-error
"Test passes if forms do not error."
[msg & forms]
(def errsym (gensym))
~(as-macro ,assert (,not= ',errsym (as-macro ,try (do ,;forms) ([_] ',errsym))) ,msg))
(defn start-suite
"Starts test suite."
[&opt name]
(default name (dyn :current-file))
(set suite-num name)
(set start-time (os/clock))
(set num-tests-passed 0)
(set num-tests-run 0))
(defn end-suite
"Ends test suite, prints summary and exits if any tests have failed."
[]
(def delta (- (os/clock) start-time))
(prinf "test suite %V finished in %.3f seconds - " suite-num delta)
(print num-tests-passed " of " num-tests-run " tests passed.")
(if (not= num-tests-passed num-tests-run) (os/exit 1)))
(defmacro timeit
```
Time the execution of `form` using `os/clock` before and after,
and print the result to stdout. Returns result of executing `form`.
Uses `tag` (default "Elapsed time:") to tag the printout.
```
[form &opt tag]
(default tag "Elapsed time:")
(with-syms [start result end]
~(do
(def ,start (os/clock))
(def ,result ,form)
(def ,end (os/clock))
(print ,tag " " (- ,end ,start) " seconds")
,result)))
(defmacro timeit-loop
``Similar to `loop`, but outputs performance statistics after completion.
Additionally defines a `:timeout` verb to iterate continuously for a given
number of seconds. If the first form of `body` is a bytes, it will be taken
as a custom tag.``
[head & body]
(var tag "Elapsed time:")
(def head2 @[;head])
(def body2 @[;body])
(with-syms [c start elapsed per-body]
(when (def i (index-of :timeout head2))
(array/insert head2 i [])
(set (head2 (+ i 1)) :iterate)
(set (head2 (+ i 2)) ~(< (- (os/clock) ,start) ,(in head2 (+ i 2)))))
(when (bytes? (get body2 0))
(set tag (in body2 0))
(array/remove body2 0))
~(do
(var ,c 0)
(def ,start (os/clock))
(loop ,head2 (++ ,c) ,;body2)
(def ,elapsed (- (os/clock) ,start))
(def ,per-body (/ ,elapsed ,c))
(cond
(< ,per-body 1e-3) (printf "%s %.3fs, %.4gµs/body" ,tag ,elapsed (* ,per-body 1_000_000))
(< ,per-body 1) (printf "%s %.3fs, %.4gms/body" ,tag ,elapsed (* ,per-body 1_000))
(printf "%s %.3fs, %.4gs/body" ,tag ,elapsed ,per-body)))))
(defmacro- capture-*
[out & body]
(with-syms [buf res]
~(do
(def ,buf @"")
(with-dyns [,out ,buf]
(def ,res (do ,;body))
[,res (string ,buf)]))))
(defmacro capture-stdout
```
Runs the form and captures stdout. Returns tuple with result of the form
and a string with captured stdout.
```
[& body]
~(as-macro ,capture-* :out ,;body))
(defmacro capture-stderr
```
Runs the form and captures stderr. Returns tuple with result of the form
and a string with captured stderr.
```
[& body]
~(as-macro ,capture-* :err ,;body))
(defmacro- suppress-* [out & body]
~(with-dyns [,out @""] ,;body))
(defmacro suppress-stdout
"Suppreses stdout from the body"
[& body]
~(as-macro ,suppress-* :out ,;body))
(defmacro suppress-stderr
"Suppreses stderr from the body"
[& body]
~(as-macro ,suppress-* :err ,;body))
(defn assert-docs
```
Assert that all symbols have proper docstring when module on the
path is required.
```
[path]
(loop [[sym val] :pairs (require path)
:when (and (symbol? sym) (not (val :private)) (not (val :ref)))]
(assert (and (val :doc)
(peg/match '(* (+ (* "(" (thru ")\n\n"))
(not "("))
(some 1) -1)
(get val :doc "")))
(string sym " does not have proper doc"))))