// Kyler Olsen // YREA SLS // String Tests // November 2025 #include #include #include #include #include "sls/string.h" #include "sls/lexer.h" #include "sls/errors.h" #include "tests/tests.h" static const size_t NUM_STRING_TESTS = 10; static TestResult pass_string_test(SlsStr test_name) { TestResult result = {.name = test_name, .status = TEST_NOT_IMPLEMENTED}; result.status = TEST_PASS; return result; } static TestResult fail_string_test(SlsStr test_name, SlsStr message) { TestResult result = { .name = test_name, .status = TEST_NOT_IMPLEMENTED }; result.status = TEST_ERROR; result.message = sls_str_cpy(message); if (result.message.str == NULL) { result.error = (SlsError){ SLS_STR("Out Of Memory Error."), 1 }; result.status = TEST_ERROR; } return result; } // Test sls_str_malloc and sls_str_cpy static TestResult test_malloc_and_copy() { const char* original = "Hello, SLS!"; SlsStr s = sls_str_malloc(original, strlen(original)); if (!s.str) return fail_string_test(SLS_STR("test_malloc_and_copy"), SLS_STR("Allocation failed")); if (strcmp(s.str, original) != 0) { sls_str_free(&s); return fail_string_test(SLS_STR("test_malloc_and_copy"), SLS_STR("Copied string mismatch")); } SlsStr copy = sls_str_cpy(s); if (!copy.str || strcmp(copy.str, original) != 0) { sls_str_free(&s); sls_str_free(©); return fail_string_test(SLS_STR("test_malloc_and_copy"), SLS_STR("sls_str_cpy failed")); } sls_str_free(&s); sls_str_free(©); return pass_string_test(SLS_STR("test_malloc_and_copy")); } // Test sls_str_cmp static TestResult test_compare_strings() { SlsStr a = sls_str_malloc("abc", 3); SlsStr b = sls_str_malloc("abc", 3); SlsStr c = sls_str_malloc("abd", 3); if (sls_str_cmp(a, b) != 0) goto fail; if (sls_str_cmp(a, c) >= 0) goto fail; if (sls_str_cmp(c, a) <= 0) goto fail; sls_str_free(&a); sls_str_free(&b); sls_str_free(&c); return pass_string_test(SLS_STR("test_compare_strings")); fail: sls_str_free(&a); sls_str_free(&b); sls_str_free(&c); return fail_string_test(SLS_STR("test_compare_strings"), SLS_STR("Comparison test failed")); } // Test sls_format for basic placeholders static TestResult test_format_basic_placeholders() { SlsStr fmt = SLS_STR("Char: %c, Int: %d, Long: %l, Unsigned: %u, Size: %z, Float: %f, C-String: %y"); const char *s = "Test"; SlsStr result = sls_format(fmt, 'X', -42, (int64_t)1234567890123, (uint64_t)9876543210, (size_t)1024, 3.14, s); if (!result.str) return fail_string_test(SLS_STR("test_format_basic_placeholders"), SLS_STR("Formatting returned NULL")); const char* expected = "Char: X, Int: -42, Long: 1234567890123, Unsigned: 9876543210, Size: 1024, Float: 3.14, C-String: Test"; if (strcmp(result.str, expected) != 0) { sls_str_free(&result); return fail_string_test(SLS_STR("test_format_basic_placeholders"), SLS_STR("Formatted string mismatch")); } sls_str_free(&result); return pass_string_test(SLS_STR("test_format_basic_placeholders")); } // Test sls_format for SLS types: %s, %t, %a, %i, %e, %b static TestResult test_format_sls_types() { // Placeholder values SlsStr sls_str_val = SLS_STR("SLS_STRING"); TokenType tok = 0; // Assuming TOKEN_TYPES_NAMES[0] exists ArrayType arr = 0; // Assuming ARRAY_TYPES_NAMES[0] exists IntegerBuiltInType ib = 0; // Assuming INTEGER_TYPES_NAMES[0] exists SlsError err = {SLS_STR("ErrorMessage"), 1}; Boolean boolean_true = TRUE; SlsStr fmt = SLS_STR("Str:%s Tok:%t Arr:%a IntType:%i Err:%e Bool:%b"); SlsStr result = sls_format(fmt, sls_str_val, tok, arr, ib, err, boolean_true); if (!result.str) return fail_string_test(SLS_STR("test_format_sls_types"), SLS_STR("Formatting returned NULL")); char expected[256]; snprintf(expected, 256, "Str:%s Tok:%s Arr:%s IntType:%s Err:%s Bool:TRUE", sls_str_val.str, TOKEN_TYPES_NAMES[tok], ARRAY_TYPES_NAMES[arr], INTEGER_TYPES_NAMES[ib], err.message.str); if (strcmp(result.str, expected) != 0) { sls_str_free(&result); return fail_string_test(SLS_STR("test_format_sls_types"), SLS_STR("Formatted string mismatch for SLS types")); } sls_str_free(&result); return pass_string_test(SLS_STR("test_format_sls_types")); } // Test sls_format with %% escape static TestResult test_format_percent_escape() { SlsStr fmt = SLS_STR("Progress: 100%% complete"); SlsStr result = sls_format(fmt); if (!result.str) return fail_string_test(SLS_STR("test_format_percent_escape"), SLS_STR("Formatting returned NULL")); if (strcmp(result.str, "Progress: 100% complete") != 0) { sls_str_free(&result); return fail_string_test(SLS_STR("test_format_percent_escape"), SLS_STR("Percent escape failed")); } sls_str_free(&result); return pass_string_test(SLS_STR("test_format_percent_escape")); } // Test sls_str_new allocation and zero-init static TestResult test_new_string_allocation() { SlsStr s = sls_str_new(10); if (!s.str) return fail_string_test(SLS_STR("test_new_string_allocation"), SLS_STR("Allocation failed")); for (size_t i = 0; i < s.len; i++) { if (s.str[i] != 0) { sls_str_free(&s); return fail_string_test(SLS_STR("test_new_string_allocation"), SLS_STR("Memory not zero-initialized")); } } sls_str_free(&s); return pass_string_test(SLS_STR("test_new_string_allocation")); } // Test empty string static TestResult test_empty_string() { SlsStr s = sls_str_malloc("", 0); if (!s.str || s.len != 0) return fail_string_test(SLS_STR("test_empty_string"), SLS_STR("Empty string allocation failed")); sls_str_free(&s); return pass_string_test(SLS_STR("test_empty_string")); } // Test long string static TestResult test_long_string() { size_t len = 1024; char* long_str = malloc(len + 1); for (size_t i = 0; i < len; i++) long_str[i] = 'A'; long_str[len] = '\0'; SlsStr s = sls_str_malloc(long_str, len); if (!s.str || s.len != len) { free(long_str); return fail_string_test(SLS_STR("test_long_string"), SLS_STR("Long string allocation failed")); } sls_str_free(&s); free(long_str); return pass_string_test(SLS_STR("test_long_string")); } // Test NULL pointer handling in sls_str_free static TestResult test_free_null() { SlsStr s = SLS_STR_NULL; sls_str_free(&s); // Should safely do nothing return pass_string_test(SLS_STR("test_free_null")); } // Test sls_str_nlen edge cases static TestResult test_str_nlen_edge() { const char* str = "ABCDE"; if (sls_str_nlen(str, 0) != 0) return fail_string_test(SLS_STR("test_str_nlen_edge"), SLS_STR("Maxlen=0 failed")); if (sls_str_nlen(str, 3) != 3) return fail_string_test(SLS_STR("test_str_nlen_edge"), SLS_STR("Maxlen=3 failed")); if (sls_str_nlen(str, 10) != 5) return fail_string_test(SLS_STR("test_str_nlen_edge"), SLS_STR("Maxlen>strlen failed")); return pass_string_test(SLS_STR("test_str_nlen_edge")); } // Run all string tests TestsReport run_string_tests() { TestsReport report = { .section = SLS_STR("string_tests"), .count = NUM_STRING_TESTS, .tests = malloc(sizeof(TestResult) * NUM_STRING_TESTS) }; size_t i = 0; report.tests[i++] = test_malloc_and_copy(); report.tests[i++] = test_compare_strings(); report.tests[i++] = test_format_basic_placeholders(); report.tests[i++] = test_format_sls_types(); report.tests[i++] = test_format_percent_escape(); report.tests[i++] = test_new_string_allocation(); report.tests[i++] = test_empty_string(); report.tests[i++] = test_long_string(); report.tests[i++] = test_free_null(); report.tests[i++] = test_str_nlen_edge(); return report; }