Merge branch 'master' into boehm-demers-weiser-gc
[bpt/guile.git] / test-suite / tests / guardians.test
CommitLineData
2e109b65
JB
1;;;; guardians.test --- test suite for Guile Guardians -*- scheme -*-
2;;;; Jim Blandy <jimb@red-bean.com> --- July 1999
3;;;;
6e7d5622 4;;;; Copyright (C) 1999, 2001, 2006 Free Software Foundation, Inc.
2e109b65 5;;;;
53befeb7
NJ
6;;;; This library is free software; you can redistribute it and/or
7;;;; modify it under the terms of the GNU Lesser General Public
8;;;; License as published by the Free Software Foundation; either
9;;;; version 3 of the License, or (at your option) any later version.
2e109b65 10;;;;
53befeb7 11;;;; This library is distributed in the hope that it will be useful,
2e109b65 12;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
53befeb7
NJ
13;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14;;;; Lesser General Public License for more details.
2e109b65 15;;;;
53befeb7
NJ
16;;;; You should have received a copy of the GNU Lesser General Public
17;;;; License along with this library; if not, write to the Free Software
18;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2e109b65
JB
19
20;;; These tests make some questionable assumptions.
6a7489ac 21;;;
2e109b65
JB
22;;; - They assume that a GC will find all dead objects, so they
23;;; will become flaky if we have a generational GC.
6a7489ac
LC
24;;;
25;;; - More generally, when a weakly referenced object doesn't disappear as
26;;; expected, it's hard to tell whether that's because of a guardian bug of
27;;; because a reference to it is being held somewhere, e.g., one some part
28;;; of the stack that hasn't been overwritten. Thus, most tests cannot
29;;; fail, they can just throw `unresolved'. We try hard to clear
30;;; references that may have been left on the stacks (see "clear refs left
31;;; on the stack" lines).
32;;;
2e109b65
JB
33;;; - They assume that objects won't be saved by the guardian until
34;;; they explicitly invoke GC --- in other words, they assume that GC
35;;; won't happen too often.
36
1eefa363
LC
37(define-module (test-guardians)
38 :use-module (test-suite lib)
39 :use-module (ice-9 documentation)
40 :use-module (ice-9 weak-vector))
9247b5bc 41
1eefa363 42\f
9247b5bc
DH
43;;;
44;;; miscellaneous
45;;;
46
47(define (documented? object)
48 (not (not (object-documentation object))))
49
2e109b65 50
2e109b65 51(gc)
2e109b65
JB
52
53;;; Who guards the guardian?
e13f1cbd
LC
54
55;;; Note: We use strings rather than symbols because symbols are usually
56;;; ``interned'', i.e., kept in a weakly-keyed hash table, thus making them
57;;; inappropriate for the tests below. Furthermore, we use `string-copy' in
58;;; order to make sure that no string is kept around in the interpreter
59;;; unwillingly (e.g., in the source-property weak hash table).
60
2e109b65
JB
61(gc)
62(define g2 (make-guardian))
e13f1cbd 63(g2 (list (string-copy "g2-garbage")))
2e109b65 64(define g3 (make-guardian))
e13f1cbd 65(g3 (list (string-copy "g3-garbage")))
2e109b65
JB
66(g3 g2)
67(pass-if "g2-garbage not collected yet" (equal? (g2) #f))
68(pass-if "g3-garbage not collected yet" (equal? (g3) #f))
69(set! g2 #f)
70(gc)
71(let ((seen-g3-garbage #f)
72 (seen-g2 #f)
73 (seen-something-else #f))
74 (let loop ()
75 (let ((saved (g3)))
76 (if saved
77 (begin
78 (cond
e13f1cbd
LC
79 ((equal? saved (list (string-copy "g3-garbage")))
80 (set! seen-g3-garbage #t))
2e109b65 81 ((procedure? saved) (set! seen-g2 saved))
e13f1cbd 82 (else (pk 'junk saved) (set! seen-something-else #t)))
2e109b65 83 (loop)))))
2924541b
MV
84 (pass-if "g3-garbage saved" (or seen-g3-garbage (throw 'unresolved)))
85 (pass-if "g2-saved" (or (procedure? seen-g2) (throw 'unresolved)))
2e109b65 86 (pass-if "nothing else saved" (not seen-something-else))
6a7489ac
LC
87
88 ;; FIXME: The following test fails because the guardian for `g2-garbage'
89 ;; disappared from the weak-car guardian list of `g2-garbage' right before
90 ;; `g2-garbage' was finalized (in `finalize_guarded ()'). Sample session
91 ;; (compiled with `-DDEBUG_GUARDIANS'):
92 ;;
93 ;; guile> (define g (make-guardian))
94 ;; guile> (let ((g2 (make-guardian)))
95 ;; (format #t "g2 = ~x~%" (object-address g2))
96 ;; (g2 (string-copy "foo"))
97 ;; (g g2))
98 ;; g2 = 81fde18
99 ;; guile> (gc)
100 ;; finalizing guarded 0x827f6a0 (1 guardians)
101 ;; guardian for 0x827f6a0 vanished
102 ;; end of finalize (0x827f6a0)
103 ;; finalizing guarded 0x81fde18 (1 guardians)
104 ;; end of finalize (0x81fde18)
105
2924541b 106 (pass-if "g2-garbage saved" (or (and (procedure? seen-g2)
e13f1cbd
LC
107 (equal? (seen-g2)
108 (list (string-copy
109 "g2-garbage"))))
2924541b 110 (throw 'unresolved))))
9247b5bc
DH
111
112(with-test-prefix "standard guardian functionality"
113
114 (with-test-prefix "make-guardian"
115
116 (pass-if "documented?"
117 (documented? make-guardian))
118
119 (pass-if "returns procedure"
120 (procedure? (make-guardian)))
121
122 (pass-if "returns new procedure each time"
123 (not (equal? (make-guardian) (make-guardian)))))
124
125 (with-test-prefix "empty guardian"
126
127 (pass-if "returns #f"
128 (eq? ((make-guardian)) #f))
129
130 (pass-if "returns always #f"
131 (let ((g (make-guardian)))
132 (and (eq? (g) #f)
133 (begin (gc) (eq? (g) #f))
134 (begin (gc) (eq? (g) #f))))))
135
136 (with-test-prefix "guarding independent objects"
137
138 (pass-if "guarding immediate"
139 (let ((g (make-guardian)))
140 (g #f)
141 (and (eq? (g) #f)
142 (begin (gc) (eq? (g) #f))
143 (begin (gc) (eq? (g) #f)))))
144
145 (pass-if "guarding non-immediate"
146 (let ((g (make-guardian)))
147 (gc)
148 (g (cons #f #f))
6a7489ac 149 (cons 'clear 'stack) ;; clear refs left on the stack
9247b5bc
DH
150 (if (not (eq? (g) #f))
151 (throw 'unresolved)
152 (begin
153 (gc)
154 (if (not (equal? (g) (cons #f #f)))
155 (throw 'unresolved)
156 (eq? (g) #f))))))
157
158 (pass-if "guarding two non-immediates"
159 (let ((g (make-guardian)))
160 (gc)
161 (g (cons #f #f))
162 (g (cons #t #t))
6a7489ac 163 (cons 'clear 'stack) ;; clear refs left on the stack
9247b5bc
DH
164 (if (not (eq? (g) #f))
165 (throw 'unresolved)
166 (begin
167 (gc)
168 (let ((l (list (g) (g))))
169 (if (not (or (equal? l (list (cons #f #f) (cons #t #t)))
170 (equal? l (list (cons #t #t) (cons #f #f)))))
171 (throw 'unresolved)
172 (eq? (g) #f)))))))
173
174 (pass-if "re-guarding non-immediates"
175 (let ((g (make-guardian)))
176 (gc)
177 (g (cons #f #f))
6a7489ac 178 (cons 'clear 'stack) ;; clear refs left on the stack
9247b5bc
DH
179 (if (not (eq? (g) #f))
180 (throw 'unresolved)
181 (begin
182 (gc)
183 (let ((p (g)))
184 (if (not (equal? p (cons #f #f)))
185 (throw 'unresolved)
186 (begin
187 (g p)
188 (set! p #f)
189 (gc)
190 (if (not (equal? (g) (cons #f #f)))
191 (throw 'unresolved)
192 (eq? (g) #f)))))))))
193
194 (pass-if "guarding living non-immediate"
195 (let ((g (make-guardian))
196 (p (cons #f #f)))
197 (g p)
198 (if (not (eq? (g) #f))
199 (throw 'fail)
200 (begin
201 (gc)
202 (not (eq? (g) p)))))))
203
204 (with-test-prefix "guarding weakly referenced objects"
205
206 (pass-if "guarded weak vector element gets returned from guardian"
207 (let ((g (make-guardian))
208 (v (weak-vector #f)))
209 (gc)
210 (let ((p (cons #f #f)))
211 (g p)
6a7489ac
LC
212 (vector-set! v 0 p)
213 (set! p #f)) ;; clear refs left on the stack
9247b5bc
DH
214 (if (not (eq? (g) #f))
215 (throw 'unresolved)
216 (begin
217 (gc)
218 (if (not (equal? (g) (cons #f #f)))
219 (throw 'unresolved)
220 (eq? (g) #f))))))
221
2924541b 222 (pass-if "guarded element of weak vector gets eventually removed from weak vector"
9247b5bc
DH
223 (let ((g (make-guardian))
224 (v (weak-vector #f)))
225 (gc)
226 (let ((p (cons #f #f)))
227 (g p)
6a7489ac
LC
228 (vector-set! v 0 p)
229 (set! p #f)) ;; clear refs left on the stack
2924541b
MV
230 (begin
231 (gc)
232 (if (not (equal? (g) (cons #f #f)))
233 (throw 'unresolved)
234 (begin
235 (gc)
236 (or (not (vector-ref v 0))
237 (throw 'unresolved))))))))
9247b5bc
DH
238
239 (with-test-prefix "guarding weak containers"
240
241 (pass-if "element of guarded weak vector gets collected"
242 (let ((g (make-guardian))
6a7489ac
LC
243 (v (weak-vector #f)))
244 ;; Note: We don't pass `(cons #f #f)' as an argument to `weak-vector'
245 ;; otherwise references to it are likely to be left on the stack.
246 (vector-set! v 0 (cons #f #f))
247
9247b5bc
DH
248 (g v)
249 (gc)
250 (if (equal? (vector-ref v 0) (cons #f #f))
251 (throw 'unresolved)
252 #t))))
253
254 (with-test-prefix "guarding guardians"
2924541b 255 #t)
9247b5bc
DH
256
257 (with-test-prefix "guarding dependent objects"
258
2924541b
MV
259 ;; We don't make any guarantees about the order objects are
260 ;; returned from guardians and therefore we skip the following
261 ;; test.
262
263 (if #f
264 (pass-if "guarding vector and element"
265 (let ((g (make-guardian)))
266 (gc)
267 (let ((p (cons #f #f)))
268 (g p)
269 (g (vector p)))
270 (if (not (eq? (g) #f))
271 (throw 'unresolved)
272 (begin
273 (gc)
274 (if (not (equal? (g) (vector (cons #f #f))))
9247b5bc 275 (throw 'unresolved)
2924541b
MV
276 (if (not (eq? (g) #f))
277 (throw 'unresolved)
278 (begin
279 (gc)
280 (if (not (equal? (g) (cons #f #f)))
281 (throw 'unresolved)
282 (eq? (g) #f)))))))))))
9247b5bc
DH
283
284 (with-test-prefix "guarding objects more than once"
2924541b
MV
285
286 (pass-if "guarding twice in one guardian"
287 (let ((g (make-guardian)))
288 (gc)
289 (let ((p (cons #f #f)))
290 (g p)
6a7489ac
LC
291 (g p)
292 (set! p #f)) ;; clear refs left on the stack
2924541b
MV
293 (if (not (eq? (g) #f))
294 (throw 'unresolved)
295 (begin
296 (gc)
297 (or (and (and=> (g) (lambda (o) (equal? o (cons #f #f))))
298 (and=> (g) (lambda (o) (equal? o (cons #f #f)))))
299 (throw 'unresolved))))))
300
301 (pass-if "guarding twice in two guardians"
302 (let ((g (make-guardian))
303 (h (make-guardian)))
304 (gc)
305 (let ((p (cons #f #f)))
306 (g p)
6a7489ac
LC
307 (h p)
308 (set! p #f)) ;; clear refs left on the stack
2924541b
MV
309 (if (not (eq? (g) #f))
310 (throw 'unresolved)
311 (begin
312 (gc)
313 (or (and (and=> (g) (lambda (o) (equal? o (cons #f #f))))
314 (and=> (h) (lambda (o) (equal? o (cons #f #f)))))
315 (throw 'unresolved)))))))
9247b5bc
DH
316
317 (with-test-prefix "guarding cyclic dependencies"
318 #t)
319
320 )