;;;; This file is for testing external-format functionality, using ;;;; test machinery which might have side effects (e.g. executing ;;;; DEFUN, writing files). Note that the tests here reach into ;;;; unexported functionality, and should not be used as a guide for ;;;; users. ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. ;;;; ;;;; While most of SBCL is derived from the CMU CL system, the test ;;;; files (like this one) were written from scratch after the fork ;;;; from CMU CL. ;;;; ;;;; This software is in the public domain and is provided with ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. (defmacro do-external-formats ((xf &optional result) &body body) (let ((nxf (gensym))) `(dolist (,nxf sb-impl::*external-formats* ,result) (let ((,xf (first (first ,nxf)))) ,@body)))) (do-external-formats (xf) (with-open-file (s "/dev/null" :direction :input :external-format xf) (assert (eq (read-char s nil s) s)))) ;;; Test standard character read-write equivalency over all external formats. (let ((standard-characters "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!$\"'(),_-./:;?+<=>#%&*@[\\]{|}`^~")) (do-external-formats (xf) (with-open-file (s "external-format-test.txt" :direction :output :if-exists :supersede :external-format xf) (loop for character across standard-characters do (write-char character s))) (with-open-file (s "external-format-test.txt" :direction :input :external-format xf) (loop for character across standard-characters do (assert (eql (read-char s) character)))))) (delete-file "external-format-test.txt") #-sb-unicode (progn (test-util:report-test-status) (sb-ext:quit :unix-status 104)) ;;; Test UTF-8 writing and reading of 1, 2, 3 and 4 octet characters with ;;; all possible offsets. Tests for buffer edge bugs. fd-stream buffers are ;;; 4096 wide. (dotimes (width-1 4) (let ((character (code-char (elt '(1 #x81 #x801 #x10001) width-1)))) (dotimes (offset (+ width-1 1)) (with-open-file (s "external-format-test.txt" :direction :output :if-exists :supersede :external-format :utf-8) (dotimes (n offset) (write-char #\a s)) (dotimes (n 4097) (write-char character s))) (with-open-file (s "external-format-test.txt" :direction :input :external-format :utf-8) (dotimes (n offset) (assert (eql (read-char s) #\a))) (dotimes (n 4097) (assert (eql (read-char s) character))) (assert (eql (read-char s nil s) s)))))) ;;; Test character decode restarts. (with-open-file (s "external-format-test.txt" :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte 65 s) (write-byte 66 s) (write-byte #xe0 s) (write-byte 67 s)) (with-open-file (s "external-format-test.txt" :direction :input :external-format :utf-8) (handler-bind ((sb-int:character-decoding-error #'(lambda (decoding-error) (declare (ignore decoding-error)) (invoke-restart 'sb-int:attempt-resync)))) (assert (equal (read-line s nil s) "ABC")) (assert (equal (read-line s nil s) s)))) (with-open-file (s "external-format-test.txt" :direction :input :external-format :utf-8) (handler-bind ((sb-int:character-decoding-error #'(lambda (decoding-error) (declare (ignore decoding-error)) (invoke-restart 'sb-int:force-end-of-file)))) (assert (equal (read-line s nil s) "AB")) (assert (equal (read-line s nil s) s)))) ;;; Test character encode restarts. (with-open-file (s "external-format-test.txt" :direction :output :if-exists :supersede :external-format :latin-1) (handler-bind ((sb-int:character-encoding-error #'(lambda (encoding-error) (declare (ignore encoding-error)) (invoke-restart 'sb-impl::output-nothing)))) (write-char #\A s) (write-char #\B s) (write-char (code-char 322) s) (write-char #\C s))) (with-open-file (s "external-format-test.txt" :direction :input :external-format :latin-1) (assert (equal (read-line s nil s) "ABC")) (assert (equal (read-line s nil s) s))) (with-open-file (s "external-format-test.txt" :direction :output :if-exists :supersede :external-format :latin-1) (handler-bind ((sb-int:character-encoding-error #'(lambda (encoding-error) (declare (ignore encoding-error)) (invoke-restart 'sb-impl::output-nothing)))) (let ((string (make-array 4 :element-type 'character :initial-contents `(#\A #\B ,(code-char 322) #\C)))) (write-string string s)))) (with-open-file (s "external-format-test.txt" :direction :input :external-format :latin-1) (assert (equal (read-line s nil s) "ABC")) (assert (equal (read-line s nil s) s))) ;;; Test skipping character-decode-errors in comments. (let ((s (open "external-format-test.lisp" :direction :output :if-exists :supersede :external-format :latin-1))) (unwind-protect (progn (write-string ";;; ABCD" s) (write-char (code-char 233) s) (terpri s) (close s) (compile-file "external-format-test.lisp" :external-format :utf-8)) (delete-file s) (let ((p (probe-file (compile-file-pathname "external-format-test.lisp")))) (when p (delete-file p))))) ;;;; KOI8-R external format (with-open-file (s "external-format-test.txt" :direction :output :if-exists :supersede :external-format :koi8-r) (write-char (code-char #xB0) s) (assert (eq (handler-case (progn (write-char (code-char #xBAAD) s) :bad) (sb-int:character-encoding-error () :good)) :good))) (with-open-file (s "external-format-test.txt" :direction :input :element-type '(unsigned-byte 8)) (let ((byte (read-byte s))) (assert (= (eval byte) #x9C)))) (with-open-file (s "external-format-test.txt" :direction :input :external-format :koi8-r) (let ((char (read-char s))) (assert (= (char-code (eval char)) #xB0)))) (delete-file "external-format-test.txt")