779 lines
26 KiB
Lua
779 lines
26 KiB
Lua
require("tests")
|
|
|
|
-- Test data
|
|
local test_string = "Hello, World!"
|
|
local multi_line = "Line 1\nLine 2\nLine 3"
|
|
local padded_string = " Hello World "
|
|
local unicode_string = "café naïve résumé"
|
|
local mixed_case = "hELLo WoRLd"
|
|
|
|
-- ======================================================================
|
|
-- BASIC STRING OPERATIONS
|
|
-- ======================================================================
|
|
|
|
test("string.split", function()
|
|
-- Basic split
|
|
local parts = string.split("a,b,c,d", ",")
|
|
assert_equal(4, #parts)
|
|
assert_equal("a", parts[1])
|
|
assert_equal("d", parts[4])
|
|
|
|
-- Empty delimiter (character split)
|
|
local chars = string.split("abc", "")
|
|
assert_equal(3, #chars)
|
|
assert_equal("a", chars[1])
|
|
assert_equal("c", chars[3])
|
|
|
|
-- Empty string
|
|
local empty_parts = string.split("", ",")
|
|
assert_equal(1, #empty_parts)
|
|
assert_equal("", empty_parts[1])
|
|
|
|
-- No matches
|
|
local no_match = string.split("hello", ",")
|
|
assert_equal(1, #no_match)
|
|
assert_equal("hello", no_match[1])
|
|
|
|
-- Multiple consecutive delimiters
|
|
local multiple = string.split("a,,b,", ",")
|
|
assert_equal(4, #multiple)
|
|
assert_equal("a", multiple[1])
|
|
assert_equal("", multiple[2])
|
|
assert_equal("b", multiple[3])
|
|
assert_equal("", multiple[4])
|
|
end)
|
|
|
|
test("string.join", function()
|
|
assert_equal("a-b-c", string.join({"a", "b", "c"}, "-"))
|
|
assert_equal("abc", string.join({"a", "b", "c"}, ""))
|
|
assert_equal("", string.join({}, ","))
|
|
assert_equal("a", string.join({"a"}, ","))
|
|
|
|
-- Mixed types (should convert to string)
|
|
assert_equal("1,2,3", string.join({1, 2, 3}, ","))
|
|
end)
|
|
|
|
test("string.trim", function()
|
|
assert_equal("Hello World", string.trim(padded_string))
|
|
assert_equal("", string.trim(""))
|
|
assert_equal("", string.trim(" "))
|
|
assert_equal("hello", string.trim("hello"))
|
|
assert_equal("a b", string.trim(" a b "))
|
|
assert_equal("a b", string.trim("xxxa bxxx", "x"))
|
|
end)
|
|
|
|
test("string.trim_left", function()
|
|
assert_equal("Hello World ", string.trim_left(padded_string))
|
|
assert_equal("hello", string.trim_left("hello"))
|
|
assert_equal("", string.trim_left(""))
|
|
|
|
-- Custom cutset
|
|
assert_equal("Helloxxx", string.trim_left("xxxHelloxxx", "x"))
|
|
assert_equal("yHelloxxx", string.trim_left("xyHelloxxx", "x"))
|
|
assert_equal("", string.trim_left("xxxx", "x"))
|
|
end)
|
|
|
|
test("string.trim_right", function()
|
|
assert_equal(" Hello World", string.trim_right(padded_string))
|
|
assert_equal("hello", string.trim_right("hello"))
|
|
assert_equal("", string.trim_right(""))
|
|
|
|
-- Custom cutset
|
|
assert_equal("xxxHello", string.trim_right("xxxHelloxxx", "x"))
|
|
assert_equal("", string.trim_right("xxxx", "x"))
|
|
end)
|
|
|
|
test("string.upper", function()
|
|
assert_equal("HELLO", string.upper("hello"))
|
|
assert_equal("HELLO123!", string.upper("Hello123!"))
|
|
assert_equal("", string.upper(""))
|
|
assert_equal("ABC", string.upper("abc"))
|
|
end)
|
|
|
|
test("string.lower", function()
|
|
assert_equal("hello", string.lower("HELLO"))
|
|
assert_equal("hello123!", string.lower("HELLO123!"))
|
|
assert_equal("", string.lower(""))
|
|
assert_equal("abc", string.lower("ABC"))
|
|
end)
|
|
|
|
test("string.title", function()
|
|
assert_equal("Hello World", string.title("hello world"))
|
|
assert_equal("Hello World", string.title("HELLO WORLD"))
|
|
assert_equal("", string.title(""))
|
|
assert_equal("A", string.title("a"))
|
|
assert_equal("Test_Case", string.title("test_case"))
|
|
end)
|
|
|
|
test("string.contains", function()
|
|
assert_equal(true, string.contains(test_string, "World"))
|
|
assert_equal(false, string.contains(test_string, "world"))
|
|
assert_equal(true, string.contains(test_string, ""))
|
|
assert_equal(false, string.contains("", "a"))
|
|
assert_equal(true, string.contains("abc", "b"))
|
|
end)
|
|
|
|
test("string.starts_with", function()
|
|
assert_equal(true, string.starts_with(test_string, "Hello"))
|
|
assert_equal(false, string.starts_with(test_string, "hello"))
|
|
assert_equal(true, string.starts_with(test_string, ""))
|
|
assert_equal(false, string.starts_with("", "a"))
|
|
assert_equal(true, string.starts_with("hello", "h"))
|
|
end)
|
|
|
|
test("string.ends_with", function()
|
|
assert_equal(true, string.ends_with(test_string, "!"))
|
|
assert_equal(false, string.ends_with(test_string, "?"))
|
|
assert_equal(true, string.ends_with(test_string, ""))
|
|
assert_equal(false, string.ends_with("", "a"))
|
|
assert_equal(true, string.ends_with("hello", "o"))
|
|
end)
|
|
|
|
test("string.replace", function()
|
|
assert_equal("hi world hi", string.replace("hello world hello", "hello", "hi"))
|
|
assert_equal("hello", string.replace("hello", "xyz", "abc"))
|
|
assert_equal("", string.replace("hello", "hello", ""))
|
|
assert_equal("xyzxyz", string.replace("abcabc", "abc", "xyz"))
|
|
|
|
-- Special characters
|
|
assert_equal("h*llo", string.replace("hello", "e", "*"))
|
|
end)
|
|
|
|
test("string.replace_n", function()
|
|
assert_equal("hi world hello", string.replace_n("hello world hello", "hello", "hi", 1))
|
|
assert_equal("hi world hi", string.replace_n("hello world hello", "hello", "hi", 2))
|
|
assert_equal("hello world hello", string.replace_n("hello world hello", "hello", "hi", 0))
|
|
assert_equal("hello world hello", string.replace_n("hello world hello", "xyz", "hi", 5))
|
|
end)
|
|
|
|
test("string.index", function()
|
|
assert_equal(7, string.index("hello world", "world"))
|
|
assert_equal(nil, string.index("hello world", "xyz"))
|
|
assert_equal(1, string.index("hello", "h"))
|
|
assert_equal(5, string.index("hello", "o"))
|
|
assert_equal(1, string.index("hello", ""))
|
|
end)
|
|
|
|
test("string.last_index", function()
|
|
assert_equal(7, string.last_index("hello hello", "hello"))
|
|
assert_equal(nil, string.last_index("hello world", "xyz"))
|
|
assert_equal(1, string.last_index("hello", "h"))
|
|
assert_equal(9, string.last_index("hello o o", "o"))
|
|
end)
|
|
|
|
test("string.count", function()
|
|
assert_equal(3, string.count("hello hello hello", "hello"))
|
|
assert_equal(0, string.count("hello world", "xyz"))
|
|
assert_equal(2, string.count("hello", "l"))
|
|
assert_equal(6, string.count("hello", ""))
|
|
end)
|
|
|
|
test("string.repeat_", function()
|
|
assert_equal("abcabcabc", string.repeat_("abc", 3))
|
|
assert_equal("", string.repeat_("x", 0))
|
|
assert_equal("x", string.repeat_("x", 1))
|
|
assert_equal("", string.repeat_("", 5))
|
|
end)
|
|
|
|
test("string.reverse", function()
|
|
assert_equal("olleh", string.reverse("hello"))
|
|
assert_equal("", string.reverse(""))
|
|
assert_equal("a", string.reverse("a"))
|
|
assert_equal("dcba", string.reverse("abcd"))
|
|
|
|
-- Test with Go fallback for longer strings
|
|
local long_str = string.rep("abc", 50)
|
|
local reversed = string.reverse(long_str)
|
|
assert_equal(string.length(long_str), string.length(reversed))
|
|
end)
|
|
|
|
test("string.length", function()
|
|
assert_equal(5, string.length("hello"))
|
|
assert_equal(0, string.length(""))
|
|
assert_equal(1, string.length("a"))
|
|
|
|
-- Unicode length
|
|
assert_equal(4, string.length("café"))
|
|
assert_equal(17, string.length(unicode_string))
|
|
end)
|
|
|
|
test("string.byte_length", function()
|
|
assert_equal(5, string.byte_length("hello"))
|
|
assert_equal(0, string.byte_length(""))
|
|
assert_equal(1, string.byte_length("a"))
|
|
|
|
-- Unicode byte length (UTF-8)
|
|
assert_equal(5, string.byte_length("café")) -- é is 2 bytes
|
|
assert_equal(21, string.byte_length(unicode_string)) -- accented chars are 2 bytes each
|
|
end)
|
|
|
|
test("string.lines", function()
|
|
local lines = string.lines(multi_line)
|
|
assert_equal(3, #lines)
|
|
assert_equal("Line 1", lines[1])
|
|
assert_equal("Line 3", lines[3])
|
|
|
|
-- Empty string
|
|
assert_table_equal({""}, string.lines(""))
|
|
|
|
-- Different line endings
|
|
assert_table_equal({"a", "b"}, string.lines("a\nb"))
|
|
assert_table_equal({"a", "b"}, string.lines("a\r\nb"))
|
|
assert_table_equal({"a", "b"}, string.lines("a\rb"))
|
|
|
|
-- Trailing newline
|
|
assert_table_equal({"a", "b"}, string.lines("a\nb\n"))
|
|
end)
|
|
|
|
test("string.words", function()
|
|
local words = string.words("Hello world test")
|
|
assert_equal(3, #words)
|
|
assert_equal("Hello", words[1])
|
|
assert_equal("test", words[3])
|
|
|
|
-- Extra whitespace
|
|
assert_table_equal({"Hello", "world"}, string.words(" Hello world "))
|
|
|
|
-- Empty string
|
|
assert_table_equal({}, string.words(""))
|
|
assert_table_equal({}, string.words(" "))
|
|
|
|
-- Single word
|
|
assert_table_equal({"hello"}, string.words("hello"))
|
|
end)
|
|
|
|
test("string.pad_left", function()
|
|
assert_equal(" hi", string.pad_left("hi", 5))
|
|
assert_equal("000hi", string.pad_left("hi", 5, "0"))
|
|
assert_equal("hello", string.pad_left("hello", 3))
|
|
assert_equal("hi", string.pad_left("hi", 2))
|
|
assert_equal("hi", string.pad_left("hi", 0))
|
|
|
|
-- Unicode padding
|
|
assert_equal(" café", string.pad_left("café", 6))
|
|
end)
|
|
|
|
test("string.pad_right", function()
|
|
assert_equal("hi ", string.pad_right("hi", 5))
|
|
assert_equal("hi***", string.pad_right("hi", 5, "*"))
|
|
assert_equal("hello", string.pad_right("hello", 3))
|
|
assert_equal("hi", string.pad_right("hi", 2))
|
|
assert_equal("hi", string.pad_right("hi", 0))
|
|
|
|
-- Unicode padding
|
|
assert_equal("café ", string.pad_right("café", 6))
|
|
end)
|
|
|
|
test("string.slice", function()
|
|
assert_equal("ell", string.slice("hello", 2, 4))
|
|
assert_equal("ello", string.slice("hello", 2))
|
|
assert_equal("", string.slice("hello", 10))
|
|
assert_equal("h", string.slice("hello", 1, 1))
|
|
assert_equal("", string.slice("hello", 3, 2))
|
|
|
|
-- Negative indices
|
|
assert_equal("lo", string.slice("hello", 4, -1))
|
|
|
|
-- Unicode slicing
|
|
assert_equal("afé", string.slice("café", 2, 4))
|
|
end)
|
|
|
|
-- ======================================================================
|
|
-- REGULAR EXPRESSIONS
|
|
-- ======================================================================
|
|
|
|
test("string.match", function()
|
|
assert_equal(true, string.match("hello123", "%d+") ~= nil)
|
|
assert_equal(false, string.match("hello", "%d+") ~= nil)
|
|
assert_equal(true, string.match("hello", "^[a-z]+$") ~= nil)
|
|
assert_equal(false, string.match("Hello", "^[a-z]+$") ~= nil)
|
|
assert_equal(true, string.match("testing", "test") ~= nil)
|
|
end)
|
|
|
|
test("string.find_match", function()
|
|
assert_equal("123", string.find_match("hello123world", "%d+"))
|
|
assert_equal(nil, string.find_match("hello", "%d+"))
|
|
assert_equal("test", string.find_match("testing", "test"))
|
|
assert_equal("world", string.find_match("hello world", "world"))
|
|
end)
|
|
|
|
test("string.find_all", function()
|
|
local matches = string.find_all("123 and 456 and 789", "%d+")
|
|
assert_equal(3, #matches)
|
|
assert_equal("123", matches[1])
|
|
assert_equal("789", matches[3])
|
|
|
|
-- No matches
|
|
assert_table_equal({}, string.find_all("hello", "%d+"))
|
|
|
|
-- Multiple matches
|
|
local overlaps = string.find_all("test test test", "test")
|
|
assert_equal(3, #overlaps)
|
|
end)
|
|
|
|
test("string.gsub", function()
|
|
assert_equal("helloXXXworldXXX", (string.gsub("hello123world456", "%d+", "XXX")))
|
|
assert_equal("hello world", (string.gsub("hello world", "%s+", " ")))
|
|
assert_equal("abc abc abc", (string.gsub("test abc test", "test", "abc")))
|
|
|
|
-- No matches
|
|
assert_equal("hello", (string.gsub("hello", "%d+", "XXX")))
|
|
end)
|
|
|
|
-- ======================================================================
|
|
-- TYPE CONVERSION & VALIDATION
|
|
-- ======================================================================
|
|
|
|
test("string.to_number", function()
|
|
assert_equal(123, string.to_number("123"))
|
|
assert_equal(123.45, string.to_number("123.45"))
|
|
assert_equal(-42, string.to_number("-42"))
|
|
assert_equal(nil, string.to_number("not_a_number"))
|
|
assert_equal(nil, string.to_number(""))
|
|
assert_equal(42, string.to_number(" 42 "))
|
|
end)
|
|
|
|
test("string.is_numeric", function()
|
|
assert_equal(true, string.is_numeric("123"))
|
|
assert_equal(true, string.is_numeric("123.45"))
|
|
assert_equal(true, string.is_numeric("-42"))
|
|
assert_equal(false, string.is_numeric("abc"))
|
|
assert_equal(false, string.is_numeric(""))
|
|
assert_equal(true, string.is_numeric(" 42 "))
|
|
end)
|
|
|
|
test("string.is_alpha", function()
|
|
assert_equal(true, string.is_alpha("hello"))
|
|
assert_equal(false, string.is_alpha("hello123"))
|
|
assert_equal(false, string.is_alpha(""))
|
|
assert_equal(false, string.is_alpha("hello!"))
|
|
assert_equal(true, string.is_alpha("ABC"))
|
|
end)
|
|
|
|
test("string.is_alphanumeric", function()
|
|
assert_equal(true, string.is_alphanumeric("hello123"))
|
|
assert_equal(false, string.is_alphanumeric("hello!"))
|
|
assert_equal(false, string.is_alphanumeric(""))
|
|
assert_equal(true, string.is_alphanumeric("ABC123"))
|
|
assert_equal(true, string.is_alphanumeric("hello"))
|
|
end)
|
|
|
|
test("string.is_empty", function()
|
|
assert_equal(true, string.is_empty(""))
|
|
assert_equal(true, string.is_empty(nil))
|
|
assert_equal(false, string.is_empty("hello"))
|
|
assert_equal(false, string.is_empty(" "))
|
|
end)
|
|
|
|
test("string.is_blank", function()
|
|
assert_equal(true, string.is_blank(""))
|
|
assert_equal(true, string.is_blank(" "))
|
|
assert_equal(true, string.is_blank(nil))
|
|
assert_equal(false, string.is_blank("hello"))
|
|
assert_equal(false, string.is_blank(" a "))
|
|
end)
|
|
|
|
test("string.is_utf8", function()
|
|
assert_equal(true, string.is_utf8("hello"))
|
|
assert_equal(true, string.is_utf8("café"))
|
|
assert_equal(true, string.is_utf8(""))
|
|
assert_equal(true, string.is_utf8(unicode_string))
|
|
end)
|
|
|
|
-- ======================================================================
|
|
-- ADVANCED STRING OPERATIONS
|
|
-- ======================================================================
|
|
|
|
test("string.capitalize", function()
|
|
assert_equal("Hello World", string.capitalize("hello world"))
|
|
assert_equal("Hello", string.capitalize("hello"))
|
|
assert_equal("", string.capitalize(""))
|
|
assert_equal("A", string.capitalize("a"))
|
|
end)
|
|
|
|
test("string.camel_case", function()
|
|
assert_equal("helloWorld", string.camel_case("hello world"))
|
|
assert_equal("hello", string.camel_case("hello"))
|
|
assert_equal("", string.camel_case(""))
|
|
assert_equal("testCaseExample", string.camel_case("test case example"))
|
|
end)
|
|
|
|
test("string.pascal_case", function()
|
|
assert_equal("HelloWorld", string.pascal_case("hello world"))
|
|
assert_equal("Hello", string.pascal_case("hello"))
|
|
assert_equal("", string.pascal_case(""))
|
|
assert_equal("TestCaseExample", string.pascal_case("test case example"))
|
|
end)
|
|
|
|
test("string.snake_case", function()
|
|
assert_equal("hello_world", string.snake_case("Hello World"))
|
|
assert_equal("hello", string.snake_case("hello"))
|
|
assert_equal("", string.snake_case(""))
|
|
assert_equal("test_case_example", string.snake_case("Test Case Example"))
|
|
end)
|
|
|
|
test("string.kebab_case", function()
|
|
assert_equal("hello-world", string.kebab_case("Hello World"))
|
|
assert_equal("hello", string.kebab_case("hello"))
|
|
assert_equal("", string.kebab_case(""))
|
|
assert_equal("test-case-example", string.kebab_case("Test Case Example"))
|
|
end)
|
|
|
|
test("string.screaming_snake_case", function()
|
|
assert_equal("HELLO_WORLD", string.screaming_snake_case("hello world"))
|
|
assert_equal("HELLO", string.screaming_snake_case("hello"))
|
|
assert_equal("", string.screaming_snake_case(""))
|
|
assert_equal("TEST_CASE", string.screaming_snake_case("test case"))
|
|
end)
|
|
|
|
test("string.center", function()
|
|
assert_equal(" hi ", string.center("hi", 6))
|
|
assert_equal("**hi***", string.center("hi", 7, "*"))
|
|
assert_equal("hello", string.center("hello", 3))
|
|
assert_equal("hi", string.center("hi", 2))
|
|
assert_equal(" hi ", string.center("hi", 4))
|
|
end)
|
|
|
|
test("string.truncate", function()
|
|
assert_equal("hello...", string.truncate("hello world", 8))
|
|
assert_equal("hello>>", string.truncate("hello world", 8, ">>"))
|
|
assert_equal("hi", string.truncate("hi", 10))
|
|
assert_equal("...", string.truncate("hello", 3))
|
|
assert_equal("h>", string.truncate("hello", 2, ">"))
|
|
end)
|
|
|
|
test("string.wrap", function()
|
|
local wrapped = string.wrap("The quick brown fox jumps over the lazy dog", 10)
|
|
assert_equal("table", type(wrapped))
|
|
assert(#wrapped > 1, "should wrap into multiple lines")
|
|
|
|
-- Each line should be within limit
|
|
for _, line in ipairs(wrapped) do
|
|
assert(string.length(line) <= 10, "line should be within width limit: " .. line)
|
|
end
|
|
|
|
-- Empty string
|
|
assert_table_equal({""}, string.wrap("", 10))
|
|
|
|
-- Single word longer than width
|
|
local long_word = string.wrap("supercalifragilisticexpialidocious", 10)
|
|
assert_equal(1, #long_word)
|
|
end)
|
|
|
|
test("string.dedent", function()
|
|
local indented = " line1\n line2\n line3"
|
|
local dedented = string.dedent(indented)
|
|
local lines = string.lines(dedented)
|
|
|
|
assert_equal("line1", lines[1])
|
|
assert_equal("line2", lines[2])
|
|
assert_equal("line3", lines[3])
|
|
|
|
-- Mixed indentation
|
|
local mixed = " a\n b\n c"
|
|
local mixed_result = string.dedent(mixed)
|
|
local mixed_lines = string.lines(mixed_result)
|
|
assert_equal("a", mixed_lines[1])
|
|
assert_equal(" b", mixed_lines[2])
|
|
assert_equal("c", mixed_lines[3])
|
|
end)
|
|
|
|
test("string.escape", function()
|
|
assert_equal("hello%.world", string.escape("hello.world"))
|
|
assert_equal("a%+b%*c%?", string.escape("a+b*c?"))
|
|
assert_equal("%[%]%(%)", string.escape("[]()"))
|
|
assert_equal("hello", string.escape("hello"))
|
|
end)
|
|
|
|
test("string.shell_quote", function()
|
|
assert_equal("'hello world'", string.shell_quote("hello world"))
|
|
assert_equal("'it'\"'\"'s great'", string.shell_quote("it's great"))
|
|
assert_equal("hello", string.shell_quote("hello"))
|
|
assert_equal("hello-world.txt", string.shell_quote("hello-world.txt"))
|
|
end)
|
|
|
|
test("string.url_encode", function()
|
|
assert_equal("hello%20world", string.url_encode("hello world"))
|
|
assert_equal("hello", string.url_encode("hello"))
|
|
assert_equal("hello%21%40%23", string.url_encode("hello!@#"))
|
|
end)
|
|
|
|
test("string.url_decode", function()
|
|
assert_equal("hello world", string.url_decode("hello%20world"))
|
|
assert_equal("hello world", string.url_decode("hello+world"))
|
|
assert_equal("hello", string.url_decode("hello"))
|
|
assert_equal("hello!@#", string.url_decode("hello%21%40%23"))
|
|
|
|
-- Round trip
|
|
local original = "hello world!@#"
|
|
local encoded = string.url_encode(original)
|
|
assert_equal(original, string.url_decode(encoded))
|
|
end)
|
|
|
|
test("string.template", function()
|
|
local context = {
|
|
user = {name = "Jane", role = "admin"},
|
|
count = 5
|
|
}
|
|
local template = "User ${user.name} (${user.role}) has ${count} items"
|
|
local result = string.template(template, context)
|
|
assert_equal("User Jane (admin) has 5 items", result)
|
|
|
|
-- Missing variables
|
|
local incomplete = string.template("Hello ${name} and ${unknown}", {name = "John"})
|
|
assert_equal("Hello John and ", incomplete)
|
|
|
|
-- Missing nested property
|
|
local missing = string.template("${user.missing}", context)
|
|
assert_equal("", missing)
|
|
|
|
-- No variables
|
|
assert_equal("Hello world", string.template("Hello world", {}))
|
|
end)
|
|
|
|
test("string.random", function()
|
|
local random1 = string.random(10)
|
|
local random2 = string.random(10)
|
|
|
|
assert_equal(10, string.length(random1))
|
|
assert_equal(10, string.length(random2))
|
|
assert(random1 ~= random2, "random strings should be different")
|
|
|
|
-- Custom charset
|
|
local custom = string.random(5, "abc")
|
|
assert_equal(5, string.length(custom))
|
|
|
|
-- Zero length
|
|
assert_equal("", string.random(0))
|
|
end)
|
|
|
|
test("string.slug", function()
|
|
assert_equal("hello-world", string.slug("Hello World"))
|
|
assert_equal("cafe-restaurant", string.slug("Café & Restaurant"))
|
|
assert_equal("specialcharacters", string.slug("Special!@#$%Characters"))
|
|
assert_equal("", string.slug(""))
|
|
assert_equal("test", string.slug("test"))
|
|
end)
|
|
|
|
test("string.iequals", function()
|
|
assert_equal(true, string.iequals("Hello", "HELLO"))
|
|
assert_equal(true, string.iequals("hello", "hello"))
|
|
assert_equal(false, string.iequals("Hello", "world"))
|
|
assert_equal(true, string.iequals("", ""))
|
|
end)
|
|
|
|
test("string.is_whitespace", function()
|
|
assert_equal(true, string.is_whitespace(" "))
|
|
assert_equal(true, string.is_whitespace(""))
|
|
assert_equal(true, string.is_whitespace("\t\n\r "))
|
|
assert_equal(false, string.is_whitespace("hello"))
|
|
assert_equal(false, string.is_whitespace(" a "))
|
|
end)
|
|
|
|
test("string.strip_whitespace", function()
|
|
assert_equal("hello", string.strip_whitespace("h e l l o"))
|
|
assert_equal("helloworld", string.strip_whitespace("hello world"))
|
|
assert_equal("", string.strip_whitespace(" "))
|
|
assert_equal("abc", string.strip_whitespace("a\tb\nc"))
|
|
end)
|
|
|
|
test("string.normalize_whitespace", function()
|
|
assert_equal("hello world test", string.normalize_whitespace("hello world test"))
|
|
assert_equal("a b c", string.normalize_whitespace(" a b c "))
|
|
assert_equal("", string.normalize_whitespace(" "))
|
|
assert_equal("hello", string.normalize_whitespace("hello"))
|
|
end)
|
|
|
|
test("string.extract_numbers", function()
|
|
local numbers = string.extract_numbers("The price is $123.45 and tax is 8.5%")
|
|
assert_equal(2, #numbers)
|
|
assert_close(123.45, numbers[1])
|
|
assert_close(8.5, numbers[2])
|
|
|
|
local negative = string.extract_numbers("Temperature: -15.5 degrees")
|
|
assert_equal(1, #negative)
|
|
assert_close(-15.5, negative[1])
|
|
|
|
-- No numbers
|
|
assert_table_equal({}, string.extract_numbers("hello world"))
|
|
end)
|
|
|
|
test("string.remove_accents", function()
|
|
assert_equal("cafe", string.remove_accents("café"))
|
|
assert_equal("resume", string.remove_accents("résumé"))
|
|
assert_equal("naive", string.remove_accents("naïve"))
|
|
assert_equal("hello", string.remove_accents("hello"))
|
|
assert_equal("", string.remove_accents(""))
|
|
|
|
-- Mixed case
|
|
assert_equal("Cafe", string.remove_accents("Café"))
|
|
end)
|
|
|
|
-- ======================================================================
|
|
-- EDGE CASES AND ERROR HANDLING
|
|
-- ======================================================================
|
|
|
|
test("Empty String Handling", function()
|
|
assert_table_equal({""}, string.split("", ","))
|
|
assert_equal("", string.join({}, ","))
|
|
assert_equal("", string.trim(""))
|
|
assert_equal("", string.reverse(""))
|
|
assert_equal("", string.repeat_("", 5))
|
|
assert_table_equal({""}, string.lines(""))
|
|
assert_table_equal({}, string.words(""))
|
|
assert_equal("", string.slice("", 1, 5))
|
|
assert_equal("", string.slug(""))
|
|
end)
|
|
|
|
test("Large String Handling", function()
|
|
local large_string = string.rep("test ", 1000)
|
|
|
|
assert_equal(5000, string.length(large_string))
|
|
assert_equal(1000, string.count(large_string, "test"))
|
|
|
|
local words = string.words(large_string)
|
|
assert_equal(1000, #words)
|
|
|
|
local trimmed = string.trim(large_string)
|
|
assert_equal(true, string.ends_with(trimmed, "test"))
|
|
|
|
-- Should use Go for reverse on large strings
|
|
local reversed = string.reverse(large_string)
|
|
assert_equal(string.length(large_string), string.length(reversed))
|
|
end)
|
|
|
|
test("Unicode Handling", function()
|
|
local unicode_str = "Hello 🌍 World 🚀"
|
|
|
|
assert_equal(true, string.contains(unicode_str, "🌍"))
|
|
assert_equal(true, string.starts_with(unicode_str, "Hello"))
|
|
assert_equal(true, string.ends_with(unicode_str, "🚀"))
|
|
|
|
local parts = string.split(unicode_str, " ")
|
|
assert_equal(4, #parts)
|
|
assert_equal("🌍", parts[2])
|
|
|
|
-- Length should count Unicode characters, not bytes
|
|
assert_equal(15, string.length(unicode_str))
|
|
assert(string.byte_length(unicode_str) > 15, "byte length should be larger")
|
|
end)
|
|
|
|
test("Boundary Conditions", function()
|
|
-- Index boundary tests
|
|
assert_equal("", string.slice("hello", 6))
|
|
assert_equal("", string.slice("hello", 1, 0))
|
|
assert_equal("hello", string.slice("hello", 1, 100))
|
|
|
|
-- Padding boundary tests
|
|
assert_equal("hi", string.pad_left("hi", 0))
|
|
assert_equal("hi", string.pad_right("hi", 1))
|
|
|
|
-- Count boundary tests
|
|
assert_equal(0, string.count("", "a"))
|
|
assert_equal(1, string.count("", ""))
|
|
|
|
-- Replace boundary tests
|
|
assert_equal("", string.replace_n("hello", "hello", "", 1))
|
|
assert_equal("hello", string.replace_n("hello", "x", "y", 0))
|
|
end)
|
|
|
|
-- ======================================================================
|
|
-- INTEGRATION TESTS
|
|
-- ======================================================================
|
|
|
|
test("String Processing Pipeline", function()
|
|
local messy_input = " HELLO, world! How ARE you? "
|
|
|
|
-- Clean and normalize
|
|
local cleaned = string.normalize_whitespace(string.trim(messy_input))
|
|
local lowered = string.lower(cleaned)
|
|
local words = string.words(lowered)
|
|
local filtered = {}
|
|
|
|
for _, word in ipairs(words) do
|
|
local clean_word = string.gsub(word, "[%p]", "") -- Remove punctuation using Lua pattern
|
|
if string.length(clean_word) > 2 then
|
|
table.insert(filtered, clean_word)
|
|
end
|
|
end
|
|
|
|
local result = string.join(filtered, "-")
|
|
assert_equal("hello-world-how-are-you", result)
|
|
end)
|
|
|
|
test("Text Analysis", function()
|
|
local text = "The quick brown fox jumps over the lazy dog. The dog was sleeping."
|
|
|
|
local word_count = #string.words(text)
|
|
local sentence_count = string.count(text, ".")
|
|
local the_count = string.count(string.lower(text), "the")
|
|
|
|
assert_equal(13, word_count)
|
|
assert_equal(2, sentence_count)
|
|
assert_equal(3, the_count)
|
|
|
|
-- Template processing
|
|
local template = "Found ${word_count} words and ${the_count} instances of 'the'"
|
|
local vars = {word_count = word_count, the_count = the_count}
|
|
local summary = string.template(template, vars)
|
|
|
|
assert_equal("Found 13 words and 3 instances of 'the'", summary)
|
|
end)
|
|
|
|
test("Case Conversion Chain", function()
|
|
local original = "Hello World Test Case"
|
|
|
|
-- Test conversion chain
|
|
local snake = string.snake_case(original)
|
|
local camel = string.camel_case(original)
|
|
local pascal = string.pascal_case(original)
|
|
local kebab = string.kebab_case(original)
|
|
local screaming = string.screaming_snake_case(original)
|
|
|
|
assert_equal("hello_world_test_case", snake)
|
|
assert_equal("helloWorldTestCase", camel)
|
|
assert_equal("HelloWorldTestCase", pascal)
|
|
assert_equal("hello-world-test-case", kebab)
|
|
assert_equal("HELLO_WORLD_TEST_CASE", screaming)
|
|
|
|
-- Convert back should be similar
|
|
local back_to_words = string.split(snake, "_")
|
|
local rejoined = string.join(back_to_words, " ")
|
|
local capitalized = string.title(rejoined)
|
|
|
|
assert_equal("Hello World Test Case", capitalized)
|
|
end)
|
|
|
|
-- ======================================================================
|
|
-- PERFORMANCE TESTS
|
|
-- ======================================================================
|
|
|
|
test("Performance Characteristics", function()
|
|
local large_text = string.rep("The quick brown fox jumps over the lazy dog. ", 1000)
|
|
|
|
-- Test that operations complete in reasonable time
|
|
local start = os.clock()
|
|
|
|
local words = string.words(large_text)
|
|
local lines = string.lines(large_text)
|
|
local replaced = string.replace(large_text, "fox", "cat")
|
|
local parts = string.split(large_text, " ")
|
|
local reversed = string.reverse(large_text)
|
|
|
|
local elapsed = os.clock() - start
|
|
|
|
-- Verify results
|
|
assert(#words > 8000, "should extract many words")
|
|
assert(string.contains(replaced, "cat"), "replacement should work")
|
|
assert(#parts > 8000, "should split into many parts")
|
|
assert_equal(string.length(large_text), string.length(reversed))
|
|
|
|
print(string.format(" Processed %d characters in %.3fs", string.length(large_text), elapsed))
|
|
|
|
-- Performance should be reasonable (< 1 second for this test)
|
|
assert(elapsed < 1.0, "operations should complete quickly")
|
|
end)
|
|
|
|
summary()
|
|
test_exit()
|