YREA-SLS/SLS_C/tests/string_tests.c

225 lines
7.9 KiB
C

// Kyler Olsen
// YREA SLS
// String Tests
// November 2025
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#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(&copy);
return fail_string_test(SLS_STR("test_malloc_and_copy"), SLS_STR("sls_str_cpy failed"));
}
sls_str_free(&s);
sls_str_free(&copy);
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;
}