-
Notifications
You must be signed in to change notification settings - Fork 448
/
test_helper.clj
149 lines (124 loc) · 4.38 KB
/
test_helper.clj
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
(ns test-helper
"Helpful functions and macro's for writing Overtone tests."
(:use overtone.core
clojure.test)
(:import [java.util.concurrent TimeoutException]))
;; ns helpers
;; borrowed from clojure.test-helper
(defmacro eval-in-temp-ns
"Evaluates the given forms in a temporary ns and restores the
current ns when done. Ensures that the temporary ns is removed."
[& forms]
`(let [temp-ns# (gensym)]
(try
(binding [*ns* *ns*]
(in-ns temp-ns#)
(clojure.core/use 'clojure.core)
(eval '(do ~@forms)))
(finally
(remove-ns temp-ns#)))))
;; Async Helpers
;;
;; Useful bits of code for automated testing of asynchronous
;; code.
(defn invoke-timeout
"Invokes the function 'f' with the given timeout. Attempts to
interrupt the current thread if the timeout is exceeded. Returns the
result of invoking 'f' or throws a TimeoutException."
[f timeout-ms]
(let [thr (Thread/currentThread)
fut (future (Thread/sleep timeout-ms)
(.interrupt thr))]
(try (f)
(catch InterruptedException e
(throw (TimeoutException. "Execution timed out!")))
(finally
(future-cancel fut)))))
(defmacro timeout
"Invokes a body of expressions with the given timeout. Attempts to
interrupt the current thread if the timeout is exceeded. Returns the
result of the last expression or throws a TimeoutException."
[ms & body]
`(invoke-timeout (^{:once true} fn [] ~@body) ~ms))
(defn wait-while
"Blocks the current thread while `pred` returns true.
Optional arguments [default]:
`timeout-ms` time in ms to wait before TimeoutException [nil]
`interval-ms` time in ms to wait before re-invoking `pred` [1]"
([pred]
(wait-while pred nil 1))
([pred timeout-ms]
(wait-while pred timeout-ms 1))
([pred timeout-ms interval-ms]
(let [thunk #(loop []
(when (pred)
(Thread/sleep interval-ms)
(recur)))]
(if timeout-ms
(invoke-timeout thunk timeout-ms)
(thunk)))))
(defn wait-until
"Blocks the current thread until `pred` returns true.
See `wait-while` for supported options."
([pred]
(wait-until pred nil 1))
([pred timeout-ms]
(wait-until pred timeout-ms 1))
([pred timeout-ms interval-ms]
(wait-while (complement pred) timeout-ms interval-ms)))
;; Test Fixtures
(def with-server-sync #'overtone.sc.machinery.server.comms/with-server-sync)
(defn with-internal-server
"Fixture. Ensures that a fresh scsynth server is booted before
running your tests. Kill's any pre-existing server and cleans up
when done."
[f]
(kill-server)
(boot-internal-server)
(wait-until-mixer-booted)
(f)
(kill-server))
(defn with-sync-reset
"Fixture. Ensures that the server gets reset after each test.
Synchronously stops active nodes in the default foundation-group,
clears the osc message queue, and kills all scheduled jobs in the
player-pool if any."
[f] (do (f) (sync-event :reset)))
;; Some quick tests to verify test-helpers...
(deftest eval-in-temp-ns-test
(testing "without errors..."
(let [ns *ns*
ns-count (count (all-ns))]
(eval-in-temp-ns (+ 1 2 3))
(is (= ns-count (count (all-ns))) "removes temp-ns when done")
(is (= ns *ns*) "restores original ns")))
(testing "with errors..."
(let [ns *ns*
ns-count (count (all-ns))]
(try (eval-in-temp-ns (/ 1 0))
(catch java.lang.ArithmeticException e))
(is (= ns-count (count (all-ns))) "removes temp-ns when done")
(is (= ns *ns*) "restores original ns"))))
(deftest invoke-timeout-test
(testing "invoke-timeout..."
(let [n (Thread/activeCount)]
(invoke-timeout #(Thread/sleep 100) 1000)
(is (= n (Thread/activeCount)) "cleans up threads")
(is (thrown? TimeoutException (invoke-timeout #(Thread/sleep 1000) 100))
"throws TimeoutException"))))
(deftest wait-while-test
(testing "wait-while..."
(let [done? (atom nil)]
(future (Thread/sleep 1000)
(reset! done? :done))
(wait-while #(not @done?))
(is (= :done @done?)
"delays the current thread"))
(let [done? (atom nil)]
(future (Thread/sleep 1000)
(reset! done? :done))
(is (thrown? TimeoutException (wait-while #(not @done?) 100))
"throws TimeoutException"))))
(comment
(run-tests)
)