+
+;;; regression test: STRING->UTF8 didn't properly handle a non-zero
+;;; START argument.
+(assert (equalp #(50) (string-to-octets "42" :start 1 :external-format :utf-8)))
+
+;;; STRING->UTF8 should cope with NIL strings if a null range is required
+(assert (equalp #() (string-to-octets "" :external-format :utf-8)))
+(assert (equalp #() (string-to-octets (make-array 0 :element-type nil)
+ :external-format :utf-8)))
+(assert (equalp #() (string-to-octets (make-array 5 :element-type nil)
+ :start 3 :end 3 :external-format :utf-8)))
+(assert (equalp #(0) (string-to-octets (make-array 5 :element-type nil)
+ :start 3 :end 3 :null-terminate t
+ :external-format :utf-8)))
+
+;;; whoops: the iso-8859-2 format referred to an undefined symbol.
+#+sb-unicode
+(assert (equalp #(251) (string-to-octets (string (code-char 369))
+ :external-format :latin-2)))
+
+(with-test (:name (:euc-jp :decoding-errors) :skipped-on '(not :sb-unicode))
+ (handler-bind ((sb-int:character-decoding-error
+ (lambda (c) (use-value #\? c))))
+ (assert (string= "?{?"
+ (octets-to-string
+ (coerce #(182 123 253 238) '(vector (unsigned-byte 8)))
+ :external-format :euc-jp)))))
+
+(with-test (:name (:utf-8 :surrogates :encoding-errors) :skipped-on '(not :sb-unicode))
+ (handler-bind ((sb-int:character-encoding-error
+ (lambda (c) (use-value #\? c))))
+ (assert (equalp (string-to-octets (string (code-char #xd800))
+ :external-format :utf-8)
+ (vector (char-code #\?))))))
+(with-test (:name (:utf-8 :surrogates :decoding-errors) :skipped-on '(not :sb-unicode))
+ (handler-bind ((sb-int:character-decoding-error
+ (lambda (c) (use-value #\? c))))
+ (assert (find #\? (octets-to-string
+ (coerce #(237 160 128) '(vector (unsigned-byte 8)))
+ :external-format :utf-8)))))
+
+(with-test (:name (:ucs-2 :out-of-range :encoding-errors) :skipped-on '(not :sb-unicode))
+ (handler-bind ((sb-int:character-encoding-error
+ (lambda (c) (use-value "???" c))))
+ (assert (equalp (string-to-octets (string (code-char #x10001))
+ :external-format :ucs-2le)
+ #(63 0 63 0 63 0))))
+ (handler-bind ((sb-int:character-encoding-error
+ (lambda (c) (use-value "???" c))))
+ (assert (equalp (string-to-octets (string (code-char #x10001))
+ :external-format :ucs-2be)
+ #(0 63 0 63 0 63)))))
+
+(with-test (:name (:ucs-4 :out-of-range :decoding-errors) :skipped-on '(not :sb-unicode))
+ (handler-bind ((sb-int:character-decoding-error
+ (lambda (c) (use-value "???" c))))
+ (assert (equalp (octets-to-string (coerce '(1 2 3 4) '(vector (unsigned-byte 8)))
+ :external-format :ucs-4le)
+ "???")))
+ (assert (equalp (octets-to-string (coerce '(#xff #xff #x10 #x00) '(vector (unsigned-byte 8)))
+ :external-format :ucs-4le)
+ (string (code-char #x10ffff))))
+ (handler-bind ((sb-int:character-decoding-error
+ (lambda (c) (use-value "???" c))))
+ (assert (equalp (octets-to-string (coerce '(1 2 3 4) '(vector (unsigned-byte 8)))
+ :external-format :ucs-4be)
+ "???"))
+ (assert (equalp (octets-to-string (coerce '(#x00 #x10 #xff #xff) '(vector (unsigned-byte 8)))
+ :external-format :ucs-4be)
+ (string (code-char #x10ffff))))))
+
+(with-test (:name (:utf-16le :ensure-roundtrip) :skipped-on '(not :sb-unicode))
+ (flet ((enc (x)
+ (string-to-octets x :external-format :utf-16le))
+ (dec (x)
+ (octets-to-string (coerce x '(vector (unsigned-byte 8)))
+ :external-format :utf-16le)))
+ (let ((string (map 'string 'code-char
+ '(#x20 #x200 #x2000 #x10000 #x10401 #x10fffd)))
+ (octets #(#x20 0 0 #x2 0 #x20 0 #xd8 0 #xdc 1 #xd8 1 #xdc #xff #xdb #xfd #xdf)))
+ (assert (equalp (enc string) octets))
+ (assert (equalp (dec octets) string)))))
+
+(with-test (:name (:utf-16le :encoding-error) :skipped-on '(not :sb-unicode))
+ (flet ((enc (x)
+ (string-to-octets x :external-format '(:utf-16le :replacement #\?)))
+ (dec (x)
+ (octets-to-string (coerce x '(vector (unsigned-byte 8)))
+ :external-format :utf-16le)))
+ (let ((string (map 'string 'code-char '(#xd800 #xdc00 #xfffe #x10ffff))))
+ (assert (equalp (enc string) #(63 0 63 0 63 0 63 0))))))
+
+(with-test (:name (:utf-16be :ensure-roundtrip) :skipped-on '(not :sb-unicode))
+ (flet ((enc (x)
+ (string-to-octets x :external-format :utf-16be))
+ (dec (x)
+ (octets-to-string (coerce x '(vector (unsigned-byte 8)))
+ :external-format :utf-16be)))
+ (let ((string (map 'string 'code-char
+ '(#x20 #x200 #x2000 #x10000 #x10401 #x10fffd)))
+ (octets #(0 #x20 #x2 0 #x20 0 #xd8 0 #xdc 0 #xd8 1 #xdc 1 #xdb #xff #xdf #xfd)))
+ (assert (equalp (enc string) octets))
+ (assert (equalp (dec octets) string)))))
+
+(with-test (:name (:utf-16be :encoding-error) :skipped-on '(not :sb-unicode))
+ (flet ((enc (x)
+ (string-to-octets x :external-format '(:utf-16be :replacement #\?)))
+ (dec (x)
+ (octets-to-string (coerce x '(vector (unsigned-byte 8)))
+ :external-format :utf-16be)))
+ (let ((string (map 'string 'code-char '(#xd800 #xdc00 #xfffe #x10ffff))))
+ (assert (equalp (enc string) #(0 63 0 63 0 63 0 63))))))
+
+
+(with-test (:name (:utf-32le :ensure-roundtrip) :skipped-on '(not :sb-unicode))
+ (flet ((enc (x)
+ (string-to-octets x :external-format :utf-32le))
+ (dec (x)
+ (octets-to-string (coerce x '(vector (unsigned-byte 8)))
+ :external-format :utf-32le)))
+ (let ((string (map 'string 'code-char
+ '(#x20 #x200 #x2000 #x10000 #x10401 #x10fffd)))
+ (octets #(#x20 0 0 0 0 #x2 0 0 0 #x20 0 0 0 0 1 0 1 4 1 0 #xfd #xff #x10 0)))
+ (assert (equalp (enc string) octets))
+ (assert (equalp (dec octets) string)))))
+
+(with-test (:name (:utf-32le :encoding-error) :skipped-on '(not :sb-unicode))
+ (flet ((enc (x)
+ (string-to-octets x :external-format '(:utf-32le :replacement #\?)))
+ (dec (x)
+ (octets-to-string (coerce x '(vector (unsigned-byte 8)))
+ :external-format :utf-32le)))
+ (let ((string (map 'string 'code-char '(#xd800 #xdc00 #xfffe #x10ffff))))
+ (assert (equalp (enc string) #(63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0))))))
+
+
+(with-test (:name (:utf-32be :ensure-roundtrip) :skipped-on '(not :sb-unicode))
+ (flet ((enc (x)
+ (string-to-octets x :external-format :utf-32be))
+ (dec (x)
+ (octets-to-string (coerce x '(vector (unsigned-byte 8)))
+ :external-format :utf-32be)))
+ (let ((string (map 'string 'code-char
+ '(#x20 #x200 #x2000 #x10000 #x10401 #x10fffd)))
+ (octets #(0 0 0 #x20 0 0 #x2 0 0 0 #x20 0 0 1 0 0 0 1 4 1 0 #x10 #xff #xfd)))
+ (assert (equalp (enc string) octets))
+ (assert (equalp (dec octets) string)))))
+
+(with-test (:name (:utf-32be :encoding-error) :skipped-on '(not :sb-unicode))
+ (flet ((enc (x)
+ (string-to-octets x :external-format '(:utf-32be :replacement #\?)))
+ (dec (x)
+ (octets-to-string (coerce x '(vector (unsigned-byte 8)))
+ :external-format :utf-32be)))
+ (let ((string (map 'string 'code-char '(#xd800 #xdc00 #xfffe #x10ffff))))
+ (assert (equalp (enc string) #(0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63))))))