Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IDictionary.ContainsKey assertion case sensitivity issue. #60

Closed
voicu-matei opened this issue Jan 8, 2014 · 10 comments
Closed

IDictionary.ContainsKey assertion case sensitivity issue. #60

voicu-matei opened this issue Jan 8, 2014 · 10 comments
Milestone

Comments

@voicu-matei
Copy link
Contributor

[TestMethod]
public void ReproTest()
{
IDictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{"name", "name description"}
};

        //The following 2 lines assert the same and should both pass
        dictionary.ContainsKey("NaMe").Should().BeTrue(); //passes
        dictionary.Should().ContainKey("NaMe"); //fails
    }
@dennisdoomen
Copy link
Member

Hmm, it seems we're not relying on the dictionary's own equality algorithms then...

@voicu-matei
Copy link
Contributor Author

I took a quick look at the code and it seems that indeed the dictionary's EqualityComparer is not used.

@voicu-matei
Copy link
Contributor Author

I'm trying to fix it myself, but it's not possible to retrieve the Comparer from an IDictionary<K,V>.

GenericDictionaryAssertions.cs line 334.

var missingKeys = expectedKeys.Except(Subject.Keys);

could become

var missingKeys = expectedKeys.Except(Subject.Keys);

var dictionarySubject = Subject as Dictionary<TKey, TValue>;
if (dictionarySubject != null)
{
missingKeys = expectedKeys.Except(Subject.Keys, dictionarySubject.Comparer);
}

But this solves only the Dictionary problem.
Stuff like ConcurrentDictionary<,> will still not work as this is a different impl of IDictionary<,>. Still trying to find a generic way to fix this.
I also notice that the sources are linked from the 3.5 to the 4.0 project, so I cannot include System.Collections.Concurrent to test for ConcurrentDictionary.

@voicu-matei
Copy link
Contributor Author

Reflection on Subject.GetType() and check for a public property of type IEqualityComparer of TKey ?
Could work.

@voicu-matei
Copy link
Contributor Author

GenericDictionaryAssertions.cs line 334.

var missingKeys = expectedKeys.Except(Subject.Keys);

becomes:

var missingKeys = expectedKeys.Except(Subject.Keys);

var comparerPropertyInfo = Subject.GetType().GetProperties(BindingFlags.Public)
.FirstOrDefault(p => p.PropertyType == typeof(IEqualityComparer));

if(comparerPropertyInfo != null)
{
var comparer = (IEqualityComparer)comparerPropertyInfo.GetValue(Subject, null);
missingKeys = expectedKeys.Except(Subject.Keys, comparer);
}

Do you agree?

@voicu-matei
Copy link
Contributor Author

Still no good for ConcurrentDictionary because that one does not expose the IEqualityComparer publicly. Would need to look for private fields of that type also.

Pfiu....

@dennisdoomen
Copy link
Member

Maybe we should just rewrite that code to use the ContainsKey() method of the dictionary. That'll use whatever the dictionary uses internally.

@voicu-matei
Copy link
Contributor Author

Ahaaa, indeed.

var missingKeys = expectedKeys.Except(Subject.Keys);
//becomes
var missingKeys = expectedKeys.Where(key => !Subject.ContainsKey(key));

This is the obvious way. What was I thinking!?!
Thanks!

@dennisdoomen
Copy link
Member

Don't worry. I'm looking at it from a large distance so my mind is not clouded by the interiors of a dictionary :-)

@dennisdoomen
Copy link
Member

Fixed by pull request #61.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants