1 ;;;; guardians.test --- test suite for Guile Guardians -*- scheme -*-
2 ;;;; Jim Blandy <jimb@red-bean.com> --- July 1999
4 ;;;; Copyright (C) 1999, 2001, 2006 Free Software Foundation, Inc.
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.
11 ;;;; This library is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;;;; Lesser General Public License for more details.
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
20 ;;; These tests make some questionable assumptions.
22 ;;; - They assume that a GC will find all dead objects, so they
23 ;;; will become flaky if we have a generational GC.
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).
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.
37 (define-module (test-guardians)
38 :use-module (test-suite lib)
39 :use-module (ice-9 documentation)
40 :use-module (ice-9 weak-vector))
47 (define (documented? object)
48 (not (not (object-documentation object))))
53 ;;; Who guards the guardian?
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).
62 (define g2 (make-guardian))
63 (g2 (list (string-copy "g2-garbage")))
64 (define g3 (make-guardian))
65 (g3 (list (string-copy "g3-garbage")))
67 (pass-if "g2-garbage not collected yet" (equal? (g2) #f))
68 (pass-if "g3-garbage not collected yet" (equal? (g3) #f))
71 (let ((seen-g3-garbage #f)
73 (seen-something-else #f))
79 ((equal? saved (list (string-copy "g3-garbage")))
80 (set! seen-g3-garbage #t))
81 ((procedure? saved) (set! seen-g2 saved))
82 (else (pk 'junk saved) (set! seen-something-else #t)))
84 (pass-if "g3-garbage saved" (or seen-g3-garbage (throw 'unresolved)))
85 (pass-if "g2-saved" (or (procedure? seen-g2) (throw 'unresolved)))
86 (pass-if "nothing else saved" (not seen-something-else))
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'):
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"))
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)
106 (pass-if "g2-garbage saved" (or (and (procedure? seen-g2)
110 (throw 'unresolved))))
112 (with-test-prefix "standard guardian functionality"
114 (with-test-prefix "make-guardian"
116 (pass-if "documented?"
117 (documented? make-guardian))
119 (pass-if "returns procedure"
120 (procedure? (make-guardian)))
122 (pass-if "returns new procedure each time"
123 (not (equal? (make-guardian) (make-guardian)))))
125 (with-test-prefix "empty guardian"
127 (pass-if "returns #f"
128 (eq? ((make-guardian)) #f))
130 (pass-if "returns always #f"
131 (let ((g (make-guardian)))
133 (begin (gc) (eq? (g) #f))
134 (begin (gc) (eq? (g) #f))))))
136 (with-test-prefix "guarding independent objects"
138 (pass-if "guarding immediate"
139 (let ((g (make-guardian)))
142 (begin (gc) (eq? (g) #f))
143 (begin (gc) (eq? (g) #f)))))
145 (pass-if "guarding non-immediate"
146 (let ((g (make-guardian)))
149 (cons 'clear 'stack) ;; clear refs left on the stack
150 (if (not (eq? (g) #f))
154 (if (not (equal? (g) (cons #f #f)))
158 (pass-if "guarding two non-immediates"
159 (let ((g (make-guardian)))
163 (cons 'clear 'stack) ;; clear refs left on the stack
164 (if (not (eq? (g) #f))
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)))))
174 (pass-if "re-guarding non-immediates"
175 (let ((g (make-guardian)))
178 (cons 'clear 'stack) ;; clear refs left on the stack
179 (if (not (eq? (g) #f))
184 (if (not (equal? p (cons #f #f)))
190 (if (not (equal? (g) (cons #f #f)))
194 (pass-if "guarding living non-immediate"
195 (let ((g (make-guardian))
198 (if (not (eq? (g) #f))
202 (not (eq? (g) p)))))))
204 (with-test-prefix "guarding weakly referenced objects"
206 (pass-if "guarded weak vector element gets returned from guardian"
207 (let ((g (make-guardian))
208 (v (weak-vector #f)))
210 (let ((p (cons #f #f)))
213 (set! p #f)) ;; clear refs left on the stack
214 (if (not (eq? (g) #f))
218 (if (not (equal? (g) (cons #f #f)))
222 (pass-if "guarded element of weak vector gets eventually removed from weak vector"
223 (let ((g (make-guardian))
224 (v (weak-vector #f)))
226 (let ((p (cons #f #f)))
229 (set! p #f)) ;; clear refs left on the stack
232 (if (not (equal? (g) (cons #f #f)))
236 (or (not (vector-ref v 0))
237 (throw 'unresolved))))))))
239 (with-test-prefix "guarding weak containers"
241 (pass-if "element of guarded weak vector gets collected"
242 (let ((g (make-guardian))
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))
250 (if (equal? (vector-ref v 0) (cons #f #f))
254 (with-test-prefix "guarding guardians"
257 (with-test-prefix "guarding dependent objects"
259 ;; We don't make any guarantees about the order objects are
260 ;; returned from guardians and therefore we skip the following
264 (pass-if "guarding vector and element"
265 (let ((g (make-guardian)))
267 (let ((p (cons #f #f)))
270 (if (not (eq? (g) #f))
274 (if (not (equal? (g) (vector (cons #f #f))))
276 (if (not (eq? (g) #f))
280 (if (not (equal? (g) (cons #f #f)))
282 (eq? (g) #f)))))))))))
284 (with-test-prefix "guarding objects more than once"
286 (pass-if "guarding twice in one guardian"
287 (let ((g (make-guardian)))
289 (let ((p (cons #f #f)))
292 (set! p #f)) ;; clear refs left on the stack
293 (if (not (eq? (g) #f))
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))))))
301 (pass-if "guarding twice in two guardians"
302 (let ((g (make-guardian))
305 (let ((p (cons #f #f)))
308 (set! p #f)) ;; clear refs left on the stack
309 (if (not (eq? (g) #f))
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)))))))
317 (with-test-prefix "guarding cyclic dependencies"