Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / test-suite / tests / weaks.test
index b469887..1d53fc4 100644 (file)
@@ -1,5 +1,5 @@
 ;;;; weaks.test --- tests guile's weaks     -*- scheme -*-
-;;;; Copyright (C) 1999, 2001, 2003, 2006 Free Software Foundation, Inc.
+;;;; Copyright (C) 1999, 2001, 2003, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 ;;;; 
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
 ;;; other reasons why they might not work as tested here, so if you
 ;;; haven't done anything to weaks, don't sweat it :)
 
-(use-modules (test-suite lib)
-            (ice-9 weak-vector))
+(define-module (test-weaks)
+  #:use-module (test-suite lib)
+  #:use-module (ice-9 weak-vector)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26))
+
 
 ;;; Creation functions 
 
                     exception:wrong-type-arg
                     (list->weak-vector 32)))
 
- (with-test-prefix "make-weak-key-alist-vector"
+ (with-test-prefix "make-weak-key-hash-table"
                   (pass-if "create"
-                    (make-weak-key-alist-vector 17)
+                    (make-weak-key-hash-table 17)
                     #t)
                   (pass-if-exception "bad-args"
                     exception:wrong-type-arg
-                    (make-weak-key-alist-vector '(bad arg))))
- (with-test-prefix "make-weak-value-alist-vector"
+                    (make-weak-key-hash-table '(bad arg))))
+ (with-test-prefix "make-weak-value-hash-table"
                   (pass-if "create"
-                    (make-weak-value-alist-vector 17)
+                    (make-weak-value-hash-table 17)
                     #t)
                   (pass-if-exception "bad-args"
                     exception:wrong-type-arg
-                    (make-weak-value-alist-vector '(bad arg))))
+                    (make-weak-value-hash-table '(bad arg))))
 
- (with-test-prefix "make-doubly-weak-alist-vector"
+ (with-test-prefix "make-doubly-weak-hash-table"
                   (pass-if "create"
-                    (make-doubly-weak-alist-vector 17)
+                    (make-doubly-weak-hash-table 17)
                     #t)
                   (pass-if-exception "bad-args"
                     exception:wrong-type-arg
-                    (make-doubly-weak-alist-vector '(bad arg)))))
+                    (make-doubly-weak-hash-table '(bad arg)))))
 
 
 
 
 (define global-weak (make-weak-vector 10 #f))
 (begin
-  (vector-set! global-weak 0 "string")
-  (vector-set! global-weak 1 "beans")
-  (vector-set! global-weak 2 "to")
-  (vector-set! global-weak 3 "utah")
-  (vector-set! global-weak 4 "yum yum")
+  (vector-set! global-weak 0 (string-copy "string"))
+  (vector-set! global-weak 1 (string-copy "beans"))
+  (vector-set! global-weak 2 (string-copy "to"))
+  (vector-set! global-weak 3 (string-copy "utah"))
+  (vector-set! global-weak 4 (string-copy "yum yum"))
   (gc))
 
 ;;; Normal weak vectors
                       (not (vector-ref global-weak 4)))
                  (throw 'unresolved))))))
 
- (let ((x (make-weak-key-alist-vector 17))
-      (y (make-weak-value-alist-vector 17))
-      (z (make-doubly-weak-alist-vector 17))
+\f
+;;;
+;;; Weak hash tables & weak alist vectors.
+;;;
+
+(define (valid? value initial-value)
+  ;; Return true if VALUE is "valid", i.e., if it's either #f or
+  ;; INITIAL-VALUE.  The idea is to make sure `hash-ref' doesn't return
+  ;; garbage.
+  (or (not value)
+      (equal? value initial-value)))
+
+ (let ((x (make-weak-key-hash-table 17))
+      (y (make-weak-value-hash-table 17))
+      (z (make-doubly-weak-hash-table 17))
       (test-key "foo")
       (test-value "bar"))
   (with-test-prefix
    "weak-hash"
    (pass-if "lives"
            (begin
-             (hashq-set! x test-key test-value)
-             (hashq-set! y test-key test-value)
-             (hashq-set! z test-key test-value)
+             (hash-set! x test-key test-value)
+             (hash-set! y test-key test-value)
+             (hash-set! z test-key test-value)
              (gc)
              (gc)
-             (and (hashq-ref x test-key)
-                  (hashq-ref y test-key)
-                  (hashq-ref z test-key)
+             (and (hash-ref x test-key)
+                  (hash-ref y test-key)
+                  (hash-ref z test-key)
                   #t)))
+
+   ;; In the tests below we use `string-copy' to avoid the risk of
+   ;; unintended retention of a string that we want to be GC'd.
+
    (pass-if "weak-key dies"
-           (begin
-             (hashq-set! x "this" "is")
-             (hashq-set! x "a" "test")
-             (hashq-set! x "of" "the")
-             (hashq-set! x "emergency" "weak")
-             (hashq-set! x "key" "hash system")
-             (gc)
-             (and 
-              (or (not (hashq-ref x "this"))
-                  (not (hashq-ref x "a"))
-                  (not (hashq-ref x "of"))
-                  (not (hashq-ref x "emergency"))
-                  (not (hashq-ref x "key")))
-              (hashq-ref x test-key)
-              #t)))
+            (begin
+              (hash-set! x (string-copy "this") "is")
+              (hash-set! x (string-copy "a") "test")
+              (hash-set! x (string-copy "of") "the")
+              (hash-set! x (string-copy "emergency") "weak")
+              (hash-set! x (string-copy "key") "hash system")
+              (gc)
+              (let ((values (map (cut hash-ref x <>)
+                                 '("this" "a" "of" "emergency" "key"))))
+                (and (every valid? values
+                            '("is" "test" "the" "weak" "hash system"))
+                     (any not values)
+                     (hash-ref x test-key)
+                     #t))))
 
    (pass-if "weak-value dies"
-           (begin
-             (hashq-set! y "this" "is")
-             (hashq-set! y "a" "test")
-             (hashq-set! y "of" "the")
-             (hashq-set! y "emergency" "weak")
-             (hashq-set! y "value" "hash system")
-             (gc)
-             (and (or (not (hashq-ref y "this"))
-                      (not (hashq-ref y "a"))
-                      (not (hashq-ref y "of"))
-                      (not (hashq-ref y "emergency"))
-                      (not (hashq-ref y "value")))
-                  (hashq-ref y test-key)
-                  #t)))
+            (begin
+              (hash-set! y "this" (string-copy "is"))
+              (hash-set! y "a" (string-copy "test"))
+              (hash-set! y "of" (string-copy "the"))
+              (hash-set! y "emergency" (string-copy "weak"))
+              (hash-set! y "value" (string-copy "hash system"))
+              (gc)
+              (let ((values (map (cut hash-ref y <>)
+                                 '("this" "a" "of" "emergency" "key"))))
+                (and (every valid? values
+                            '("is" "test" "the" "weak" "hash system"))
+                     (any not values)
+                     (hash-ref y test-key)
+                     #t))))
+
    (pass-if "doubly-weak dies"
-           (begin
-             (hashq-set! z "this" "is")
-             (hashq-set! z "a" "test")
-             (hashq-set! z "of" "the")
-             (hashq-set! z "emergency" "weak")
-             (hashq-set! z "all" "hash system")
-             (gc)
-             (and (or (not (hashq-ref z "this"))
-                      (not (hashq-ref z "a"))
-                      (not (hashq-ref z "of"))
-                      (not (hashq-ref z "emergency"))
-                      (not (hashq-ref z "all")))
-                  (hashq-ref z test-key)
-                  #t)))))
+            (begin
+              (hash-set! z (string-copy "this") (string-copy "is"))
+              (hash-set! z "a" (string-copy "test"))
+              (hash-set! z (string-copy "of") "the")
+              (hash-set! z "emergency" (string-copy "weak"))
+              (hash-set! z (string-copy "all") (string-copy "hash system"))
+              (gc)
+              (let ((values (map (cut hash-ref z <>)
+                                 '("this" "a" "of" "emergency" "key"))))
+                (and (every valid? values
+                            '("is" "test" "the" "weak" "hash system"))
+                     (any not values)
+                     (hash-ref z test-key)
+                     #t))))
+
+   (pass-if "hash-set!, weak val, im -> im"
+     (let ((t (make-weak-value-hash-table)))
+       (hash-set! t "foo" 1)
+       (hash-set! t "foo" 2)
+       (equal? (hash-ref t "foo") 2)))
+
+   (pass-if "hash-set!, weak val, im -> nim"
+     (let ((t (make-weak-value-hash-table)))
+       (hash-set! t "foo" 1)
+       (hash-set! t "foo" "baz")
+       (equal? (hash-ref t "foo") "baz")))
+
+   (pass-if "hash-set!, weak val, nim -> nim"
+     (let ((t (make-weak-value-hash-table)))
+       (hash-set! t "foo" "bar")
+       (hash-set! t "foo" "baz")
+       (equal? (hash-ref t "foo") "baz")))
+
+   (pass-if "hash-set!, weak val, nim -> im"
+     (let ((t (make-weak-value-hash-table)))
+       (hash-set! t "foo" "bar")
+       (hash-set! t "foo" 1)
+       (equal? (hash-ref t "foo") 1)))
+
+   (pass-if "hash-set!, weak key, returns value"
+     (let ((t (make-weak-value-hash-table))
+           (val (string #\f #\o #\o)))
+       (eq? (hashq-set! t "bar" val)
+            (hashv-set! t "bar" val)
+            (hash-set! t "bar" val)
+            val)))
+
+   (pass-if "assoc can do anything"
+            ;; Until 1.9.12, as hash table's custom ASSOC procedure was
+            ;; called with the GC lock alloc held, which imposed severe
+            ;; restrictions on what it could do (bug #29616).  This test
+            ;; makes sure this is no longer the case.
+            (let ((h (make-doubly-weak-hash-table 2))
+                  (c 123)
+                  (k "GNU"))
+
+              (define (assoc-ci key bucket)
+                (make-list 123) ;; this should be possible
+                (gc)            ;; this too
+                (find (lambda (p)
+                        (string-ci=? key (car p)))
+                      bucket))
+
+              (hashx-set! string-hash-ci assoc-ci h
+                          (string-copy "hello") (string-copy "world"))
+              (hashx-set! string-hash-ci assoc-ci h
+                          k "Guile")
+
+              (and (every (cut valid? <> "Guile")
+                          (unfold (cut >= <> c)
+                                  (lambda (_)
+                                    (hashx-ref string-hash-ci assoc-ci
+                                               h "gnu"))
+                                  1+
+                                  0))
+                   (every (cut valid? <> "world")
+                          (unfold (cut >= <> c)
+                                  (lambda (_)
+                                    (hashx-ref string-hash-ci assoc-ci
+                                               h "HELLO"))
+                                  1+
+                                  0))
+                   #t)))))