273 lines
9.8 KiB
EmacsLisp
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"
|
|
}
|