diff --git a/SLS_C/include/tests/tests.h b/SLS_C/include/tests/tests.h index 565d581..ab6d3a2 100644 --- a/SLS_C/include/tests/tests.h +++ b/SLS_C/include/tests/tests.h @@ -37,6 +37,7 @@ typedef struct { TestResult* tests; } TestsReport; +TestsReport run_string_tests(); TestsReport run_lexer_tests(); #endif // SLS_TESTS_H diff --git a/SLS_C/tests/string_tests.c b/SLS_C/tests/string_tests.c new file mode 100644 index 0000000..569237f --- /dev/null +++ b/SLS_C/tests/string_tests.c @@ -0,0 +1,224 @@ +// 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; +} diff --git a/SLS_C/tests/tests.c b/SLS_C/tests/tests.c index ace6cb0..c46f7fa 100644 --- a/SLS_C/tests/tests.c +++ b/SLS_C/tests/tests.c @@ -22,7 +22,7 @@ typedef struct { uint16_t total; } TestCounts; -static void lexer_test_report(TestsReport reports, TestCounts *counts) { +static void test_report(TestsReport reports, TestCounts *counts) { counts->total += reports.count; for (size_t i = 0; i < reports.count; i++) { switch (reports.tests[i].status) { @@ -78,8 +78,10 @@ int main(void) { .total = 0, }; - TestsReport lexer_reports = run_lexer_tests(); - lexer_test_report(lexer_reports, &counts); + printf(" ===== SlsStr Tests =====\n"); + test_report(run_string_tests(), &counts); + printf(" ===== Lexer Tests =====\n"); + test_report(run_lexer_tests(), &counts); printf(" ===== Tests Overview =====\n"); if (counts.errored > 0)