-
Notifications
You must be signed in to change notification settings - Fork 722
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
DictionaryContainsKeyConstraint behaviour is inconstant with Dictionary.ContainsKey when the dictionary uses a custom Comparer #2837
Comments
Until this is fixed, you can use Assert.That(dictionary, Does.ContainKey("hello").Using((IComparer)StringComparer.OrdinalIgnoreCase)); |
Failing unit tests for this issue are at #2838, currently marked explicit. |
Added failing tests to demonstrate #2837
I can take a look at this, I have a local branch and have the unit tests which were nicely added by Eamon. |
Sounds great, thanks @DaiMichael! From a quick look at the code on my phone however, it looks like we may be in ‘breaking change’ territory here. DictionaryContainsKeyConstraint currently uses NUnitEqualityComparer, rather than the default comparer for a type as a dictionary would. NUnitEqualityComparer has various additions that allow certain types which wouldn’t compar equal with normal .NET Equals() to ‘be equal’. Given the nature of the constraint, my opinion right now is that we should make the change so this constraint always uses the comparer of the dictionary - despite the fact that may break some existing users tests. It’s probably worth waiting for others on @nunit/framework-team to chime in however, on what they think the best way to take this is! Like I say, I’ve only looked on my phone, so this may all be wrong! |
So having a bit more of a look, at first stab I would look to check to see if the passed in Dictionary has a I haven't see if this would break any tests yet but it should only change behaviour when the use case requires it?! Famous last words obviously. I'll make the change locally and see what comes out in the wash... |
@DaiMichael I agree that would avoid broken tests - but I worry it's complicating the 'expected result' a lot to avoid the breaking change. I'm personally currently erring on the side of going for the breaking change - but keen to here what others think. 🙂 |
It would be cool to see a test the change will break. Possibly two of it can break on both directions. |
I'd rather make the breaking change. It seems wrong to have to read Can we instead recognize the |
I'll look to proceed with the, non-easy way 😉 |
@CharliePoole @jnm2 @ChrisMaddock I've done the change, shamelessly taken the code @jnm2 posted up for looking for the The new code fixes the 2 new tests, yay! 🎉 Code on my branch Failures
So I guess it comes down to whether we want to break the current use cases? We could default to using the old method if we can't find I'm all 👂's on what people think is the best way to proceed? |
Is
Probably the best way to proceed is to either deprecate the .IgnoreCase and .Using options, or else internally keep a second code path. Rather than keeping the existing code though, it's tempting to me to generate a collection assertion like @rprouse What do you think so far? Is my straw-man ContainsKey a good thing, and should we keep existing behavior if .IgnoreCase is touched? @DaiMichael If we do this, I'd like to see/contribute tests showing the new ContainsKey code working against:
|
@jnm2 I agree in that I would add a lot more test cases as you mention but I wanted to gauge what the end game was before writing a lot of tests, only for them to be discarded if we changed tact. |
I see, thanks! |
I agree with all your comments, @jnm2. To me, DictionaryContainsKeyConstraint is testing a very specific thing, so other constraints should be used for testing other things!
I especially like this idea! But do think we should deprecate if we go for that, as that's could create some unexpected behaviour for anyone writing new tests! The purpose of this change, in my eyes, would be to avoid breaking compilation for existing tests. |
@ChrisMaddock I was thinking we'd still return a |
@jnm2 I don't think we should test in this case and it isn't currently working as Duck Type can't find a |
Okay, I've checked the tests in but this isn't complete as I have a few on As per above comment
The 2 tests which just implement the Finally... 😓 I still have the two test from first check in So questions are
|
Sorry, I didn't explain what I meant! We're on the same page. That's why I proposed adding a negative test: that way we show that we are intentionally not supporting it. With question 2, I don't have a strong leaning on this one. We either keep the original implementation to fall back to, or we hard-obsolete those methods which the team has not wanted to do when hard-obsoletion was suggested in the past. @ChrisMaddock, @rprouse? |
I hadn't meant that you should explicitly inherit from |
@jnm2 It's been a lonnnnggg week in work... I was just being dumb on the negative tests and actually the plain objects with I'll revisit... ditto on the I'll take look at the mark |
I'd agree this is preferable 🙂 |
I've finished up on the additional unit tests but not commited yet. Marking I can't think of a way of allowing backwards compatibilty and marking it
This will obviously work but isn't particularly pretty 😞 Any better thoughts. |
@DaiMichael We'd do the obsoletion by declaring shadowing methods on the DictionaryContainsKeyConstraint class via the |
@jnm2 - I had started that approach. I perhaps ask you guys too many questions... It's just I don't want to waste anyone's time by making pull requests that are not want is wanted. So we now have a bunch more tests as requested and I have deprecated the other calls used in the tests with backwards compatability for the deprecated calls. I'll do a pull request now... 😉 |
Fixed comments Updated var name and test names.
We've already discussed how inheriting from CollectionConstraint is a leaky abstraction. @DaiMichael brought to our attention that CollectionConstraint.ApplyTo throws ArgumentException for things that aren't IEnumerable:
This is a problem if we want to enable DictionaryContainsKeyConstraint to work on dictionaries that don't implement interfaces. Should we override ApplyTo to get rid of this check, or should we require the IEnumerable interface as a marker before we duck-type and use the ContainsKey method? |
To play devils advocate 👿 Is a plain object (as per test) a |
The syntax people will be reading is |
Very fair point 👍, as I'm thinking from the lower
So where we support this in the framework is mute to a degree. |
I have implemented this and checked in. I have overriden the base .... I can always revert if decided last minute ... |
I was confused when you said overridden, since shadowing and overriding are different things, but by looking at the code I see we're on the same page. =) |
Fix for #2837 DictionaryContainsKeyConstraint behaviour ignores the dictionary key comparer.
…es the dictionary key comparer."
Revert "Fix for #2837 DictionaryContainsKeyConstraint behaviour ignores the dictionary key comparer."
@ChrisMaddock This should be reopened until https://github.com/DaiMichael/nunit/tree/issue-2837 is rebased in a new pull request, right? |
It should, sorry! |
@ChrisMaddock - Soooo.. I think I have rebased, all seems to run, do you want me to do another PR? Also - With regards to the "failing" tests. I don't have an issue locally but I'm a tad confused as in nunit.framework we reference standard but in nunit.framework.test we are referencing netcore ? I don't understand that.... |
Yes please @DaiMichael!
That's strange! The issue I thought we had before, the CI build will catch - so we should be able to see if the problems still there.
I'm very much not the best person to explain this...but .NET Standard is the "API" that these builds target - but the tests must be ran on an actual platform. The platforms we run those tests on is .NET Core. |
@ChrisMaddock - okay ignore all of the last message... I am working on this... post haste but confusion/ misunderstanding of github when I started helping (sic) out means that I have a polluted branch (on this issue) and I have some of another change (in an earlier version) in there. I've spent the day been rather fustrated but I have detangled the mess but I need to remove the bad commit to this branch now. I will then be able to rebase (properly) and I suspect I will see the failing unit tests. Hopefully an exciting day doing this tomorrow. Luckly I just had a hip op (no, I'm not that old ;)) and I'm limited (i.e. I can't) on my cycling!
I understand how it all works, I think the branch issue from above was making a mess, I've only just been been dipping my toe into Standard/Core/Framework recently so I'm also a bit noob around it and easily confused. |
Gah - I know that feeling well...I'm a mercurial-man, so regularly end up in a mess with git as soon as something non-trivial happens! Hope you can get things sorted out - let us know if we can help at all! 🙂 |
Since I'm the one that caused all those changes underneath you, I'll gladly rebase your changes and fix merge conflicts if you'd like. |
I'm 99.9% sure this is my fault. I have a very old check in from the #2786 issue, I must have committed a very early version to this branch, now I've detangled my branches and my master.... I should be able to remove the bad commit. If I'm still struggling by eod tomorrow, I might blame you 😋 and ask for help, but fingers crossed. @ChrisMaddock - amen to mecurial... |
New PR #2967 |
DictionaryContainsKeyConstraint behaviour ignores the dictionary key comparer Fixes #2837
If you have a dictionary that was created with a custom comparer then the DictionaryContainsKeyConstraint does not work as expected.
The text was updated successfully, but these errors were encountered: