Skip to content

ContainsKey doesn't support IgnoreCase, IgnoreWhiteSpace, or IgnoreLineEndingFormat #4981

Description

@Bartleby2718

Summary

IgnoreLineEndingFormat (added in #4975) doesn't work for ContainsKey.

Minimal Reproducible Example

	// tested with 4.4.0-alpha.0.17
	[Test]
	public void ContainKey()
	{
		Dictionary<string, int> values = new() { { "a\r", 1 } };
		Assert.That(values, Does.ContainKey("a\n").IgnoreLineEndingFormat);
	}

Explanation

The current implementation of DictionaryContainsKeyConstraint uses reflection:

private static MethodInfo? GetContainsKeyMethod(object keyedItemContainer)
{
var instanceType = keyedItemContainer.GetType();
var method = FindContainsKeyMethod(instanceType)
?? instanceType
.GetInterfaces()
.Concat(GetBaseTypes(instanceType))
.Select(FindContainsKeyMethod)
.FirstOrDefault(m => m is not null);
return method;
}

Unlike Enumerable.Contains, however, Dictionary<TKey,TValue>.ContainsKey(TKey) doesn't have an overload that takes in IEqualityComparer<TSource>. Therefore, DictionaryContainsKeyConstraint cannot use the IgnoreLineEndingFormatStringComparer

internal sealed class IgnoreLineEndingFormatStringComparer : IEqualityComparer<string>
and therefore fails to treat "a\r" and "a\n" equally.

Potential Solution

Haven't looked too much into the code base, but the first thing I can think of is (in pseudocode):

  1. for IDictionary<string, TValue>, do d.Keys.ToArray().Contains(key, IgnoreLineEndingFormatComparer<string>)
  2. for IEnumerable<KeyValuePair<string, TValue>>, do d.Select(kvp => kvp.Key).Contains(key, IgnoreLineEndingFormatComparer<string>)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions