guardians.test 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. ;;;; guardians.test --- test suite for Guile Guardians -*- scheme -*-
  2. ;;;; Jim Blandy <jimb@red-bean.com> --- July 1999
  3. ;;;;
  4. ;;;; Copyright (C) 1999, 2001, 2006, 2014 Free Software Foundation, Inc.
  5. ;;;;
  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.
  10. ;;;;
  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.
  15. ;;;;
  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
  19. ;;; These tests make some questionable assumptions.
  20. ;;;
  21. ;;; - They assume that a GC will find all dead objects, so they
  22. ;;; will become flaky if we have a generational GC.
  23. ;;;
  24. ;;; - More generally, when a weakly referenced object doesn't disappear as
  25. ;;; expected, it's hard to tell whether that's because of a guardian bug of
  26. ;;; because a reference to it is being held somewhere, e.g., one some part
  27. ;;; of the stack that hasn't been overwritten. Thus, most tests cannot
  28. ;;; fail, they can just throw `unresolved'. We try hard to clear
  29. ;;; references that may have been left on the stacks (see "clear refs left
  30. ;;; on the stack" lines).
  31. ;;;
  32. ;;; - They assume that objects won't be saved by the guardian until
  33. ;;; they explicitly invoke GC --- in other words, they assume that GC
  34. ;;; won't happen too often.
  35. (define-module (test-guardians)
  36. :use-module (test-suite lib)
  37. :use-module (ice-9 documentation)
  38. :use-module (ice-9 weak-vector))
  39. ;;;
  40. ;;; miscellaneous
  41. ;;;
  42. (define (documented? object)
  43. (not (not (object-documentation object))))
  44. (gc)
  45. ;;; Who guards the guardian?
  46. ;;; Note: We use strings rather than symbols because symbols are usually
  47. ;;; ``interned'', i.e., kept in a weakly-keyed hash table, thus making them
  48. ;;; inappropriate for the tests below. Furthermore, we use `string-copy' in
  49. ;;; order to make sure that no string is kept around in the interpreter
  50. ;;; unwillingly (e.g., in the source-property weak hash table).
  51. (gc)
  52. (define g2 (make-guardian))
  53. (g2 (list (string-copy "g2-garbage")))
  54. (define g3 (make-guardian))
  55. (g3 (list (string-copy "g3-garbage")))
  56. (g3 g2)
  57. (pass-if "g2-garbage not collected yet" (equal? (g2) #f))
  58. (pass-if "g3-garbage not collected yet" (equal? (g3) #f))
  59. (set! g2 #f)
  60. (gc)
  61. (let ((seen-g3-garbage #f)
  62. (seen-g2 #f)
  63. (seen-something-else #f))
  64. (let loop ()
  65. (let ((saved (g3)))
  66. (if saved
  67. (begin
  68. (cond
  69. ((equal? saved (list (string-copy "g3-garbage")))
  70. (set! seen-g3-garbage #t))
  71. ((procedure? saved) (set! seen-g2 saved))
  72. (else (pk 'junk saved) (set! seen-something-else #t)))
  73. (loop)))))
  74. (pass-if "g3-garbage saved" (or seen-g3-garbage (throw 'unresolved)))
  75. (pass-if "g2-saved" (or (procedure? seen-g2) (throw 'unresolved)))
  76. (pass-if "nothing else saved" (not seen-something-else))
  77. ;; FIXME: The following test fails because the guardian for `g2-garbage'
  78. ;; disappared from the weak-car guardian list of `g2-garbage' right before
  79. ;; `g2-garbage' was finalized (in `finalize_guarded ()'). Sample session
  80. ;; (compiled with `-DDEBUG_GUARDIANS'):
  81. ;;
  82. ;; guile> (define g (make-guardian))
  83. ;; guile> (let ((g2 (make-guardian)))
  84. ;; (format #t "g2 = ~x~%" (object-address g2))
  85. ;; (g2 (string-copy "foo"))
  86. ;; (g g2))
  87. ;; g2 = 81fde18
  88. ;; guile> (gc)
  89. ;; finalizing guarded 0x827f6a0 (1 guardians)
  90. ;; guardian for 0x827f6a0 vanished
  91. ;; end of finalize (0x827f6a0)
  92. ;; finalizing guarded 0x81fde18 (1 guardians)
  93. ;; end of finalize (0x81fde18)
  94. (pass-if "g2-garbage saved" (or (and (procedure? seen-g2)
  95. (equal? (seen-g2)
  96. (list (string-copy
  97. "g2-garbage"))))
  98. (throw 'unresolved))))
  99. (with-test-prefix "standard guardian functionality"
  100. (with-test-prefix "make-guardian"
  101. (pass-if "documented?"
  102. (documented? make-guardian))
  103. (pass-if "returns procedure"
  104. (procedure? (make-guardian)))
  105. (pass-if "returns new procedure each time"
  106. (not (equal? (make-guardian) (make-guardian)))))
  107. (with-test-prefix "empty guardian"
  108. (pass-if "returns #f"
  109. (eq? ((make-guardian)) #f))
  110. (pass-if "returns always #f"
  111. (let ((g (make-guardian)))
  112. (and (eq? (g) #f)
  113. (begin (gc) (eq? (g) #f))
  114. (begin (gc) (eq? (g) #f))))))
  115. (with-test-prefix "guarding independent objects"
  116. (pass-if "guarding immediate"
  117. (let ((g (make-guardian)))
  118. (g #f)
  119. (and (eq? (g) #f)
  120. (begin (gc) (eq? (g) #f))
  121. (begin (gc) (eq? (g) #f)))))
  122. (pass-if "guarding non-immediate"
  123. (let ((g (make-guardian)))
  124. (gc)
  125. (g (cons #f #f))
  126. (cons 'clear 'stack) ;; clear refs left on the stack
  127. (if (not (eq? (g) #f))
  128. (throw 'unresolved)
  129. (begin
  130. (gc)
  131. (if (not (equal? (g) (cons #f #f)))
  132. (throw 'unresolved)
  133. (eq? (g) #f))))))
  134. (pass-if "guarding two non-immediates"
  135. (let ((g (make-guardian)))
  136. (gc)
  137. (g (cons #f #f))
  138. (g (cons #t #t))
  139. (cons 'clear 'stack) ;; clear refs left on the stack
  140. (if (not (eq? (g) #f))
  141. (throw 'unresolved)
  142. (begin
  143. (gc)
  144. (let ((l (list (g) (g))))
  145. (if (not (or (equal? l (list (cons #f #f) (cons #t #t)))
  146. (equal? l (list (cons #t #t) (cons #f #f)))))
  147. (throw 'unresolved)
  148. (eq? (g) #f)))))))
  149. (pass-if "re-guarding non-immediates"
  150. (let ((g (make-guardian)))
  151. (gc)
  152. (g (cons #f #f))
  153. (cons 'clear 'stack) ;; clear refs left on the stack
  154. (if (not (eq? (g) #f))
  155. (throw 'unresolved)
  156. (begin
  157. (gc)
  158. (let ((p (g)))
  159. (if (not (equal? p (cons #f #f)))
  160. (throw 'unresolved)
  161. (begin
  162. (g p)
  163. (set! p #f)
  164. (gc)
  165. (if (not (equal? (g) (cons #f #f)))
  166. (throw 'unresolved)
  167. (eq? (g) #f)))))))))
  168. (pass-if "guarding living non-immediate"
  169. (let ((g (make-guardian))
  170. (p (cons #f #f)))
  171. (g p)
  172. (if (not (eq? (g) #f))
  173. (throw 'fail)
  174. (begin
  175. (gc)
  176. (not (eq? (g) p)))))))
  177. (with-test-prefix "guarding weakly referenced objects"
  178. (pass-if "guarded weak vector element gets returned from guardian"
  179. (let ((g (make-guardian))
  180. (v (weak-vector #f)))
  181. (gc)
  182. (let ((p (cons #f #f)))
  183. (g p)
  184. (weak-vector-set! v 0 p)
  185. (set! p #f)) ;; clear refs left on the stack
  186. (if (not (eq? (g) #f))
  187. (throw 'unresolved)
  188. (begin
  189. (gc)
  190. (if (not (equal? (g) (cons #f #f)))
  191. (throw 'unresolved)
  192. (eq? (g) #f))))))
  193. (pass-if "guarded element of weak vector gets eventually removed from weak vector"
  194. (let ((g (make-guardian))
  195. (v (weak-vector #f)))
  196. (gc)
  197. (let ((p (cons #f #f)))
  198. (g p)
  199. (weak-vector-set! v 0 p)
  200. (set! p #f)) ;; clear refs left on the stack
  201. (begin
  202. (gc)
  203. (if (not (equal? (g) (cons #f #f)))
  204. (throw 'unresolved)
  205. (begin
  206. (gc)
  207. (or (not (weak-vector-ref v 0))
  208. (throw 'unresolved))))))))
  209. (with-test-prefix "guarding weak containers"
  210. (pass-if "element of guarded weak vector gets collected"
  211. (let ((g (make-guardian))
  212. (v (weak-vector #f)))
  213. ;; Note: We don't pass `(cons #f #f)' as an argument to `weak-vector'
  214. ;; otherwise references to it are likely to be left on the stack.
  215. (weak-vector-set! v 0 (cons #f #f))
  216. (g v)
  217. (gc)
  218. (if (equal? (weak-vector-ref v 0) (cons #f #f))
  219. (throw 'unresolved)
  220. #t))))
  221. (with-test-prefix "guarding guardians"
  222. #t)
  223. (with-test-prefix "guarding dependent objects"
  224. ;; We don't make any guarantees about the order objects are
  225. ;; returned from guardians and therefore we skip the following
  226. ;; test.
  227. (if #f
  228. (pass-if "guarding vector and element"
  229. (let ((g (make-guardian)))
  230. (gc)
  231. (let ((p (cons #f #f)))
  232. (g p)
  233. (g (vector p)))
  234. (if (not (eq? (g) #f))
  235. (throw 'unresolved)
  236. (begin
  237. (gc)
  238. (if (not (equal? (g) (vector (cons #f #f))))
  239. (throw 'unresolved)
  240. (if (not (eq? (g) #f))
  241. (throw 'unresolved)
  242. (begin
  243. (gc)
  244. (if (not (equal? (g) (cons #f #f)))
  245. (throw 'unresolved)
  246. (eq? (g) #f)))))))))))
  247. (with-test-prefix "guarding objects more than once"
  248. (pass-if "guarding twice in one guardian"
  249. (let ((g (make-guardian)))
  250. (gc)
  251. (let ((p (cons #f #f)))
  252. (g p)
  253. (g p)
  254. (set! p #f)) ;; clear refs left on the stack
  255. (if (not (eq? (g) #f))
  256. (throw 'unresolved)
  257. (begin
  258. (gc)
  259. (or (and (and=> (g) (lambda (o) (equal? o (cons #f #f))))
  260. (and=> (g) (lambda (o) (equal? o (cons #f #f)))))
  261. (throw 'unresolved))))))
  262. (pass-if "guarding twice in two guardians"
  263. (let ((g (make-guardian))
  264. (h (make-guardian)))
  265. (gc)
  266. (let ((p (cons #f #f)))
  267. (g p)
  268. (h p)
  269. (set! p #f)) ;; clear refs left on the stack
  270. (if (not (eq? (g) #f))
  271. (throw 'unresolved)
  272. (begin
  273. (gc)
  274. (or (and (and=> (g) (lambda (o) (equal? o (cons #f #f))))
  275. (and=> (h) (lambda (o) (equal? o (cons #f #f)))))
  276. (throw 'unresolved)))))))
  277. (with-test-prefix "guarding cyclic dependencies"
  278. #t)
  279. )