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.
3.1 KiB
Stubs
Unit tests link against the unit-under-test plus a parallel set of "stub"
implementations of every dependency. Stubs are organised by module under
tests/unittests/<module>/.
Layout
| Stub directory | Replaces |
|---|---|
tests/unittests/chatlog/ |
src/chatlog.c |
tests/unittests/command/ |
parts of src/command/ |
tests/unittests/config/ |
src/config/ (accounts, cafile, ...) |
tests/unittests/database/ |
src/database.c |
tests/unittests/event/ |
src/event/ |
tests/unittests/log/ |
src/log.c |
tests/unittests/omemo/ |
src/omemo/ |
tests/unittests/otr/ |
src/otr/ |
tests/unittests/pgp/ |
src/pgp/ |
tests/unittests/plugins/ |
src/plugins/ |
tests/unittests/tools/ |
src/tools/ |
tests/unittests/ui/ |
src/ui/ |
tests/unittests/xmpp/ |
src/xmpp/ |
tests/unittests/unittests/ |
top-level utility stubs |
Files are named stub_<module>.c (sometimes split, e.g.
tests/unittests/config/stub_accounts.c, stub_cafile.c).
Two stub flavours
Pass-through default
Returns a benign default (NULL, FALSE, 0). Used when the test does not care about the call.
void
chatlog_msg_in(...)
{
// no-op
}
will_return-driven
The stub pops a value queued by the test:
jabber_conn_status_t
connection_get_status(void)
{
return (jabber_conn_status_t)mock();
}
Test side:
will_return(connection_get_status, JABBER_CONNECTED);
If the stub is will_return-driven, every test that exercises a code
path through it must queue a value, or cmocka aborts.
expect_*-driven
The stub asserts argument values against expectations:
void
cons_bad_cmd_usage(const char* const cmd)
{
check_expected(cmd);
}
Test side:
expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT);
When to add a stub
- You call a new function from production code, and the call site is reachable from a unit test.
make checklink fails with an undefined-symbol error.
Procedure:
- Locate the matching stub module by callee path:
src/foo/bar.c→tests/unittests/foo/stub_bar.c. Create the stub file if absent. - Stub the new function with the right flavour:
- Pass-through if tests don't need to observe / drive it.
mock()if a test needs to inject a return value.check_expected()if a test needs to assert an argument.
- Wire the new stub
.cinto the build. Seetests/unittests/Makefile.am(or whatever wires the stubs into theunitteststarget).
When to extend an existing stub
If a stub already pass-through and a test now needs to drive it, change the
stub to mock(). Then every test (existing and new) reaching that stub
must will_return — be ready to update unrelated tests.
Convention notes
- Stubs do not include real headers from
src/<module>/if doing so would pull in the very symbol they replace. Forward-declare instead. tests/unittests/ui/stub_ai.cis a UI-side stub for the AI client surface consumed bysrc/ui/.- The
tests/unittests/unittests/directory holds top-level catch-alls that do not fit a single module.