master: Add a test for utf8-to-character-string

stassats via Sbcl-commits <[email protected]> Thu, 23 Jul 2026 20:50:58 +0000
Newsgroups gmane.lisp.steel-bank.cvs
Message-ID <[email protected]>
The branch "master" has been updated in SBCL:
       via  392382ba0ba71e0bee6159350ad8dbc55c61fd20 (commit)
      from  223bc344bd4120ba6838af0d0edc923b51a2f5ff (commit)

- Log -----------------------------------------------------------------
commit 392382ba0ba71e0bee6159350ad8dbc55c61fd20
Author: Stas Boukarev <[email protected]>
Date:   Thu Jul 23 23:49:48 2026 +0300

    Add a test for utf8-to-character-string
---
 tests/utf-8.impure.lisp | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/tests/utf-8.impure.lisp b/tests/utf-8.impure.lisp
index 233caf565..4a69553ce 100644
--- a/tests/utf-8.impure.lisp
+++ b/tests/utf-8.impure.lisp
@@ -197,3 +197,76 @@
                  (error "(encode-test ~s ~a) => ~a /= ~a" string (length octets)
                         result octets))))
           (free-protected-array string))))
+
+(defun validate-utf8 (vector)
+  (macrolet ((return-if-not-cont (x)
+               `(let ((x ,x))
+                  (unless (<= #x80 x #xBF)
+                    (return index))
+                  x)))
+    (let ((index 0)
+          (length (length vector)))
+      (loop while (< index length)
+            do
+            (let ((b0 (aref vector index)))
+              (cond
+                ;; ASCII
+                ((< b0 #x80)
+                 (incf index 1))
+                ;; 2 bytes
+                ((<= #xC2 b0 #xDF)
+                 (when (>= (+ index 1) length)
+                   (return index))
+                 (return-if-not-cont (aref vector (+ index 1)))
+                 (incf index 2))
+
+                ;; 3 bytes
+                ((<= #xE0 b0 #xEF)
+                 (when (>= (+ index 2) length)
+                   (return index))
+                 (let ((b1 (return-if-not-cont (aref vector (+ index 1))))
+                       (b2 (return-if-not-cont (aref vector (+ index 2)))))
+                   (declare (ignore b2 ))
+                   (unless (if (= b0 #xE0)
+                               (<= #xA0 b1 #xBF) ; Overlong
+                               (if (= b0 #xED)
+                                   (<= #x80 b1 #x9F) ; Surrogate halves
+                                   t))
+                     (return index)))
+                 (incf index 3))
+                ;; 4 bytes
+                ((<= #xF0 b0 #xF4)
+                 (when (>= (+ index 3) length)
+                   (return index))
+                 (let ((b1 (return-if-not-cont (aref vector (+ index 1))))
+                       (b2 (return-if-not-cont (aref vector (+ index 2))))
+                       (b3 (return-if-not-cont (aref vector (+ index 3)))))
+                   (declare (ignore b2 b3))
+                   (unless (if (= b0 #xF0)
+                               (<= #x90 b1 #xBF) ; Overlong
+                               (if (= b0 #xF4)
+                                   (<= #x80 b1 #x8F) ; Too Large
+                                   t))
+                     (return index)))
+                 (incf index 4))
+                (t (return index))))))))
+
+
+(with-test (:name :utf8-to-character-string)
+  (let ((vector (make-array sb-impl::+bytes-per-buffer+ :element-type '(unsigned-byte 8)))
+        (ibuf (sb-impl::alloc-buffer))
+        (string (make-protected-array 512 'character nil)))
+    (setf (sb-impl::buffer-tail ibuf) sb-impl::+bytes-per-buffer+)
+    (loop repeat (* 512 #+slow 10)
+          do
+          (map-into vector (lambda () (random 256)))
+          (setf (sb-impl::buffer-head ibuf) 0
+                (sb-impl::buffer-tail ibuf) sb-impl::+bytes-per-buffer+)
+          (sb-kernel:copy-ub8-to-system-area vector 0 (sb-impl::buffer-sap ibuf) 0 (length vector))
+          (let* ((bad (validate-utf8 vector))
+                 (chars (sb-vm::utf8-to-character-string 0 (length string) string ibuf))
+                 (bytes (sb-impl::buffer-head ibuf))
+                 (decoded (octets-to-string vector :end bad)))
+            (when bad
+              (assert (>= bad bytes)))
+            (assert (string= string decoded :end1 chars :end2 chars))))))

-----------------------------------------------------------------------


hooks/post-receive
-- 
SBCL