#! /usr/bin/env sscm -C UTF-8

;;  Filename : test-string-proc.scm
;;  About    : unit test for R5RS string procedures
;;
;;  Copyright (c) 2007-2008 SigScheme Project <uim-en AT googlegroups.com>
;;
;;  All rights reserved.
;;
;;  Redistribution and use in source and binary forms, with or without
;;  modification, are permitted provided that the following conditions
;;  are met:
;;
;;  1. Redistributions of source code must retain the above copyright
;;     notice, this list of conditions and the following disclaimer.
;;  2. Redistributions in binary form must reproduce the above copyright
;;     notice, this list of conditions and the following disclaimer in the
;;     documentation and/or other materials provided with the distribution.
;;  3. Neither the name of authors nor the names of its contributors
;;     may be used to endorse or promote products derived from this software
;;     without specific prior written permission.
;;
;;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
;;  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
;;  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
;;  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
;;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
;;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
;;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
;;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
;;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
;;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

(require-extension (sscm-ext))

(require-extension (unittest))

(if (and sigscheme?
         (not (symbol-bound? 'make-string)))
    (test-skip "non-core string procedures of R5RS is not enabled"))

(define tn test-name)
(define cp string-copy)

(define mutable?
  (if sigscheme?
      %%string-mutable?
      (lambda (s) #t)))

(define pair-mutable?
  (if sigscheme?
      %%pair-mutable?
      (lambda (kons) #t)))

;;
;; All procedures that take a string as argument are tested with
;; both immutable and mutable string.
;;
;; See "3.4 Storage model" of R5RS
;;


(tn "make-string invalid forms")
(assert-error  (tn) (lambda () (make-string -2)))
(assert-error  (tn) (lambda () (make-string -1)))
(assert-error  (tn) (lambda () (make-string -2 #\a)))
(assert-error  (tn) (lambda () (make-string -1 #\a)))
(assert-error  (tn) (lambda () (make-string #\a)))
(assert-error  (tn) (lambda () (make-string 1 32)))
(tn "make-string")
(assert-equal? (tn) ""         (make-string 0))
(assert-equal? (tn) "?"        (make-string 1))
(assert-equal? (tn) "??"       (make-string 2))
(assert-equal? (tn) "???"      (make-string 3))
(assert-equal? (tn) ""         (make-string 0 #\a))
(assert-equal? (tn) "a"        (make-string 1 #\a))
(assert-equal? (tn) "aa"       (make-string 2 #\a))
(assert-equal? (tn) "aaa"      (make-string 3 #\a))
(assert-equal? (tn) ""         (make-string 0 #\あ))
(assert-equal? (tn) "あ"       (make-string 1 #\あ))
(assert-equal? (tn) "ああ"     (make-string 2 #\あ))
(assert-equal? (tn) "あああ"   (make-string 3 #\あ))
(tn "make-string NUL filler")
(assert-equal? (tn) ""         (make-string 0 #x00))
(if (and sigscheme?
         (not (provided? "null-capable-string")))
    (begin
      (assert-error  (tn) (lambda () (make-string 1 #x00)))
      (assert-error  (tn) (lambda () (make-string 2 #x00)))
      (assert-error  (tn) (lambda () (make-string 3 #x00)))))

(tn "string invalid forms")
(assert-error (tn) (lambda ()  (string #t)))
(assert-error (tn) (lambda ()  (string "a")))
(tn "string")
(assert-equal? (tn) ""         (string))
(assert-equal? (tn) "a"        (string #\a))
(assert-equal? (tn) "ab"       (string #\a #\b))
(assert-equal? (tn) "あ"       (string #\あ))
(assert-equal? (tn) "あう"     (string #\あ #\う))
(assert-equal? (tn) "aあb"     (string #\a #\あ #\b))
(assert-equal? (tn) "あaう"    (string #\あ #\a #\う))
(assert-equal? (tn) "aあbう"   (string #\a #\あ #\b #\う))
(assert-equal? (tn) "あaうb"   (string #\あ #\a #\う #\b))
(tn "string mutability")
(assert-true   (tn) (mutable?  (string)))
(assert-true   (tn) (mutable?  (string #\a)))
(assert-true   (tn) (mutable?  (string #\a #\b)))
(assert-true   (tn) (mutable?  (string #\あ)))
(assert-true   (tn) (mutable?  (string #\あ #\う)))
(assert-true   (tn) (mutable?  (string #\a #\あ #\b)))
(assert-true   (tn) (mutable?  (string #\あ #\a #\う)))
(assert-true   (tn) (mutable?  (string #\a #\あ #\b #\う)))
(assert-true   (tn) (mutable?  (string #\あ #\a #\う #\b)))
(tn "string with NUL args")
(if (and sigscheme?
         (not (provided? "null-capable-string")))
    (begin
      (assert-error (tn) (lambda () (string #x00)))
      (assert-error (tn) (lambda () (string #\a #x00)))
      (assert-error (tn) (lambda () (string #x00 #\a)))
      (assert-error (tn) (lambda () (string #\a #x00 #\a)))))

(tn "string-ref invalid forms")
(assert-error  (tn) (lambda () (string-ref #\a 0)))
(assert-error  (tn) (lambda () (string-ref "a" #\1)))
(tn "string-ref immutable")
(assert-error  (tn) (lambda () (string-ref "" -2)))
(assert-error  (tn) (lambda () (string-ref "" -1)))
(assert-error  (tn) (lambda () (string-ref "" 0)))
(assert-error  (tn) (lambda () (string-ref "" 1)))
(assert-error  (tn) (lambda () (string-ref "" 2)))
(assert-error  (tn) (lambda () (string-ref "a" -2)))
(assert-error  (tn) (lambda () (string-ref "a" -1)))
(assert-equal? (tn) #\a        (string-ref "a" 0))
(assert-error  (tn) (lambda () (string-ref "a" 1)))
(assert-error  (tn) (lambda () (string-ref "a" 2)))
(assert-error  (tn) (lambda () (string-ref "ab" -2)))
(assert-error  (tn) (lambda () (string-ref "ab" -1)))
(assert-equal? (tn) #\a        (string-ref "ab" 0))
(assert-equal? (tn) #\b        (string-ref "ab" 1))
(assert-error  (tn) (lambda () (string-ref "ab" 2)))
(assert-error  (tn) (lambda () (string-ref "ab" 3)))
(assert-error  (tn) (lambda () (string-ref "あ" -2)))
(assert-error  (tn) (lambda () (string-ref "あ" -1)))
(assert-equal? (tn) #\あ       (string-ref "あ" 0))
(assert-error  (tn) (lambda () (string-ref "あ" 1)))
(assert-error  (tn) (lambda () (string-ref "あ" 2)))
(assert-error  (tn) (lambda () (string-ref "あう" -2)))
(assert-error  (tn) (lambda () (string-ref "あう" -1)))
(assert-equal? (tn) #\あ       (string-ref "あう" 0))
(assert-equal? (tn) #\う       (string-ref "あう" 1))
(assert-error  (tn) (lambda () (string-ref "あう" 2)))
(assert-error  (tn) (lambda () (string-ref "あう" 3)))
(assert-error  (tn) (lambda () (string-ref "aあb" -2)))
(assert-error  (tn) (lambda () (string-ref "aあb" -1)))
(assert-equal? (tn) #\a        (string-ref "aあb" 0))
(assert-equal? (tn) #\あ       (string-ref "aあb" 1))
(assert-equal? (tn) #\b        (string-ref "aあb" 2))
(assert-error  (tn) (lambda () (string-ref "aあb" 3)))
(assert-error  (tn) (lambda () (string-ref "aあb" 4)))
(assert-error  (tn) (lambda () (string-ref "あaう" -2)))
(assert-error  (tn) (lambda () (string-ref "あaう" -1)))
(assert-equal? (tn) #\あ       (string-ref "あaう" 0))
(assert-equal? (tn) #\a        (string-ref "あaう" 1))
(assert-equal? (tn) #\う       (string-ref "あaう" 2))
(assert-error  (tn) (lambda () (string-ref "あaう" 3)))
(assert-error  (tn) (lambda () (string-ref "あaう" 4)))
(assert-error  (tn) (lambda () (string-ref "aあbう" -2)))
(assert-error  (tn) (lambda () (string-ref "aあbう" -1)))
(assert-equal? (tn) #\a        (string-ref "aあbう" 0))
(assert-equal? (tn) #\あ       (string-ref "aあbう" 1))
(assert-equal? (tn) #\b        (string-ref "aあbう" 2))
(assert-equal? (tn) #\う       (string-ref "aあbう" 3))
(assert-error  (tn) (lambda () (string-ref "aあbう" 4)))
(assert-error  (tn) (lambda () (string-ref "aあbう" 5)))
(assert-error  (tn) (lambda () (string-ref "あaうb" -2)))
(assert-error  (tn) (lambda () (string-ref "あaうb" -1)))
(assert-equal? (tn) #\あ       (string-ref "あaうb" 0))
(assert-equal? (tn) #\a        (string-ref "あaうb" 1))
(assert-equal? (tn) #\う       (string-ref "あaうb" 2))
(assert-equal? (tn) #\b        (string-ref "あaうb" 3))
(assert-error  (tn) (lambda () (string-ref "あaうb" 4)))
(assert-error  (tn) (lambda () (string-ref "あaうb" 5)))
(tn "string-ref mutable")
(assert-error  (tn) (lambda () (string-ref (cp "") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "") -1)))
(assert-error  (tn) (lambda () (string-ref (cp "") 0)))
(assert-error  (tn) (lambda () (string-ref (cp "") 1)))
(assert-error  (tn) (lambda () (string-ref (cp "") 2)))
(assert-error  (tn) (lambda () (string-ref (cp "a") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "a") -1)))
(assert-equal? (tn) #\a        (string-ref (cp "a") 0))
(assert-error  (tn) (lambda () (string-ref (cp "a") 1)))
(assert-error  (tn) (lambda () (string-ref (cp "a") 2)))
(assert-error  (tn) (lambda () (string-ref (cp "ab") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "ab") -1)))
(assert-equal? (tn) #\a        (string-ref (cp "ab") 0))
(assert-equal? (tn) #\b        (string-ref (cp "ab") 1))
(assert-error  (tn) (lambda () (string-ref (cp "ab") 2)))
(assert-error  (tn) (lambda () (string-ref (cp "ab") 3)))
(assert-error  (tn) (lambda () (string-ref (cp "あ") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "あ") -1)))
(assert-equal? (tn) #\あ       (string-ref (cp "あ") 0))
(assert-error  (tn) (lambda () (string-ref (cp "あ") 1)))
(assert-error  (tn) (lambda () (string-ref (cp "あ") 2)))
(assert-error  (tn) (lambda () (string-ref (cp "あう") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "あう") -1)))
(assert-equal? (tn) #\あ       (string-ref (cp "あう") 0))
(assert-equal? (tn) #\う       (string-ref (cp "あう") 1))
(assert-error  (tn) (lambda () (string-ref (cp "あう") 2)))
(assert-error  (tn) (lambda () (string-ref (cp "あう") 3)))
(assert-error  (tn) (lambda () (string-ref (cp "aあb") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "aあb") -1)))
(assert-equal? (tn) #\a        (string-ref (cp "aあb") 0))
(assert-equal? (tn) #\あ       (string-ref (cp "aあb") 1))
(assert-equal? (tn) #\b        (string-ref (cp "aあb") 2))
(assert-error  (tn) (lambda () (string-ref (cp "aあb") 3)))
(assert-error  (tn) (lambda () (string-ref (cp "aあb") 4)))
(assert-error  (tn) (lambda () (string-ref (cp "あaう") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "あaう") -1)))
(assert-equal? (tn) #\あ       (string-ref (cp "あaう") 0))
(assert-equal? (tn) #\a        (string-ref (cp "あaう") 1))
(assert-equal? (tn) #\う       (string-ref (cp "あaう") 2))
(assert-error  (tn) (lambda () (string-ref (cp "あaう") 3)))
(assert-error  (tn) (lambda () (string-ref (cp "あaう") 4)))
(assert-error  (tn) (lambda () (string-ref (cp "aあbう") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "aあbう") -1)))
(assert-equal? (tn) #\a        (string-ref (cp "aあbう") 0))
(assert-equal? (tn) #\あ       (string-ref (cp "aあbう") 1))
(assert-equal? (tn) #\b        (string-ref (cp "aあbう") 2))
(assert-equal? (tn) #\う       (string-ref (cp "aあbう") 3))
(assert-error  (tn) (lambda () (string-ref (cp "aあbう") 4)))
(assert-error  (tn) (lambda () (string-ref (cp "aあbう") 5)))
(assert-error  (tn) (lambda () (string-ref (cp "あaうb") -2)))
(assert-error  (tn) (lambda () (string-ref (cp "あaうb") -1)))
(assert-equal? (tn) #\あ       (string-ref (cp "あaうb") 0))
(assert-equal? (tn) #\a        (string-ref (cp "あaうb") 1))
(assert-equal? (tn) #\う       (string-ref (cp "あaうb") 2))
(assert-equal? (tn) #\b        (string-ref (cp "あaうb") 3))
(assert-error  (tn) (lambda () (string-ref (cp "あaうb") 4)))
(assert-error  (tn) (lambda () (string-ref (cp "あaうb") 5)))

(tn "string-set! invalid forms")
(assert-error  (tn) (lambda () (string-set! #\a 0 #\z)))
(assert-error  (tn) (lambda () (string-set! (cp "a") #\1 #\z)))
(assert-error  (tn) (lambda () (string-set! (cp "a") 0 #t)))
(tn "string-set! immutable")
(assert-error  (tn) (lambda () (string-set! "" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "a" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "a" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "a" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "a" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "a" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "ab" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "ab" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "ab" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "ab" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "ab" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "ab" 3 #\z)))
(assert-error  (tn) (lambda () (string-set! "あ" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "あ" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "あ" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "あ" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "あ" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "あう" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "あう" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "あう" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "あう" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "あう" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "あう" 3 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあb" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあb" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあb" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあb" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあb" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあb" 3 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあb" 4 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaう" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaう" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaう" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaう" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaう" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaう" 3 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaう" 4 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあbう" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあbう" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 3 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 4 #\z)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 5 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaうb" -2 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaうb" -1 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 0 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 1 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 2 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 3 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 4 #\z)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 5 #\z)))
(tn "string-set! multibyte immutable")
(assert-error  (tn) (lambda () (string-set! "" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "a" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "a" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "a" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "a" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "a" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "ab" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "ab" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "ab" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "ab" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "ab" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "ab" 3 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あ" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あ" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あ" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あ" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あ" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あう" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あう" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あう" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あう" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あう" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あう" 3 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあb" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあb" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあb" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあb" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあb" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあb" 3 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあb" 4 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaう" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaう" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaう" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaう" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaう" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaう" 3 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaう" 4 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあbう" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあbう" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 3 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 4 #\ん)))
(assert-error  (tn) (lambda () (string-set! "aあbう" 5 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaうb" -2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaうb" -1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 0 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 1 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 2 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 3 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 4 #\ん)))
(assert-error  (tn) (lambda () (string-set! "あaうb" 5 #\ん)))

(define my-string-set!
  (lambda (str k ch)
    (string-set! str k ch)
    str))
(tn "string-set! mutable")
(assert-equal? (tn) (undef)    (string-set! (cp "a") 0 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "") -1 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "") 0 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "") 1 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "") 2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "a") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "a") -1 #\z)))
(assert-equal? (tn) "z"        (my-string-set! (cp "a") 0 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "a") 1 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "a") 2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "ab") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "ab") -1 #\z)))
(assert-equal? (tn) "zb"       (my-string-set! (cp "ab") 0 #\z))
(assert-equal? (tn) "az"       (my-string-set! (cp "ab") 1 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "ab") 2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "ab") 3 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あ") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あ") -1 #\z)))
(assert-equal? (tn) "z"        (my-string-set! (cp "あ") 0 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "あ") 1 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あ") 2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あう") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あう") -1 #\z)))
(assert-equal? (tn) "zう"      (my-string-set! (cp "あう") 0 #\z))
(assert-equal? (tn) "あz"      (my-string-set! (cp "あう") 1 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "あう") 2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あう") 3 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあb") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあb") -1 #\z)))
(assert-equal? (tn) "zあb"     (my-string-set! (cp "aあb") 0 #\z))
(assert-equal? (tn) "azb"      (my-string-set! (cp "aあb") 1 #\z))
(assert-equal? (tn) "aあz"     (my-string-set! (cp "aあb") 2 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあb") 3 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあb") 4 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaう") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaう") -1 #\z)))
(assert-equal? (tn) "zaう"     (my-string-set! (cp "あaう") 0 #\z))
(assert-equal? (tn) "あzう"    (my-string-set! (cp "あaう") 1 #\z))
(assert-equal? (tn) "あaz"     (my-string-set! (cp "あaう") 2 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaう") 3 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaう") 4 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあbう") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあbう") -1 #\z)))
(assert-equal? (tn) "zあbう"   (my-string-set! (cp "aあbう") 0 #\z))
(assert-equal? (tn) "azbう"    (my-string-set! (cp "aあbう") 1 #\z))
(assert-equal? (tn) "aあzう"   (my-string-set! (cp "aあbう") 2 #\z))
(assert-equal? (tn) "aあbz"    (my-string-set! (cp "aあbう") 3 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあbう") 4 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあbう") 5 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaうb") -2 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaうb") -1 #\z)))
(assert-equal? (tn) "zaうb"    (my-string-set! (cp "あaうb") 0 #\z))
(assert-equal? (tn) "あzうb"   (my-string-set! (cp "あaうb") 1 #\z))
(assert-equal? (tn) "あazb"    (my-string-set! (cp "あaうb") 2 #\z))
(assert-equal? (tn) "あaうz"   (my-string-set! (cp "あaうb") 3 #\z))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaうb") 4 #\z)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaうb") 5 #\z)))
(tn "string-set! multibyte mutable")
(assert-error  (tn) (lambda () (my-string-set! (cp "") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "") -1 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "") 0 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "") 1 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "") 2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "a") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "a") -1 #\ん)))
(assert-equal? (tn) "ん"       (my-string-set! (cp "a") 0 #\ん))
(assert-error  (tn) (lambda () (my-string-set! (cp "a") 1 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "a") 2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "ab") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "ab") -1 #\ん)))
(assert-equal? (tn) "んb"      (my-string-set! (cp "ab") 0 #\ん))
(assert-equal? (tn) "aん"      (my-string-set! (cp "ab") 1 #\ん))
(assert-error  (tn) (lambda () (my-string-set! (cp "ab") 2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "ab") 3 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あ") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あ") -1 #\ん)))
(assert-equal? (tn) "ん"       (my-string-set! (cp "あ") 0 #\ん))
(assert-error  (tn) (lambda () (my-string-set! (cp "あ") 1 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あ") 2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あう") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あう") -1 #\ん)))
(assert-equal? (tn) "んう"     (my-string-set! (cp "あう") 0 #\ん))
(assert-equal? (tn) "あん"     (my-string-set! (cp "あう") 1 #\ん))
(assert-error  (tn) (lambda () (my-string-set! (cp "あう") 2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あう") 3 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあb") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあb") -1 #\ん)))
(assert-equal? (tn) "んあb"    (my-string-set! (cp "aあb") 0 #\ん))
(assert-equal? (tn) "aんb"     (my-string-set! (cp "aあb") 1 #\ん))
(assert-equal? (tn) "aあん"    (my-string-set! (cp "aあb") 2 #\ん))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあb") 3 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあb") 4 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaう") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaう") -1 #\ん)))
(assert-equal? (tn) "んaう"    (my-string-set! (cp "あaう") 0 #\ん))
(assert-equal? (tn) "あんう"   (my-string-set! (cp "あaう") 1 #\ん))
(assert-equal? (tn) "あaん"    (my-string-set! (cp "あaう") 2 #\ん))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaう") 3 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaう") 4 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあbう") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあbう") -1 #\ん)))
(assert-equal? (tn) "んあbう"  (my-string-set! (cp "aあbう") 0 #\ん))
(assert-equal? (tn) "aんbう"   (my-string-set! (cp "aあbう") 1 #\ん))
(assert-equal? (tn) "aあんう"  (my-string-set! (cp "aあbう") 2 #\ん))
(assert-equal? (tn) "aあbん"   (my-string-set! (cp "aあbう") 3 #\ん))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあbう") 4 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "aあbう") 5 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaうb") -2 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaうb") -1 #\ん)))
(assert-equal? (tn) "んaうb"   (my-string-set! (cp "あaうb") 0 #\ん))
(assert-equal? (tn) "あんうb"  (my-string-set! (cp "あaうb") 1 #\ん))
(assert-equal? (tn) "あaんb"   (my-string-set! (cp "あaうb") 2 #\ん))
(assert-equal? (tn) "あaうん"  (my-string-set! (cp "あaうb") 3 #\ん))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaうb") 4 #\ん)))
(assert-error  (tn) (lambda () (my-string-set! (cp "あaうb") 5 #\ん)))
(tn "string-set! NUL mutable")
(if (and sigscheme?
         (not (provided? "null-capable-string")))
    (begin
      (assert-error  (tn) (lambda () (string-set! (cp "") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "a") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "a") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "a") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "a") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "a") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "ab") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "ab") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "ab") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "ab") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "ab") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "ab") 3 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あ") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あ") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あ") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あ") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あ") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あう") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あう") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あう") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あう") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あう") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あう") 3 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあb") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあb") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあb") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあb") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあb") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあb") 3 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあb") 4 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaう") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaう") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaう") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaう") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaう") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaう") 3 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaう") 4 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあbう") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあbう") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあbう") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあbう") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあbう") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあbう") 3 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあbう") 4 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "aあbう") 5 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaうb") -2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaうb") -1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaうb") 0 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaうb") 1 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaうb") 2 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaうb") 3 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaうb") 4 #x00)))
      (assert-error  (tn) (lambda () (string-set! (cp "あaうb") 5 #x00)))))
;; Tests for the bug fixed in r5040
(tn "string-set! multibyte char modification")
(assert-equal? (tn) "Aabcde" (my-string-set! (cp "あabcde") 0 #\A))
(assert-equal? (tn) "Aaう"   (my-string-set! (cp "あaう")   0 #\A))
(assert-equal? (tn) "Aaうb"  (my-string-set! (cp "あaうb")  0 #\A))

(tn "substring invalid forms")
(assert-error  (tn) (lambda () (substring #\a 0 0)))
(assert-error  (tn) (lambda () (substring "" #\0 0)))
(assert-error  (tn) (lambda () (substring "" 0 #\0)))
(tn "substring length 0 immutable")
(assert-error  (tn) (lambda () (substring "" -1 -2)))
(assert-error  (tn) (lambda () (substring "" -1 -1)))
(assert-error  (tn) (lambda () (substring "" -1 0)))
(assert-error  (tn) (lambda () (substring "" -1 1)))
(assert-error  (tn) (lambda () (substring "" 0 -1)))
(assert-equal? (tn) ""         (substring "" 0 0))
(assert-error  (tn) (lambda () (substring "" 0 1)))
(assert-error  (tn) (lambda () (substring "" 1 -1)))
(assert-error  (tn) (lambda () (substring "" 1 0)))
(assert-error  (tn) (lambda () (substring "" 1 1)))
(assert-error  (tn) (lambda () (substring "" 1 2)))
(assert-error  (tn) (lambda () (substring "" 2 -1)))
(assert-error  (tn) (lambda () (substring "" 2 0)))
(assert-error  (tn) (lambda () (substring "" 2 1)))
(assert-error  (tn) (lambda () (substring "" 2 2)))
(assert-error  (tn) (lambda () (substring "" 2 3)))
(tn "substring length 1 immutable")
(assert-error  (tn) (lambda () (substring "a" -1 -2)))
(assert-error  (tn) (lambda () (substring "a" -1 -1)))
(assert-error  (tn) (lambda () (substring "a" -1 0)))
(assert-error  (tn) (lambda () (substring "a" -1 1)))
(assert-error  (tn) (lambda () (substring "a" 0 -1)))
(assert-equal? (tn) ""         (substring "a" 0 0))
(assert-equal? (tn) "a"        (substring "a" 0 1))
(assert-error  (tn) (lambda () (substring "a" 0 2)))
(assert-error  (tn) (lambda () (substring "a" 1 -1)))
(assert-error  (tn) (lambda () (substring "a" 1 0)))
(assert-equal? (tn) ""         (substring "a" 1 1))
(assert-error  (tn) (lambda () (substring "a" 1 2)))
(assert-error  (tn) (lambda () (substring "a" 2 -1)))
(assert-error  (tn) (lambda () (substring "a" 2 0)))
(assert-error  (tn) (lambda () (substring "a" 2 1)))
(assert-error  (tn) (lambda () (substring "a" 2 2)))
(assert-error  (tn) (lambda () (substring "a" 2 3)))
(tn "substring length 2 immutable")
(assert-error  (tn) (lambda () (substring "ab" -1 -2)))
(assert-error  (tn) (lambda () (substring "ab" -1 -1)))
(assert-error  (tn) (lambda () (substring "ab" -1 0)))
(assert-error  (tn) (lambda () (substring "ab" -1 1)))
(assert-error  (tn) (lambda () (substring "ab" 0 -1)))
(assert-equal? (tn) ""         (substring "ab" 0 0))
(assert-equal? (tn) "a"        (substring "ab" 0 1))
(assert-equal? (tn) "ab"       (substring "ab" 0 2))
(assert-error  (tn) (lambda () (substring "ab" 0 3)))
(assert-error  (tn) (lambda () (substring "ab" 1 -1)))
(assert-error  (tn) (lambda () (substring "ab" 1 0)))
(assert-equal? (tn) ""         (substring "ab" 1 1))
(assert-equal? (tn) "b"        (substring "ab" 1 2))
(assert-error  (tn) (lambda () (substring "ab" 1 3)))
(assert-error  (tn) (lambda () (substring "ab" 2 -1)))
(assert-error  (tn) (lambda () (substring "ab" 2 0)))
(assert-error  (tn) (lambda () (substring "ab" 2 1)))
(assert-equal? (tn) ""         (substring "ab" 2 2))
(assert-error  (tn) (lambda () (substring "ab" 2 3)))
(assert-error  (tn) (lambda () (substring "ab" 3 -1)))
(assert-error  (tn) (lambda () (substring "ab" 3 0)))
(assert-error  (tn) (lambda () (substring "ab" 3 1)))
(assert-error  (tn) (lambda () (substring "ab" 3 2)))
(assert-error  (tn) (lambda () (substring "ab" 3 3)))
(assert-error  (tn) (lambda () (substring "ab" 3 4)))
(tn "substring length 3 immutable")
(assert-error  (tn) (lambda () (substring "abc" -1 -2)))
(assert-error  (tn) (lambda () (substring "abc" -1 -1)))
(assert-error  (tn) (lambda () (substring "abc" -1 0)))
(assert-error  (tn) (lambda () (substring "abc" -1 1)))
(assert-error  (tn) (lambda () (substring "abc" 0 -1)))
(assert-equal? (tn) ""         (substring "abc" 0 0))
(assert-equal? (tn) "a"        (substring "abc" 0 1))
(assert-equal? (tn) "ab"       (substring "abc" 0 2))
(assert-equal? (tn) "abc"      (substring "abc" 0 3))
(assert-error  (tn) (lambda () (substring "abc" 0 4)))
(assert-error  (tn) (lambda () (substring "abc" 1 -1)))
(assert-error  (tn) (lambda () (substring "abc" 1 0)))
(assert-equal? (tn) ""         (substring "abc" 1 1))
(assert-equal? (tn) "b"        (substring "abc" 1 2))
(assert-equal? (tn) "bc"       (substring "abc" 1 3))
(assert-error  (tn) (lambda () (substring "abc" 1 4)))
(assert-error  (tn) (lambda () (substring "abc" 2 -1)))
(assert-error  (tn) (lambda () (substring "abc" 2 0)))
(assert-error  (tn) (lambda () (substring "abc" 2 1)))
(assert-equal? (tn) ""         (substring "abc" 2 2))
(assert-equal? (tn) "c"        (substring "abc" 2 3))
(assert-error  (tn) (lambda () (substring "abc" 2 4)))
(assert-error  (tn) (lambda () (substring "abc" 3 -1)))
(assert-error  (tn) (lambda () (substring "abc" 3 0)))
(assert-error  (tn) (lambda () (substring "abc" 3 1)))
(assert-error  (tn) (lambda () (substring "abc" 3 2)))
(assert-equal? (tn) ""         (substring "abc" 3 3))
(assert-error  (tn) (lambda () (substring "abc" 3 4)))
(assert-error  (tn) (lambda () (substring "abc" 4 -1)))
(assert-error  (tn) (lambda () (substring "abc" 4 0)))
(assert-error  (tn) (lambda () (substring "abc" 4 1)))
(assert-error  (tn) (lambda () (substring "abc" 4 2)))
(assert-error  (tn) (lambda () (substring "abc" 4 3)))
(assert-error  (tn) (lambda () (substring "abc" 4 4)))
(assert-error  (tn) (lambda () (substring "abc" 4 5)))
(tn "substring length 4 immutable")
(assert-error  (tn) (lambda () (substring "abcd" -1 -2)))
(assert-error  (tn) (lambda () (substring "abcd" -1 -1)))
(assert-error  (tn) (lambda () (substring "abcd" -1 0)))
(assert-error  (tn) (lambda () (substring "abcd" -1 1)))
(assert-error  (tn) (lambda () (substring "abcd" 0 -1)))
(assert-equal? (tn) ""         (substring "abcd" 0 0))
(assert-equal? (tn) "a"        (substring "abcd" 0 1))
(assert-equal? (tn) "ab"       (substring "abcd" 0 2))
(assert-equal? (tn) "abc"      (substring "abcd" 0 3))
(assert-equal? (tn) "abcd"     (substring "abcd" 0 4))
(assert-error  (tn) (lambda () (substring "abcd" 0 5)))
(assert-error  (tn) (lambda () (substring "abcd" 1 -1)))
(assert-error  (tn) (lambda () (substring "abcd" 1 0)))
(assert-equal? (tn) ""         (substring "abcd" 1 1))
(assert-equal? (tn) "b"        (substring "abcd" 1 2))
(assert-equal? (tn) "bc"       (substring "abcd" 1 3))
(assert-equal? (tn) "bcd"      (substring "abcd" 1 4))
(assert-error  (tn) (lambda () (substring "abcd" 1 5)))
(assert-error  (tn) (lambda () (substring "abcd" 2 -1)))
(assert-error  (tn) (lambda () (substring "abcd" 2 0)))
(assert-error  (tn) (lambda () (substring "abcd" 2 1)))
(assert-equal? (tn) ""         (substring "abcd" 2 2))
(assert-equal? (tn) "c"        (substring "abcd" 2 3))
(assert-equal? (tn) "cd"       (substring "abcd" 2 4))
(assert-error  (tn) (lambda () (substring "abcd" 2 5)))
(assert-error  (tn) (lambda () (substring "abcd" 3 -1)))
(assert-error  (tn) (lambda () (substring "abcd" 3 0)))
(assert-error  (tn) (lambda () (substring "abcd" 3 1)))
(assert-error  (tn) (lambda () (substring "abcd" 3 2)))
(assert-equal? (tn) ""         (substring "abcd" 3 3))
(assert-equal? (tn) "d"        (substring "abcd" 3 4))
(assert-error  (tn) (lambda () (substring "abcd" 3 5)))
(assert-error  (tn) (lambda () (substring "abcd" 4 -1)))
(assert-error  (tn) (lambda () (substring "abcd" 4 0)))
(assert-error  (tn) (lambda () (substring "abcd" 4 1)))
(assert-error  (tn) (lambda () (substring "abcd" 4 2)))
(assert-error  (tn) (lambda () (substring "abcd" 4 3)))
(assert-equal? (tn) ""         (substring "abcd" 4 4))
(assert-error  (tn) (lambda () (substring "abcd" 4 5)))
(assert-error  (tn) (lambda () (substring "abcd" 5 -1)))
(assert-error  (tn) (lambda () (substring "abcd" 5 0)))
(assert-error  (tn) (lambda () (substring "abcd" 5 1)))
(assert-error  (tn) (lambda () (substring "abcd" 5 2)))
(assert-error  (tn) (lambda () (substring "abcd" 5 3)))
(assert-error  (tn) (lambda () (substring "abcd" 5 4)))
(assert-error  (tn) (lambda () (substring "abcd" 5 5)))
(assert-error  (tn) (lambda () (substring "abcd" 5 6)))

(tn "substring multibyte length 1 immutable")
(assert-error  (tn) (lambda () (substring "あ" -1 -2)))
(assert-error  (tn) (lambda () (substring "あ" -1 -1)))
(assert-error  (tn) (lambda () (substring "あ" -1 0)))
(assert-error  (tn) (lambda () (substring "あ" -1 1)))
(assert-error  (tn) (lambda () (substring "あ" 0 -1)))
(assert-equal? (tn) ""         (substring "あ" 0 0))
(assert-equal? (tn) "あ"       (substring "あ" 0 1))
(assert-error  (tn) (lambda () (substring "あ" 0 2)))
(assert-error  (tn) (lambda () (substring "あ" 1 -1)))
(assert-error  (tn) (lambda () (substring "あ" 1 0)))
(assert-equal? (tn) ""         (substring "あ" 1 1))
(assert-error  (tn) (lambda () (substring "あ" 1 2)))
(assert-error  (tn) (lambda () (substring "あ" 2 -1)))
(assert-error  (tn) (lambda () (substring "あ" 2 0)))
(assert-error  (tn) (lambda () (substring "あ" 2 1)))
(assert-error  (tn) (lambda () (substring "あ" 2 2)))
(assert-error  (tn) (lambda () (substring "あ" 2 3)))
(tn "substring multibyte length 2 immutable")
(assert-error  (tn) (lambda () (substring "あい" -1 -2)))
(assert-error  (tn) (lambda () (substring "あい" -1 -1)))
(assert-error  (tn) (lambda () (substring "あい" -1 0)))
(assert-error  (tn) (lambda () (substring "あい" -1 1)))
(assert-error  (tn) (lambda () (substring "あい" 0 -1)))
(assert-equal? (tn) ""         (substring "あい" 0 0))
(assert-equal? (tn) "あ"       (substring "あい" 0 1))
(assert-equal? (tn) "あい"     (substring "あい" 0 2))
(assert-error  (tn) (lambda () (substring "あい" 0 3)))
(assert-error  (tn) (lambda () (substring "あい" 1 -1)))
(assert-error  (tn) (lambda () (substring "あい" 1 0)))
(assert-equal? (tn) ""         (substring "あい" 1 1))
(assert-equal? (tn) "い"       (substring "あい" 1 2))
(assert-error  (tn) (lambda () (substring "あい" 1 3)))
(assert-error  (tn) (lambda () (substring "あい" 2 -1)))
(assert-error  (tn) (lambda () (substring "あい" 2 0)))
(assert-error  (tn) (lambda () (substring "あい" 2 1)))
(assert-equal? (tn) ""         (substring "あい" 2 2))
(assert-error  (tn) (lambda () (substring "あい" 2 3)))
(assert-error  (tn) (lambda () (substring "あい" 3 -1)))
(assert-error  (tn) (lambda () (substring "あい" 3 0)))
(assert-error  (tn) (lambda () (substring "あい" 3 1)))
(assert-error  (tn) (lambda () (substring "あい" 3 2)))
(assert-error  (tn) (lambda () (substring "あい" 3 3)))
(assert-error  (tn) (lambda () (substring "あい" 3 4)))
(tn "substring multibyte length 3 immutable")
(assert-error  (tn) (lambda () (substring "あいう" -1 -2)))
(assert-error  (tn) (lambda () (substring "あいう" -1 -1)))
(assert-error  (tn) (lambda () (substring "あいう" -1 0)))
(assert-error  (tn) (lambda () (substring "あいう" -1 1)))
(assert-error  (tn) (lambda () (substring "あいう" 0 -1)))
(assert-equal? (tn) ""         (substring "あいう" 0 0))
(assert-equal? (tn) "あ"       (substring "あいう" 0 1))
(assert-equal? (tn) "あい"     (substring "あいう" 0 2))
(assert-equal? (tn) "あいう"   (substring "あいう" 0 3))
(assert-error  (tn) (lambda () (substring "あいう" 0 4)))
(assert-error  (tn) (lambda () (substring "あいう" 1 -1)))
(assert-error  (tn) (lambda () (substring "あいう" 1 0)))
(assert-equal? (tn) ""         (substring "あいう" 1 1))
(assert-equal? (tn) "い"       (substring "あいう" 1 2))
(assert-equal? (tn) "いう"     (substring "あいう" 1 3))
(assert-error  (tn) (lambda () (substring "あいう" 1 4)))
(assert-error  (tn) (lambda () (substring "あいう" 2 -1)))
(assert-error  (tn) (lambda () (substring "あいう" 2 0)))
(assert-error  (tn) (lambda () (substring "あいう" 2 1)))
(assert-equal? (tn) ""         (substring "あいう" 2 2))
(assert-equal? (tn) "う"       (substring "あいう" 2 3))
(assert-error  (tn) (lambda () (substring "あいう" 2 4)))
(assert-error  (tn) (lambda () (substring "あいう" 3 -1)))
(assert-error  (tn) (lambda () (substring "あいう" 3 0)))
(assert-error  (tn) (lambda () (substring "あいう" 3 1)))
(assert-error  (tn) (lambda () (substring "あいう" 3 2)))
(assert-equal? (tn) ""         (substring "あいう" 3 3))
(assert-error  (tn) (lambda () (substring "あいう" 3 4)))
(assert-error  (tn) (lambda () (substring "あいう" 4 -1)))
(assert-error  (tn) (lambda () (substring "あいう" 4 0)))
(assert-error  (tn) (lambda () (substring "あいう" 4 1)))
(assert-error  (tn) (lambda () (substring "あいう" 4 2)))
(assert-error  (tn) (lambda () (substring "あいう" 4 3)))
(assert-error  (tn) (lambda () (substring "あいう" 4 4)))
(assert-error  (tn) (lambda () (substring "あいう" 4 5)))
(tn "substring multibyte length 4 immutable")
(assert-error  (tn) (lambda () (substring "あいうえ" -1 -2)))
(assert-error  (tn) (lambda () (substring "あいうえ" -1 -1)))
(assert-error  (tn) (lambda () (substring "あいうえ" -1 0)))
(assert-error  (tn) (lambda () (substring "あいうえ" -1 1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 0 -1)))
(assert-equal? (tn) ""         (substring "あいうえ" 0 0))
(assert-equal? (tn) "あ"       (substring "あいうえ" 0 1))
(assert-equal? (tn) "あい"     (substring "あいうえ" 0 2))
(assert-equal? (tn) "あいう"   (substring "あいうえ" 0 3))
(assert-equal? (tn) "あいうえ" (substring "あいうえ" 0 4))
(assert-error  (tn) (lambda () (substring "あいうえ" 0 5)))
(assert-error  (tn) (lambda () (substring "あいうえ" 1 -1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 1 0)))
(assert-equal? (tn) ""         (substring "あいうえ" 1 1))
(assert-equal? (tn) "い"       (substring "あいうえ" 1 2))
(assert-equal? (tn) "いう"     (substring "あいうえ" 1 3))
(assert-equal? (tn) "いうえ"   (substring "あいうえ" 1 4))
(assert-error  (tn) (lambda () (substring "あいうえ" 1 5)))
(assert-error  (tn) (lambda () (substring "あいうえ" 2 -1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 2 0)))
(assert-error  (tn) (lambda () (substring "あいうえ" 2 1)))
(assert-equal? (tn) ""         (substring "あいうえ" 2 2))
(assert-equal? (tn) "う"       (substring "あいうえ" 2 3))
(assert-equal? (tn) "うえ"     (substring "あいうえ" 2 4))
(assert-error  (tn) (lambda () (substring "あいうえ" 2 5)))
(assert-error  (tn) (lambda () (substring "あいうえ" 3 -1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 3 0)))
(assert-error  (tn) (lambda () (substring "あいうえ" 3 1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 3 2)))
(assert-equal? (tn) ""         (substring "あいうえ" 3 3))
(assert-equal? (tn) "え"       (substring "あいうえ" 3 4))
(assert-error  (tn) (lambda () (substring "あいうえ" 3 5)))
(assert-error  (tn) (lambda () (substring "あいうえ" 4 -1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 4 0)))
(assert-error  (tn) (lambda () (substring "あいうえ" 4 1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 4 2)))
(assert-error  (tn) (lambda () (substring "あいうえ" 4 3)))
(assert-equal? (tn) ""         (substring "あいうえ" 4 4))
(assert-error  (tn) (lambda () (substring "あいうえ" 4 5)))
(assert-error  (tn) (lambda () (substring "あいうえ" 5 -1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 5 0)))
(assert-error  (tn) (lambda () (substring "あいうえ" 5 1)))
(assert-error  (tn) (lambda () (substring "あいうえ" 5 2)))
(assert-error  (tn) (lambda () (substring "あいうえ" 5 3)))
(assert-error  (tn) (lambda () (substring "あいうえ" 5 4)))
(assert-error  (tn) (lambda () (substring "あいうえ" 5 5)))
(assert-error  (tn) (lambda () (substring "あいうえ" 5 6)))

(tn "substring mixed multibyte and singlebyte immutable")
(assert-error  (tn) (lambda () (substring "aいuえ" -1 -2)))
(assert-error  (tn) (lambda () (substring "aいuえ" -1 -1)))
(assert-error  (tn) (lambda () (substring "aいuえ" -1 0)))
(assert-error  (tn) (lambda () (substring "aいuえ" -1 1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 0 -1)))
(assert-equal? (tn) ""         (substring "aいuえ" 0 0))
(assert-equal? (tn) "a"        (substring "aいuえ" 0 1))
(assert-equal? (tn) "aい"      (substring "aいuえ" 0 2))
(assert-equal? (tn) "aいu"     (substring "aいuえ" 0 3))
(assert-equal? (tn) "aいuえ"   (substring "aいuえ" 0 4))
(assert-error  (tn) (lambda () (substring "aいuえ" 0 5)))
(assert-error  (tn) (lambda () (substring "aいuえ" 1 -1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 1 0)))
(assert-equal? (tn) ""         (substring "aいuえ" 1 1))
(assert-equal? (tn) "い"       (substring "aいuえ" 1 2))
(assert-equal? (tn) "いu"      (substring "aいuえ" 1 3))
(assert-equal? (tn) "いuえ"    (substring "aいuえ" 1 4))
(assert-error  (tn) (lambda () (substring "aいuえ" 1 5)))
(assert-error  (tn) (lambda () (substring "aいuえ" 2 -1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 2 0)))
(assert-error  (tn) (lambda () (substring "aいuえ" 2 1)))
(assert-equal? (tn) ""         (substring "aいuえ" 2 2))
(assert-equal? (tn) "u"        (substring "aいuえ" 2 3))
(assert-equal? (tn) "uえ"      (substring "aいuえ" 2 4))
(assert-error  (tn) (lambda () (substring "aいuえ" 2 5)))
(assert-error  (tn) (lambda () (substring "aいuえ" 3 -1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 3 0)))
(assert-error  (tn) (lambda () (substring "aいuえ" 3 1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 3 2)))
(assert-equal? (tn) ""         (substring "aいuえ" 3 3))
(assert-equal? (tn) "え"       (substring "aいuえ" 3 4))
(assert-error  (tn) (lambda () (substring "aいuえ" 3 5)))
(assert-error  (tn) (lambda () (substring "aいuえ" 4 -1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 4 0)))
(assert-error  (tn) (lambda () (substring "aいuえ" 4 1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 4 2)))
(assert-error  (tn) (lambda () (substring "aいuえ" 4 3)))
(assert-equal? (tn) ""         (substring "aいuえ" 4 4))
(assert-error  (tn) (lambda () (substring "aいuえ" 4 5)))
(assert-error  (tn) (lambda () (substring "aいuえ" 5 -1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 5 0)))
(assert-error  (tn) (lambda () (substring "aいuえ" 5 1)))
(assert-error  (tn) (lambda () (substring "aいuえ" 5 2)))
(assert-error  (tn) (lambda () (substring "aいuえ" 5 3)))
(assert-error  (tn) (lambda () (substring "aいuえ" 5 4)))
(assert-error  (tn) (lambda () (substring "aいuえ" 5 5)))
(assert-error  (tn) (lambda () (substring "aいuえ" 5 6)))

(tn "substring mutable")
(assert-equal? (tn) ""         (substring (cp "") 0 0))
(assert-equal? (tn) "a"        (substring (cp "a") 0 1))
(assert-equal? (tn) "あ"       (substring (cp "あ") 0 1))
(assert-equal? (tn) "いuえ"    (substring (cp "aいuえ") 1 4))

(tn "substring result mutability")
(assert-true   (tn) (mutable?  (substring     ""        0 0)))
(assert-true   (tn) (mutable?  (substring     "a"       0 1)))
(assert-true   (tn) (mutable?  (substring     "あ"      0 1)))
(assert-true   (tn) (mutable?  (substring     "aいuえ"  1 4)))
(assert-true   (tn) (mutable?  (substring (cp "")       0 0)))
(assert-true   (tn) (mutable?  (substring (cp "a")      0 1)))
(assert-true   (tn) (mutable?  (substring (cp "あ")     0 1)))
(assert-true   (tn) (mutable?  (substring (cp "aいuえ") 1 4)))


(tn "string->list invalid forms")
(assert-error  (tn) (lambda ()           (string->list '())))
(assert-error  (tn) (lambda ()           (string->list '(#\a))))
(assert-error  (tn) (lambda ()           (string->list #\a)))
(tn "string->list immutable")
(assert-equal? (tn) '()                  (string->list ""))
(assert-equal? (tn) '(#\a)               (string->list "a"))
(assert-equal? (tn) '(#\a #\b)           (string->list "ab"))
(assert-equal? (tn) '(#\あ)              (string->list "あ"))
(assert-equal? (tn) '(#\あ #\う)         (string->list "あう"))
(assert-equal? (tn) '(#\a #\あ #\b)      (string->list "aあb"))
(assert-equal? (tn) '(#\あ #\a #\う)     (string->list "あaう"))
(assert-equal? (tn) '(#\a #\あ #\b #\う) (string->list "aあbう"))
(assert-equal? (tn) '(#\あ #\a #\う #\b) (string->list "あaうb"))
(tn "string->list mutable")
(assert-equal? (tn) '()                  (string->list (cp "")))
(assert-equal? (tn) '(#\a)               (string->list (cp "a")))
(assert-equal? (tn) '(#\a #\b)           (string->list (cp "ab")))
(assert-equal? (tn) '(#\あ)              (string->list (cp "あ")))
(assert-equal? (tn) '(#\あ #\う)         (string->list (cp "あう")))
(assert-equal? (tn) '(#\a #\あ #\b)      (string->list (cp "aあb")))
(assert-equal? (tn) '(#\あ #\a #\う)     (string->list (cp "あaう")))
(assert-equal? (tn) '(#\a #\あ #\b #\う) (string->list (cp "aあbう")))
(assert-equal? (tn) '(#\あ #\a #\う #\b) (string->list (cp "あaうb")))
(tn "string->list mutability")
(assert-true   (tn) (pair-mutable?       (string->list "a")))
(assert-true   (tn) (pair-mutable?       (string->list "ab")))
(assert-true   (tn) (pair-mutable?       (string->list "あ")))
(assert-true   (tn) (pair-mutable?       (string->list "あう")))
(assert-true   (tn) (pair-mutable?       (string->list "aあb")))
(assert-true   (tn) (pair-mutable?       (string->list "あaう")))
(assert-true   (tn) (pair-mutable?       (string->list "aあbう")))
(assert-true   (tn) (pair-mutable?       (string->list "あaうb")))

(tn "list->string invalid forms")
(assert-error (tn) (lambda ()  (list->string #t)))
(assert-error (tn) (lambda ()  (list->string '(#t))))
(assert-error (tn) (lambda ()  (list->string '(#\a . #t))))
(tn "list->string")
(assert-equal? (tn) ""         (list->string '()))
(assert-equal? (tn) "a"        (list->string '(#\a)))
(assert-equal? (tn) "ab"       (list->string '(#\a #\b)))
(assert-equal? (tn) "あ"       (list->string '(#\あ)))
(assert-equal? (tn) "あう"     (list->string '(#\あ #\う)))
(assert-equal? (tn) "aあb"     (list->string '(#\a #\あ #\b)))
(assert-equal? (tn) "あaう"    (list->string '(#\あ #\a #\う)))
(assert-equal? (tn) "aあbう"   (list->string '(#\a #\あ #\b #\う)))
(assert-equal? (tn) "あaうb"   (list->string '(#\あ #\a #\う #\b)))
(tn "list->string mutability")
(assert-true   (tn) (mutable?  (list->string '())))
(assert-true   (tn) (mutable?  (list->string '(#\a))))
(assert-true   (tn) (mutable?  (list->string '(#\a #\b))))
(assert-true   (tn) (mutable?  (list->string '(#\あ))))
(assert-true   (tn) (mutable?  (list->string '(#\あ #\う))))
(assert-true   (tn) (mutable?  (list->string '(#\a #\あ #\b))))
(assert-true   (tn) (mutable?  (list->string '(#\あ #\a #\う))))
(assert-true   (tn) (mutable?  (list->string '(#\a #\あ #\b #\う))))
(assert-true   (tn) (mutable?  (list->string '(#\あ #\a #\う #\b))))
(tn "list->string with NUL args")
(if (and sigscheme?
         (not (provided? "null-capable-string")))
    (begin
      (assert-error (tn) (lambda () (list->string '(#x00))))
      (assert-error (tn) (lambda () (list->string '(#\a #x00))))
      (assert-error (tn) (lambda () (list->string '(#x00 #\a))))
      (assert-error (tn) (lambda () (list->string '(#\a #x00 #\a))))))
(tn "list->string improper lists")
(assert-error (tn) (lambda () (list->string '(#\あ #\a #\う . #\b))))
;; circular lists
(define clst1 (list #\a))
(set-cdr! clst1 clst1)
(define clst2 (list #\a #\b))
(set-cdr! (list-tail clst2 1) clst2)
(define clst3 (list #\a #\b #\c))
(set-cdr! (list-tail clst3 2) clst3)
(define clst4 (list #\a #\b #\c #\d))
(set-cdr! (list-tail clst4 3) clst4)
(if (and sigscheme?
         (provided? "strict-argcheck"))
    (begin
      (assert-error (tn) (lambda () (list->string clst1)))
      (assert-error (tn) (lambda () (list->string clst2)))
      (assert-error (tn) (lambda () (list->string clst3)))
      (assert-error (tn) (lambda () (list->string clst4)))))

(tn "string-fill! immutable")
(assert-error  (tn) (lambda ()           (string-fill! "" #\z)))
(assert-error  (tn) (lambda ()           (string-fill! "a" #\z)))
(assert-error  (tn) (lambda ()           (string-fill! "ab" #\z)))
(assert-error  (tn) (lambda ()           (string-fill! "あ" #\z)))
(assert-error  (tn) (lambda ()           (string-fill! "あう" #\z)))
(assert-error  (tn) (lambda ()           (string-fill! "aあb" #\z)))
(assert-error  (tn) (lambda ()           (string-fill! "あaう" #\z)))
(assert-error  (tn) (lambda ()           (string-fill! "aあbう" #\z)))
(assert-error  (tn) (lambda ()           (string-fill! "あaうb" #\z)))
(tn "string-fill! multibyte immutable")
(assert-error  (tn) (lambda ()           (string-fill! "" #\ん)))
(assert-error  (tn) (lambda ()           (string-fill! "a" #\ん)))
(assert-error  (tn) (lambda ()           (string-fill! "ab" #\ん)))
(assert-error  (tn) (lambda ()           (string-fill! "あ" #\ん)))
(assert-error  (tn) (lambda ()           (string-fill! "あう" #\ん)))
(assert-error  (tn) (lambda ()           (string-fill! "aあb" #\ん)))
(assert-error  (tn) (lambda ()           (string-fill! "あaう" #\ん)))
(assert-error  (tn) (lambda ()           (string-fill! "aあbう" #\ん)))
(assert-error  (tn) (lambda ()           (string-fill! "あaうb" #\ん)))

(define my-string-fill!
  (lambda (str ch)
    (string-fill! str ch)
    str))
(tn "string-fill! mutable")
(assert-equal? (tn) (undef)              (string-fill!    (cp "a") #\z))
(assert-equal? (tn) ""                   (my-string-fill! (cp "") #\z))
(assert-equal? (tn) "z"                  (my-string-fill! (cp "a") #\z))
(assert-equal? (tn) "zz"                 (my-string-fill! (cp "ab") #\z))
(assert-equal? (tn) "z"                  (my-string-fill! (cp "あ") #\z))
(assert-equal? (tn) "zz"                 (my-string-fill! (cp "あう") #\z))
(assert-equal? (tn) "zzz"                (my-string-fill! (cp "aあb") #\z))
(assert-equal? (tn) "zzz"                (my-string-fill! (cp "あaう") #\z))
(assert-equal? (tn) "zzzz"               (my-string-fill! (cp "aあbう") #\z))
(assert-equal? (tn) "zzzz"               (my-string-fill! (cp "あaうb") #\z))
(tn "string-fill! multibyte mutable")
(assert-equal? (tn) (undef)              (string-fill!    (cp "a") #\ん))
(assert-equal? (tn) ""                   (my-string-fill! (cp "") #\ん))
(assert-equal? (tn) "ん"                 (my-string-fill! (cp "a") #\ん))
(assert-equal? (tn) "んん"               (my-string-fill! (cp "ab") #\ん))
(assert-equal? (tn) "ん"                 (my-string-fill! (cp "あ") #\ん))
(assert-equal? (tn) "んん"               (my-string-fill! (cp "あう") #\ん))
(assert-equal? (tn) "んんん"             (my-string-fill! (cp "aあb") #\ん))
(assert-equal? (tn) "んんん"             (my-string-fill! (cp "あaう") #\ん))
(assert-equal? (tn) "んんんん"           (my-string-fill! (cp "aあbう") #\ん))
(assert-equal? (tn) "んんんん"           (my-string-fill! (cp "あaうb") #\ん))
(tn "string-fill! mutability")
(assert-true   (tn) (mutable?            (my-string-fill! (cp "") #\z)))
(assert-true   (tn) (mutable?            (my-string-fill! (cp "a") #\z)))
(assert-true   (tn) (mutable?            (my-string-fill! (cp "ab") #\z)))
(assert-true   (tn) (mutable?            (my-string-fill! (cp "あ") #\z)))
(assert-true   (tn) (mutable?            (my-string-fill! (cp "あう") #\z)))
(assert-true   (tn) (mutable?            (my-string-fill! (cp "aあb") #\z)))
(assert-true   (tn) (mutable?            (my-string-fill! (cp "あaう") #\z)))
(assert-true   (tn) (mutable?            (my-string-fill! (cp "aあbう") #\z)))
(assert-true   (tn) (mutable?            (my-string-fill! (cp "あaうb") #\z)))

(tn "%%string-reconstruct!")
(assert-error  (tn) (lambda () (%%string-reconstruct! "")))
(assert-error  (tn) (lambda () (%%string-reconstruct! "const str")))
(assert-error  (tn) (lambda () (%%string-reconstruct! "あaう")))
(assert-equal? (tn) 0 (string-length (string-copy "")))
(assert-equal? (tn) 9 (string-length (string-copy "const str")))
(assert-equal? (tn) 3 (string-length (string-copy "あaう")))
(assert-equal? (tn) 0 (string-length (with-char-codec "ISO-8859-1"
                                       (lambda ()
                                         (%%string-reconstruct!
                                          (string-copy ""))))))
(assert-equal? (tn) 9 (string-length (with-char-codec "ISO-8859-1"
                                       (lambda ()
                                         (%%string-reconstruct!
                                          (string-copy "const str"))))))
(assert-equal? (tn) 7 (string-length (with-char-codec "ISO-8859-1"
                                       (lambda ()
                                         (%%string-reconstruct!
                                          (string-copy "あaう"))))))
(let ((byte-str (with-char-codec "ISO-8859-1"
                  (lambda ()
                    (%%string-reconstruct!
                     (string-copy "あaう"))))))
  (assert-equal? (tn) 7 (string-length byte-str))
  ;; reconstruct as UTF-8 string
  (assert-equal? (tn) 3 (string-length (%%string-reconstruct! byte-str))))

(total-report)
