Agent-Logs-Url: https://github.com/tbamud/tbamud/sessions/dd8af74a-9ecb-485b-851a-96b38b3cfc79 Co-authored-by: welcor <357770+welcor@users.noreply.github.com>
4.4 KiB
tbaMUD Unit Testing
Updated 2026-04
Overview
tbaMUD has a C unit-test suite built on the
Unity framework. Tests live in the
tests/ directory alongside the vendored Unity source.
tests/
Makefile.in – Autoconf template; processed by configure
test_stubs.c – Weak-symbol stubs that satisfy mud headers
unity_to_junit.py – Converts Unity output to JUnit XML
test_class.c – Tests for src/class.c
test_interpreter.c – Tests for src/interpreter.c
test_random.c – Tests for src/random.c
test_utils.c – Tests for src/utils.c
vendor/unity/ – Vendored Unity test framework
Prerequisites
| Requirement | Notes |
|---|---|
| C compiler (gcc or clang) | Same compiler used to build the mud |
| GNU make | Any POSIX-compatible make works |
| Python 3 | Required only for JUnit XML conversion (unity_to_junit.py) |
| autoconf / configure | Already needed to build the mud |
Running the tests
Run ./configure from the repository root first (only needed once):
./configure
Then build and run all tests from the tests/ directory:
cd tests
make test
make test performs the following steps for each test binary:
- Compiles the test binary (if not already up to date).
- Runs the binary and captures stdout/stderr to
test-results/<name>.out. - Measures wall-clock elapsed time.
- Converts the Unity output to JUnit XML via
unity_to_junit.py, writingtest-results/<name>.xml. - Prints
[PASS] <name>or[FAIL] <name>and exits non-zero if any binary failed.
To build the test binaries without running them:
cd tests
make
To remove all test binaries and result files:
cd tests
make clean
Test suites
| Binary | Source under test | Test file |
|---|---|---|
test_utils |
src/utils.c, src/random.c |
test_utils.c |
test_random |
src/random.c, rand_number/dice in src/utils.c |
test_random.c |
test_interpreter |
src/interpreter.c |
test_interpreter.c |
test_class |
src/class.c |
test_class.c |
Writing a new test
Adding a test case to an existing suite
- Open the relevant
test_<name>.cfile. - Write a function with the signature
void test_my_feature(void). - Use Unity assertion macros such as
TEST_ASSERT_EQUAL_INT,TEST_ASSERT_NULL,TEST_ASSERT_TRUE, etc. - Register the function in the
main()block:RUN_TEST(test_my_feature);
Example:
void test_str_cmp_equal_strings(void)
{
TEST_ASSERT_EQUAL_INT(0, str_cmp("hello", "hello"));
}
Creating a new test suite
-
Create
tests/test_<module>.c. Copy the boilerplate from an existing suite: includeunity.h, definesetUp/tearDown(may be empty), write test functions, and provide amain()that callsUNITY_BEGIN(),RUN_TEST(...)for each function, andreturn UNITY_END();. -
Add the binary to
tests/Makefile.in:- Add the name to the
TESTSvariable. - Add a build rule:
test_<module>: $(UNITY_SRC) $(STUBS_SRC) $(UTILS_SRC) \ $(SRCDIR)/<module>.c test_<module>.c $(COMPILE) -o $@ $^ $(LIBS)
- Add the name to the
-
Re-run
./configurefrom the repository root to regeneratetests/Makefilefrom the updatedtests/Makefile.in.
Stubs
Many mud source files reference global variables and functions that are only
meaningful at runtime (e.g. descriptor_list, log()). test_stubs.c
provides zero-initialised definitions and __attribute__((weak)) stub
implementations for these symbols so that test binaries link without pulling
in the full mud.
If a new test requires a function not yet stubbed, add a weak stub to
test_stubs.c:
__attribute__((weak)) void my_function(void) { /* no-op */ }
JUnit XML output and CI
unity_to_junit.py reads Unity's line-oriented output on stdin and writes a
JUnit-compatible XML file. It accepts an optional third argument with the
elapsed wall-clock time in seconds (provided by the make test target):
usage: unity_to_junit.py <suite_name> <output.xml> [elapsed_seconds]
The GitHub Actions workflow (.github/workflows/build.yml) runs make test
on every push and pull request against master. After the tests finish the
dorny/test-reporter action reads tests/test-results/*.xml and publishes a
formatted report as a GitHub Check with pass/fail counts and per-suite
execution times.