Files
cproof-context/testing/unit-tests.md
jabber.developer2 22977846a3 docs: split context into layered, agent-oriented files
Replace the single file-structure.md with a stratified layout designed
for AI/agent skill consumption: tables and concrete identifiers over
prose, files loaded on demand, content separated by churn rate.

Layers:
- architecture/  stable structural reference (overview, source-map,
                 test-map, data-flow)
- patterns/      memory, commands, autocomplete, events, xmpp,
                 encryption, ui, plugins
- testing/       unit-tests, stubs, functional-tests, bench
- build/         local, docker, ci
- playbooks/     add-command, add-test, add-autocomplete,
                 add-event-handler, add-encryption
- gotchas.md     append-only dated entries (seven seed entries)
- wip/           branch-specific notes; deleted on merge to master

Stable layers describe cproof on master only. In-flight feature
branches (currently feat/ai) get a single file under wip/.

INDEX.md is the entry map with churn labels; SKILL.md is the
always-loaded skill hint pointing to it.
2026-04-30 20:52:06 +03:00

3.1 KiB

Unit tests

Framework: cmocka, accessed via tests/prof_cmocka.h (a thin compatibility wrapper). Run via make check.

File layout

  • One test file per topic: tests/unittests/test_<topic>.c + matching test_<topic>.h.
  • Header declares each test function (one per cmocka_unit_test*).
  • Runner: tests/unittests/unittests.c#includes every header, calls cmocka_run_group_tests() over a single big array.

Registration

Inside unittests.c, every test name appears in the array passed to cmocka_run_group_tests:

const struct CMUnitTest tests[] = {
    cmocka_unit_test(test_caps_show_basic),
    cmocka_unit_test_setup_teardown(test_join_room, muc_before_test, muc_after_test),
    // ...
};

Convenience macros are defined near the top, e.g.:

#define muc_unit_test(f) cmocka_unit_test_setup_teardown(f, muc_before_test, muc_after_test)

Test function shape

void
test_account_set_jid_succeeds(void** state)
{
    // Arrange
    will_return(connection_get_status, JABBER_CONNECTED);
    will_return(session_get_account_name, "alice@example.com");

    ProfAccount* account = account_new("alice@example.com", ...);
    will_return(accounts_get_account, account);

    // Act
    gchar* args[] = { "set", "alice@example.com", "jid", "alice@example.org", NULL };
    gboolean ok = cmd_account(NULL, CMD_ACCOUNT, args);

    // Assert
    assert_true(ok);
}

cmocka primitives in heavy use

Primitive When
will_return(fn, value) Queue a return value for a stubbed function. Each call to the stub pops one.
will_return_count(fn, value, n) Queue the same value n times.
expect_string(fn, param, "...") Stub asserts that the named argument equals this string.
expect_value(fn, param, value) Stub asserts equality on a non-string.
expect_any(fn, param) Stub accepts any value (still pops the queue).
assert_true / assert_false / assert_string_equal / assert_int_equal Assertions inside the test.
cmocka_unit_test(fn) Plain registration.
cmocka_unit_test_setup_teardown(fn, setup, teardown) With per-test fixture.

expect_* queues are checked at test end — missing calls fail the test.

Group setup / teardown

For sets of tests sharing fixture: define a _setup and _teardown and register via cmocka_unit_test_setup_teardown. Examples in unittests.c: muc_before_test, muc_after_test, keyhandlers_setup, keyhandlers_teardown.

What gets stubbed

Tests run against the production .c files of the unit under test, with stubs replacing all dependencies. See testing/stubs.md for the layout. Standard idiom: every external function the unit calls must have a stub returning either a fixed value or a will_return-driven one.

Running a single test

make check runs everything. To narrow:

./tests/unittests/unittests --filter <test_name_pattern>

(Confirm via unittests --help; cmocka filter support depends on version.)

See also

  • testing/stubs.md — adding/extending stubs.
  • playbooks/add-test.md — adding a new test file end-to-end.