Files
2026-05-05 01:38:51 -05:00

273 lines
9.8 KiB
EmacsLisp

// 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"
}