(define-library (srfi 130 test)
  (export run-tests)
  (import (scheme base) (scheme char)
          (chibi char-set) (chibi char-set full) (chibi test)
          (srfi 130))
  (begin
    (define (sc str c)
      (string-index->cursor str c))
    (define (string-index->index str pred . o)
      (string-cursor->index str (apply string-index str pred o)))
    (define (string-index-right->index str pred . o)
      (string-cursor->index str (apply string-index-right str pred o)))
    (define char-set:not-letter (char-set-complement char-set:letter))
    (define (run-tests)
      (test-begin "srfi-130: cursor-based string library")

      ;; tests adapted from Gauche's SRFI 13 tests, via Chicken

      (test "string-null?" #f (string-null? "abc"))
      (test "string-null?" #t (string-null? ""))
      (test "string-every" #t (string-every #\a ""))
      (test "string-every" #t (string-every #\a "aaaa"))
      (test "string-every" #f (string-every #\a "aaba"))
      (test "string-every" #t (string-every char-set:lower-case "aaba"))
      (test "string-every" #f (string-every char-set:lower-case "aAba"))
      (test "string-every" #t (string-every char-set:lower-case ""))
      (test "string-every" #t (string-every (lambda (x) (char->integer x)) "aAbA"))
      (test "string-every" #t (string-every (lambda (x) (error "hoge")) ""))
      (test "string-any" #t (string-any #\a "aaaa"))
      (test "string-any" #f (string-any #\a "Abcd"))
      (test "string-any" #f (string-any #\a ""))
      (test "string-any" #t (string-any char-set:lower-case "ABcD"))
      (test "string-any" #f (string-any char-set:lower-case "ABCD"))
      (test "string-any" #f (string-any char-set:lower-case ""))
      (test "string-any" (char->integer #\a)
        (string-any (lambda (x) (char->integer x)) "aAbA"))

      (test "string-tabulate" "0123456789"
        (string-tabulate (lambda (code)
                           (integer->char (+ code (char->integer #\0))))
                         10))
      (test "string-tabulate" ""
        (string-tabulate (lambda (code)
                           (integer->char (+ code (char->integer #\0))))
                         0))

      (test "reverse-list->string" "cBa"
        (reverse-list->string '(#\a #\B #\c)))
      (test "reverse-list->string" ""
        (reverse-list->string '()))

      (test "substring/cursors" "cde" (substring/cursors "abcde" 2 5))
      (test "substring/cursors" "cd"  (substring/cursors "abcde" 2 4))

      (test "string-copy!" "abCDEfg"
        (let ((x (string-copy "abcdefg")))
          (string-copy! x 2 "CDE")
          x))
      (test "string-copy!" "abCDEfg"
        (let ((x (string-copy "abcdefg")))
          (string-copy! x 2 "ZABCDE" 3)
          x))
      (test "string-copy!" "abCDEfg"
        (let ((x (string-copy "abcdefg")))
          (string-copy! x 2 "ZABCDEFG" 3 6)
          x))

      (test "string-take" "Pete S"  (string-take "Pete Szilagyi" 6))
      (test "string-take" ""        (string-take "Pete Szilagyi" 0))
      (test "string-take" "Pete Szilagyi" (string-take "Pete Szilagyi" 13))
      (test "string-drop" "zilagyi" (string-drop "Pete Szilagyi" 6))
      (test "string-drop" "Pete Szilagyi" (string-drop "Pete Szilagyi" 0))
      (test "string-drop" ""        (string-drop "Pete Szilagyi" 13))

      (test "string-take-right" "rules" (string-take-right "Beta rules" 5))
      (test "string-take-right" ""      (string-take-right "Beta rules" 0))
      (test "string-take-right" "Beta rules" (string-take-right "Beta rules" 10))
      (test "string-drop-right" "Beta " (string-drop-right "Beta rules" 5))
      (test "string-drop-right" "Beta rules" (string-drop-right "Beta rules" 0))
      (test "string-drop-right" ""      (string-drop-right "Beta rules" 10))

      (test "string-pad" "  325" (string-pad "325" 5))
      (test "string-pad" "71325" (string-pad "71325" 5))
      (test "string-pad" "71325" (string-pad "8871325" 5))
      (test "string-pad" "~~325" (string-pad "325" 5 #\~))
      (test "string-pad" "~~~25" (string-pad "325" 5 #\~ 1))
      (test "string-pad" "~~~~2" (string-pad "325" 5 #\~ 1 2))
      (test "string-pad-right" "325  " (string-pad-right "325" 5))
      (test "string-pad-right" "71325" (string-pad-right "71325" 5))
      (test "string-pad-right" "88713" (string-pad-right "8871325" 5))
      (test "string-pad-right" "325~~" (string-pad-right "325" 5 #\~))
      (test "string-pad-right" "25~~~" (string-pad-right "325" 5 #\~ 1))
      (test "string-pad-right" "2~~~~" (string-pad-right "325" 5 #\~ 1 2))

      (test "string-trim"  "a b c d  \n"
        (string-trim "  \t  a b c d  \n"))
      (test "string-trim"  "\t  a b c d  \n"
        (string-trim "  \t  a b c d  \n" #\space))
      (test "string-trim"  "a b c d  \n"
        (string-trim "4358948a b c d  \n" char-numeric?))

      (test "string-trim-right"  "  \t  a b c d"
        (string-trim-right "  \t  a b c d  \n"))
      (test "string-trim-right"  "  \t  a b c d  "
        (string-trim-right "  \t  a b c d  \n" (lambda (ch) (eqv? ch #\newline))))
      (test "string-trim-right"  "349853a b c d"
        (string-trim-right "349853a b c d03490" char-numeric?))

      (test "string-trim-both"  "a b c d"
        (string-trim-both "  \t  a b c d  \n"))
      (test "string-trim-both"  "  \t  a b c d  "
        (string-trim-both "  \t  a b c d  \n" (lambda (ch) (eqv? ch #\newline))))
      (test "string-trim-both"  "a b c d"
        (string-trim-both "349853a b c d03490" char-numeric?))

      ;; TODO: bunch of string= families

      (test "string-prefix-length" 5
        (string-prefix-length "cancaNCAM" "cancancan"))
      (test "string-suffix-length" 2
        (string-suffix-length "CanCan" "cankancan"))

      (test "string-prefix?" #t (string-prefix? "abcd" "abcdefg"))
      (test "string-prefix?" #f (string-prefix? "abcf" "abcdefg"))
      (test "string-suffix?" #t (string-suffix? "defg" "abcdefg"))
      (test "string-suffix?" #f (string-suffix? "aefg" "abcdefg"))

      (test "string-index #1" 4
        (string-index->index "abcd:efgh:ijkl" (lambda (ch) (eqv? ch #\:))))
      (test "string-index #2" 4
        (string-index->index "abcd:efgh;ijkl" (lambda (ch) (char-set-contains? char-set:not-letter ch))))
      (test "string-index #3" 14
        (string-index->index "abcd:efgh;ijkl" (lambda (ch) (char-set-contains? char-set:digit ch))))
      (test "string-index #4" 9
        (string-index->index "abcd:efgh:ijkl" (lambda (ch) (eqv? ch #\:)) 5))
      (test "string-index-right #1" 5
        (string-index-right->index "abcd:efgh;ijkl" (lambda (ch) (eqv? ch #\:))))
      (test "string-index-right #2" 10
        (string-index-right->index "abcd:efgh;ijkl" (lambda (ch) (char-set-contains? char-set:not-letter ch))))
      (test "string-index-right #3" 14
        (string-index-right->index "abcd:efgh;ijkl" char-alphabetic?))
      (test "string-index-right #4" 10
        (string-index-right->index "abcd:efgh;ijkl" (lambda (ch) (char-set-contains? char-set:not-letter ch)) 7))

      (test "string-count #1" 2
        (string-count "abc def\tghi jkl" (lambda (ch) (eqv? ch #\space))))
      (test "string-count #2" 3
        (string-count "abc def\tghi jkl" char-whitespace?))
      (test "string-count #3" 2
        (string-count "abc def\tghi jkl" char-whitespace? 4))
      (test "string-count #4" 1
        (string-count "abc def\tghi jkl" char-whitespace? 4 9))
      (let ((s "Ma mere l'oye"))
        (test-assert "string-contains"
          (string-contains s "mer"))
        (test "string-contains" #f
          (string-contains s "Mer"))
        (test-assert "string-contains"
          (string-contains s "mer" 1))
        (test-assert "string-contains"
          (string-contains s "mer" 1 8))
        (test-not "string-contains"
                  (string-contains s "mer" 4 8))
        (test-not "string-contains"
                  (string-contains s "mer" 1 5)))
      (let ((s "eek -- it's a geek."))
        (test 15 (string-cursor->index s (string-contains-right s "ee")))
        (test 15 (string-cursor->index s (string-contains-right s "ee" 12 18)))
        (test 19 (string-cursor->index s (string-contains-right s "")))
        (test 0 (string-cursor->index "" (string-contains-right "" "")))
        (test #f (string-contains-right s "kee" 12 18)))

      (test "string-reverse" "nomel on nolem on"
        (string-reverse "no melon no lemon"))
      (test "string-reverse" "nomel on"
        (string-reverse "no melon no lemon" 9))
      (test "string-reverse" "on"
        (string-reverse "no melon no lemon" 9 11))

      (test "string-append" #f
        (let ((s "test")) (eq? s (string-append s))))
      (test "string-concatenate" #f
        (let ((s "test")) (eq? s (string-concatenate (list s)))))
      (test "string-concatenate" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
        (string-concatenate
         '("A" "B" "C" "D" "E" "F" "G" "H"
           "I" "J" "K" "L" "M" "N" "O" "P"
           "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
           "a" "b" "c" "d" "e" "f" "g" "h"
           "i" "j" "k" "l" "m" "n" "o" "p"
           "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")))
      (test "string-concatenate-reverse" "zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA"
        (string-concatenate-reverse
         '("A" "B" "C" "D" "E" "F" "G" "H"
           "I" "J" "K" "L" "M" "N" "O" "P"
           "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
           "a" "b" "c" "d" "e" "f" "g" "h"
           "i" "j" "k" "l" "m" "n" "o" "p"
           "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")))
      (test "string-concatenate-reverse" #f
        (let ((s "test"))
          (eq? s (string-concatenate-reverse (list s)))))

      (test "string-map" "svool"
        (string-map (lambda (c)
                      (integer->char (- 219 (char->integer c))))
                    "hello"))
      ;; (test "string-map" "vool"
      ;;   (string-map (lambda (c)
      ;;                 (integer->char (- 219 (char->integer c))))
      ;;               "hello" 1))
      ;; (test "string-map" "vo"
      ;;   (string-map (lambda (c)
      ;;                 (integer->char (- 219 (char->integer c))))
      ;;               "hello" 1 3))

      (test "string-fold" '(#\o #\l #\l #\e #\h . #t)
        (string-fold cons #t "hello"))
      (test "string-fold" '(#\l #\e . #t)
        (string-fold cons #t "hello" 1 3))
      (test "string-fold-right" '(#\h #\e #\l #\l #\o . #t)
        (string-fold-right cons #t "hello"))
      (test "string-fold-right" '(#\e #\l . #t)
        (string-fold-right cons #t "hello" 1 3))

      (test "string-unfold" "hello"
        (string-unfold null? car cdr '(#\h #\e #\l #\l #\o)))
      (test "string-unfold" "hi hello"
        (string-unfold null? car cdr '(#\h #\e #\l #\l #\o) "hi "))
      (test "string-unfold" "hi hello ho"
        (string-unfold null? car cdr
                       '(#\h #\e #\l #\l #\o) "hi "
                       (lambda (x) " ho")))

      (test "string-unfold-right" "olleh"
        (string-unfold-right null? car cdr '(#\h #\e #\l #\l #\o)))
      (test "string-unfold-right" "olleh hi"
        (string-unfold-right null? car cdr '(#\h #\e #\l #\l #\o) " hi"))
      (test "string-unfold-right" "ho olleh hi"
        (string-unfold-right null? car cdr
                             '(#\h #\e #\l #\l #\o) " hi"
                             (lambda (x) "ho ")))

      (test "string-for-each" "CLtL"
        (let ((out (open-output-string))
              (prev #f))
          (string-for-each (lambda (c)
                             (if (or (not prev)
                                     (char-whitespace? prev))
                                 (write-char c out))
                             (set! prev c))
                           "Common Lisp, the Language")

          (get-output-string out)))
      ;; (test "string-for-each" "oLtL"
      ;;   (let ((out (open-output-string))
      ;;         (prev #f))
      ;;     (string-for-each (lambda (c)
      ;;                        (if (or (not prev)
      ;;                                (char-whitespace? prev))
      ;;                            (write-char c out))
      ;;                        (set! prev c))
      ;;                      "Common Lisp, the Language" 1)
      ;;     (get-output-string out)))
      ;; (test "string-for-each" "oL"
      ;;   (let ((out (open-output-string))
      ;;         (prev #f))
      ;;     (string-for-each (lambda (c)
      ;;                        (if (or (not prev)
      ;;                                (char-whitespace? prev))
      ;;                            (write-char c out))
      ;;                        (set! prev c))
      ;;                      "Common Lisp, the Language" 1 10)
      ;;     (get-output-string out)))

      (test "string-for-each-cursor" '(4 3 2 1 0)
        (let ((r '()))
          (string-for-each-cursor (lambda (i) (set! r (cons i r))) "hello")
          (map (lambda (sc) (string-cursor->index "hello" sc)) r)))
      (test "string-for-each-cursor" '(4 3 2 1)
        (let ((r '()))
          (string-for-each-cursor (lambda (i) (set! r (cons i r))) "hello" 1)
          (map (lambda (sc) (string-cursor->index "hello" sc)) r)))
      (test "string-for-each-cursor" '(2 1)
        (let ((r '()))
          (string-for-each-cursor (lambda (i) (set! r (cons i r))) "hello" 1 3)
          (map (lambda (sc) (string-cursor->index "hello" sc)) r)))

      (test "string-replicate" "cdefab"
        (string-replicate "abcdef" 2 8))
      (test "string-replicate" "efabcd"
        (string-replicate "abcdef" -2 4))
      (test "string-replicate" "abcabca"
        (string-replicate "abc" 0 7))
      (test "string-replicate" "defdefd"
        (string-replicate "abcdefg" 0 7 3 6))
      (test "string-replicate" ""
        (string-replicate "abcdefg" 9 9 3 6))

      (test "string-replace" "abcdXYZghi"
        (string-replace "abcdefghi" "XYZ" 4 6))
      (test "string-replace" "abcdZghi"
        (string-replace "abcdefghi" "XYZ" 4 6 2))
      (test "string-replace" "abcdZefghi"
        (string-replace "abcdefghi" "XYZ" 4 4 2))
      (test "string-replace" "abcdefghi"
        (string-replace "abcdefghi" "XYZ" 4 4 1 1))
      (test "string-replace" "abcdhi"
        (string-replace "abcdefghi" "" 4 7))

      (test "string-filter" "rrrr"
        (string-filter (lambda (ch) (eqv? ch #\r))
                       "Help make programs run, run, RUN!"))
      (test "string-filter" "HelpmakeprogramsrunrunRUN"
        (string-filter char-alphabetic? "Help make programs run, run, RUN!"))

      (test "string-filter" "programsrunrun"
        (string-filter (lambda (c) (char-lower-case? c))
                       "Help make programs run, run, RUN!"
                       10))
      (test "string-filter" ""
        (string-filter (lambda (c) (char-lower-case? c)) ""))
      (test "string-remove" "Help make pogams un, un, RUN!"
        (string-remove (lambda (ch) (eqv? ch #\r))
                       "Help make programs run, run, RUN!"))
      (test "string-remove" "   , , !"
        (string-remove char-alphabetic? "Help make programs run, run, RUN!"))
      (test "string-remove" " , , RUN!"
        (string-remove (lambda (c) (char-lower-case? c))
                       "Help make programs run, run, RUN!"
                       10))
      (test "string-remove" ""
        (string-remove (lambda (c) (char-lower-case? c)) ""))

      (test "foo:bar:baz"
          (string-join '("foo" "bar" "baz") ":"))
      (test "foo:bar:baz:"
          (string-join '("foo" "bar" "baz") ":" 'suffix))
      (test "" (string-join '() ":"))
      (test "" (string-join '("") ":"))
      (test "" (string-join '() ":" 'suffix))
      (test ":" (string-join '("") ":" 'suffix))

      (test '("foo" "bar" "baz")
          (string-split "foo:bar:baz" ":"))
      (test '("foo" "bar" "baz" "")
          (string-split "foo:bar:baz:" ":"))
      (test '("foo" "bar" "baz")
          (string-split "foo:bar:baz:" ":" 'suffix))
      (test '("foo" "bar:baz:")
          (string-split "foo:bar:baz:" ":" 'suffix 1))
      (test '("foo" "bar" "baz:")
          (string-split "foo:bar:baz:" ":" 'suffix 2))
      (test '() (string-split "" ":"))
      (test '() (string-split "" ":" 'suffix))
      (test '("") (string-split ":" ":" 'suffix))
      (test '("foo" "bar" "baz")
          (string-split ":foo:bar:baz" ":" 'prefix))

      ;; from SRFI 130 test suite
      (test '() (string-split "" ""))
      (test '("a" "b" "c") (string-split "abc" ""))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " "))
      (test '("" "there" "ya" "go" "")
          (string-split "***there***ya***go***" "***"))
      (test '() (string-split "" "" 'infix))
      (test '("a" "b" "c") (string-split "abc" "" 'infix))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " " 'infix))
      (test '("" "there" "ya" "go" "")
          (string-split "***there***ya***go***" "***" 'infix))
      (test-error (string-split "" "" 'strict-infix))
      (test '("a" "b" "c") (string-split "abc" "" 'strict-infix))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " " 'strict-infix))
      (test '("" "there" "ya" "go" "")
          (string-split "***there***ya***go***" "***" 'strict-infix))
      (test '() (string-split "" "" 'prefix))
      (test '("a" "b" "c") (string-split "abc" "" 'prefix))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " " 'prefix))
      (test '("there" "ya" "go" "")
          (string-split "***there***ya***go***" "***" 'prefix))
      (test '() (string-split "" "" 'suffix))
      (test '("a" "b" "c") (string-split "abc" "" 'suffix))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " " 'suffix))
      (test '("" "there" "ya" "go")
          (string-split "***there***ya***go***" "***" 'suffix))
      (test '() (string-split "" "" 'infix #f))
      (test '("a" "b" "c") (string-split "abc" "" 'infix #f))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " " 'infix #f))
      (test '("" "there" "ya" "go" "")
          (string-split "***there***ya***go***" "***" 'infix #f))
      (test '("a" "b" "c") (string-split "abc" "" 'strict-infix #f))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " " 'strict-infix #f))
      (test '("" "there" "ya" "go" "")
          (string-split "***there***ya***go***" "***" 'strict-infix #f))
      (test '() (string-split "" "" 'prefix #f))
      (test '("a" "b" "c") (string-split "abc" "" 'prefix #f))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " " 'prefix #f))
      (test '("there" "ya" "go" "")
          (string-split "***there***ya***go***" "***" 'prefix #f))
      (test '() (string-split "" "" 'suffix #f))
      (test '("a" "b" "c") (string-split "abc" "" 'suffix #f))
      (test '("too" "" "much" "" "data")
          (string-split "too  much  data" " " 'suffix #f))
      (test '("" "there" "ya" "go")
          (string-split "***there***ya***go***" "***" 'suffix #f))
      (test-error (string-split "" "" 'strict-infix 3))
      (test '("a" "b" "c") (string-split "abc" "" 'strict-infix 3))
      (test '("too" "" "much" " data")
          (string-split "too  much  data" " " 'strict-infix 3))
      (test '("" "there" "ya" "go***")
          (string-split "***there***ya***go***" "***" 'strict-infix 3))
      (test '() (string-split "" "" 'prefix 3))
      (test '("a" "b" "c") (string-split "abc" "" 'prefix 3))
      (test '("too" "" "much" " data")
          (string-split "too  much  data" " " 'prefix 3))
      (test '("there" "ya" "go***")
          (string-split "***there***ya***go***" "***" 'prefix 3))
      (test '() (string-split "" "" 'suffix 3))
      (test '("a" "b" "c") (string-split "abc" "" 'suffix 3))
      (test '("too" "" "much" " data")
          (string-split "too  much  data" " " 'suffix 3))
      (test '("" "there" "ya" "go***")
          (string-split "***there***ya***go***" "***" 'suffix 3))
      (test-error (string-split "" "" 'strict-infix 3 0))
      (test '("b" "c") (string-split "abc" "" 'strict-infix 3 1))
      (test '("oo" "" "much" " data")
          (string-split "too  much  data" " " 'strict-infix 3 1))
      (test '("**there" "ya" "go" "")
          (string-split "***there***ya***go***" "***" 'strict-infix 3 1))
      (test '() (string-split "" "" 'prefix 3 0))
      (test '("b" "c") (string-split "abc" "" 'prefix 3 1))
      (test '("oo" "" "much" " data")
          (string-split "too  much  data" " " 'prefix 3 1))
      (test '("**there" "ya" "go" "")
          (string-split "***there***ya***go***" "***" 'prefix 3 1))
      (test '() (string-split "" "" 'suffix 3 0))
      (test '("b" "c") (string-split "abc" "" 'suffix 3 1))
      (test '("oo" "" "much" " data")
          (string-split "too  much  data" " " 'suffix 3 1))
      (test '("**there" "ya" "go")
          (string-split "***there***ya***go***" "***" 'suffix 3 1))
      (test-error (string-split "" "" 'strict-infix 3 0 0))
      (test '("b") (string-split "abc" "" 'strict-infix 3 1 2))
      (test '("oo" "" "much" " ")
          (string-split "too  much  data" " " 'strict-infix 3 1 11))
      (test '() (string-split "" "" 'prefix 3 0 0))
      (test '("b") (string-split "abc" "" 'prefix 3 1 2))
      (test '("oo" "" "much" " ")
          (string-split "too  much  data" " " 'prefix 3 1 11))
      (test '() (string-split "" "" 'suffix 3 0 0))
      (test '("b") (string-split "abc" "" 'suffix 3 1 2))
      (test '("oo" "" "much" " ")
          (string-split "too  much  data" " " 'suffix 3 1 11))

;;; Regression tests: check that reported bugs have been fixed

      ;; From: Matthias Radestock <matthias@sorted.org>
      ;; Date: Wed, 10 Dec 2003 21:05:22 +0100
                                        ;
      ;; Chris Double has found the following bug in the reference implementation:
                                        ;
      ;;  (string-contains "xabc" "ab") => 1    ;good
      ;;  (string-contains "aabc" "ab") => #f   ;bad
                                        ;
      ;; Matthias.

      (test "string-contains" 1
        (string-cursor->index "aabc" (string-contains "aabc" "ab")))

      (test "string-contains" 5
        (string-cursor->index "ababdabdabxxas" (string-contains "ababdabdabxxas" "abdabx")))

      ;; (message continues)
      ;;
      ;; PS: There is also an off-by-one error in the bounds check of the
      ;; unoptimized version of string-contains that is included as commented out
      ;; code in the reference implementation. This breaks things like
      ;; (string-contains "xab" "ab") and (string-contains "ab" "ab").

      ;; This off-by-one bug has been fixed in the comments of the version
      ;; of SRFI-13 shipped with Larceny.  In a version of the code without
      ;; the fix the following test will catch the bug:

      (test "string-contains" 0
        (string-cursor->index "ab" (string-contains "ab" "ab")))

      ;; even string-cursor->index/index->cursor are polymorphic :(
      (let* ((s "abc")
             (i 1)
             (sc (string-index->cursor s i)))
        (test i (string-cursor->index s sc))
        (test i (string-cursor->index s i))
        (test sc (string-index->cursor s sc))
        (test sc (string-index->cursor s i)))

      (test-end))))