Summary
Declaring more than one always_expect() for the same mocked function keeps only the first; each later one is discarded with a message that's easy to misread. This also surfaces a feature gap: there's no way to have several persistent expectations routed by their when() matchers.
Observed behaviour
Two always_expects on one function, differing only in when():
always_expect(listFilesInDirectory, when(dirPath, is_equal_to_string("/a")), will_return(listA));
always_expect(listFilesInDirectory, when(dirPath, is_equal_to_string("/b")), will_return(listB));
The second emits, at its declaration line:
Mocked function [listFilesInDirectory] already has an expectation and will always be called a certain way; any expectations declared after an always expectation are discarded
Only the first always-expectation stays live.
Why the wording misleads
"will always be called a certain way" reads as a claim about the constraints (that they must match), rather than the actual rule: only one always expectation per function; later ones are dropped. It also names no workaround. Something like:
▎ "function 'X' already has an 'always' expectation; cgreen allows only one per function,
▎ so this one is discarded — use sequential expect() for differing per-call results"
would point straight at the fix.
Underlying feature gap
The triggering use was a recursive directory walk calling listFilesInDirectory(dir) an arbitrary number of times across arbitrary dirs — wanting "persistent, return routed by the dir argument." Neither FIFO expect() (order-coupled) nor a single always_expect() fits.
gmock-style argument-matched repeats (EXPECT_CALL(m, f(Eq(x))).WillRepeatedly(...)) would cover it.
Open question (not verified against source)
Does a single always_expect() with a when() actually verify its constraint per call? We only observed the "second-and-later discarded" behaviour, not this. A 3-case check would settle it: single-always satisfied / single-always violated / two routed by when.
Context
Surfaced from real usage (c-xrefactory) mocking a recursive filesystem walk; filed at suspicion level. (Drafted via Claude Code.)
Summary
Declaring more than one always_expect() for the same mocked function keeps only the first; each later one is discarded with a message that's easy to misread. This also surfaces a feature gap: there's no way to have several persistent expectations routed by their when() matchers.
Observed behaviour
Two always_expects on one function, differing only in when():
always_expect(listFilesInDirectory, when(dirPath, is_equal_to_string("/a")), will_return(listA));
always_expect(listFilesInDirectory, when(dirPath, is_equal_to_string("/b")), will_return(listB));
The second emits, at its declaration line:
Only the first always-expectation stays live.
Why the wording misleads
"will always be called a certain way" reads as a claim about the constraints (that they must match), rather than the actual rule: only one always expectation per function; later ones are dropped. It also names no workaround. Something like:
▎ "function 'X' already has an 'always' expectation; cgreen allows only one per function,
▎ so this one is discarded — use sequential expect() for differing per-call results"
would point straight at the fix.
Underlying feature gap
The triggering use was a recursive directory walk calling listFilesInDirectory(dir) an arbitrary number of times across arbitrary dirs — wanting "persistent, return routed by the dir argument." Neither FIFO expect() (order-coupled) nor a single always_expect() fits.
gmock-style argument-matched repeats (EXPECT_CALL(m, f(Eq(x))).WillRepeatedly(...)) would cover it.
Open question (not verified against source)
Does a single always_expect() with a when() actually verify its constraint per call? We only observed the "second-and-later discarded" behaviour, not this. A 3-case check would settle it: single-always satisfied / single-always violated / two routed by when.
Context
Surfaced from real usage (c-xrefactory) mocking a recursive filesystem walk; filed at suspicion level. (Drafted via Claude Code.)