Problem
AnyDictionary.ContainingKey(TKey) (added in #286) forces a key into the generated dictionary, but its value is still drawn arbitrarily from the value generator like any other entry. A test that needs a dictionary containing a specific key/value pair — e.g. { "status": "active", ... } with the rest arbitrary — cannot express it today.
Unlike the other containment methods, this is not a free routing to CollectionState: keys flow through CollectionState<TKey>, but values are produced per key in AnyDictionary.Generate() (dictionary[key] = _values.Generate()), which has no notion of a pinned value. It needs new state.
Direction (to be decided)
Add a way to pin a value for a required key. Open questions for the maintainer:
- Name / shape.
Containing(TKey key, TValue value) reads naturally but is inconsistent with ContainingKey; ContainingEntry(TKey, TValue) or a chained ContainingKey(TKey).WithValue(TValue) are alternatives. (Lean: ContainingEntry(TKey, TValue), keeping every Containing* on a dictionary explicit about what it pins.)
- Mechanism. Carry a
TKey → TValue association on AnyDictionary (alongside the key CollectionState); force each pinned key in through the existing key containment, then in Generate() consult the association before falling back to _values.Generate().
- Semantics / conflicts.
- A pinned key implies
ContainingKey, so it inherits the out-of-domain cardinality credit.
- Pinning the same key twice, or pinning a key also required via a plain
ContainingKey, needs a defined rule (last-wins vs. eager ConflictingAnyConstraintException).
- Behaviour under a custom key comparer (two keys equal under the comparer).
Acceptance criteria (subject to the naming decision)
Any.DictionaryOf(keys, values).<pin>(k, v) produces a dictionary where dict[k] equals v, the rest of the entries arbitrary, with the same out-of-domain cardinality crediting as ContainingKey(k).
- A conflicting or duplicate pin fails eagerly with a clear
ConflictingAnyConstraintException (or the agreed rule).
- The new member(s) are declared in both per-TFM
PublicAPI.Unshipped.txt baselines.
- Tests cover the happy path, an out-of-domain key, and the conflict/duplicate rule.
Context
Follow-up to #225 / #286. #225's Direction listed Containing(TKey, TValue) as an optional item; it was intentionally deferred from #286 because — unlike ContainingKey, which routes straight to CollectionState — it needs new value-pinning state and an API-naming decision.
Problem
AnyDictionary.ContainingKey(TKey)(added in #286) forces a key into the generated dictionary, but its value is still drawn arbitrarily from the value generator like any other entry. A test that needs a dictionary containing a specific key/value pair — e.g.{ "status": "active", ... }with the rest arbitrary — cannot express it today.Unlike the other containment methods, this is not a free routing to
CollectionState: keys flow throughCollectionState<TKey>, but values are produced per key inAnyDictionary.Generate()(dictionary[key] = _values.Generate()), which has no notion of a pinned value. It needs new state.Direction (to be decided)
Add a way to pin a value for a required key. Open questions for the maintainer:
Containing(TKey key, TValue value)reads naturally but is inconsistent withContainingKey;ContainingEntry(TKey, TValue)or a chainedContainingKey(TKey).WithValue(TValue)are alternatives. (Lean:ContainingEntry(TKey, TValue), keeping everyContaining*on a dictionary explicit about what it pins.)TKey → TValueassociation onAnyDictionary(alongside the keyCollectionState); force each pinned key in through the existing key containment, then inGenerate()consult the association before falling back to_values.Generate().ContainingKey, so it inherits the out-of-domain cardinality credit.ContainingKey, needs a defined rule (last-wins vs. eagerConflictingAnyConstraintException).Acceptance criteria (subject to the naming decision)
Any.DictionaryOf(keys, values).<pin>(k, v)produces a dictionary wheredict[k]equalsv, the rest of the entries arbitrary, with the same out-of-domain cardinality crediting asContainingKey(k).ConflictingAnyConstraintException(or the agreed rule).PublicAPI.Unshipped.txtbaselines.Context
Follow-up to #225 / #286. #225's Direction listed
Containing(TKey, TValue)as an optional item; it was intentionally deferred from #286 because — unlikeContainingKey, which routes straight toCollectionState— it needs new value-pinning state and an API-naming decision.