feat!: only expose indexer accessors the mock intercepts - #830
Conversation
A generated mock advertised setup and verification for both accessors of
every indexer, even when it intercepted only one. For a get-only indexer
int this[string shelf] { get; }
Setup[...].OnSet and Verify[...].Set(3) compiled and silently did
nothing: no setter body is emitted, so a write can never be recorded and
the verification could only ever report zero.
The generator now picks the facade from the accessors it actually emits
a body for, mirroring the property narrowing:
- IIndexerGetterOnlySetup<TValue, T1..Tn> / IIndexerSetterOnlySetup<
TValue, T1..Tn> (arities 1-4) replace IndexerSetup<TValue, T1..Tn> on
the setup surface, with parallel getter-only and setter-only builder
hierarchies so chaining through Returns/Throws/Do/TransitionTo stays
on the narrowed surface, plus Forever/OnlyOnce extensions for the
narrowed when-builders.
- VerificationIndexerGetterResult<TSubject, T1..Tn> and
VerificationIndexerSetterResult<TSubject, T1..Tn, TParameter> replace
VerificationIndexerResult<TSubject, TParameter> on the verify surface,
each taking only the member id of the accessor it exposes.
GetIndexerInterceptedAccessors reuses the property classification keyed
on the same Getter/Setter nullity that guards body emission, so the
surface cannot drift from what the proxy intercepts. This also covers
the cross-assembly case: an indexer such as { get; internal set; } whose
setter is invisible to the mock's assembly narrows to the getter.
BREAKING CHANGE: on an indexer the mock reads or writes but not both,
Setup[...].OnSet/OnGet, Setup[...].Returns/Throws/InitializeWith and
Verify[...].Set(...)/Got() no longer compile for the absent accessor.
Each previously compiled and silently had no effect. The library API is
additive; only generated mock surfaces narrow. Indexers with more than
four keys keep the full surface, as their setup types are generated
per-compilation.
🚀 Benchmark ResultsDetails
Details
Details
Details
Details
Details
|
- add a cross-assembly test proving an indexer whose getter is inaccessible narrows to the setter-only surface - add a generator test proving indexers with more than four keys keep the full, unnarrowed surface for asymmetric accessors - link Mockolate0002 from the indexer single-accessor docs section, mirroring the property page - correct the AppendIndexerVerifyType summary: the setter result is additionally keyed by the value type
|
…e mock intercepts (#830) by Valentin Breuß
…e mock intercepts (#830) by Valentin Breuß
The accessor narrowing introduced for indexers (#830) stopped at four keys: the narrowed setup/verify types only ship with the library for arities 1-4, so a five-key get-only indexer still offered OnSet and Verify[...].Set(...), which compiled and silently did nothing. Since the setup types for indexers with more than four keys are generated per-compilation anyway, generate the narrowed surface there too: - IndexerSetups.g.cs now emits IIndexerGetterOnlySetup / IIndexerSetterOnlySetup interface hierarchies (builders included) for each affected arity, implements them on the generated IndexerSetup class, and adds the Forever/OnlyOnce extensions for the narrowed when-builders. - Narrowed VerificationIndexerGetterResult / -SetterResult classes are generated in Mockolate.Verify, dispatching through the predicate-based MockRegistry.IndexerGot/IndexerSet overloads that the full VerificationIndexerResult already uses above four keys. Each takes only the member id and predicate of the accessor it exposes. - The facade selection in the mock emission now uses the plain accessor classification for every arity; the narrowed hierarchies are only generated for arities that need them, keyed on the same Getter/Setter nullity that guards body emission. BREAKING CHANGE: on an indexer with more than four keys that the mock reads or writes but not both, Setup[...].OnSet/OnGet, Setup[...].Returns/Throws/InitializeWith and Verify[...].Set(...)/Got() no longer compile for the absent accessor. Each previously compiled and silently had no effect. This closes the gap the four-key narrowing left; the shipped library API is unchanged.
|
This is addressed in release v3.4.0. |



A generated mock advertised setup and verification for both accessors of every indexer, even when it intercepted only one. For a get-only indexer
Setup[...].OnSet and Verify[...].Set(3) compiled and silently did nothing: no setter body is emitted, so a write can never be recorded and the verification could only ever report zero.
The generator now picks the facade from the accessors it actually emits a body for, mirroring the property narrowing:
GetIndexerInterceptedAccessors reuses the property classification keyed on the same Getter/Setter nullity that guards body emission, so the surface cannot drift from what the proxy intercepts. This also covers the cross-assembly case: an indexer such as { get; internal set; } whose setter is invisible to the mock's assembly narrows to the getter.
BREAKING CHANGE: on an indexer the mock reads or writes but not both, Setup[...].OnSet/OnGet, Setup[...].Returns/Throws/InitializeWith and Verify[...].Set(...)/Got() no longer compile for the absent accessor. Each previously compiled and silently had no effect. The library API is additive; only generated mock surfaces narrow. Indexers with more than four keys keep the full surface, as their setup types are generated per-compilation.