ports: Accept `#f' as a transcoder argument.
[guile-r6rs-libs.git] / tests / io-ports.test
blob5f5649787682643d300238c950c37b01454c2296
1 ;;; R6RS I/O Ports.
2 ;;;
3 ;;; Copyright 2007, 2009  Ludovic Courtès <ludo@gnu.org>
4 ;;;
5 ;;;
6 ;;; This program is free software; you can redistribute it and/or modify
7 ;;; it under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 2 of the License, or
9 ;;; (at your option) any later version.
10 ;;;
11 ;;; This program 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
14 ;;; GNU General Public License for more details.
15 ;;;
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with this program; if not, write to the Free Software
18 ;;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20 (define-module (test-io-ports)
21   :use-module (test-suite lib)
22   :use-module (srfi srfi-1)
23   :use-module (srfi srfi-11)
24   :use-module (rnrs io ports)
25   :use-module (rnrs bytevector))
27 ;;; All these tests assume Guile 1.8's port system, where characters are
28 ;;; treated as octets.
31 (with-test-prefix "7.2.5 End-of-File Object"
33   (pass-if "eof-object"
34     (and (eqv? (eof-object) (eof-object))
35          (eq?  (eof-object) (eof-object)))))
38 (with-test-prefix "7.2.8 Binary Input"
40   (pass-if "get-u8"
41     (let ((port (open-input-string "A")))
42       (and (= (char->integer #\A) (get-u8 port))
43            (eof-object? (get-u8 port)))))
45   (pass-if "lookahead-u8"
46     (let ((port (open-input-string "A")))
47       (and (= (char->integer #\A) (lookahead-u8 port))
48            (not (eof-object? port))
49            (= (char->integer #\A) (get-u8 port))
50            (eof-object? (get-u8 port)))))
52   (pass-if "get-bytevector-n [short]"
53     (let* ((port (open-input-string "GNU Guile"))
54            (bv (get-bytevector-n port 4)))
55       (and (bytevector? bv)
56            (equal? (bytevector->u8-list bv)
57                    (map char->integer (string->list "GNU "))))))
59   (pass-if "get-bytevector-n [long]"
60     (let* ((port (open-input-string "GNU Guile"))
61            (bv (get-bytevector-n port 256)))
62       (and (bytevector? bv)
63            (equal? (bytevector->u8-list bv)
64                    (map char->integer (string->list "GNU Guile"))))))
66   (pass-if-exception "get-bytevector-n with closed port"
67     exception:wrong-type-arg
69     (let ((port (%make-void-port "r")))
71       (close-port port)
72       (get-bytevector-n port 3)))
74   (pass-if "get-bytevector-n! [short]"
75     (let* ((port (open-input-string "GNU Guile"))
76            (bv   (make-bytevector 4))
77            (read (get-bytevector-n! port bv 0 4)))
78       (and (equal? read 4)
79            (equal? (bytevector->u8-list bv)
80                    (map char->integer (string->list "GNU "))))))
82   (pass-if "get-bytevector-n! [long]"
83     (let* ((str  "GNU Guile")
84            (port (open-input-string str))
85            (bv   (make-bytevector 256))
86            (read (get-bytevector-n! port bv 0 256)))
87       (and (equal? read (string-length str))
88            (equal? (map (lambda (i)
89                           (bytevector-u8-ref bv i))
90                         (iota read))
91                    (map char->integer (string->list str))))))
93   (pass-if "get-bytevector-some [simple]"
94     (let* ((str  "GNU Guile")
95            (port (open-input-string str))
96            (bv   (get-bytevector-some port)))
97       (and (bytevector? bv)
98            (equal? (bytevector->u8-list bv)
99                    (map char->integer (string->list str))))))
101   (pass-if "get-bytevector-some [only-some]"
102     (let* ((str   "GNU Guile")
103            (index 0)
104            (port  (make-soft-port
105                    (vector #f #f #f
106                            (lambda ()
107                              (if (>= index (string-length str))
108                                  (eof-object)
109                                  (let ((c (string-ref str index)))
110                                    (set! index (+ index 1))
111                                    c)))
112                            (lambda () #t)
113                            (lambda ()
114                              ;; Number of readily available octets: falls to
115                              ;; zero after 4 octets have been read.
116                              (- 4 (modulo index 5))))
117                    "r"))
118            (bv    (get-bytevector-some port)))
119       (and (bytevector? bv)
120            (= index 4)
121            (= (bytevector-length bv) index)
122            (equal? (bytevector->u8-list bv)
123                    (map char->integer (string->list "GNU "))))))
125   (pass-if "get-bytevector-all"
126     (let* ((str   "GNU Guile")
127            (index 0)
128            (port  (make-soft-port
129                    (vector #f #f #f
130                            (lambda ()
131                              (if (>= index (string-length str))
132                                  (eof-object)
133                                  (let ((c (string-ref str index)))
134                                    (set! index (+ index 1))
135                                    c)))
136                            (lambda () #t)
137                            (let ((cont? #f))
138                              (lambda ()
139                                ;; Number of readily available octets: falls to
140                                ;; zero after 4 octets have been read and then
141                                ;; starts again.
142                                (let ((a (if cont?
143                                             (- (string-length str) index)
144                                             (- 4 (modulo index 5)))))
145                                  (if (= 0 a) (set! cont? #t))
146                                  a))))
147                    "r"))
148            (bv    (get-bytevector-all port)))
149       (and (bytevector? bv)
150            (= index (string-length str))
151            (= (bytevector-length bv) (string-length str))
152            (equal? (bytevector->u8-list bv)
153                    (map char->integer (string->list str)))))))
156 (define (make-soft-output-port)
157   (let* ((bv (make-bytevector 1024))
158          (read-index  0)
159          (write-index 0)
160          (write-char (lambda (chr)
161                        (bytevector-u8-set! bv write-index
162                                            (char->integer chr))
163                        (set! write-index (+ 1 write-index)))))
164     (make-soft-port
165      (vector write-char
166              (lambda (str)   ;; write-string
167                (for-each write-char (string->list str)))
168              (lambda () #t)  ;; flush-output
169              (lambda ()      ;; read-char
170                (if (>= read-index (bytevector-length bv))
171                    (eof-object)
172                    (let ((c (bytevector-u8-ref bv read-index)))
173                      (set! read-index (+ read-index 1))
174                      (integer->char c))))
175              (lambda () #t)) ;; close-port
176      "rw")))
178 (with-test-prefix "7.2.11 Binary Output"
180   (pass-if "put-u8"
181     (let ((port (make-soft-output-port)))
182       (put-u8 port 77)
183       (equal? (get-u8 port) 77)))
185   (pass-if "put-bytevector [2 args]"
186     (let ((port (make-soft-output-port))
187           (bv   (make-bytevector 256)))
188       (put-bytevector port bv)
189       (equal? (bytevector->u8-list bv)
190               (bytevector->u8-list
191                (get-bytevector-n port (bytevector-length bv))))))
193   (pass-if "put-bytevector [3 args]"
194     (let ((port  (make-soft-output-port))
195           (bv    (make-bytevector 256))
196           (start 10))
197       (put-bytevector port bv start)
198       (equal? (drop (bytevector->u8-list bv) start)
199               (bytevector->u8-list
200                (get-bytevector-n port (- (bytevector-length bv) start))))))
202   (pass-if "put-bytevector [4 args]"
203     (let ((port  (make-soft-output-port))
204           (bv    (make-bytevector 256))
205           (start 10)
206           (count 77))
207       (put-bytevector port bv start count)
208       (equal? (take (drop (bytevector->u8-list bv) start) count)
209               (bytevector->u8-list
210                (get-bytevector-n port count)))))
212   (pass-if-exception "put-bytevector with closed port"
213     exception:wrong-type-arg
215     (let* ((bv   (make-bytevector 4))
216            (port (%make-void-port "w")))
218       (close-port port)
219       (put-bytevector port bv))))
222 (with-test-prefix "7.2.7 Input Ports"
224   ;; This section appears here so that it can use the binary input
225   ;; primitives.
227   (pass-if "open-bytevector-input-port [1 arg]"
228     (let* ((str "Hello Port!")
229            (bv (u8-list->bytevector (map char->integer
230                                          (string->list str))))
231            (port (open-bytevector-input-port bv))
232            (read-to-string
233             (lambda (port)
234               (let loop ((chr (read-char port))
235                          (result '()))
236                 (if (eof-object? chr)
237                     (apply string (reverse! result))
238                     (loop (read-char port)
239                           (cons chr result)))))))
241       (equal? (read-to-string port) str)))
243   (pass-if-exception "bytevector-input-port is read-only"
244     exception:wrong-type-arg
246     (let* ((str "Hello Port!")
247            (bv (u8-list->bytevector (map char->integer
248                                          (string->list str))))
249            (port (open-bytevector-input-port bv #f)))
251       (write "hello" port)))
253   (pass-if "bytevector input port supports seeking"
254     (let* ((str "Hello Port!")
255            (bv (u8-list->bytevector (map char->integer
256                                          (string->list str))))
257            (port (open-bytevector-input-port bv #f)))
259       (and (port-has-port-position? port)
260            (= 0 (port-position port))
261            (port-has-set-port-position!? port)
262            (begin
263              (set-port-position! port 6)
264              (= 6 (port-position port)))
265            (bytevector=? (get-bytevector-all port)
266                          (u8-list->bytevector
267                           (map char->integer (string->list "Port!")))))))
269   (pass-if-exception "make-custom-binary-input-port [wrong-num-args]"
270     exception:wrong-num-args
272     ;; Prior to Guile-R6RS-Libs 0.2, the last 3 arguments were wrongfully
273     ;; optional.
274     (make-custom-binary-input-port "port" (lambda args #t)))
276   (pass-if "make-custom-binary-input-port"
277     (let* ((source (make-bytevector 7777))
278            (read! (let ((pos 0)
279                         (len (bytevector-length source)))
280                     (lambda (bv start count)
281                       (let ((amount (min count (- len pos))))
282                         (if (> amount 0)
283                             (bytevector-copy! source pos
284                                               bv start amount))
285                         (set! pos (+ pos amount))
286                         amount))))
287            (port (make-custom-binary-input-port "the port" read!
288                                                 #f #f #f)))
290       (bytevector=? (get-bytevector-all port) source)))
292   (pass-if "custom binary input port does not support `port-position'"
293     (let* ((str "Hello Port!")
294            (source (open-bytevector-input-port
295                     (u8-list->bytevector
296                      (map char->integer (string->list str)))))
297            (read! (lambda (bv start count)
298                     (let ((r (get-bytevector-n! source bv start count)))
299                       (if (eof-object? r)
300                           0
301                           r))))
302            (port (make-custom-binary-input-port "the port" read!
303                                                 #f #f #f)))
304       (not (or (port-has-port-position? port)
305                (port-has-set-port-position!? port)))))
307   (pass-if "custom binary input port supports `port-position'"
308     (let* ((str "Hello Port!")
309            (source (open-bytevector-input-port
310                     (u8-list->bytevector
311                      (map char->integer (string->list str)))))
312            (read! (lambda (bv start count)
313                     (let ((r (get-bytevector-n! source bv start count)))
314                       (if (eof-object? r)
315                           0
316                           r))))
317            (get-pos (lambda ()
318                       (port-position source)))
319            (set-pos! (lambda (pos)
320                        (set-port-position! source pos)))
321            (port (make-custom-binary-input-port "the port" read!
322                                                 get-pos set-pos! #f)))
324       (and (port-has-port-position? port)
325            (= 0 (port-position port))
326            (port-has-set-port-position!? port)
327            (begin
328              (set-port-position! port 6)
329              (= 6 (port-position port)))
330            (bytevector=? (get-bytevector-all port)
331                          (u8-list->bytevector
332                           (map char->integer (string->list "Port!")))))))
334   (pass-if "custom binary input port `close-proc' is called"
335     (let* ((closed?  #f)
336            (read!    (lambda (bv start count) 0))
337            (get-pos  (lambda () 0))
338            (set-pos! (lambda (pos) #f))
339            (close!   (lambda () (set! closed? #t)))
340            (port     (make-custom-binary-input-port "the port" read!
341                                                     get-pos set-pos!
342                                                     close!)))
344       (close-port port)
345       closed?)))
348 (with-test-prefix "8.2.10 Output ports"
350   (pass-if "open-bytevector-output-port"
351     (let-values (((port get-content)
352                   (open-bytevector-output-port #f)))
353       (let ((source (make-bytevector 7777)))
354         (put-bytevector port source)
355         (and (bytevector=? (get-content) source)
356              (bytevector=? (get-content) (make-bytevector 0))))))
358   (pass-if "open-bytevector-output-port [put-u8]"
359     (let-values (((port get-content)
360                   (open-bytevector-output-port)))
361       (put-u8 port 77)
362       (and (bytevector=? (get-content) (make-bytevector 1 77))
363            (bytevector=? (get-content) (make-bytevector 0)))))
365   (pass-if "open-bytevector-output-port [display]"
366     (let-values (((port get-content)
367                   (open-bytevector-output-port)))
368       (display "hello" port)
369       (and (bytevector=? (get-content) (string->utf8 "hello"))
370            (bytevector=? (get-content) (make-bytevector 0)))))
372   (pass-if "bytevector output port supports `port-position'"
373     (let-values (((port get-content)
374                   (open-bytevector-output-port)))
375       (let ((source (make-bytevector 7777))
376             (overwrite (make-bytevector 33)))
377         (and (port-has-port-position? port)
378              (port-has-set-port-position!? port)
379              (begin
380                (put-bytevector port source)
381                (= (bytevector-length source)
382                   (port-position port)))
383              (begin
384                (set-port-position! port 10)
385                (= 10 (port-position port)))
386              (begin
387                (put-bytevector port overwrite)
388                (bytevector-copy! overwrite 0 source 10
389                                  (bytevector-length overwrite))
390                (= (port-position port)
391                   (+ 10 (bytevector-length overwrite))))
392              (bytevector=? (get-content) source)
393              (bytevector=? (get-content) (make-bytevector 0))))))
395   (pass-if "make-custom-binary-output"
396     (let ((port (make-custom-binary-output-port "cbop"
397                                                 (lambda (x y z) 0)
398                                                 #f #f #f)))
399       (and (output-port? port)
400            (binary-port? port)
401            (not (port-has-port-position? port))
402            (not (port-has-set-port-position!? port)))))
404   (pass-if "make-custom-binary-output-port [partial writes]"
405     (let* ((source   (uint-list->bytevector (iota 333)
406                                             (native-endianness) 2))
407            (sink     (make-bytevector (bytevector-length source)))
408            (sink-pos 0)
409            (eof?     #f)
410            (write!   (lambda (bv start count)
411                        (if (= 0 count)
412                            (begin
413                              (set! eof? #t)
414                              0)
415                            (let ((u8 (bytevector-u8-ref bv start)))
416                              ;; Get one byte at a time.
417                              (bytevector-u8-set! sink sink-pos u8)
418                              (set! sink-pos (+ 1 sink-pos))
419                              1))))
420            (port     (make-custom-binary-output-port "cbop" write!
421                                                      #f #f #f)))
422       (put-bytevector port source)
423       (and (= sink-pos (bytevector-length source))
424            (not eof?)
425            (bytevector=? sink source))))
427   (pass-if "make-custom-binary-output-port [full writes]"
428     (let* ((source   (uint-list->bytevector (iota 333)
429                                             (native-endianness) 2))
430            (sink     (make-bytevector (bytevector-length source)))
431            (sink-pos 0)
432            (eof?     #f)
433            (write!   (lambda (bv start count)
434                        (if (= 0 count)
435                            (begin
436                              (set! eof? #t)
437                              0)
438                            (begin
439                              (bytevector-copy! bv start
440                                                sink sink-pos
441                                                count)
442                              (set! sink-pos (+ sink-pos count))
443                              count))))
444            (port     (make-custom-binary-output-port "cbop" write!
445                                                      #f #f #f)))
446       (put-bytevector port source)
447       (and (= sink-pos (bytevector-length source))
448            (not eof?)
449            (bytevector=? sink source)))))
452 ;;; Local Variables:
453 ;;; coding: latin-1
454 ;;; mode: scheme
455 ;;; End: