mirror of
https://github.com/tbamud/tbamud.git
synced 2026-04-30 04:41:51 +02:00
Add Unity-based unit test infrastructure (Phase 1: 117 tests passing)
Agent-Logs-Url: https://github.com/tbamud/tbamud/sessions/d5b86db2-e5ab-4729-b8b1-2ca7cf01c6b9 Co-authored-by: welcor <357770+welcor@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
552461df51
commit
fff58ccab3
482
tests/test_utils.c
Normal file
482
tests/test_utils.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/**
|
||||
* @file test_utils.c
|
||||
* Unit tests for pure / near-pure functions in src/utils.c
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "sysdep.h"
|
||||
#include "structs.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* Redirect mud log output so basic_mud_vlog() doesn't print the
|
||||
* "SYSERR: Using log() before stream was initialized!" warning. */
|
||||
extern FILE *logfile;
|
||||
|
||||
void setUp(void) { logfile = stderr; }
|
||||
void tearDown(void) { logfile = NULL; }
|
||||
|
||||
/* =========================================================
|
||||
* prune_crlf
|
||||
* ========================================================= */
|
||||
|
||||
void test_prune_crlf_strips_crlf(void)
|
||||
{
|
||||
char s[] = "hello\r\n";
|
||||
prune_crlf(s);
|
||||
TEST_ASSERT_EQUAL_STRING("hello", s);
|
||||
}
|
||||
|
||||
void test_prune_crlf_strips_lf_only(void)
|
||||
{
|
||||
char s[] = "hello\n";
|
||||
prune_crlf(s);
|
||||
TEST_ASSERT_EQUAL_STRING("hello", s);
|
||||
}
|
||||
|
||||
void test_prune_crlf_no_op_on_clean(void)
|
||||
{
|
||||
char s[] = "hello";
|
||||
prune_crlf(s);
|
||||
TEST_ASSERT_EQUAL_STRING("hello", s);
|
||||
}
|
||||
|
||||
void test_prune_crlf_multiple_trailing(void)
|
||||
{
|
||||
char s[] = "hi\r\n\r\n";
|
||||
prune_crlf(s);
|
||||
TEST_ASSERT_EQUAL_STRING("hi", s);
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* str_cmp (may be an alias for strcasecmp on this platform)
|
||||
* ========================================================= */
|
||||
|
||||
void test_str_cmp_equal_strings(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, str_cmp("hello", "hello"));
|
||||
}
|
||||
|
||||
void test_str_cmp_case_insensitive(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, str_cmp("Hello", "hello"));
|
||||
TEST_ASSERT_EQUAL_INT(0, str_cmp("HELLO", "hello"));
|
||||
}
|
||||
|
||||
void test_str_cmp_ordering_less(void)
|
||||
{
|
||||
TEST_ASSERT_LESS_THAN(0, str_cmp("a", "b"));
|
||||
}
|
||||
|
||||
void test_str_cmp_ordering_greater(void)
|
||||
{
|
||||
TEST_ASSERT_GREATER_THAN(0, str_cmp("b", "a"));
|
||||
}
|
||||
|
||||
void test_str_cmp_empty_equal(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, str_cmp("", ""));
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* strn_cmp (may be an alias for strncasecmp on this platform)
|
||||
* ========================================================= */
|
||||
|
||||
void test_strn_cmp_equal_prefix(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, strn_cmp("hello", "hello world", 5));
|
||||
}
|
||||
|
||||
void test_strn_cmp_differ_past_n(void)
|
||||
{
|
||||
/* First 5 chars same, so strn_cmp("hello!", "hellox", 5) == 0 */
|
||||
TEST_ASSERT_EQUAL_INT(0, strn_cmp("hello!", "hellox", 5));
|
||||
}
|
||||
|
||||
void test_strn_cmp_differ_within_n(void)
|
||||
{
|
||||
TEST_ASSERT_NOT_EQUAL(0, strn_cmp("abc", "xyz", 3));
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* sprintbit
|
||||
* ========================================================= */
|
||||
|
||||
void test_sprintbit_no_bits_set(void)
|
||||
{
|
||||
static const char *names[] = { "FLAG_A", "FLAG_B", "\n" };
|
||||
char result[256];
|
||||
sprintbit(0, names, result, sizeof(result));
|
||||
TEST_ASSERT_EQUAL_STRING("NOBITS ", result);
|
||||
}
|
||||
|
||||
void test_sprintbit_single_bit(void)
|
||||
{
|
||||
static const char *names[] = { "FLAG_A", "FLAG_B", "\n" };
|
||||
char result[256];
|
||||
sprintbit(1, names, result, sizeof(result));
|
||||
TEST_ASSERT_EQUAL_STRING("FLAG_A ", result);
|
||||
}
|
||||
|
||||
void test_sprintbit_multiple_bits(void)
|
||||
{
|
||||
static const char *names[] = { "FLAG_A", "FLAG_B", "\n" };
|
||||
char result[256];
|
||||
sprintbit(3, names, result, sizeof(result));
|
||||
TEST_ASSERT_EQUAL_STRING("FLAG_A FLAG_B ", result);
|
||||
}
|
||||
|
||||
void test_sprintbit_undefined_bit(void)
|
||||
{
|
||||
/* Bit 2 is beyond the named array – should produce "UNDEFINED" */
|
||||
static const char *names[] = { "FLAG_A", "FLAG_B", "\n" };
|
||||
char result[256];
|
||||
sprintbit(4, names, result, sizeof(result));
|
||||
TEST_ASSERT_EQUAL_STRING("UNDEFINED ", result);
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* sprinttype
|
||||
* ========================================================= */
|
||||
|
||||
void test_sprinttype_valid_index_zero(void)
|
||||
{
|
||||
static const char *names[] = { "ZERO", "ONE", "\n" };
|
||||
char result[64];
|
||||
sprinttype(0, names, result, sizeof(result));
|
||||
TEST_ASSERT_EQUAL_STRING("ZERO", result);
|
||||
}
|
||||
|
||||
void test_sprinttype_valid_index_one(void)
|
||||
{
|
||||
static const char *names[] = { "ZERO", "ONE", "\n" };
|
||||
char result[64];
|
||||
sprinttype(1, names, result, sizeof(result));
|
||||
TEST_ASSERT_EQUAL_STRING("ONE", result);
|
||||
}
|
||||
|
||||
void test_sprinttype_out_of_range(void)
|
||||
{
|
||||
static const char *names[] = { "ZERO", "ONE", "\n" };
|
||||
char result[64];
|
||||
sprinttype(5, names, result, sizeof(result));
|
||||
TEST_ASSERT_EQUAL_STRING("UNDEFINED", result);
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* levenshtein_distance
|
||||
* ========================================================= */
|
||||
|
||||
void test_levenshtein_identical_strings(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, levenshtein_distance("hello", "hello"));
|
||||
}
|
||||
|
||||
void test_levenshtein_empty_and_nonempty(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(5, levenshtein_distance("", "hello"));
|
||||
TEST_ASSERT_EQUAL_INT(5, levenshtein_distance("hello", ""));
|
||||
}
|
||||
|
||||
void test_levenshtein_single_insertion(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(1, levenshtein_distance("abc", "abcd"));
|
||||
}
|
||||
|
||||
void test_levenshtein_single_deletion(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(1, levenshtein_distance("abcd", "abc"));
|
||||
}
|
||||
|
||||
void test_levenshtein_single_substitution(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(1, levenshtein_distance("abc", "axc"));
|
||||
}
|
||||
|
||||
void test_levenshtein_both_empty(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, levenshtein_distance("", ""));
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* count_color_chars
|
||||
* ========================================================= */
|
||||
|
||||
void test_count_color_chars_no_codes(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, count_color_chars("hello"));
|
||||
}
|
||||
|
||||
void test_count_color_chars_empty(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, count_color_chars(""));
|
||||
}
|
||||
|
||||
void test_count_color_chars_single_color_code(void)
|
||||
{
|
||||
/* "\tR" is a two-char color escape; both are skipped (counted as overhead) */
|
||||
TEST_ASSERT_EQUAL_INT(2, count_color_chars("\tR"));
|
||||
}
|
||||
|
||||
void test_count_color_chars_double_tab(void)
|
||||
{
|
||||
/* "\t\t" is an escaped literal tab; costs 1 overhead char */
|
||||
TEST_ASSERT_EQUAL_INT(1, count_color_chars("\t\t"));
|
||||
}
|
||||
|
||||
void test_count_color_chars_mixed(void)
|
||||
{
|
||||
/* "\tRhello" → 2 overhead + 0 for "hello" */
|
||||
TEST_ASSERT_EQUAL_INT(2, count_color_chars("\tRhello"));
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* count_non_protocol_chars
|
||||
* ========================================================= */
|
||||
|
||||
void test_count_non_protocol_chars_plain(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(5, count_non_protocol_chars("hello"));
|
||||
}
|
||||
|
||||
void test_count_non_protocol_chars_empty(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, count_non_protocol_chars(""));
|
||||
}
|
||||
|
||||
void test_count_non_protocol_chars_newlines_skipped(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(5, count_non_protocol_chars("\r\nhello"));
|
||||
}
|
||||
|
||||
void test_count_non_protocol_chars_bracket_tag(void)
|
||||
{
|
||||
/* "@[bold]hi" – "@[bold]" is a protocol tag; only "hi" counted */
|
||||
TEST_ASSERT_EQUAL_INT(2, count_non_protocol_chars("@[bold]hi"));
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* atoidx
|
||||
* ========================================================= */
|
||||
|
||||
void test_atoidx_valid_number(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(42, (int)atoidx("42"));
|
||||
}
|
||||
|
||||
void test_atoidx_zero(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, (int)atoidx("0"));
|
||||
}
|
||||
|
||||
void test_atoidx_negative_returns_nowhere(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT((int)NOWHERE, (int)atoidx("-1"));
|
||||
}
|
||||
|
||||
void test_atoidx_overflow_returns_nowhere(void)
|
||||
{
|
||||
/* IDXTYPE_MAX is 65535 on this build; a larger value overflows */
|
||||
TEST_ASSERT_EQUAL_INT((int)NOWHERE, (int)atoidx("99999999"));
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* right_trim_whitespace
|
||||
* ========================================================= */
|
||||
|
||||
void test_right_trim_whitespace_trailing_spaces(void)
|
||||
{
|
||||
char *r = right_trim_whitespace("hello ");
|
||||
TEST_ASSERT_EQUAL_STRING("hello", r);
|
||||
free(r);
|
||||
}
|
||||
|
||||
void test_right_trim_whitespace_no_trailing(void)
|
||||
{
|
||||
char *r = right_trim_whitespace("hello");
|
||||
TEST_ASSERT_EQUAL_STRING("hello", r);
|
||||
free(r);
|
||||
}
|
||||
|
||||
void test_right_trim_whitespace_all_whitespace(void)
|
||||
{
|
||||
char *r = right_trim_whitespace(" ");
|
||||
TEST_ASSERT_EQUAL_STRING("", r);
|
||||
free(r);
|
||||
}
|
||||
|
||||
void test_right_trim_whitespace_empty(void)
|
||||
{
|
||||
char *r = right_trim_whitespace("");
|
||||
TEST_ASSERT_EQUAL_STRING("", r);
|
||||
free(r);
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* remove_from_string
|
||||
* ========================================================= */
|
||||
|
||||
void test_remove_from_string_word_present(void)
|
||||
{
|
||||
char s[] = "hello world";
|
||||
remove_from_string(s, "world");
|
||||
/* "world" and the trailing NUL shift left; "hello " remains */
|
||||
TEST_ASSERT_EQUAL_STRING("hello ", s);
|
||||
}
|
||||
|
||||
void test_remove_from_string_word_absent(void)
|
||||
{
|
||||
char s[] = "hello world";
|
||||
remove_from_string(s, "nope");
|
||||
TEST_ASSERT_EQUAL_STRING("hello world", s);
|
||||
}
|
||||
|
||||
void test_remove_from_string_word_at_start(void)
|
||||
{
|
||||
char s[] = "hello world";
|
||||
remove_from_string(s, "hello");
|
||||
/* "hello" removed; " world" remains */
|
||||
TEST_ASSERT_EQUAL_STRING(" world", s);
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* real_time_passed
|
||||
* ========================================================= */
|
||||
|
||||
void test_real_time_passed_hours(void)
|
||||
{
|
||||
time_t base = 1000000;
|
||||
struct time_info_data *t = real_time_passed(base + 3 * SECS_PER_REAL_HOUR, base);
|
||||
TEST_ASSERT_EQUAL_INT(3, t->hours);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->day);
|
||||
}
|
||||
|
||||
void test_real_time_passed_days(void)
|
||||
{
|
||||
time_t base = 1000000;
|
||||
struct time_info_data *t = real_time_passed(base + 2 * SECS_PER_REAL_DAY + SECS_PER_REAL_HOUR, base);
|
||||
TEST_ASSERT_EQUAL_INT(1, t->hours);
|
||||
TEST_ASSERT_EQUAL_INT(2, t->day);
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* mud_time_passed
|
||||
* ========================================================= */
|
||||
|
||||
void test_mud_time_passed_hours(void)
|
||||
{
|
||||
time_t base = 1000000;
|
||||
struct time_info_data *t = mud_time_passed(base + 2 * SECS_PER_MUD_HOUR, base);
|
||||
TEST_ASSERT_EQUAL_INT(2, t->hours);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->day);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->month);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->year);
|
||||
}
|
||||
|
||||
void test_mud_time_passed_days(void)
|
||||
{
|
||||
time_t base = 1000000;
|
||||
struct time_info_data *t = mud_time_passed(base + SECS_PER_MUD_DAY, base);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->hours);
|
||||
TEST_ASSERT_EQUAL_INT(1, t->day);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->month);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->year);
|
||||
}
|
||||
|
||||
void test_mud_time_passed_months(void)
|
||||
{
|
||||
time_t base = 1000000;
|
||||
struct time_info_data *t = mud_time_passed(base + SECS_PER_MUD_MONTH, base);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->hours);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->day);
|
||||
TEST_ASSERT_EQUAL_INT(1, t->month);
|
||||
TEST_ASSERT_EQUAL_INT(0, t->year);
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* main
|
||||
* ========================================================= */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
/* prune_crlf */
|
||||
RUN_TEST(test_prune_crlf_strips_crlf);
|
||||
RUN_TEST(test_prune_crlf_strips_lf_only);
|
||||
RUN_TEST(test_prune_crlf_no_op_on_clean);
|
||||
RUN_TEST(test_prune_crlf_multiple_trailing);
|
||||
|
||||
/* str_cmp */
|
||||
RUN_TEST(test_str_cmp_equal_strings);
|
||||
RUN_TEST(test_str_cmp_case_insensitive);
|
||||
RUN_TEST(test_str_cmp_ordering_less);
|
||||
RUN_TEST(test_str_cmp_ordering_greater);
|
||||
RUN_TEST(test_str_cmp_empty_equal);
|
||||
|
||||
/* strn_cmp */
|
||||
RUN_TEST(test_strn_cmp_equal_prefix);
|
||||
RUN_TEST(test_strn_cmp_differ_past_n);
|
||||
RUN_TEST(test_strn_cmp_differ_within_n);
|
||||
|
||||
/* sprintbit */
|
||||
RUN_TEST(test_sprintbit_no_bits_set);
|
||||
RUN_TEST(test_sprintbit_single_bit);
|
||||
RUN_TEST(test_sprintbit_multiple_bits);
|
||||
RUN_TEST(test_sprintbit_undefined_bit);
|
||||
|
||||
/* sprinttype */
|
||||
RUN_TEST(test_sprinttype_valid_index_zero);
|
||||
RUN_TEST(test_sprinttype_valid_index_one);
|
||||
RUN_TEST(test_sprinttype_out_of_range);
|
||||
|
||||
/* levenshtein_distance */
|
||||
RUN_TEST(test_levenshtein_identical_strings);
|
||||
RUN_TEST(test_levenshtein_empty_and_nonempty);
|
||||
RUN_TEST(test_levenshtein_single_insertion);
|
||||
RUN_TEST(test_levenshtein_single_deletion);
|
||||
RUN_TEST(test_levenshtein_single_substitution);
|
||||
RUN_TEST(test_levenshtein_both_empty);
|
||||
|
||||
/* count_color_chars */
|
||||
RUN_TEST(test_count_color_chars_no_codes);
|
||||
RUN_TEST(test_count_color_chars_empty);
|
||||
RUN_TEST(test_count_color_chars_single_color_code);
|
||||
RUN_TEST(test_count_color_chars_double_tab);
|
||||
RUN_TEST(test_count_color_chars_mixed);
|
||||
|
||||
/* count_non_protocol_chars */
|
||||
RUN_TEST(test_count_non_protocol_chars_plain);
|
||||
RUN_TEST(test_count_non_protocol_chars_empty);
|
||||
RUN_TEST(test_count_non_protocol_chars_newlines_skipped);
|
||||
RUN_TEST(test_count_non_protocol_chars_bracket_tag);
|
||||
|
||||
/* atoidx */
|
||||
RUN_TEST(test_atoidx_valid_number);
|
||||
RUN_TEST(test_atoidx_zero);
|
||||
RUN_TEST(test_atoidx_negative_returns_nowhere);
|
||||
RUN_TEST(test_atoidx_overflow_returns_nowhere);
|
||||
|
||||
/* right_trim_whitespace */
|
||||
RUN_TEST(test_right_trim_whitespace_trailing_spaces);
|
||||
RUN_TEST(test_right_trim_whitespace_no_trailing);
|
||||
RUN_TEST(test_right_trim_whitespace_all_whitespace);
|
||||
RUN_TEST(test_right_trim_whitespace_empty);
|
||||
|
||||
/* remove_from_string */
|
||||
RUN_TEST(test_remove_from_string_word_present);
|
||||
RUN_TEST(test_remove_from_string_word_absent);
|
||||
RUN_TEST(test_remove_from_string_word_at_start);
|
||||
|
||||
/* real_time_passed */
|
||||
RUN_TEST(test_real_time_passed_hours);
|
||||
RUN_TEST(test_real_time_passed_days);
|
||||
|
||||
/* mud_time_passed */
|
||||
RUN_TEST(test_mud_time_passed_hours);
|
||||
RUN_TEST(test_mud_time_passed_days);
|
||||
RUN_TEST(test_mud_time_passed_months);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
Reference in New Issue
Block a user