1 ;;;; This file is for testing external-format functionality, using
2 ;;;; test machinery which might have side effects (e.g. executing
3 ;;;; DEFUN, writing files). Note that the tests here reach into
4 ;;;; unexported functionality, and should not be used as a guide for
7 ;;;; This software is part of the SBCL system. See the README file for
10 ;;;; While most of SBCL is derived from the CMU CL system, the test
11 ;;;; files (like this one) were written from scratch after the fork
14 ;;;; This software is in the public domain and is provided with
15 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
16 ;;;; more information.
18 (defmacro do-external-formats ((xf &optional result) &body body)
20 `(loop for ,nxf being the hash-values of sb-impl::*external-formats*
21 do (let ((,xf (first (sb-impl::ef-names ,nxf))))
24 (defvar *test-path* "external-format-test.tmp")
26 (with-test (:name :end-of-file)
27 (do-external-formats (xf)
28 (with-open-file (s #-win32 "/dev/null" #+win32 "nul" :direction :input :external-format xf)
29 (assert (eq (read-char s nil s) s)))))
31 ;;; Test standard character read-write equivalency over all external formats.
35 (do-external-formats (xf)
36 (pushnew `(with-test (:name (:standard-character :read-write-equivalency ,xf))
37 (let ((standard-characters "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!$\"'(),_-./:;?+<=>#%&*@[\\]{|}`^~"))
38 (with-open-file (s *test-path* :direction :output
39 :if-exists :supersede :external-format ,xf)
40 (loop for character across standard-characters
41 do (write-char character s)))
42 (with-open-file (s *test-path* :direction :input
44 (loop for character across standard-characters
45 do (let ((got (read-char s)))
46 (unless (eql character got)
47 (error "wanted ~S, got ~S" character got)))))))
48 tests :key #'cadr :test #'equal))
52 (delete-file *test-path*)
55 (test-util:report-test-status)
56 (sb-ext:exit :code 104))
58 ;;; Test UTF-8 writing and reading of 1, 2, 3 and 4 octet characters with
59 ;;; all possible offsets. Tests for buffer edge bugs. fd-stream buffers are
62 (let ((character (code-char (elt '(1 #x81 #x801 #x10001) width-1))))
63 (dotimes (offset (+ width-1 1))
64 (with-open-file (s *test-path* :direction :output
65 :if-exists :supersede :external-format :utf-8)
68 (dotimes (n (+ 4 sb-impl::+bytes-per-buffer+))
69 (write-char character s)))
70 (with-open-file (s *test-path* :direction :input
71 :external-format :utf-8)
73 (assert (eql (read-char s) #\a)))
74 (dotimes (n (+ 4 sb-impl::+bytes-per-buffer+))
75 (let ((got (read-char s)))
76 (unless (eql got character)
77 (error "wanted ~S, got ~S (~S)" character got n))))
78 (assert (eql (read-char s nil s) s))))))
80 ;;; Test character decode restarts.
81 (with-open-file (s *test-path* :direction :output
82 :if-exists :supersede :element-type '(unsigned-byte 8))
87 (with-open-file (s *test-path* :direction :input
88 :external-format :utf-8)
91 ((sb-int:character-decoding-error #'(lambda (decoding-error)
92 (declare (ignore decoding-error))
93 (when (> (incf count) 1)
94 (error "too many errors"))
96 'sb-int:attempt-resync))))
97 (assert (equal (read-line s nil s) "ABC"))
98 (assert (equal (read-line s nil s) s)))))
99 (with-open-file (s *test-path* :direction :input
100 :external-format :utf-8)
103 ((sb-int:character-decoding-error #'(lambda (decoding-error)
104 (declare (ignore decoding-error))
105 (when (> (incf count) 1)
106 (error "too many errors"))
108 'sb-int:force-end-of-file))))
109 (assert (equal (read-line s nil s) "AB"))
111 (assert (equal (read-line s nil s) s)))))
113 ;;; And again with more data to account for buffering (this was briefly)
114 ;;; broken in early 0.9.6.
115 (with-open-file (s *test-path* :direction :output
116 :if-exists :supersede :element-type '(unsigned-byte 8))
117 (let ((a (make-array 50
118 :element-type '(unsigned-byte 64)
119 :initial-contents (map 'list #'char-code
120 "1234567890123456789012345678901234567890123456789."))))
121 (setf (aref a 49) (char-code #\Newline))
123 (write-sequence a s))
126 (write-sequence a s))))
127 (with-test (:name (:character-decode-large :attempt-resync)
129 (with-open-file (s *test-path* :direction :input
130 :external-format :utf-8)
133 ((sb-int:character-decoding-error (lambda (decoding-error)
134 (declare (ignore decoding-error))
135 (when (> (incf count) 1)
136 (error "too many errors"))
138 'sb-int:attempt-resync)))
139 ;; The failure mode is an infinite loop, add a timeout to
141 (sb-ext:timeout (lambda () (error "Timeout"))))
142 (sb-ext:with-timeout 5
144 (assert (equal (read-line s nil s)
145 "1234567890123456789012345678901234567890123456789"))))))))
147 (with-test (:name (:character-decode-large :force-end-of-file))
148 (with-open-file (s *test-path* :direction :input
149 :external-format :utf-8)
152 ((sb-int:character-decoding-error (lambda (decoding-error)
153 (declare (ignore decoding-error))
154 (when (> (incf count) 1)
155 (error "too many errors"))
157 'sb-int:force-end-of-file)))
158 ;; The failure mode is an infinite loop, add a timeout to detetct it.
159 (sb-ext:timeout (lambda () (error "Timeout"))))
160 (sb-ext:with-timeout 5
162 (assert (equal (read-line s nil s)
163 "1234567890123456789012345678901234567890123456789")))
165 (assert (equal (read-line s nil s) s)))))))
167 ;;; Test character encode restarts.
168 (with-open-file (s *test-path* :direction :output
169 :if-exists :supersede :external-format :latin-1)
171 ((sb-int:character-encoding-error #'(lambda (encoding-error)
172 (declare (ignore encoding-error))
174 'sb-impl::output-nothing))))
177 (write-char (code-char 322) s)
179 (with-open-file (s *test-path* :direction :input
180 :external-format :latin-1)
181 (assert (equal (read-line s nil s) "ABC"))
182 (assert (equal (read-line s nil s) s)))
184 (with-open-file (s *test-path* :direction :output
185 :if-exists :supersede :external-format :latin-1)
187 ((sb-int:character-encoding-error #'(lambda (encoding-error)
188 (declare (ignore encoding-error))
190 'sb-impl::output-nothing))))
191 (let ((string (make-array 4 :element-type 'character
192 :initial-contents `(#\A #\B ,(code-char 322)
194 (write-string string s))))
195 (with-open-file (s *test-path* :direction :input
196 :external-format :latin-1)
197 (assert (equal (read-line s nil s) "ABC"))
198 (assert (equal (read-line s nil s) s)))
200 ;;; Test skipping character-decode-errors in comments.
201 (let ((s (open "external-format-test.lisp" :direction :output
202 :if-exists :supersede :external-format :latin-1)))
205 (write-string ";;; ABCD" s)
206 (write-char (code-char 233) s)
209 (compile-file "external-format-test.lisp" :external-format :utf-8))
211 (let ((p (probe-file (compile-file-pathname "external-format-test.lisp"))))
216 ;;;; KOI8-R external format
217 (with-open-file (s *test-path* :direction :output
218 :if-exists :supersede :external-format :koi8-r)
219 (write-char (code-char #xB0) s)
223 (write-char (code-char #xBAAD) s)
225 (sb-int:character-encoding-error ()
228 (with-open-file (s *test-path* :direction :input
229 :element-type '(unsigned-byte 8))
230 (let ((byte (read-byte s)))
231 (assert (= (eval byte) #x9C))))
232 (with-open-file (s *test-path* :direction :input
233 :external-format :koi8-r)
234 (let ((char (read-char s)))
235 (assert (= (char-code (eval char)) #xB0))))
236 (delete-file *test-path*)
238 (let* ((koi8-r-codes (coerce '(240 210 201 215 197 212 33) '(vector (unsigned-byte 8))))
239 (uni-codes #(1055 1088 1080 1074 1077 1090 33))
241 (string (octets-to-string koi8-r-codes :external-format :koi8-r))
242 (uni-decoded (map 'vector #'char-code string)))
243 (assert (equalp (map 'vector #'char-code (octets-to-string koi8-r-codes :external-format :koi8-r))
245 (assert (equalp (string-to-octets (map 'string #'code-char uni-codes) :external-format :koi8-r)
248 ;;; tests of FILE-STRING-LENGTH
249 (let ((standard-characters "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!$\"'(),_-./:;?+<=>#%&*@[\\]{|}`^~"))
250 (do-external-formats (xf)
251 (with-open-file (s *test-path* :direction :output
253 (loop for x across standard-characters
254 for position = (file-position s)
255 for char-length = (file-string-length s x)
257 do (assert (= (file-position s) (+ position char-length))))
258 (let ((position (file-position s))
259 (string-length (file-string-length s standard-characters)))
260 (write-string standard-characters s)
261 (assert (= (file-position s) (+ position string-length)))))
262 (delete-file *test-path*)))
264 (let ((char-codes '(0 1 255 256 511 512 1023 1024 2047 2048 4095 4096
265 8191 8192 16383 16384 32767 32768 65535 65536 131071
266 131072 262143 262144)))
267 (with-open-file (s *test-path* :direction :output
268 :external-format :utf-8)
269 (dolist (code char-codes)
270 (let* ((char (code-char code))
271 (position (file-position s))
272 (char-length (file-string-length s char)))
274 (assert (= (file-position s) (+ position char-length)))))
275 (let* ((string (map 'string #'code-char char-codes))
276 (position (file-position s))
277 (string-length (file-string-length s string)))
278 (write-string string s)
279 (assert (= (file-position s) (+ position string-length))))))
282 ;;; See sbcl-devel "Subject: Bug in FILE-POSITION on UTF-8-encoded files"
283 ;;; by Lutz Euler on 2006-03-05 for more details.
284 (with-test (:name (:file-position :utf-8))
285 (let ((path *test-path*))
286 (with-open-file (s path
288 :if-exists :supersede
289 :element-type '(unsigned-byte 8))
290 ;; Write #\*, encoded in UTF-8, to the file.
292 ;; Append #\adiaeresis, encoded in UTF-8, to the file.
293 (write-sequence '(195 164) s))
294 (with-open-file (s path :external-format :utf-8)
296 (let ((pos (file-position s))
297 (char (read-char s)))
298 (format t "read character with code ~a successfully from file position ~a~%"
299 (char-code char) pos)
300 (file-position s pos)
301 (format t "set file position back to ~a, trying to read-char again~%" pos)
302 (let ((new-char (read-char s)))
303 (assert (char= char new-char)))))
305 (delete-file *test-path*)
307 ;;; We used to call STREAM-EXTERNAL-FORMAT on the stream in the error
308 ;;; when printing a coding error, but that didn't work if the stream
309 ;;; was closed by the time the error was printed. See sbcl-devel
310 ;;; "Subject: Printing coding errors for closed streams" by Zach Beane
311 ;;; on 2008-10-16 for more info.
312 (with-test (:name (:character-coding-error-stream-external-format))
313 (flet ((first-file-character ()
314 (with-open-file (stream *test-path* :external-format :utf-8)
315 (read-char stream))))
316 (with-open-file (stream *test-path*
318 :if-exists :supersede
319 :element-type '(unsigned-byte 8))
320 (write-byte 192 stream))
321 (princ-to-string (nth-value 1 (ignore-errors (first-file-character))))))
322 (delete-file *test-path*)
324 ;;; External format support in SB-ALIEN
326 (with-test (:name (:sb-alien :vanilla))
327 (define-alien-routine strdup c-string (str c-string))
328 (assert (equal "foo" (strdup "foo"))))
330 (with-test (:name (:sb-alien :utf-8 :utf-8))
331 (define-alien-routine strdup (c-string :external-format :utf-8)
332 (str (c-string :external-format :utf-8)))
333 (assert (equal "foo" (strdup "foo"))))
335 (with-test (:name (:sb-alien :latin-1 :utf-8))
336 (define-alien-routine strdup (c-string :external-format :latin-1)
337 (str (c-string :external-format :utf-8)))
338 (assert (= (length (strdup (string (code-char 246))))
341 (with-test (:name (:sb-alien :utf-8 :latin-1))
342 (define-alien-routine strdup (c-string :external-format :utf-8)
343 (str (c-string :external-format :latin-1)))
344 (assert (equal (string (code-char 228))
345 (strdup (concatenate 'string
346 (list (code-char 195))
347 (list (code-char 164)))))))
349 (with-test (:name (:sb-alien :ebcdic :ebcdic))
350 (define-alien-routine strdup (c-string :external-format :ebcdic-us)
351 (str (c-string :external-format :ebcdic-us)))
352 (assert (equal "foo" (strdup "foo"))))
354 (with-test (:name (:sb-alien :latin-1 :ebcdic))
355 (define-alien-routine strdup (c-string :external-format :latin-1)
356 (str (c-string :external-format :ebcdic-us)))
357 (assert (not (equal "foo" (strdup "foo")))))
359 (with-test (:name (:sb-alien :simple-base-string))
360 (define-alien-routine strdup (c-string :external-format :ebcdic-us
361 :element-type base-char)
362 (str (c-string :external-format :ebcdic-us)))
363 (assert (typep (strdup "foo") 'simple-base-string)))
365 (with-test (:name (:input-replacement :at-end-of-file))
367 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
369 (handler-bind ((sb-int:character-decoding-error
371 (invoke-restart 'sb-impl::input-replacement #\?))))
372 (with-open-file (s *test-path* :external-format :utf-8)
374 ((char= (read-char s) #\?)
375 (assert (or (= i (char-code #\?)) (> i 127))))
376 (t (assert (and (not (= i (char-code #\?))) (< i 128)))))))))
378 (with-test (:name (:unibyte-invalid-codepoints :cp857))
380 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
382 (with-open-file (s *test-path* :external-format :cp857)
383 (handler-case (read-char s)
384 (error () (assert (member i '(#xd5 #xe7 #xf2))))
385 (:no-error (char) (assert (not (member i '(#xd5 #xe7 #xf2)))))))))
386 (delete-file *test-path*)
388 (with-test (:name (:unibyte-input-replacement :cp857))
390 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
392 (with-open-file (s *test-path* :external-format '(:cp857 :replacement #\?))
393 (let ((char (read-char s)))
396 (assert (member i `(,(char-code #\?) #xd5 #xe7 #xf2))))
397 (t (assert (not (member i `(,(char-code #\?) #xd5 #xe7 #xf2))))))))))
398 (delete-file *test-path*)
400 (with-test (:name (:unibyte-output-replacement :cp857))
401 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:cp857 :replacement #\?))
403 (write-char (code-char i) s)))
404 (with-open-file (s *test-path* :external-format '(:cp857))
405 (let ((string (make-string 256)))
406 (read-sequence string s)
408 (assert (= (char-code (char string i)) i)))
409 (assert (= 38 (count #\? string :start 128))))))
410 (delete-file *test-path*)
412 (with-test (:name (:unibyte-input-replacement :ascii))
414 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
416 (with-open-file (s *test-path* :external-format '(:ascii :replacement #\?))
417 (let ((char (read-char s)))
420 (assert (or (= i (char-code #\?)) (> i 127))))
421 (t (assert (and (< i 128) (not (= i (char-code #\?)))))))))))
422 (delete-file *test-path*)
424 (with-test (:name (:unibyte-output-replacement :ascii))
425 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:ascii :replacement #\?))
427 (write-char (code-char i) s)))
428 (with-open-file (s *test-path* :external-format '(:ascii))
429 (let ((string (make-string 256)))
430 (read-sequence string s)
432 (assert (= (char-code (char string i)) i)))
433 (assert (= 128 (count #\? string :start 128))))))
434 (delete-file *test-path*)
436 (with-test (:name (:unibyte-input-replacement :latin-1))
438 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
440 (with-open-file (s *test-path* :external-format '(:latin-1 :replacement #\?))
441 (let ((char (read-char s)))
442 (assert (= (char-code char) i))))))
443 (delete-file *test-path*)
445 (with-test (:name (:unibyte-output-replacement :latin-1))
446 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-1 :replacement #\?))
448 (write-char (code-char i) s)))
449 (with-open-file (s *test-path* :external-format '(:latin-1))
450 (let ((string (make-string 257)))
451 (read-sequence string s)
453 (assert (= (char-code (char string i)) i)))
454 (assert (char= #\? (char string 256))))))
455 (delete-file *test-path*)
458 (with-test (:name (:unibyte-input-replacement :latin-2))
460 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
462 (with-open-file (s *test-path* :external-format '(:latin-2 :replacement #\?))
463 (let ((char (read-char s)))
465 ((< i #xa1) (assert (= (char-code char) i)))
468 (delete-file *test-path*)
470 (with-test (:name (:unibyte-output-replacement :latin-2))
471 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-2 :replacement #\?))
473 (write-char (code-char i) s)))
474 (with-open-file (s *test-path* :external-format '(:latin-2))
475 (let ((string (make-string 256)))
476 (read-sequence string s)
478 (assert (= (char-code (char string i)) i)))
479 (assert (= 57 (count #\? string :start #xa1))))))
480 (delete-file *test-path*)
483 (with-test (:name (:unibyte-input-replacement :latin-3))
485 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
487 (with-open-file (s *test-path* :external-format '(:latin-3 :replacement #\?))
488 (let ((char (read-char s)))
491 (assert #1=(or (= i (char-code #\?))
492 (member i '(#xa5 #xae #xbe #xc3 #xd0 #xe3 #xf0)))))
493 (t (assert (not #1#))))))))
494 (delete-file *test-path*)
496 (with-test (:name (:unibyte-output-replacement :latin-3))
497 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-3 :replacement #\?))
499 (write-char (code-char i) s)))
500 (with-open-file (s *test-path* :external-format '(:latin-3))
501 (let ((string (make-string 256)))
502 (read-sequence string s)
504 (assert (= (char-code (char string i)) i)))
505 (assert (= 35 (count #\? string :start #xa1))))))
506 (delete-file *test-path*)
509 (with-test (:name (:unibyte-input-replacement :latin-4))
511 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
513 (with-open-file (s *test-path* :external-format '(:latin-4 :replacement #\?))
514 (let ((char (read-char s)))
516 ((< i #xa1) (assert (= (char-code char) i)))
519 (delete-file *test-path*)
521 (with-test (:name (:unibyte-output-replacement :latin-4))
522 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-4 :replacement #\?))
524 (write-char (code-char i) s)))
525 (with-open-file (s *test-path* :external-format '(:latin-4))
526 (let ((string (make-string 256)))
527 (read-sequence string s)
529 (assert (= (char-code (char string i)) i)))
530 (assert (= 50 (count #\? string :start #xa1))))))
531 (delete-file *test-path*)
534 (with-test (:name (:unibyte-input-replacement :iso-8859-5))
536 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
538 (with-open-file (s *test-path* :external-format '(:iso-8859-5 :replacement #\?))
539 (let ((char (read-char s)))
541 ((= (char-code char) i)
542 (assert (or (< i #xa1) (= i #xad))))
543 (t (assert (and (>= i #xa1) (/= i #xad)))))))))
544 (delete-file *test-path*)
546 (with-test (:name (:unibyte-output-replacement :iso-8859-5))
547 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-5 :replacement #\?))
549 (write-char (code-char i) s)))
550 (with-open-file (s *test-path* :external-format '(:iso-8859-5))
551 (let ((string (make-string 256)))
552 (read-sequence string s)
554 (assert (= (char-code (char string i)) i)))
555 (assert (= 93 (count #\? string :start #xa1))))))
556 (delete-file *test-path*)
559 (with-test (:name (:unibyte-input-replacement :iso-8859-6))
561 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
563 (with-open-file (s *test-path* :external-format '(:iso-8859-6 :replacement #\?))
564 (let ((char (read-char s)))
567 (assert #1=(or (= i (char-code #\?))
568 (<= #xa1 i #xa3) (<= #xa5 i #xab) (<= #xae i #xba)
569 (<= #xbc i #xbe) (= i #xc0) (<= #xdb i #xdf)
571 (t (assert (not #1#))))))))
572 (delete-file *test-path*)
574 (with-test (:name (:unibyte-output-replacement :iso-8859-6))
575 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-6 :replacement #\?))
577 (write-char (code-char i) s)))
578 (with-open-file (s *test-path* :external-format '(:iso-8859-6))
579 (let ((string (make-string 256)))
580 (read-sequence string s)
582 (assert (= (char-code (char string i)) i)))
583 (assert (= 93 (count #\? string :start #xa1))))))
584 (delete-file *test-path*)
587 (with-test (:name (:unibyte-input-replacement :iso-8859-7))
589 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
591 (with-open-file (s *test-path* :external-format '(:iso-8859-7 :replacement #\?))
592 (let ((char (read-char s)))
595 (assert #1=(or (= i (char-code #\?))
596 (member i '(#xa4 #xa5 #xaa #xae #xd2 #xff)))))
597 (t (assert (not #1#))))))))
598 (delete-file *test-path*)
600 (with-test (:name (:unibyte-output-replacement :iso-8859-7))
601 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-7 :replacement #\?))
603 (write-char (code-char i) s)))
604 (with-open-file (s *test-path* :external-format '(:iso-8859-7))
605 (let ((string (make-string 256)))
606 (read-sequence string s)
608 (assert (= (char-code (char string i)) i)))
609 (assert (= 80 (count #\? string :start #xa1))))))
610 (delete-file *test-path*)
613 (with-test (:name (:unibyte-input-replacement :iso-8859-8))
615 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
617 (with-open-file (s *test-path* :external-format '(:iso-8859-8 :replacement #\?))
618 (let ((char (read-char s)))
621 (assert #1=(or (= i (char-code #\?))
622 (= i #xa1) (<= #xbf i #xde) (>= i #xfb))))
623 (t (assert (not #1#))))))))
624 (delete-file *test-path*)
626 (with-test (:name (:unibyte-output-replacement :iso-8859-8))
627 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-8 :replacement #\?))
629 (write-char (code-char i) s)))
630 (with-open-file (s *test-path* :external-format '(:iso-8859-8))
631 (let ((string (make-string 256)))
632 (read-sequence string s)
634 (assert (= (char-code (char string i)) i)))
635 (assert (= 67 (count #\? string :start #xa1))))))
636 (delete-file *test-path*)
639 (with-test (:name (:unibyte-input-replacement :latin-5))
641 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
643 (with-open-file (s *test-path* :external-format '(:latin-5 :replacement #\?))
644 (let ((char (read-char s)))
645 (assert (or (and (= (char-code char) i)
646 (not (member i '(#xd0 #xdd #xde #xf0 #xfd #xfe))))
647 (and (member i '(#xd0 #xdd #xde #xf0 #xfd #xfe))
648 (not (char= char #\?)))))))))
649 (delete-file *test-path*)
651 (with-test (:name (:unibyte-output-replacement :latin-5))
652 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-5 :replacement #\?))
654 (write-char (code-char i) s)))
655 (with-open-file (s *test-path* :external-format '(:latin-5))
656 (let ((string (make-string 256)))
657 (read-sequence string s)
659 (assert (= (char-code (char string i)) i)))
660 (assert (= 6 (count #\? string :start #xd0))))))
661 (delete-file *test-path*)
664 (with-test (:name (:unibyte-input-replacement :latin-6))
666 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
668 (with-open-file (s *test-path* :external-format '(:latin-6 :replacement #\?))
669 (let ((char (read-char s)))
670 (assert (or (= (char-code char) i)
671 (and (<= #xa1 i #xff)
672 (not (char= char #\?)))))))))
673 (delete-file *test-path*)
675 (with-test (:name (:unibyte-output-replacement :latin-6))
676 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-6 :replacement #\?))
678 (write-char (code-char i) s)))
679 (with-open-file (s *test-path* :external-format '(:latin-6))
680 (let ((string (make-string 256)))
681 (read-sequence string s)
683 (assert (= (char-code (char string i)) i)))
684 (assert (= 46 (count #\? string :start #xa1))))))
685 (delete-file *test-path*)
687 ;;; iso-8859-11 tests
688 (with-test (:name (:unibyte-input-replacement :iso-8859-11))
690 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
692 (with-open-file (s *test-path* :external-format '(:iso-8859-11 :replacement #\?))
693 (let ((char (read-char s)))
696 (assert (member i #1=`(,(char-code #\?) #xdb #xdc #xdd #xde #xfc #xfd #xfe #xff))))
697 (t (assert (not (member i #1#)))))))))
698 (delete-file *test-path*)
700 (with-test (:name (:unibyte-output-replacement :iso-8859-11))
701 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-11 :replacement #\?))
703 (write-char (code-char i) s)))
704 (with-open-file (s *test-path* :external-format '(:iso-8859-11))
705 (let ((string (make-string 256)))
706 (read-sequence string s)
708 (assert (= (char-code (char string i)) i)))
709 (assert (= 95 (count #\? string :start #xa1))))))
710 (delete-file *test-path*)
713 (with-test (:name (:unibyte-input-replacement :latin-7))
715 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
717 (with-open-file (s *test-path* :external-format '(:latin-7 :replacement #\?))
718 (let ((char (read-char s)))
719 (assert (or (= (char-code char) i)
720 (and (<= #xa1 i #xff)
721 (not (char= char #\?)))))))))
722 (delete-file *test-path*)
724 (with-test (:name (:unibyte-output-replacement :latin-7))
725 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-7 :replacement #\?))
727 (write-char (code-char i) s)))
728 (with-open-file (s *test-path* :external-format '(:latin-7))
729 (let ((string (make-string 256)))
730 (read-sequence string s)
732 (assert (= (char-code (char string i)) i)))
733 (dolist (i '(#xd8 #xc6 #xf8 #xe6))
734 (assert (char/= (char string i) #\?)))
735 (assert (= 52 (count #\? string :start #xa1))))))
736 (delete-file *test-path*)
739 (with-test (:name (:unibyte-input-replacement :latin-8))
741 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
743 (with-open-file (s *test-path* :external-format '(:latin-8 :replacement #\?))
744 (let ((char (read-char s)))
745 (assert (or (= (char-code char) i)
746 (and (<= #xa1 i #xfe)
747 (not (char= char #\?)))))))))
748 (delete-file *test-path*)
750 (with-test (:name (:unibyte-output-replacement :latin-8))
751 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-8 :replacement #\?))
753 (write-char (code-char i) s)))
754 (with-open-file (s *test-path* :external-format '(:latin-8))
755 (let ((string (make-string 256)))
756 (read-sequence string s)
758 (assert (= (char-code (char string i)) i)))
759 (assert (= 31 (count #\? string :start #xa1))))))
760 (delete-file *test-path*)
763 (with-test (:name (:unibyte-input-replacement :latin-9))
765 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
767 (with-open-file (s *test-path* :external-format '(:latin-9 :replacement #\?))
768 (let ((char (read-char s)))
769 (assert (or (and (= (char-code char) i)
770 (not (member i '(#xa4 #xa6 #xa8 #xb4 #xb8 #xbc #xbd #xbe))))
771 (and (member i '(#xa4 #xa6 #xa8 #xb4 #xb8 #xbc #xbd #xbe))
772 (not (char= char #\?)))))))))
773 (delete-file *test-path*)
775 (with-test (:name (:unibyte-output-replacement :latin-9))
776 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-9 :replacement #\?))
778 (write-char (code-char i) s)))
779 (with-open-file (s *test-path* :external-format '(:latin-9))
780 (let ((string (make-string 256)))
781 (read-sequence string s)
783 (assert (= (char-code (char string i)) i)))
784 (assert (= 8 (count #\? string :start #xa4))))))
785 (delete-file *test-path*)
788 (with-test (:name (:unibyte-input-replacement :koi8-r))
790 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
792 (with-open-file (s *test-path* :external-format '(:koi8-r :replacement #\?))
793 (let ((char (read-char s)))
794 (cond ((= (char-code char) i)
796 (t (assert (> i 127))))))))
797 (delete-file *test-path*)
799 (with-test (:name (:unibyte-output-replacement :koi8-r))
800 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:koi8-r :replacement #\?))
802 (write-char (code-char i) s)))
803 (with-open-file (s *test-path* :external-format '(:koi8-r))
804 (let ((string (make-string 256)))
805 (read-sequence string s)
807 (assert (= (char-code (char string i)) i)))
808 (assert (= 122 (count #\? string :start #x80))))))
809 (delete-file *test-path*)
812 (with-test (:name (:unibyte-input-replacement :koi8-u))
814 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
816 (with-open-file (s *test-path* :external-format '(:koi8-u :replacement #\?))
817 (let ((char (read-char s)))
818 (cond ((= (char-code char) i)
820 (t (assert (> i 127))))))))
821 (delete-file *test-path*)
823 (with-test (:name (:unibyte-output-replacement :koi8-u))
824 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:koi8-u :replacement #\?))
826 (write-char (code-char i) s)))
827 (with-open-file (s *test-path* :external-format '(:koi8-u))
828 (let ((string (make-string 256)))
829 (read-sequence string s)
831 (assert (= (char-code (char string i)) i)))
832 (assert (= 122 (count #\? string :start #x80))))))
833 (delete-file *test-path*)
835 ;;; x-mac-cyrillic tests
836 (with-test (:name (:unibyte-input-replacement :x-mac-cyrillic))
838 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
840 (with-open-file (s *test-path* :external-format '(:x-mac-cyrillic :replacement #\?))
841 (let ((char (read-char s)))
842 (cond ((= (char-code char) i)
843 (assert (or (< i 128) (member i '(#xa2 #xa3 #xa9 #xb1 #xb5)))))
844 (t (assert (and (> i 127)
845 (not (member i '(#xa2 #xa3 #xa9 #xb1 #xb5)))))))))))
846 (delete-file *test-path*)
848 (with-test (:name (:unibyte-output-replacement :x-mac-cyrillic))
849 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:x-mac-cyrillic :replacement #\?))
851 (write-char (code-char i) s)))
852 (with-open-file (s *test-path* :external-format '(:x-mac-cyrillic))
853 (let ((string (make-string 256)))
854 (read-sequence string s)
856 (assert (= (char-code (char string i)) i)))
857 (assert (= 113 (count #\? string :start #x80))))))
858 (delete-file *test-path*)
861 (with-test (:name (:multibyte :ucs2le))
863 (array (map-into (make-array size :element-type '(unsigned-byte 16))
864 (lambda () (random #x10000)))))
865 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
867 (write-byte (ldb (byte 8 0) (aref array i)) s)
868 (write-byte (ldb (byte 8 8) (aref array i)) s)))
869 (with-open-file (s *test-path* :external-format :ucs2le)
870 (let ((string (make-string size)))
871 (read-sequence string s)
873 (assert (= (char-code (char string i)) (aref array i))))))))
875 (with-test (:name (:multibyte :ucs2be))
877 (array (map-into (make-array size :element-type '(unsigned-byte 16))
878 (lambda () (random #x10000)))))
879 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
881 (write-byte (ldb (byte 8 8) (aref array i)) s)
882 (write-byte (ldb (byte 8 0) (aref array i)) s)))
883 (with-open-file (s *test-path* :external-format :ucs2be)
884 (let ((string (make-string size)))
885 (read-sequence string s)
887 (assert (= (char-code (char string i)) (aref array i))))))))
889 (with-test (:name (:multibyte :output-replacement :ucs2le))
891 (string (map-into (make-string size)
892 (lambda () (code-char (random #x10000))))))
893 (setf (char string 0) (code-char #x10001)
894 (char string (1- size)) (code-char #x10002))
895 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:ucs2le :replacement #\replacement_character))
896 (write-string string s))
897 (with-open-file (s *test-path* :external-format :ucs2le)
898 (let ((new (make-string size)))
899 (read-sequence new s)
900 (assert (char= (char new 0) #\replacement_character))
901 (assert (char= (char new (1- size)) #\replacement_character))
902 (assert (string= string new :start1 1 :start2 1 :end1 (1- size) :end2 (1- size)))))))
904 (with-test (:name (:multibyte :output-replacement :ucs2be))
906 (string (map-into (make-string size)
907 (lambda () (code-char (random #x10000))))))
908 (setf (char string 0) (code-char #x10001)
909 (char string (1- size)) (code-char #x10002))
910 (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:ucs2be :replacement #\replacement_character))
911 (write-string string s))
912 (with-open-file (s *test-path* :external-format :ucs2be)
913 (let ((new (make-string size)))
914 (read-sequence new s)
915 (assert (char= (char new 0) #\replacement_character))
916 (assert (char= (char new (1- size)) #\replacement_character))
917 (assert (string= string new :start1 1 :start2 1 :end1 (1- size) :end2 (1- size)))))))
919 (with-test (:name (:multibyte :input-replacement :ucs4le))
920 (let ((octets (coerce '(0 1 1 0 1 0 0 1) '(vector (unsigned-byte 8)))))
921 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
922 (write-sequence octets s))
923 (with-open-file (s *test-path* :external-format '(:ucs4le :replacement #\replacement_character))
924 (let ((string (read-line s)))
925 (assert (char= (char string 0) (code-char #x10100)))
926 (assert (char= (char string 1) #\replacement_character))))))
928 (with-test (:name (:multibyte :input-replacement :ucs4le))
929 (let ((octets (coerce '(0 1 1 0 1 0 0 1) '(vector (unsigned-byte 8)))))
930 (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
931 (write-sequence octets s))
932 (with-open-file (s *test-path* :external-format '(:ucs4be :replacement #\replacement_character))
933 (let ((string (read-line s)))
934 (assert (char= (char string 0) (code-char #x10100)))
935 (assert (char= (char string 1) #\replacement_character))))))
938 (with-test (:name (:utf-16le :roundtrip))
939 (let ((string (map 'string 'code-char '(#x20 #x200 #x2000 #xfffd #x10fffd))))
940 (with-open-file (s *test-path* :direction :output :if-exists :supersede
941 :external-format :utf-16le)
942 (write-string string s))
943 (with-open-file (s *test-path* :external-format :utf-16le)
944 (assert (string= string (read-line s))))))
945 (with-test (:name (:utf-16be :roundtrip))
946 (let ((string (map 'string 'code-char '(#x20 #x200 #x2000 #xfffd #x10fffd))))
947 (with-open-file (s *test-path* :direction :output :if-exists :supersede
948 :external-format :utf-16be)
949 (write-string string s))
950 (with-open-file (s *test-path* :external-format :utf-16be)
951 (assert (string= string (read-line s))))))
952 (with-test (:name (:utf-16le :encoding-error))
953 (let ((string (map 'string 'code-char '(#x20 #xfffe #xdc00 #xd800 #x1fffe #x20))))
954 (with-open-file (s *test-path* :direction :output :if-exists :supersede
955 :external-format '(:utf-16le :replacement #\?))
956 (write-string string s))
957 (with-open-file (s *test-path* :external-format :utf-16le)
958 (assert (string= " ???? " (read-line s))))))
959 (with-test (:name (:utf-16be :encoding-error))
960 (let ((string (map 'string 'code-char '(#x20 #xfffe #xdc00 #xd800 #x1fffe #x20))))
961 (with-open-file (s *test-path* :direction :output :if-exists :supersede
962 :external-format '(:utf-16be :replacement #\?))
963 (write-string string s))
964 (with-open-file (s *test-path* :external-format :utf-16be)
965 (assert (string= " ???? " (read-line s))))))
967 (with-test (:name (:utf-32le :roundtrip))
968 (let ((string (map 'string 'code-char '(#x20 #x200 #x2000 #xfffd #x10fffd))))
969 (with-open-file (s *test-path* :direction :output :if-exists :supersede
970 :external-format :utf-32le)
971 (write-string string s))
972 (with-open-file (s *test-path* :external-format :utf-32le)
973 (assert (string= string (read-line s))))))
974 (with-test (:name (:utf-32be :roundtrip))
975 (let ((string (map 'string 'code-char '(#x20 #x200 #x2000 #xfffd #x10fffd))))
976 (with-open-file (s *test-path* :direction :output :if-exists :supersede
977 :external-format :utf-32be)
978 (write-string string s))
979 (with-open-file (s *test-path* :external-format :utf-32be)
980 (assert (string= string (read-line s))))))
981 (with-test (:name (:utf-32le :encoding-error))
982 (let ((string (map 'string 'code-char '(#x20 #xfffe #xdc00 #xd800 #x1fffe #x20))))
983 (with-open-file (s *test-path* :direction :output :if-exists :supersede
984 :external-format '(:utf-32le :replacement #\?))
985 (write-string string s))
986 (with-open-file (s *test-path* :external-format :utf-32le)
987 (assert (string= " ???? " (read-line s))))))
988 (with-test (:name (:utf-32be :encoding-error))
989 (let ((string (map 'string 'code-char '(#x20 #xfffe #xdc00 #xd800 #x1fffe #x20))))
990 (with-open-file (s *test-path* :direction :output :if-exists :supersede
991 :external-format '(:utf-32be :replacement #\?))
992 (write-string string s))
993 (with-open-file (s *test-path* :external-format :utf-32be)
994 (assert (string= " ???? " (read-line s))))))
996 (with-test (:name :invalid-external-format :fails-on :win32)
997 (labels ((test-error (e)
998 (assert (typep e 'error))
999 (unless (equal "Undefined external-format: :BAD-FORMAT"
1000 (princ-to-string e))
1001 (error "Bad error:~% ~A" e)))
1005 (open "/dev/null" :direction direction :external-format :bad-format
1006 :if-exists :overwrite)
1013 (run-program "sh" '() :input :stream :external-format :bad-format)
1017 (string-to-octets "foobar" :external-format :bad-format)
1020 (let ((octets (string-to-octets "foobar" :external-format :latin1)))
1022 (octets-to-string octets :external-format :bad-format)
1025 (with-test (:name :lp713063)
1026 (with-open-file (f *test-path*
1028 :external-format '(:euc-jp :replacement #\?)
1029 :if-exists :supersede)
1030 (write-string (make-string 3 :initial-element #\horizontal_bar) f))
1031 (assert (equal "???"
1032 (with-open-file (f *test-path*
1034 :external-format :euc-jp)
1036 (delete-file *test-path*))