Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / test-suite / tests / r6rs-ports.test
CommitLineData
8aa47f26 1;;;; r6rs-ports.test --- R6RS I/O port tests. -*- coding: utf-8; -*-
1ee2c72e 2;;;;
6dce942c 3;;;; Copyright (C) 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
8aa47f26 4;;;; Ludovic Courtès
1ee2c72e
LC
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
53befeb7
NJ
9;;;; version 3 of the License, or (at your option) any later version.
10;;;;
1ee2c72e
LC
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.
53befeb7 15;;;;
1ee2c72e
LC
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
20(define-module (test-io-ports)
d4b81637 21 #:use-module (test-suite lib)
b6a66c21 22 #:use-module (test-suite guile-test)
d4b81637
LC
23 #:use-module (srfi srfi-1)
24 #:use-module (srfi srfi-11)
25 #:use-module (rnrs io ports)
b6a66c21 26 #:use-module (rnrs io simple)
b1e76e8f 27 #:use-module (rnrs exceptions)
d4b81637 28 #:use-module (rnrs bytevectors))
1ee2c72e 29
b6a66c21
AR
30(define-syntax pass-if-condition
31 (syntax-rules ()
32 ((_ name predicate body0 body ...)
33 (let ((cookie (list 'cookie)))
34 (pass-if name
35 (eq? cookie (guard (c ((predicate c) cookie))
36 body0 body ...)))))))
37
38(define (test-file)
39 (data-file-name "ports-test.tmp"))
40
41;; A input/output port that swallows all output, and produces just
42;; spaces on input. Reading and writing beyond `failure-position'
43;; produces `system-error' exceptions. Used for testing exception
44;; behavior.
45(define* (make-failing-port #:optional (failure-position 0))
46 (define (maybe-fail index errno)
47 (if (> index failure-position)
48 (scm-error 'system-error
49 'failing-port
50 "I/O beyond failure position" '()
51 (list errno))))
52 (let ((read-index 0)
53 (write-index 0))
54 (define (write-char chr)
55 (set! write-index (+ 1 write-index))
56 (maybe-fail write-index ENOSPC))
57 (make-soft-port
58 (vector write-char
59 (lambda (str) ;; write-string
60 (for-each write-char (string->list str)))
61 (lambda () #t) ;; flush-output
62 (lambda () ;; read-char
63 (set! read-index (+ read-index 1))
64 (maybe-fail read-index EIO)
65 #\space)
66 (lambda () #t)) ;; close-port
67 "rw")))
68
dfc4d56d
AR
69(define (call-with-bytevector-output-port/transcoded transcoder receiver)
70 (call-with-bytevector-output-port
71 (lambda (bv-port)
72 (call-with-port (transcoded-port bv-port transcoder)
73 receiver))))
74
1ee2c72e
LC
75\f
76(with-test-prefix "7.2.5 End-of-File Object"
77
78 (pass-if "eof-object"
79 (and (eqv? (eof-object) (eof-object))
b04f841d
AW
80 (eq? (eof-object) (eof-object))))
81
82 (pass-if "port-eof?"
83 (port-eof? (open-input-string ""))))
1ee2c72e
LC
84
85\f
86(with-test-prefix "7.2.8 Binary Input"
87
88 (pass-if "get-u8"
89 (let ((port (open-input-string "A")))
90 (and (= (char->integer #\A) (get-u8 port))
91 (eof-object? (get-u8 port)))))
92
93 (pass-if "lookahead-u8"
94 (let ((port (open-input-string "A")))
95 (and (= (char->integer #\A) (lookahead-u8 port))
8aa47f26 96 (= (char->integer #\A) (lookahead-u8 port))
1ee2c72e
LC
97 (= (char->integer #\A) (get-u8 port))
98 (eof-object? (get-u8 port)))))
99
8aa47f26 100 (pass-if "lookahead-u8 non-ASCII"
6dce942c 101 (let ((port (open-input-string "λ")))
8aa47f26
LC
102 (and (= 206 (lookahead-u8 port))
103 (= 206 (lookahead-u8 port))
104 (= 206 (get-u8 port))
105 (= 187 (lookahead-u8 port))
106 (= 187 (lookahead-u8 port))
107 (= 187 (get-u8 port))
108 (eof-object? (lookahead-u8 port))
109 (eof-object? (get-u8 port)))))
110
3fa88220
LC
111 (pass-if "lookahead-u8: result is unsigned"
112 ;; Bug #31081.
113 (let ((port (open-bytevector-input-port #vu8(255))))
114 (= (lookahead-u8 port) 255)))
115
1ee2c72e
LC
116 (pass-if "get-bytevector-n [short]"
117 (let* ((port (open-input-string "GNU Guile"))
118 (bv (get-bytevector-n port 4)))
119 (and (bytevector? bv)
120 (equal? (bytevector->u8-list bv)
121 (map char->integer (string->list "GNU "))))))
122
123 (pass-if "get-bytevector-n [long]"
124 (let* ((port (open-input-string "GNU Guile"))
125 (bv (get-bytevector-n port 256)))
126 (and (bytevector? bv)
127 (equal? (bytevector->u8-list bv)
128 (map char->integer (string->list "GNU Guile"))))))
129
130 (pass-if-exception "get-bytevector-n with closed port"
131 exception:wrong-type-arg
132
133 (let ((port (%make-void-port "r")))
134
135 (close-port port)
136 (get-bytevector-n port 3)))
137
138 (pass-if "get-bytevector-n! [short]"
139 (let* ((port (open-input-string "GNU Guile"))
140 (bv (make-bytevector 4))
141 (read (get-bytevector-n! port bv 0 4)))
142 (and (equal? read 4)
143 (equal? (bytevector->u8-list bv)
144 (map char->integer (string->list "GNU "))))))
145
146 (pass-if "get-bytevector-n! [long]"
147 (let* ((str "GNU Guile")
148 (port (open-input-string str))
149 (bv (make-bytevector 256))
150 (read (get-bytevector-n! port bv 0 256)))
151 (and (equal? read (string-length str))
152 (equal? (map (lambda (i)
153 (bytevector-u8-ref bv i))
154 (iota read))
155 (map char->integer (string->list str))))))
156
157 (pass-if "get-bytevector-some [simple]"
158 (let* ((str "GNU Guile")
159 (port (open-input-string str))
160 (bv (get-bytevector-some port)))
161 (and (bytevector? bv)
162 (equal? (bytevector->u8-list bv)
163 (map char->integer (string->list str))))))
164
1ee2c72e
LC
165 (pass-if "get-bytevector-all"
166 (let* ((str "GNU Guile")
167 (index 0)
168 (port (make-soft-port
169 (vector #f #f #f
170 (lambda ()
171 (if (>= index (string-length str))
172 (eof-object)
173 (let ((c (string-ref str index)))
174 (set! index (+ index 1))
175 c)))
176 (lambda () #t)
177 (let ((cont? #f))
178 (lambda ()
179 ;; Number of readily available octets: falls to
180 ;; zero after 4 octets have been read and then
181 ;; starts again.
182 (let ((a (if cont?
183 (- (string-length str) index)
184 (- 4 (modulo index 5)))))
185 (if (= 0 a) (set! cont? #t))
186 a))))
187 "r"))
188 (bv (get-bytevector-all port)))
189 (and (bytevector? bv)
190 (= index (string-length str))
191 (= (bytevector-length bv) (string-length str))
192 (equal? (bytevector->u8-list bv)
193 (map char->integer (string->list str)))))))
194
195\f
196(define (make-soft-output-port)
197 (let* ((bv (make-bytevector 1024))
198 (read-index 0)
199 (write-index 0)
200 (write-char (lambda (chr)
201 (bytevector-u8-set! bv write-index
202 (char->integer chr))
203 (set! write-index (+ 1 write-index)))))
204 (make-soft-port
205 (vector write-char
206 (lambda (str) ;; write-string
207 (for-each write-char (string->list str)))
208 (lambda () #t) ;; flush-output
209 (lambda () ;; read-char
210 (if (>= read-index (bytevector-length bv))
211 (eof-object)
212 (let ((c (bytevector-u8-ref bv read-index)))
213 (set! read-index (+ read-index 1))
214 (integer->char c))))
215 (lambda () #t)) ;; close-port
216 "rw")))
217
218(with-test-prefix "7.2.11 Binary Output"
219
220 (pass-if "put-u8"
221 (let ((port (make-soft-output-port)))
222 (put-u8 port 77)
223 (equal? (get-u8 port) 77)))
224
bf08e10f
LC
225 ;; Note: The `put-bytevector' tests below require a Latin-1 locale so
226 ;; that the `scm_from_locale_stringn' call in `sf_write' will let all
227 ;; the bytes through, unmodified. This is hacky, but we can't use
228 ;; "custom binary output ports" here because they're only tested
229 ;; later.
230
1ee2c72e 231 (pass-if "put-bytevector [2 args]"
bf08e10f
LC
232 (with-latin1-locale
233 (let ((port (make-soft-output-port))
234 (bv (make-bytevector 256)))
235 (put-bytevector port bv)
236 (equal? (bytevector->u8-list bv)
237 (bytevector->u8-list
238 (get-bytevector-n port (bytevector-length bv)))))))
1ee2c72e
LC
239
240 (pass-if "put-bytevector [3 args]"
bf08e10f
LC
241 (with-latin1-locale
242 (let ((port (make-soft-output-port))
243 (bv (make-bytevector 256))
244 (start 10))
245 (put-bytevector port bv start)
246 (equal? (drop (bytevector->u8-list bv) start)
247 (bytevector->u8-list
248 (get-bytevector-n port (- (bytevector-length bv) start)))))))
1ee2c72e
LC
249
250 (pass-if "put-bytevector [4 args]"
bf08e10f
LC
251 (with-latin1-locale
252 (let ((port (make-soft-output-port))
253 (bv (make-bytevector 256))
254 (start 10)
255 (count 77))
256 (put-bytevector port bv start count)
257 (equal? (take (drop (bytevector->u8-list bv) start) count)
258 (bytevector->u8-list
259 (get-bytevector-n port count))))))
1ee2c72e
LC
260
261 (pass-if-exception "put-bytevector with closed port"
262 exception:wrong-type-arg
263
264 (let* ((bv (make-bytevector 4))
265 (port (%make-void-port "w")))
266
267 (close-port port)
7b041912
LC
268 (put-bytevector port bv)))
269
270 (pass-if "put-bytevector with UTF-16 string port"
271 (let* ((str "hello, world")
272 (bv (string->utf16 str)))
273 (equal? str
6dce942c
MW
274 (call-with-output-string
275 (lambda (port)
276 (set-port-encoding! port "UTF-16BE")
277 (put-bytevector port bv))))))
7b041912 278
ef7e4ba3 279 (pass-if "put-bytevector with wrong-encoding string port"
7b041912
LC
280 (let* ((str "hello, world")
281 (bv (string->utf16 str)))
c62da8f8 282 (catch 'decoding-error
ef7e4ba3 283 (lambda ()
6dce942c 284 (with-fluids ((%default-port-conversion-strategy 'error))
ef7e4ba3 285 (call-with-output-string
6dce942c
MW
286 (lambda (port)
287 (set-port-encoding! port "UTF-32")
288 (put-bytevector port bv)))
d3a1a74c 289 #f)) ; fail if we reach this point
c62da8f8
LC
290 (lambda (key subr message errno port)
291 (string? (strerror errno)))))))
1ee2c72e
LC
292
293\f
3ae5a02f
AR
294(define (test-input-file-opener open filename)
295 (let ((contents (string->utf8 "GNU λ")))
0687e826
AR
296 ;; Create file
297 (call-with-output-file filename
298 (lambda (port) (put-bytevector port contents)))
299
3ae5a02f 300 (pass-if "opens binary input port with correct contents"
0687e826 301 (with-fluids ((%default-port-encoding "UTF-8"))
3ae5a02f
AR
302 (call-with-port (open-file-input-port filename)
303 (lambda (port)
304 (and (binary-port? port)
305 (input-port? port)
306 (bytevector=? contents (get-bytevector-all port))))))))
0687e826 307
3ae5a02f
AR
308 (delete-file filename))
309
310(with-test-prefix "7.2.7 Input Ports"
311
312 (with-test-prefix "open-file-input-port"
313 (test-input-file-opener open-file-input-port (test-file)))
314
1ee2c72e
LC
315 ;; This section appears here so that it can use the binary input
316 ;; primitives.
317
318 (pass-if "open-bytevector-input-port [1 arg]"
319 (let* ((str "Hello Port!")
320 (bv (u8-list->bytevector (map char->integer
321 (string->list str))))
322 (port (open-bytevector-input-port bv))
323 (read-to-string
324 (lambda (port)
325 (let loop ((chr (read-char port))
326 (result '()))
327 (if (eof-object? chr)
328 (apply string (reverse! result))
329 (loop (read-char port)
330 (cons chr result)))))))
331
332 (equal? (read-to-string port) str)))
333
96128014
LC
334 (pass-if "bytevector-input-port is binary"
335 (with-fluids ((%default-port-encoding "UTF-8"))
336 (binary-port? (open-bytevector-input-port #vu8(1 2 3)))))
337
1ee2c72e
LC
338 (pass-if-exception "bytevector-input-port is read-only"
339 exception:wrong-type-arg
340
341 (let* ((str "Hello Port!")
342 (bv (u8-list->bytevector (map char->integer
343 (string->list str))))
344 (port (open-bytevector-input-port bv #f)))
345
346 (write "hello" port)))
347
348 (pass-if "bytevector input port supports seeking"
349 (let* ((str "Hello Port!")
350 (bv (u8-list->bytevector (map char->integer
351 (string->list str))))
352 (port (open-bytevector-input-port bv #f)))
353
354 (and (port-has-port-position? port)
355 (= 0 (port-position port))
356 (port-has-set-port-position!? port)
357 (begin
358 (set-port-position! port 6)
359 (= 6 (port-position port)))
360 (bytevector=? (get-bytevector-all port)
361 (u8-list->bytevector
362 (map char->integer (string->list "Port!")))))))
363
c89b4529
IP
364 (pass-if "bytevector input port can seek to very end"
365 (let ((empty (open-bytevector-input-port '#vu8()))
366 (not-empty (open-bytevector-input-port '#vu8(1 2 3))))
367 (and (begin (set-port-position! empty (port-position empty))
368 (= 0 (port-position empty)))
369 (begin (get-bytevector-n not-empty 3)
370 (set-port-position! not-empty (port-position not-empty))
371 (= 3 (port-position not-empty))))))
372
1ee2c72e
LC
373 (pass-if-exception "make-custom-binary-input-port [wrong-num-args]"
374 exception:wrong-num-args
375
376 ;; Prior to Guile-R6RS-Libs 0.2, the last 3 arguments were wrongfully
377 ;; optional.
378 (make-custom-binary-input-port "port" (lambda args #t)))
379
380 (pass-if "make-custom-binary-input-port"
381 (let* ((source (make-bytevector 7777))
382 (read! (let ((pos 0)
383 (len (bytevector-length source)))
384 (lambda (bv start count)
385 (let ((amount (min count (- len pos))))
386 (if (> amount 0)
387 (bytevector-copy! source pos
388 bv start amount))
389 (set! pos (+ pos amount))
390 amount))))
391 (port (make-custom-binary-input-port "the port" read!
392 #f #f #f)))
393
96128014
LC
394 (and (binary-port? port)
395 (input-port? port)
396 (bytevector=? (get-bytevector-all port) source))))
1ee2c72e
LC
397
398 (pass-if "custom binary input port does not support `port-position'"
399 (let* ((str "Hello Port!")
400 (source (open-bytevector-input-port
401 (u8-list->bytevector
402 (map char->integer (string->list str)))))
403 (read! (lambda (bv start count)
404 (let ((r (get-bytevector-n! source bv start count)))
405 (if (eof-object? r)
406 0
407 r))))
408 (port (make-custom-binary-input-port "the port" read!
409 #f #f #f)))
410 (not (or (port-has-port-position? port)
411 (port-has-set-port-position!? port)))))
412
413 (pass-if "custom binary input port supports `port-position'"
414 (let* ((str "Hello Port!")
415 (source (open-bytevector-input-port
416 (u8-list->bytevector
417 (map char->integer (string->list str)))))
418 (read! (lambda (bv start count)
419 (let ((r (get-bytevector-n! source bv start count)))
420 (if (eof-object? r)
421 0
422 r))))
423 (get-pos (lambda ()
424 (port-position source)))
425 (set-pos! (lambda (pos)
426 (set-port-position! source pos)))
427 (port (make-custom-binary-input-port "the port" read!
428 get-pos set-pos! #f)))
429
430 (and (port-has-port-position? port)
431 (= 0 (port-position port))
432 (port-has-set-port-position!? port)
433 (begin
434 (set-port-position! port 6)
435 (= 6 (port-position port)))
436 (bytevector=? (get-bytevector-all port)
437 (u8-list->bytevector
438 (map char->integer (string->list "Port!")))))))
439
440 (pass-if "custom binary input port `close-proc' is called"
441 (let* ((closed? #f)
442 (read! (lambda (bv start count) 0))
443 (get-pos (lambda () 0))
444 (set-pos! (lambda (pos) #f))
445 (close! (lambda () (set! closed? #t)))
446 (port (make-custom-binary-input-port "the port" read!
447 get-pos set-pos!
448 close!)))
449
450 (close-port port)
4574ec21 451 (gc) ; Test for marking a closed port.
ead04a04
AR
452 closed?))
453
454 (pass-if "standard-input-port is binary"
455 (with-fluids ((%default-port-encoding "UTF-8"))
456 (binary-port? (standard-input-port)))))
1ee2c72e
LC
457
458\f
3ae5a02f
AR
459(define (test-output-file-opener open filename)
460 (with-fluids ((%default-port-encoding "UTF-8"))
461 (pass-if "opens binary output port"
462 (call-with-port (open filename)
463 (lambda (port)
464 (put-bytevector port '#vu8(1 2 3))
465 (and (binary-port? port)
466 (output-port? port))))))
467
468 (pass-if-condition "exception: already-exists"
469 i/o-file-already-exists-error?
470 (open filename))
471
472 (pass-if "no-fail no-truncate"
473 (and
474 (call-with-port (open filename (file-options no-fail no-truncate))
475 (lambda (port)
476 (= 0 (port-position port))))
477 (= 3 (stat:size (stat filename)))))
478
479 (pass-if "no-fail"
480 (and
481 (call-with-port (open filename (file-options no-fail))
482 binary-port?)
483 (= 0 (stat:size (stat filename)))))
b6a66c21 484
3ae5a02f 485 (delete-file filename)
b6a66c21 486
3ae5a02f
AR
487 (pass-if-condition "exception: does-not-exist"
488 i/o-file-does-not-exist-error?
489 (open filename (file-options no-create))))
490
491(with-test-prefix "8.2.10 Output ports"
492
493 (with-test-prefix "open-file-output-port"
494 (test-output-file-opener open-file-output-port (test-file)))
b6a66c21 495
1ee2c72e
LC
496 (pass-if "open-bytevector-output-port"
497 (let-values (((port get-content)
498 (open-bytevector-output-port #f)))
499 (let ((source (make-bytevector 7777)))
500 (put-bytevector port source)
501 (and (bytevector=? (get-content) source)
502 (bytevector=? (get-content) (make-bytevector 0))))))
96128014
LC
503
504 (pass-if "bytevector-output-port is binary"
505 (binary-port? (open-bytevector-output-port)))
506
a653d32a
AR
507 (pass-if "open-bytevector-output-port [extract after close]"
508 (let-values (((port get-content)
509 (open-bytevector-output-port)))
510 (let ((source (make-bytevector 12345 #xFE)))
511 (put-bytevector port source)
512 (close-port port)
513 (bytevector=? (get-content) source))))
1ee2c72e
LC
514
515 (pass-if "open-bytevector-output-port [put-u8]"
516 (let-values (((port get-content)
517 (open-bytevector-output-port)))
518 (put-u8 port 77)
519 (and (bytevector=? (get-content) (make-bytevector 1 77))
520 (bytevector=? (get-content) (make-bytevector 0)))))
521
522 (pass-if "open-bytevector-output-port [display]"
523 (let-values (((port get-content)
524 (open-bytevector-output-port)))
525 (display "hello" port)
526 (and (bytevector=? (get-content) (string->utf8 "hello"))
527 (bytevector=? (get-content) (make-bytevector 0)))))
528
529 (pass-if "bytevector output port supports `port-position'"
530 (let-values (((port get-content)
531 (open-bytevector-output-port)))
532 (let ((source (make-bytevector 7777))
533 (overwrite (make-bytevector 33)))
534 (and (port-has-port-position? port)
535 (port-has-set-port-position!? port)
536 (begin
537 (put-bytevector port source)
538 (= (bytevector-length source)
539 (port-position port)))
540 (begin
541 (set-port-position! port 10)
542 (= 10 (port-position port)))
543 (begin
544 (put-bytevector port overwrite)
545 (bytevector-copy! overwrite 0 source 10
546 (bytevector-length overwrite))
547 (= (port-position port)
548 (+ 10 (bytevector-length overwrite))))
549 (bytevector=? (get-content) source)
550 (bytevector=? (get-content) (make-bytevector 0))))))
551
96128014 552 (pass-if "make-custom-binary-output-port"
1ee2c72e
LC
553 (let ((port (make-custom-binary-output-port "cbop"
554 (lambda (x y z) 0)
555 #f #f #f)))
556 (and (output-port? port)
557 (binary-port? port)
558 (not (port-has-port-position? port))
559 (not (port-has-set-port-position!? port)))))
560
561 (pass-if "make-custom-binary-output-port [partial writes]"
562 (let* ((source (uint-list->bytevector (iota 333)
563 (native-endianness) 2))
564 (sink (make-bytevector (bytevector-length source)))
565 (sink-pos 0)
566 (eof? #f)
567 (write! (lambda (bv start count)
568 (if (= 0 count)
569 (begin
570 (set! eof? #t)
571 0)
572 (let ((u8 (bytevector-u8-ref bv start)))
573 ;; Get one byte at a time.
574 (bytevector-u8-set! sink sink-pos u8)
575 (set! sink-pos (+ 1 sink-pos))
576 1))))
577 (port (make-custom-binary-output-port "cbop" write!
578 #f #f #f)))
579 (put-bytevector port source)
580 (and (= sink-pos (bytevector-length source))
581 (not eof?)
582 (bytevector=? sink source))))
583
584 (pass-if "make-custom-binary-output-port [full writes]"
585 (let* ((source (uint-list->bytevector (iota 333)
586 (native-endianness) 2))
587 (sink (make-bytevector (bytevector-length source)))
588 (sink-pos 0)
589 (eof? #f)
590 (write! (lambda (bv start count)
591 (if (= 0 count)
592 (begin
593 (set! eof? #t)
594 0)
595 (begin
596 (bytevector-copy! bv start
597 sink sink-pos
598 count)
599 (set! sink-pos (+ sink-pos count))
600 count))))
601 (port (make-custom-binary-output-port "cbop" write!
602 #f #f #f)))
603 (put-bytevector port source)
604 (and (= sink-pos (bytevector-length source))
605 (not eof?)
ead04a04
AR
606 (bytevector=? sink source))))
607
608 (pass-if "standard-output-port is binary"
609 (with-fluids ((%default-port-encoding "UTF-8"))
610 (binary-port? (standard-output-port))))
611
612 (pass-if "standard-error-port is binary"
613 (with-fluids ((%default-port-encoding "UTF-8"))
614 (binary-port? (standard-error-port)))))
1ee2c72e 615
d4b81637 616\f
1044537d 617(with-test-prefix "8.2.6 Input and output ports"
d4b81637 618
1044537d 619 (pass-if "transcoded-port [output]"
8aa47f26 620 (let ((s "Hello\nÄÖÜ"))
1044537d
AR
621 (bytevector=?
622 (string->utf8 s)
dfc4d56d
AR
623 (call-with-bytevector-output-port/transcoded (make-transcoder (utf-8-codec))
624 (lambda (utf8-port)
625 (put-string utf8-port s))))))
d4b81637 626
1044537d 627 (pass-if "transcoded-port [input]"
8aa47f26 628 (let ((s "Hello\nÄÖÜ"))
1044537d
AR
629 (string=?
630 s
631 (get-string-all
632 (transcoded-port (open-bytevector-input-port (string->utf8 s))
633 (make-transcoder (utf-8-codec)))))))
d4b81637 634
1044537d 635 (pass-if "transcoded-port [input line]"
8aa47f26 636 (string=? "ÄÖÜ"
1044537d 637 (get-line (transcoded-port
8aa47f26 638 (open-bytevector-input-port (string->utf8 "ÄÖÜ\nFooBar"))
d4b81637
LC
639 (make-transcoder (utf-8-codec))))))
640
641 (pass-if "transcoded-port [error handling mode = raise]"
642 (let* ((t (make-transcoder (utf-8-codec) (native-eol-style)
643 (error-handling-mode raise)))
644 (b (open-bytevector-input-port #vu8(255 2 1)))
645 (tp (transcoded-port b t)))
b1e76e8f
LC
646 (guard (c ((i/o-decoding-error? c)
647 (eq? (i/o-error-port c) tp)))
d3a1a74c
LC
648 (get-line tp)
649 #f))) ; fail if we reach this point
d4b81637
LC
650
651 (pass-if "transcoded-port [error handling mode = replace]"
652 (let* ((t (make-transcoder (utf-8-codec) (native-eol-style)
653 (error-handling-mode replace)))
654 (b (open-bytevector-input-port #vu8(255 1 2 3 103 110 117)))
655 (tp (transcoded-port b t)))
eed98cbc
LC
656 (string-suffix? "gnu" (get-line tp))))
657
658 (pass-if "transcoded-port, output [error handling mode = raise]"
659 (let-values (((p get)
660 (open-bytevector-output-port)))
661 (let* ((t (make-transcoder (latin-1-codec) (native-eol-style)
662 (error-handling-mode raise)))
663 (tp (transcoded-port p t)))
664 (guard (c ((i/o-encoding-error? c)
665 (and (eq? (i/o-error-port c) tp)
666 (char=? (i/o-encoding-error-char c) #\λ)
667 (bytevector=? (get) (string->utf8 "The letter ")))))
668 (put-string tp "The letter λ cannot be represented in Latin-1.")
ead04a04
AR
669 #f))))
670
ead04a04
AR
671 (pass-if "port-transcoder [transcoded port]"
672 (let* ((p (transcoded-port (open-bytevector-input-port (string->utf8 "foo"))
673 (make-transcoder (utf-8-codec))))
674 (t (port-transcoder p)))
675 (and t
676 (transcoder-codec t)
677 (eq? (native-eol-style)
678 (transcoder-eol-style t))
679 (eq? (error-handling-mode replace)
680 (transcoder-error-handling-mode t))))))
1044537d 681
a6c377f7
AR
682(with-test-prefix "8.2.9 Textual input"
683
684 (pass-if "get-string-n [short]"
685 (let ((port (open-input-string "GNU Guile")))
686 (string=? "GNU " (get-string-n port 4))))
687 (pass-if "get-string-n [long]"
688 (let ((port (open-input-string "GNU Guile")))
689 (string=? "GNU Guile" (get-string-n port 256))))
690 (pass-if "get-string-n [eof]"
691 (let ((port (open-input-string "")))
692 (eof-object? (get-string-n port 4))))
693
694 (pass-if "get-string-n! [short]"
695 (let ((port (open-input-string "GNU Guile"))
696 (s (string-copy "Isn't XXX great?")))
697 (and (= 3 (get-string-n! port s 6 3))
b6a66c21
AR
698 (string=? s "Isn't GNU great?"))))
699
700 (with-test-prefix "read error"
701 (pass-if-condition "get-char" i/o-read-error?
702 (get-char (make-failing-port)))
703 (pass-if-condition "lookahead-char" i/o-read-error?
704 (lookahead-char (make-failing-port)))
705 ;; FIXME: these are not yet exception-correct
706 #|
707 (pass-if-condition "get-string-n" i/o-read-error?
708 (get-string-n (make-failing-port) 5))
709 (pass-if-condition "get-string-n!" i/o-read-error?
710 (get-string-n! (make-failing-port) (make-string 5) 0 5))
711 |#
712 (pass-if-condition "get-string-all" i/o-read-error?
713 (get-string-all (make-failing-port 100)))
714 (pass-if-condition "get-line" i/o-read-error?
715 (get-line (make-failing-port)))
716 (pass-if-condition "get-datum" i/o-read-error?
717 (get-datum (make-failing-port)))))
718
dfc4d56d
AR
719(define (encoding-error-predicate char)
720 (lambda (c)
721 (and (i/o-encoding-error? c)
722 (char=? char (i/o-encoding-error-char c)))))
723
b6a66c21
AR
724(with-test-prefix "8.2.12 Textual Output"
725
726 (with-test-prefix "write error"
727 (pass-if-condition "put-char" i/o-write-error?
728 (put-char (make-failing-port) #\G))
729 (pass-if-condition "put-string" i/o-write-error?
730 (put-string (make-failing-port) "Hello World!"))
731 (pass-if-condition "put-datum" i/o-write-error?
dfc4d56d
AR
732 (put-datum (make-failing-port) '(hello world!))))
733 (with-test-prefix "encoding error"
734 (pass-if-condition "put-char" (encoding-error-predicate #\λ)
735 (call-with-bytevector-output-port/transcoded
736 (make-transcoder (latin-1-codec)
737 (native-eol-style)
738 (error-handling-mode raise))
739 (lambda (port)
740 (put-char port #\λ))))
741 (pass-if-condition "put-string" (encoding-error-predicate #\λ)
742 (call-with-bytevector-output-port/transcoded
743 (make-transcoder (latin-1-codec)
744 (native-eol-style)
745 (error-handling-mode raise))
746 (lambda (port)
747 (put-string port "FooλBar"))))))
b6a66c21
AR
748
749(with-test-prefix "8.3 Simple I/O"
750 (with-test-prefix "read error"
751 (pass-if-condition "read-char" i/o-read-error?
752 (read-char (make-failing-port)))
753 (pass-if-condition "peek-char" i/o-read-error?
754 (peek-char (make-failing-port)))
755 (pass-if-condition "read" i/o-read-error?
756 (read (make-failing-port))))
757 (with-test-prefix "write error"
758 (pass-if-condition "display" i/o-write-error?
759 (display "Hi there!" (make-failing-port)))
760 (pass-if-condition "write" i/o-write-error?
761 (write '(hi there!) (make-failing-port)))
762 (pass-if-condition "write-char" i/o-write-error?
763 (write-char #\G (make-failing-port)))
764 (pass-if-condition "newline" i/o-write-error?
765 (newline (make-failing-port))))
766 (let ((filename (test-file)))
767 ;; ensure the test file exists
768 (call-with-output-file filename
769 (lambda (port) (write "foo" port)))
770 (pass-if "call-with-input-file [port is textual]"
771 (call-with-input-file filename textual-port?))
772 (pass-if-condition "call-with-input-file [exception: not-found]"
773 i/o-file-does-not-exist-error?
774 (call-with-input-file ",this-is-highly-unlikely-to-exist!"
775 values))
776 (pass-if-condition "call-with-output-file [exception: already-exists]"
777 i/o-file-already-exists-error?
778 (call-with-output-file filename
779 values))
780 (delete-file filename)))
a6c377f7 781
3ae5a02f
AR
782(with-test-prefix "8.2.13 Input/output ports"
783 (with-test-prefix "open-file-input/output-port [output]"
784 (test-output-file-opener open-file-input/output-port (test-file)))
785 (with-test-prefix "open-file-input/output-port [input]"
786 (test-input-file-opener open-file-input/output-port (test-file))))
787
1ee2c72e 788;;; Local Variables:
1ee2c72e 789;;; mode: scheme
b1e76e8f 790;;; eval: (put 'guard 'scheme-indent-function 1)
1ee2c72e 791;;; End: