Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions DEVLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5334,3 +5334,116 @@ NULL-callback / IP-stack-introspection paths were already in place.
-o -name '*.h'` which is the canonical safe form; restrict the
glob explicitly when batch-formatting, never trust extension
filtering inside the tool.

## 2026-05-10 — S24.02 CALLED_* test macro sweep + E24 rename

### Summary

Test-hygiene chore deferred from S12.18: every call-count assertion
across the test base now uses one of three intent-named macros backed
by a `<name>CallCount` token-paste rule. `Tests/Support/TestUtils.h`
hosts the macros; the enum stays in `CososoTesting` to ringfence the
NEVER/ONCE/TWICE/THRICE identifiers.

```c
CALLED_FUNCTION(handler, ONCE) // local static int counter
CALLED_FAKE(SocketFake_Send, TWICE) // global-state fake getter
CALLED_FAKE_ON(SenderFake_Send, inner, ONCE) // instance-parameter getter
```

Three pre-existing implementations folded into the new design:

- `CHECK_HANDLER_INVOKED_ONCE` / `CHECK_HANDLER_NOT_INVOKED` in
`SolidSyslogErrorTest.cpp` (tiny, hard-coded to one variable).
- The single expression-form `CALLED_FUNCTION(f, n)` already in
`Tests/TestUtils.h` and used by `SolidSyslogSwitchingSenderTest.cpp`
(every call site there was structurally a `CALLED_FAKE_ON` after the
SenderFake `*Count` → `*CallCount` rename).
- The bool flags `storeFullCallbackInvoked` /
`computeIntegrityCalled` / `verifyIntegrityCalled` in
`SolidSyslogBlockStoreTest.cpp` converted to int counters, so tests
now also catch unexpected double-fires.

Final per-file shape: every test executable (`SolidSyslogTests`,
`ExampleTests`, `SolidSyslogFreeRtosDatagramTest`, `CmsdkUartTest`,
`SolidSyslogFreeRtosSysUpTimeTest`, `SolidSyslogFreeRtosStaticResolverTest`,
plus the Winsock variants compiled in CI only) opts in via
`#include "TestUtils.h"` + `using namespace CososoTesting;`. 1088 host
tests + 50 FreeRtos host tests green; coverage 100% lines/functions
unchanged.

### Decisions

