diff --git a/Src/FluentAssertions/Common/DictionaryHelpers.cs b/Src/FluentAssertions/Common/DictionaryHelpers.cs index 99b3e92d6d..a152c63b00 100644 --- a/Src/FluentAssertions/Common/DictionaryHelpers.cs +++ b/Src/FluentAssertions/Common/DictionaryHelpers.cs @@ -58,9 +58,17 @@ static bool ContainsKey(TCollection collection, TKey key) static bool TryGetValue(TCollection collection, TKey key, out TValue value) { Func areSameOrEqual = ObjectExtensions.GetComparer(); - KeyValuePair matchingPair = collection.FirstOrDefault(kvp => areSameOrEqual(kvp.Key, key)); - value = matchingPair.Value; - return matchingPair.Equals(default(KeyValuePair)); + foreach (var kvp in collection) + { + if (areSameOrEqual(kvp.Key, key)) + { + value = kvp.Value; + return true; + } + } + + value = default; + return false; } } diff --git a/Tests/FluentAssertions.Specs/Collections/GenericDictionaryAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Collections/GenericDictionaryAssertionSpecs.cs index a60f261f50..86c451cf7d 100644 --- a/Tests/FluentAssertions.Specs/Collections/GenericDictionaryAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Collections/GenericDictionaryAssertionSpecs.cs @@ -874,7 +874,7 @@ public void When_asserting_dictionary_with_items_is_not_empty_it_should_succeed( dictionary.Should().NotBeEmpty(); } - #if !NET5_0_OR_GREATER +#if !NET5_0_OR_GREATER [Fact] public void When_asserting_dictionary_with_items_is_not_empty_it_should_enumerate_the_dictionary_only_once() @@ -889,7 +889,7 @@ public void When_asserting_dictionary_with_items_is_not_empty_it_should_enumerat trackingDictionary.Enumerator.LoopCount.Should().Be(1); } - #endif +#endif [Fact] public void When_asserting_dictionary_without_items_is_not_empty_it_should_fail() @@ -2638,6 +2638,15 @@ public void When_a_dictionary_like_collection_contains_the_expected_key_it_shoul act.Should().NotThrow(); } + [Theory] + [MemberData(nameof(SingleDictionaryData))] + public void When_a_dictionary_like_collection_contains_the_expected_key_and_value_it_should_succeed(T subject) + where T : IEnumerable> + { + // Assert + subject.Should().Contain(1, 42); + } + [Theory] [MemberData(nameof(SingleDictionaryData))] public void When_a_dictionary_like_collection_contains_the_expected_value_it_should_succeed(T subject) @@ -2675,6 +2684,19 @@ private static object[] Dictionaries() }; } + [Fact] + public void When_a_dictionary_like_collection_contains_the_default_key_it_should_succeed() + { + // Arrange + var subject = new List>() { new(0, 0) }; + + // Act + Action act = () => subject.Should().Contain(0, 0); + + // Assert + act.Should().NotThrow(); + } + /// /// This class only implements , /// as also implements . diff --git a/docs/_pages/releases.md b/docs/_pages/releases.md index 5b69bb9c9b..67a7567595 100644 --- a/docs/_pages/releases.md +++ b/docs/_pages/releases.md @@ -20,6 +20,7 @@ sidebar: * Variable name is not captured after await assertion - [#1770](https://github.com/fluentassertions/fluentassertions/pull/1770) * `OccurredEvent` ordering on monitored object is now done via thread-safe counter - [#1773](https://github.com/fluentassertions/fluentassertions/pull/1773) * Avoid a `NullReferenceException` when testing an application compiled with .NET Native - [#1776](https://github.com/fluentassertions/fluentassertions/pull/1776) +* Calling `ContainKey[s]` and `[Not]Contain(key, value)` on dictionary-like enumerables - [#1785](https://github.com/fluentassertions/fluentassertions/pull/1785) ## 6.3.0