diff --git a/Dummies.UnitTests/AnyCollectionTests.cs b/Dummies.UnitTests/AnyCollectionTests.cs index 6fac877..c62d724 100644 --- a/Dummies.UnitTests/AnyCollectionTests.cs +++ b/Dummies.UnitTests/AnyCollectionTests.cs @@ -351,6 +351,19 @@ public void DictionaryContainingKeyInsideDomainDoesNotInflate() { Check.That(conflict.Message).Contains("2 distinct value"); } + [Fact(DisplayName = "ContainingAnyKey: a key drawn from a generator is forced into the dictionary; null is rejected (issue #287).")] + public void DictionaryContainingAnyKeyForcesADrawnKey() { + // The drawn key (4242) lies outside the key generator's own {1..9} domain, so it is supplied directly and + // extends the effective cardinality — the ContainingAny path, now reaching dictionary keys. + for (int i = 0; i < SampleCount; i++) { + Dictionary dictionary = + Any.DictionaryOf(Any.Int32().Between(1, 9), Any.String().NonEmpty()).NonEmpty().ContainingAnyKey(Any.Int32().OneOf(4242)).Generate(); + Check.That(dictionary.ContainsKey(4242)).IsTrue(); + } + + Check.ThatCode(() => Any.DictionaryOf(Any.Int32(), Any.Int32()).ContainingAnyKey(null!)).Throws(); + } + [Fact(DisplayName = "PairOf and TripleOf assemble value tuples from constrained parts.")] public void PairAndTriple() { for (int i = 0; i < SampleCount; i++) { diff --git a/Dummies/AnyDictionary.cs b/Dummies/AnyDictionary.cs index 38933ae..4009c6c 100644 --- a/Dummies/AnyDictionary.cs +++ b/Dummies/AnyDictionary.cs @@ -95,6 +95,23 @@ public AnyDictionary ContainingKey(TKey key) { return With(_keys.WithContaining(key, $"ContainingKey({AnyDerivation.Display(key)})")); } + /// + /// Requires the dictionary to contain an entry whose key is drawn from at + /// generation time — the key analogue of a collection's ContainingAny. Named apart from + /// to keep the two cases legible: pins a concrete + /// key known now, whereas this draws one from a generator when the dictionary is built. The drawn key takes + /// one entry's room and its value is generated like any other. + /// + /// The generator whose drawn key the dictionary must contain. + /// A new generator carrying the added constraint. + /// Thrown when is null. + /// Thrown when the constraint contradicts a constraint already declared. + public AnyDictionary ContainingAnyKey(IAny generator) { + if (generator is null) { throw new ArgumentNullException(nameof(generator)); } + + return With(_keys.WithContaining(generator, "ContainingAnyKey()")); + } + /// public Dictionary Generate() { List keys = _keys.Materialize(_source ?? AmbientRandomSource.Instance); diff --git a/Dummies/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/Dummies/PublicAPI/net8.0/PublicAPI.Unshipped.txt index 913325c..078d195 100644 --- a/Dummies/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/Dummies/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -116,6 +116,7 @@ Dummies.AnyDecimal.OneOf(params decimal[]! values) -> Dummies.AnyDecimal! Dummies.AnyDecimal.Positive() -> Dummies.AnyDecimal! Dummies.AnyDecimal.Zero() -> Dummies.AnyDecimal! Dummies.AnyDictionary +Dummies.AnyDictionary.ContainingAnyKey(Dummies.IAny! generator) -> Dummies.AnyDictionary! Dummies.AnyDictionary.ContainingKey(TKey key) -> Dummies.AnyDictionary! Dummies.AnyDictionary.Empty() -> Dummies.AnyDictionary! Dummies.AnyDictionary.Generate() -> System.Collections.Generic.Dictionary! diff --git a/Dummies/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/Dummies/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index 5bc982e..de183a7 100644 --- a/Dummies/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/Dummies/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -101,6 +101,7 @@ Dummies.AnyDecimal.OneOf(params decimal[]! values) -> Dummies.AnyDecimal! Dummies.AnyDecimal.Positive() -> Dummies.AnyDecimal! Dummies.AnyDecimal.Zero() -> Dummies.AnyDecimal! Dummies.AnyDictionary +Dummies.AnyDictionary.ContainingAnyKey(Dummies.IAny! generator) -> Dummies.AnyDictionary! Dummies.AnyDictionary.ContainingKey(TKey key) -> Dummies.AnyDictionary! Dummies.AnyDictionary.Empty() -> Dummies.AnyDictionary! Dummies.AnyDictionary.Generate() -> System.Collections.Generic.Dictionary!