// test_string.el - native test suite for runtime/string.el // // Covers: type conversions, core primitives, comparison and search, // case conversion, whitespace trimming, replacement, repetition, // reversal, prefix/suffix stripping, padding, counting, character // classification, splitting, and joining. test "int-to-str" { let s: String = int_to_str(42) assert s == "42", "int 42 to string" let neg: String = int_to_str(-7) assert neg == "-7", "negative int to string" let zero: String = int_to_str(0) assert zero == "0", "zero to string" } test "str-to-int" { let n: Int = str_to_int("123") assert n == 123, "parse 123" let neg: Int = str_to_int("-5") assert neg == -5, "parse negative" let zero: Int = str_to_int("0") assert zero == 0, "parse zero" } test "bool-to-str" { let t: String = bool_to_str(true) assert t == "true", "true to string" let f: String = bool_to_str(false) assert f == "false", "false to string" } test "str-len" { let n: Int = str_len("hello") assert n == 5, "length of hello" let e: Int = str_len("") assert e == 0, "length of empty string" let space: Int = str_len("a b") assert space == 3, "length with spaces" } test "str-eq" { assert str_eq("abc", "abc"), "identical strings are equal" assert !str_eq("abc", "ABC"), "case-sensitive comparison" assert str_eq("", ""), "empty strings are equal" assert !str_eq("a", "b"), "different single chars" } test "str-slice" { let s: String = str_slice("hello world", 6, 11) assert s == "world", "slice end of string" let start: String = str_slice("hello world", 0, 5) assert start == "hello", "slice start of string" let empty: String = str_slice("hello", 2, 2) assert empty == "", "zero-length slice" } test "str-starts-ends-with" { assert str_starts_with("hello world", "hello"), "starts with hello" assert str_ends_with("hello world", "world"), "ends with world" assert !str_starts_with("hello world", "world"), "does not start with world" assert !str_ends_with("hello world", "hello"), "does not end with hello" assert str_starts_with("abc", ""), "empty prefix always matches" assert str_ends_with("abc", ""), "empty suffix always matches" } test "str-contains" { assert str_contains("hello world", "world"), "contains world" assert str_contains("hello world", "lo wo"), "contains interior substring" assert !str_contains("hello world", "xyz"), "does not contain xyz" assert str_contains("abc", ""), "empty sub is always contained" assert !str_contains("", "x"), "empty string does not contain nonempty sub" } test "str-index-of" { let i: Int = str_index_of("hello world", "world") assert i == 6, "index of world" let j: Int = str_index_of("hello world", "xyz") assert j == -1, "not found returns -1" let k: Int = str_index_of("aabbcc", "bb") assert k == 2, "index of bb in aabbcc" } test "str-last-index-of" { let i: Int = str_last_index_of("abcabc", "bc") assert i == 4, "last occurrence of bc" let j: Int = str_last_index_of("hello", "xyz") assert j == -1, "not found returns -1" let k: Int = str_last_index_of("aaa", "a") assert k == 2, "last single-char match" } test "str-to-upper-lower" { let up: String = str_to_upper("hello") assert up == "HELLO", "to upper" let lo: String = str_to_lower("WORLD") assert lo == "world", "to lower" let mixed: String = str_to_upper("Hello World") assert mixed == "HELLO WORLD", "mixed to upper" let empty: String = str_to_lower("") assert empty == "", "empty stays empty" } test "str-trim" { let s: String = str_trim(" hello ") assert s == "hello", "trim both ends" let lonly: String = str_trim(" hello") assert lonly == "hello", "trim left only" let ronly: String = str_trim("hello ") assert ronly == "hello", "trim right only" let tabs: String = str_trim("\thello\n") assert tabs == "hello", "trim tabs and newlines" let empty: String = str_trim(" ") assert empty == "", "all whitespace trims to empty" } test "str-replace" { let s: String = str_replace("hello world", "world", "there") assert s == "hello there", "replace word" let none: String = str_replace("hello", "xyz", "abc") assert none == "hello", "no match leaves string unchanged" let multi: String = str_replace("aaa", "a", "b") assert multi == "bbb", "replace all occurrences" let empty_from: String = str_replace("hello", "", "x") assert empty_from == "hello", "empty from returns original" } test "str-repeat" { let s: String = str_repeat("ab", 3) assert s == "ababab", "repeat 3 times" let once: String = str_repeat("x", 1) assert once == "x", "repeat once" let zero: String = str_repeat("abc", 0) assert zero == "", "repeat zero times" let neg: String = str_repeat("abc", -1) assert neg == "", "negative repeat is empty" } test "str-reverse" { let s: String = str_reverse("hello") assert s == "olleh", "reverse hello" let single: String = str_reverse("a") assert single == "a", "reverse single char" let empty: String = str_reverse("") assert empty == "", "reverse empty string" let palindrome: String = str_reverse("racecar") assert palindrome == "racecar", "reverse palindrome" } test "str-strip-prefix-suffix" { let p: String = str_strip_prefix("foobar", "foo") assert p == "bar", "strip prefix foo" let no_prefix: String = str_strip_prefix("foobar", "baz") assert no_prefix == "foobar", "no match leaves string unchanged" let s: String = str_strip_suffix("hello.md", ".md") assert s == "hello", "strip suffix .md" let no_suffix: String = str_strip_suffix("hello.md", ".txt") assert no_suffix == "hello.md", "non-matching suffix unchanged" } test "str-strip-chars" { let s: String = str_strip_chars(" \thello \n", " \t\n") assert s == "hello", "strip whitespace chars" let dots: String = str_strip_chars("...hello...", ".") assert dots == "hello", "strip dot chars" let all: String = str_strip_chars("aaa", "a") assert all == "", "strip all chars leaves empty" } test "str-pad-left-right" { let l: String = str_pad_left("42", 5, "0") assert l == "00042", "zero-pad left to width 5" let r: String = str_pad_right("hi", 5, "-") assert r == "hi---", "dash-pad right to width 5" let no_pad: String = str_pad_left("hello", 3, "x") assert no_pad == "hello", "no pad when string already wide enough" } test "str-count" { let n: Int = str_count("abc abc abc", "abc") assert n == 3, "count three occurrences" let overlap: Int = str_count("aaa", "aa") assert overlap == 1, "non-overlapping count" let zero: Int = str_count("hello", "xyz") assert zero == 0, "not found gives 0" let empty_sub: Int = str_count("hello", "") assert empty_sub == 0, "empty sub gives 0" } test "str-count-lines-words-letters" { let s: String = "hello world\nfoo bar" let lines: Int = str_count_lines(s) let words: Int = str_count_words(s) let letters: Int = str_count_letters(s) assert lines == 2, "line count" assert words == 4, "word count" assert letters == 16, "letter count" } test "str-count-chars-and-digits" { let digits: Int = str_count_digits("abc123def456") assert digits == 6, "six digits" let none: Int = str_count_digits("hello") assert none == 0, "no digits" let chars: Int = str_count_chars("hello") assert chars == 5, "five ASCII chars" } test "char-classes" { assert is_letter("A"), "A is a letter" assert is_digit("7"), "7 is a digit" assert is_whitespace(" "), "space is whitespace" assert !is_letter("3"), "3 is not a letter" assert !is_digit("X"), "X is not a digit" assert is_alphanumeric("abc123"), "abc123 is alphanumeric" assert !is_alphanumeric("abc!"), "abc! is not alphanumeric" assert is_uppercase("ABC"), "ABC is uppercase" assert is_lowercase("abc"), "abc is lowercase" assert !is_uppercase("Abc"), "mixed is not uppercase" } test "str-split" { let parts: [String] = str_split("a,b,c", ",") let n: Int = native_list_len(parts) assert n == 3, "split into 3 parts" let p0: String = native_list_get(parts, 0) let p1: String = native_list_get(parts, 1) let p2: String = native_list_get(parts, 2) assert p0 == "a", "first part" assert p1 == "b", "second part" assert p2 == "c", "third part" } test "str-split-lines" { let lines: [String] = str_split_lines("alpha\nbeta\r\ngamma\n") let n: Int = native_list_len(lines) assert n == 3, "split into 3 lines" let l0: String = native_list_get(lines, 0) let l1: String = native_list_get(lines, 1) let l2: String = native_list_get(lines, 2) assert l0 == "alpha", "first line" assert l1 == "beta", "second line strips CR" assert l2 == "gamma", "third line" } test "str-join" { let parts: [String] = native_list_empty() let parts = native_list_append(parts, "alpha") let parts = native_list_append(parts, "beta") let parts = native_list_append(parts, "gamma") let result: String = str_join(parts, ", ") assert result == "alpha, beta, gamma", "join with separator" let empty_parts: [String] = native_list_empty() let empty_result: String = str_join(empty_parts, ",") assert empty_result == "", "join empty list gives empty string" } test "str-char-at" { let c: String = str_char_at("hello", 1) assert c == "e", "char at index 1" let first: String = str_char_at("abc", 0) assert first == "a", "first char" let oob: String = str_char_at("abc", 10) assert oob == "", "out of bounds returns empty" } test "url-encode-decode" { let encoded: String = url_encode("hello world") assert !str_contains(encoded, " "), "space is encoded" let decoded: String = url_decode(encoded) assert decoded == "hello world", "round-trip decode" }