Unit Tests
Dawn unit tests live in dawn/tests/ and are built into a standalone
dawntest application that runs inside the NuttX simulator. Tests use
a Unity-based harness with lightweight local mocks. Every source file
under dawn/src/ has a corresponding test file.
They run automatically as part of dawnpy-tests (the
Simulator unit tests step, nsh_tests config).
Organization
dawn/tests/
├── common/ - object system, descriptor, bindable, handler
├── io/ - all IO type implementations
├── prog/ - all PROG type implementations
├── proto/ - all PROTO type implementations
├── dev/ - descriptor and inspector subsystems
├── porting/ - NuttX platform abstraction layer
└── mocks/ - shared fake and spy helpers
Running Selected Tests
dawntest --list # list modules
dawntest --module io # run one module
dawntest --test io.test_io_handler_user_factory # run one case
dawntest --prefix proto. # run by prefix
Mocking Conventions
Mocks in dawn/tests/mocks/ follow two conventions:
Fake - deterministic behaviour, no call tracking.
Spy - fake behaviour plus call recording via
MockTrace(dawn/tests/include/test_mock_expect.hxx).
Common spy assertions:
ASSERT_CALLS(trace, "create", N);
ASSERT_CALL_ORDER(trace, expected_order);
ASSERT_CALL_AT(trace, idx, "create", id);
Test Style
A test case exercises one behaviour. If you find yourself writing
“first do X, then do Y, then do Z”, write three test cases instead of
one. Keeping cases small means a failure points at the exact behaviour
that broke instead of a 200-line lifecycle, and re-running a single
scenario is one dawntest --test ... invocation.
Guidelines:
One behaviour per case. A read-back test is separate from a write-back test. A bool case is separate from a uint32 case. An out-of-range error path is its own case, not an extra assert glued onto the happy path.
Soft size target: ~50 lines per case. Boilerplate setup is excluded - factor repeated configure/init/bind sequences into file-local static helpers. A case over 100 lines must carry a comment explaining why splitting is impractical.
Naming:
test_<module>_<feature>_<scenario>- e.g.test_io_limits_validate_uint32_boundaries,test_proto_can_push_bool. The scenario is the differentiator; prefer concrete names (read_out_of_range) over generic ones (error).One Description block per case. The existing
// Description: ...banner above the function is a one-line summary of what the case asserts, in plain English.Helpers stay file-local. Promote a helper to a shared header in
dawn/tests/include/only when three or more files reuse it.