~ chicken-r7rs (master) 64ed36736e514c9a7b81856bbb60669cf95b8ba0
commit 64ed36736e514c9a7b81856bbb60669cf95b8ba0
Author: Peter Bex <peter@more-magic.net>
AuthorDate: Sat Jun 8 15:10:30 2013 +0000
Commit: Evan Hanson <evhan@foldling.org>
CommitDate: Sat Jun 8 15:10:30 2013 +0000
Fix call-with-port, it should only close the port on normal return. Add a test for this.
diff --git a/scheme.base.scm b/scheme.base.scm
index 8037b83..65d1ca6 100644
--- a/scheme.base.scm
+++ b/scheme.base.scm
@@ -161,7 +161,10 @@
;;;
(define (call-with-port port proc)
- (dynamic-wind void (lambda () (proc port)) (lambda () (close-port port))))
+ (receive ret
+ (proc port)
+ (close-port port)
+ (apply values ret)))
(define (close-port port)
(cond ((input-port? port)
diff --git a/tests/run.scm b/tests/run.scm
index e33838a..2c33573 100644
--- a/tests/run.scm
+++ b/tests/run.scm
@@ -15,45 +15,69 @@
((_ . body) (handle-exceptions e e . body))))
(test-group "exceptions"
- (test "with-exception-handler (escape)"
- 'exception
- (call-with-current-continuation
- (lambda (k)
- (with-exception-handler
- (lambda (e) (k 'exception))
- (lambda () (+ 1 (raise 'an-error)))))))
- (test-error "with-exception-handler (return)"
- (with-exception-handler
- (lambda (e) 'ignore)
- (lambda () (+ 1 (raise 'an-error)))))
- (test-error "with-exception-handler (raise)"
- (with-exception-handler
- (lambda (e) 'ignore)
- (lambda () (+ 1 (raise 'an-error)))))
- (test "with-exception-handler (raise-continuable)"
- 65
- (with-exception-handler
- (lambda (e) 42)
- (lambda () (+ (raise-continuable "should be a number") 23))))
- (test "error-object? (#f)" #f (error-object? 'no))
- (test "error-object? (#t)" #t (error-object? (catch (car '()))))
- (test "error-object-message" "fubar" (error-object-message (catch (error "fubar"))))
- (test "error-object-irritants" '(42) (error-object-irritants (catch (error "fubar" 42))))
- (test "read-error? (#f)" #f (read-error? (catch (car '()))))
- (test "read-error? (#t)" #t (read-error? (catch (read-from-string ")"))))
- (test "file-error? (#f)" #f (file-error? (catch (car '()))))
- (test "file-error? (#t)" #t (file-error? (catch (open-input-file "foo"))))
- (test-error "guard (no match)"
- (guard (condition ((assq 'c condition))) (raise '((a . 42)))))
- (test "guard (match)"
- '(b . 23)
- (guard (condition ((assq 'b condition))) (raise '((b . 23)))))
- (test "guard (=>)"
- 42
- (guard (condition ((assq 'a condition) => cdr)) (raise '((a . 42)))))
- (test "guard (multiple)"
- '(b . 23)
- (guard (condition
- ((assq 'a condition) => cdr)
- ((assq 'b condition)))
- (raise '((b . 23))))))
+ (test "with-exception-handler (escape)"
+ 'exception
+ (call-with-current-continuation
+ (lambda (k)
+ (with-exception-handler
+ (lambda (e) (k 'exception))
+ (lambda () (+ 1 (raise 'an-error)))))))
+ (test-error "with-exception-handler (return)"
+ (with-exception-handler
+ (lambda (e) 'ignore)
+ (lambda () (+ 1 (raise 'an-error)))))
+ (test-error "with-exception-handler (raise)"
+ (with-exception-handler
+ (lambda (e) 'ignore)
+ (lambda () (+ 1 (raise 'an-error)))))
+ (test "with-exception-handler (raise-continuable)"
+ 65
+ (with-exception-handler
+ (lambda (e) 42)
+ (lambda () (+ (raise-continuable "should be a number") 23))))
+ (test "error-object? (#f)" #f (error-object? 'no))
+ (test "error-object? (#t)" #t (error-object? (catch (car '()))))
+ (test "error-object-message" "fubar" (error-object-message (catch (error "fubar"))))
+ (test "error-object-irritants" '(42) (error-object-irritants (catch (error "fubar" 42))))
+ (test "read-error? (#f)" #f (read-error? (catch (car '()))))
+ (test "read-error? (#t)" #t (read-error? (catch (read-from-string ")"))))
+ (test "file-error? (#f)" #f (file-error? (catch (car '()))))
+ (test "file-error? (#t)" #t (file-error? (catch (open-input-file "foo"))))
+ (test-error "guard (no match)"
+ (guard (condition ((assq 'c condition))) (raise '((a . 42)))))
+ (test "guard (match)"
+ '(b . 23)
+ (guard (condition ((assq 'b condition))) (raise '((b . 23)))))
+ (test "guard (=>)"
+ 42
+ (guard (condition ((assq 'a condition) => cdr)) (raise '((a . 42)))))
+ (test "guard (multiple)"
+ '(b . 23)
+ (guard (condition
+ ((assq 'a condition) => cdr)
+ ((assq 'b condition)))
+ (raise '((b . 23))))))
+
+;; call-with-port is not supposed to close its port when leaving the
+;; dynamic extent, only on normal return.
+(test-group "ports"
+ (let*-values (((jump-back? jump!) (call/cc (lambda (k) (values #f k))))
+ (_ (and jump-back? (jump! (void))))
+ ((string)
+ (call-with-output-string
+ (lambda (the-string-port)
+ (test "call-with-port returns all values yielded by proc"
+ '(1 2 3)
+ (receive (call-with-port
+ the-string-port
+ (lambda (p)
+ (display "foo" p)
+ ;; Leave the dynamic extent momentarily;
+ ;; jump! will immediately return with #t.
+ (call/cc (lambda (k) (jump! #t k)))
+ (display "bar" p)
+ (values 1 2 3)))))
+ (test-assert "call-with-port closes the port on normal return"
+ (port-closed? the-string-port))))))
+ (test "call-with-port passes the port correctly and allows temporary escapes"
+ "foobar" string)))
Trap