Skip to content

Dummies: let AnyDictionary pin the value for a required key #288

Description

@Reefact

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:

  1. 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.)
  2. 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().
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions