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()