Files
cproof-context/playbooks/add-test.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

2.4 KiB

Playbook: add a unit test file

Recipe for a new tests/unittests/test_<topic>.c + .h pair.

1. Create the header

tests/unittests/test_<topic>.h:

#ifndef TEST_<TOPIC>_H
#define TEST_<TOPIC>_H

void test_<topic>_<scenario_1>(void** state);
void test_<topic>_<scenario_2>(void** state);

#endif

One declaration per test function. Headers exist solely so unittests.c can include them and reference each function symbol.

2. Create the source

tests/unittests/test_<topic>.c:

#include "config.h"
#include "prof_cmocka.h"

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>

#include "test_<topic>.h"
// ... includes for the unit under test and any types it needs ...

void
test_<topic>_<scenario_1>(void** state)
{
    // Arrange — `will_return`, `expect_string`, etc.
    // Act    — call the unit
    // Assert — `assert_*`
}

3. Register in unittests.c

#include "test_<topic>.h"

// inside the tests[] array passed to cmocka_run_group_tests:
cmocka_unit_test(test_<topic>_<scenario_1>),
cmocka_unit_test(test_<topic>_<scenario_2>),

If multiple tests share fixture, add a setup / teardown pair and use cmocka_unit_test_setup_teardown (or define a per-topic macro near the top of unittests.c, like muc_unit_test).

4. Stubs

For each external function the unit calls, ensure a stub exists in the matching tests/unittests/<module>/stub_*.c. Three flavours:

  • Pass-through — no observation needed.
  • mock() / will_return — test injects return values.
  • check_expected() / expect_* — test asserts arguments.

See testing/stubs.md.

5. Wire into Make

tests/unittests/Makefile.am (or the active wiring file): add test_<topic>.c to the unittests_SOURCES (or equivalent) list. Same for any new stub file.

6. Build & run

Inside Docker:

./autogen.sh && ./configure && make -j$(nproc) check

Diagnose failures via tests/unittests/unittests.log and the cmocka stderr output.

7. Conventions

  • Test functions: test_<topic>_<scenario> — never test_topic1, test_topic2. Names should describe the scenario.
  • One assertion focus per test (multiple assert_* calls are fine; multiple unrelated assertions are not).
  • Don't reuse stubs across topic suites unless the call truly is uniform — diverging behaviour is a strong sign you want a dedicated stub.
  • No I/O in unit tests. Filesystem, network, ncurses are all stubbed.