- **E24 renamed from "Hardening" to "Code Hygiene".** The epic body
was already written for cross-cutting non-functional sweeps; only
the title was wrong. Robustness-style "hardening" work lives in
E12 / E25 / E26 and didn't need its own home. S24.01 (IWYU) and
S24.02 (this story) both fit the renamed scope cleanly.
- **Reuse `TestUtils.h`, don't add a separate `CallCount.h`.** The
`CososoTesting` namespace + NEVER/ONCE/TWICE/THRICE enum already
lived there to ringfence common identifiers; introducing a parallel
header would have duplicated the enum or risked ODR drift. Moved
`TestUtils.h` from `Tests/` to `Tests/Support/` so non-`Tests/`-root
executables (Example, FreeRtos) inherit it through the established
Support include path rather than via implicit-source-dir lookup.
- **Three macros, not one.** A single macro can't both token-paste a
bare name (`fooCallCount`) and accept an arbitrary expression
(`fake.callCount()`) — the existing flexible expression form was
effectively `CALLED_FAKE_ON` with the rename done. Splitting into
CALLED_FUNCTION / CALLED_FAKE / CALLED_FAKE_ON keeps each call-site
declarative about whether it's a local counter, global getter, or
instance getter, and the token paste enforces the naming rule at
compile time.
- **Counter rename rule: `<functionName>CallCount`.** Functions keep
their existing names; counters are derived. This preferred renaming
the variable (`getPortCallCount` → `SpyGetPortCallCount`,
`storeFullCallbackCount` → `CountStoreFullInvocationsCallCount`)
over renaming the function. Verbose in a couple of places but
consistent — and `CALLED_FUNCTION(<funcName>, ONCE)` reads the same
way regardless of how long the function name is.
- **Bool → int even where the test only cared "was it called".**
Cheap upgrade in test power: a future double-fire bug now fails the
existing assertion rather than slipping through.
- **Skipped a `CountStoreFull/CountThresholdCrossings` rename.** The
function names already encode the intent ("count store-full
invocations"); the variable suffix mirroring is enough. Renaming
the function would have widened the diff for no reader benefit.

### Deferred

- **`spy.callCount` struct member in `ExampleInteractiveTest.cpp`.**
Different shape (member of a struct), low payoff to convert. Left
as raw `LONGS_EQUAL`; not a counter source the macro family is
designed to address. Out of scope per the story body.
- **`firstSocketCallCount` snapshot variable in
`SolidSyslogStreamSenderTest.cpp`.** It's a *snapshot* of a fake
getter's value at one point in time, not a counter that increments.
Name happens to end in `CallCount` but it doesn't fit the macro's
contract; left alone (and the assertion that uses it now passes the
expression as `count` to `CALLED_FAKE`, which works because the
macro accepts any integral expression).

### Open questions

- None. CI on the PR will exercise the Windows / OpenSSL integration
/ BDD jobs that aren't run locally; if the Winsock variants need a
follow-up tweak we'll see it on the PR check run.

### Process notes

- Per-file conversion was mechanical sed: literal counts 0/1/2/3
mapped to NEVER/ONCE/TWICE/THRICE, anything higher (e.g. the
12-setsockopt-calls site in `SolidSyslogStreamSenderTest`) passed
through as a numeric literal. Order matters in the sed cascade —
function-call-form patterns must run before bare-variable-form
patterns, otherwise the bare-variable regex eats the `CallCount\)`
inside `CallCount()\)`.
- Discovered partway through that `Tests/TestUtils.h` already had a
`CALLED_FUNCTION` macro (different signature) and a `CososoTesting`
namespace. The audit had missed it because the search was for
`*CallCount` patterns and the existing implementation took an
arbitrary expression. Surfaced and re-planned mid-stream rather
than blowing past it.
- Rebased onto main after the S12.18 DEVLOG (#320) squash-merged, and
pruned five `[gone]`-tracking local branches that survived earlier
squash merges.
12 changes: 8 additions & 4 deletions Tests/DatagramFakeTest.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#include "DatagramFake.h"
#include "SolidSyslogDatagram.h"
#include "TestUtils.h"
#include "CppUTest/TestHarness.h"

using namespace CososoTesting; // NOLINT(google-build-using-namespace) -- test-file scope only; brings NEVER/ONCE/TWICE/THRICE into scope for the CALLED_*
// macros

// clang-format off
TEST_GROUP(DatagramFake)
{
Expand All @@ -23,7 +27,7 @@ TEST(DatagramFake, CreateSucceeds)
TEST(DatagramFake, OpenIncrementsCount)
{
SolidSyslogDatagram_Open(datagram);
LONGS_EQUAL(1, DatagramFake_OpenCallCount(datagram));
CALLED_FAKE_ON(DatagramFake_Open, datagram, ONCE);
}

TEST(DatagramFake, OpenReturnsTrue)
Expand All @@ -35,7 +39,7 @@ TEST(DatagramFake, SendIncrementsCount)
{
const char payload[] = "hi";
SolidSyslogDatagram_SendTo(datagram, payload, sizeof(payload), nullptr);
LONGS_EQUAL(1, DatagramFake_SendCallCount(datagram));
CALLED_FAKE_ON(DatagramFake_Send, datagram, ONCE);
}

TEST(DatagramFake, SendDefaultsToSent)
Expand Down Expand Up @@ -64,7 +68,7 @@ TEST(DatagramFake, SendCapturesBufferAndSize)
TEST(DatagramFake, MaxPayloadIncrementsCount)
{
SolidSyslogDatagram_MaxPayload(datagram);
LONGS_EQUAL(1, DatagramFake_MaxPayloadCallCount(datagram));
CALLED_FAKE_ON(DatagramFake_MaxPayload, datagram, ONCE);
}

TEST(DatagramFake, MaxPayloadReturnsConfiguredValue)
Expand All @@ -76,5 +80,5 @@ TEST(DatagramFake, MaxPayloadReturnsConfiguredValue)
TEST(DatagramFake, CloseIncrementsCount)
{
SolidSyslogDatagram_Close(datagram);
LONGS_EQUAL(1, DatagramFake_CloseCallCount(datagram));
CALLED_FAKE_ON(DatagramFake_Close, datagram, ONCE);
}
14 changes: 9 additions & 5 deletions Tests/Example/ExampleServiceThreadTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@
#include "SocketFake.h"
#include "ClockFake.h"
#include "SolidSyslogPrival.h"
#include "TestUtils.h"
#include "CppUTest/TestHarness.h"

static int sleepCallCount;
using namespace CososoTesting; // NOLINT(google-build-using-namespace) -- test-file scope only; brings NEVER/ONCE/TWICE/THRICE into scope for the CALLED_*
// macros

static int SleepFakeCallCount;
static int lastSleepMs;
static volatile bool* sleepShutdownFlag;

static void SleepFake(int milliseconds)
{
sleepCallCount++;
SleepFakeCallCount++;
lastSleepMs = milliseconds;
if (sleepShutdownFlag != nullptr)
{
Expand Down Expand Up @@ -56,7 +60,7 @@ TEST_GROUP(ExampleServiceThread)
ClockFake_Reset();
ClockFake_SetTime(1743768600, 0);
shutdown = true;
sleepCallCount = 0;
SleepFakeCallCount = 0;
lastSleepMs = 0;
sleepShutdownFlag = nullptr;

Expand Down Expand Up @@ -91,7 +95,7 @@ TEST_GROUP(ExampleServiceThread)
TEST(ExampleServiceThread, DoesNotSendWhenBufferEmpty)
{
ExampleServiceThread_Run(&shutdown, SleepFake);
LONGS_EQUAL(0, SocketFake_SendtoCallCount());
CALLED_FAKE(SocketFake_Sendto, NEVER);
}

TEST(ExampleServiceThread, YieldsOneMillisecondAfterEachServiceTick)
Expand All @@ -101,6 +105,6 @@ TEST(ExampleServiceThread, YieldsOneMillisecondAfterEachServiceTick)

ExampleServiceThread_Run(&shutdown, SleepFake);

LONGS_EQUAL(1, sleepCallCount);
CALLED_FUNCTION(SleepFake, ONCE);
LONGS_EQUAL(1, lastSleepMs);
}
10 changes: 7 additions & 3 deletions Tests/Example/SolidSyslogExampleTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
#include "SolidSyslogExample.h"
#include "ClockFake.h"
#include "SocketFake.h"
#include "TestUtils.h"
#include "CppUTest/TestHarness.h"

using namespace CososoTesting; // NOLINT(google-build-using-namespace) -- test-file scope only; brings NEVER/ONCE/TWICE/THRICE into scope for the CALLED_*
// macros

static const char* const STDIN_SEND_ONE = "/tmp/solidsyslog_test_send1.txt";
static const char* const STDIN_SEND_THREE = "/tmp/solidsyslog_test_send3.txt";

Expand Down Expand Up @@ -84,7 +88,7 @@ TEST(SolidSyslogExample, RunWithNoArgsReturnsZero)
TEST(SolidSyslogExample, RunSendsOneMessage)
{
RunWithNoArgs();
LONGS_EQUAL(1, SocketFake_SendtoCallCount());
CALLED_FAKE(SocketFake_Sendto, ONCE);
}

TEST(SolidSyslogExample, DefaultMessageContainsLocal0InfoPrival)
Expand Down Expand Up @@ -147,7 +151,7 @@ TEST(SolidSyslogExample, SocketCreatedWithUdpDgram)
TEST(SolidSyslogExample, SocketClosedAfterRun)
{
RunWithNoArgs();
LONGS_EQUAL(1, SocketFake_CloseCallCount());
CALLED_FAKE(SocketFake_Close, ONCE);
}

TEST(SolidSyslogExample, MsgIdFlagAppearsInMessage)
Expand All @@ -167,7 +171,7 @@ TEST(SolidSyslogExample, SendCommandSendsMultipleMessages)
char arg0[] = "SolidSyslogExample";
char* argv[] = {arg0, nullptr};
Run(1, argv);
LONGS_EQUAL(3, SocketFake_SendtoCallCount());
CALLED_FAKE(SocketFake_Sendto, THRICE);
}

TEST(SolidSyslogExample, MessageFlagAppearsInMessage)
Expand Down
3 changes: 3 additions & 0 deletions Tests/FreeRtos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ else()
${CMAKE_SOURCE_DIR}/Platform/FreeRtos/Interface
${CMAKE_SOURCE_DIR}/Core/Interface
${CMAKE_SOURCE_DIR}/Core/Source
${CMAKE_SOURCE_DIR}/Tests/Support
${CMAKE_SOURCE_DIR}/Tests/Support/FreeRtosFakes/Interface
$ENV{FREERTOS_KERNEL_PATH}/include
$ENV{FREERTOS_PLUS_TCP_PATH}/source/include
Expand All @@ -53,6 +54,7 @@ else()
${CMAKE_SOURCE_DIR}/Platform/FreeRtos/Interface
${CMAKE_SOURCE_DIR}/Core/Interface
${CMAKE_SOURCE_DIR}/Core/Source
${CMAKE_SOURCE_DIR}/Tests/Support
${CMAKE_SOURCE_DIR}/Tests/Support/FreeRtosFakes/Interface
$ENV{FREERTOS_KERNEL_PATH}/include
$ENV{FREERTOS_PLUS_TCP_PATH}/source/include
Expand Down Expand Up @@ -104,6 +106,7 @@ target_link_libraries(CmsdkUartTest PRIVATE

target_include_directories(CmsdkUartTest PRIVATE
${CMAKE_SOURCE_DIR}/Example/FreeRtos/Common
${CMAKE_SOURCE_DIR}/Tests/Support
)

add_test(NAME CmsdkUartTest COMMAND CmsdkUartTest)
6 changes: 5 additions & 1 deletion Tests/FreeRtos/CmsdkUartTest.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include "TestUtils.h"
#include "CppUTest/TestHarness.h"

using namespace CososoTesting; // NOLINT(google-build-using-namespace) -- test-file scope only; brings NEVER/ONCE/TWICE/THRICE into scope for the CALLED_*
// macros

#include "CmsdkUart.h"
#include "CmsdkUartFake.h"

Expand Down Expand Up @@ -106,7 +110,7 @@ TEST(CmsdkUart, GetCharReturnsImmediatelyWhenReceiverHasByte)
CmsdkUartFake_SetReadsBeforeRxReady(0);
CmsdkUartFake_SetReceivedByte('X');
LONGS_EQUAL('X', CmsdkUart_GetChar());
LONGS_EQUAL(0, CmsdkUartFake_SleepCallCount());
CALLED_FAKE(CmsdkUartFake_Sleep, NEVER);
}

TEST(CmsdkUart, GetCharSpinsAfterReArmFromImmediateReadyToDelayedReady)
Expand Down
Loading
Loading