From e2751591c8c0cd51a0f01d20efdda559e736a34d Mon Sep 17 00:00:00 2001 From: Maizie Date: Mon, 9 Nov 2026 12:38:15 -0500 Subject: [PATCH 1/3] Add cmocka setup, smoke tests, and CI --- .github/workflows/ci.yml | 21 +++++++++++++++++++++ .gitignore | 5 +++++ Makefile | 17 +++++++++++++++++ tests/test_smoke.c | 17 +++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 tests/test_smoke.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3c53843 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI +on: + push: + branches: [main] + pull_request: + +jobs: + ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: sudo apt-get update && sudo apt-get install -y build-essential pkg-config libcmocka-dev + - run: make test + + fedora: + runs-on: ubuntu-latest + container: fedora:latest + steps: + - run: dnf install -y git gcc make pkgconf-pkg-config cmocka-devel libasan libubsan + - uses: actions/checkout@v4 + - run: make test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..74c5d43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + + +tests/test_* +!tests/test_*.c +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..66f8a26 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +CC ?= gcc +CFLAGS += -std=c11 -Wall -Wextra -g -Isrc +SAN = -fsanitize=address,undefined -fno-omit-frame-pointer +CMOCKA_LIBS := $(shell pkg-config --libs cmocka) + +TEST_SRCS := $(wildcard tests/test_*.c) +TESTS := $(TEST_SRCS:.c=) + +.PHONY: test clean +test: $(TESTS) + @for t in $(TESTS); do echo "== $$t"; ./$$t || exit 1; done + +tests/test_%: tests/test_%.c + $(CC) $(CFLAGS) $(SAN) $< $(wildcard src/$*.c) -o $@ $(CMOCKA_LIBS) $(WRAP_test_$*) + +clean: + rm -f $(TESTS) diff --git a/tests/test_smoke.c b/tests/test_smoke.c new file mode 100644 index 0000000..e05f9e5 --- /dev/null +++ b/tests/test_smoke.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +static void test_cmocka_works(void **state) { + (void)state; + assert_int_equal(1 + 1, 2); +} + +int main() { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_cmocka_works), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} From 254f35a01187cbe0af6dc5ac6647a8db3724e1bc Mon Sep 17 00:00:00 2001 From: Maizie Date: Mon, 9 Nov 2026 14:15:33 -0500 Subject: [PATCH 2/3] ci fedora error fix? --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c53843..d82e392 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,6 @@ jobs: runs-on: ubuntu-latest container: fedora:latest steps: - - run: dnf install -y git gcc make pkgconf-pkg-config cmocka-devel libasan libubsan + - run: dnf install -y git gcc make pkgconf-pkg-config libcmocka-devel libasan libubsan - uses: actions/checkout@v4 - run: make test From 572754e42ab295b4edef7c209bde0269aa0d24e2 Mon Sep 17 00:00:00 2001 From: Maizie Date: Mon, 9 Nov 2026 13:16:51 -0500 Subject: [PATCH 3/3] Add cmocka test template --- tests/template.c.example | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 tests/template.c.example diff --git a/tests/template.c.example b/tests/template.c.example new file mode 100644 index 0000000..34c9491 --- /dev/null +++ b/tests/template.c.example @@ -0,0 +1,78 @@ +/* cmocka test template + * + * HOW TO USE: + * 1. Copy this file: `cp tests/template.c.example tests/test_.c` - must match the src file name + * 2. Replace placeholders + * 3. Write tests + * 4. List every test created in the `tests[]` in main + * 5. Run: `make test` + * + * - list of common assertions at bottom + */ + +// these headers are required by cmocka - keep in order +#include +#include +#include +#include + +#include +//TODO: #include ".h" // header of the code under test + +// ex: basic test +static void test_(void **state) { + (void)state; + + // set up inputs + // call function under test + // check result + assert_int_equal(1 + 1, 2); //FIXME +} + +// ex: edge/error case +static void test_(void **state) { + (void)state; + assert_int_equal(my_function(NULL), -1); +} + +// ex: setup/teardown +static int setup(void **state) { + *state = malloc(sizeof(int)); + return (*state == NULL) ? -1 : 0; +} +static int teardown(void **state) { + free(*state); + return 0; +} + +// ex: mock syst call (needs a matching `WRAP_test_ line in Makefile - `WRAP_test_actions = -Wl,--wrap=kill`) +int __wrap_kill(pid_t pid, int sig) { + check_expected(pid); + check_expected(sig); + return mock_type(int); +} +/* to use in a test: + * expect_value(__wrap_kill, pid 1234); + * expect_value(__wrap_kill, sig, SIGTERM); + * will_return(__wrap_kill, 0); + */ + + +// register tests +int main(void) { + const struct CMUnitTest tests[] = { + cmock_unit_test(test_), + cmocka_unit_test_setup_teardown(test_x, setup, teardown), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} + +/* COMMON ASSERTIONS: + * assert_true(x) / assert_false(x) + * assert_int_equal(actual, expected) / assert_int_not_equal(a, b) + * assert_string_equal(actual, expected) + * assert_null(p) / assert_non_null(p) + * assert_float_equal(actual, expected, epsilon) + * assert_in_range(x, min, max) + * assert_memory_equal(a, b, size) + */