;; String/regex primitive tests

(defsuite
  "string-char-at"
  (deftest "char-at first" (assert= "h" (char-at "hello" 0)))
  (deftest "char-at middle" (assert= "l" (char-at "hello" 2)))
  (deftest "char-at last" (assert= "o" (char-at "hello" 4)))
  (deftest "char-at out of bounds" (assert= nil (char-at "hello" 10)))
  (deftest "char-at negative" (assert= nil (char-at "hello" -1))))

(defsuite
  "string-char-code"
  (deftest "char-code a" (assert= 97 (char-code "a")))
  (deftest "char-code A" (assert= 65 (char-code "A")))
  (deftest "char-code 0" (assert= 48 (char-code "0")))
  (deftest "char-code space" (assert= 32 (char-code " ")))
  (deftest
    "char-code roundtrip"
    (assert= "a" (char-from-code (char-code "a"))))
  (deftest
    "char-from-code roundtrip"
    (assert= 65 (char-code (char-from-code 65)))))

(defsuite
  "string-parse-number"
  (deftest "parse-number integer" (assert= 42 (parse-number "42")))
  (deftest "parse-number float" (assert= 3.14 (parse-number "3.14")))
  (deftest "parse-number negative" (assert= -7 (parse-number "-7")))
  (deftest
    "parse-number negative float"
    (assert= -2.5 (parse-number "-2.5")))
  (deftest "parse-number zero" (assert= 0 (parse-number "0")))
  (deftest
    "parse-number invalid returns nil"
    (assert= nil (parse-number "abc")))
  (deftest "parse-number empty returns nil" (assert= nil (parse-number ""))))

(defsuite
  "regex-match"
  (deftest
    "regex-match simple"
    (let
      ((r (regex-match "h.llo" "hello world")))
      (assert (list? r))
      (assert= "hello" (first r))))
  (deftest "regex-match no match" (assert= nil (regex-match "xyz" "hello")))
  (deftest
    "regex-match with group"
    (let
      ((r (regex-match "(h)ello" "hello")))
      (assert (list? r))
      (assert= "hello" (first r))
      (assert= "h" (nth r 1))))
  (deftest
    "regex-match digits"
    (let
      ((r (regex-match "[0-9]+" "abc123def")))
      (assert= "123" (first r))))
  (deftest
    "regex-match anchored"
    (assert= nil (regex-match "^world" "hello world")))
  (deftest
    "regex-match start"
    (let
      ((r (regex-match "^hello" "hello world")))
      (assert= "hello" (first r)))))

(defsuite
  "regex-match?"
  (deftest "regex-match? true" (assert (regex-match? "h.llo" "hello")))
  (deftest "regex-match? false" (assert (not (regex-match? "xyz" "hello"))))
  (deftest
    "regex-match? digit pattern"
    (assert (regex-match? "[0-9]" "abc1")))
  (deftest
    "regex-match? empty pattern"
    (assert (regex-match? "" "anything"))))

(defsuite
  "regex-find-all"
  (deftest
    "find-all digits"
    (let
      ((result (regex-find-all "[0-9]" "a1b2c3")))
      (assert= 3 (len result))
      (assert= "1" (first result))
      (assert= "3" (nth result 2))))
  (deftest
    "find-all words"
    (let
      ((result (regex-find-all "[a-z]+" "hello 123 world")))
      (assert= 2 (len result))
      (assert= "hello" (first result))
      (assert= "world" (nth result 1))))
  (deftest
    "find-all no matches"
    (assert= (list) (regex-find-all "[0-9]" "abc")))
  (deftest
    "find-all multi-char"
    (let
      ((result (regex-find-all "ab" "xababx")))
      (assert= 2 (len result))
      (assert= "ab" (first result))
      (assert= "ab" (nth result 1)))))

(defsuite
  "regex-replace"
  (deftest
    "replace all digits"
    (assert= "a_b_c_" (regex-replace "[0-9]" "_" "a1b2c3")))
  (deftest
    "replace word"
    (assert= "hi hi" (regex-replace "hello" "hi" "hello hello")))
  (deftest
    "replace no match"
    (assert= "hello" (regex-replace "xyz" "!" "hello")))
  (deftest
    "replace empty pattern"
    (assert= "hello" (regex-replace "^$" "!" "hello"))))

(defsuite
  "regex-replace-first"
  (deftest
    "replace-first digit"
    (assert= "a_b2c3" (regex-replace-first "[0-9]" "_" "a1b2c3")))
  (deftest
    "replace-first no match"
    (assert= "hello" (regex-replace-first "xyz" "!" "hello"))))

(defsuite
  "regex-split"
  (deftest
    "split on whitespace"
    (assert= (list "hello" "world") (regex-split "[ \t]+" "hello  world")))
  (deftest
    "split on comma-space"
    (assert= (list "a" "b" "c") (regex-split ", *" "a, b,c")))
  (deftest
    "split no match"
    (assert= (list "hello") (regex-split ";" "hello")))
  (deftest
    "split digits"
    (assert= (list "a" "b" "c") (regex-split "[0-9]+" "a1b23c"))))

(defsuite
  "string-split-multichar"
  (deftest
    "split on multi-char separator"
    (assert= (list "a" "b" "c") (split "a::b::c" "::")))
  (deftest "split on arrow" (assert= (list "a" "b") (split "a->b" "->"))))