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

Assert.Equal for JValue with mismatching types asserts to true. #2713

Closed
gurustron opened this issue May 12, 2023 · 6 comments
Closed

Assert.Equal for JValue with mismatching types asserts to true. #2713

gurustron opened this issue May 12, 2023 · 6 comments

Comments

@gurustron
Copy link

gurustron commented May 12, 2023

Not sure that this is worth fixing or not, and maybe it is actually will work in the next release (as I can see there is some refactoring going on) but consider the following (from SO question, some explanation for 2.4.2 xunit version there):

Repro:

[Fact]
public void Test2()
{
    var jvLeft = JToken.FromObject(1);
    var jvRight = JToken.FromObject("bar");

    // some "debug" checks
    Assert.True(jvLeft is JValue);
    Assert.Empty(jvLeft);
    Assert.Throws<FormatException>(() => (jvRight as IComparable).CompareTo(jvLeft));

    Assert.Equal(jvRight, jvLeft); // output: pass
}

Expected:
Fail

Actual:
Passes

Workaround
Use Assert.StrictEqual (works correctly for JValues) or more generic approach - Assert.True(JToken.DeepEquals(jvRight, jvLeft));.

@gurustron gurustron changed the title Assert.Equal for JValue with mismatching types asserts to true/ Assert.Equal for JValue with mismatching types asserts to true. May 15, 2023
@bradwilson
Copy link
Member

bradwilson commented May 15, 2023

This is because JToken derives from IEnumerable, so it gets treated like a collection. You can see this by flipping Assert.Equal to Assert.NotEqual:

Assert.NotEqual() Failure: Collections are equal
Expected: Not []
Actual:       []

The actual fix here would be for JSON.NET to implement one of the many equality/comparability interfaces provided in .NET. We currently look for and support:

  • IEquatable<T> (1)
  • IStructuralEquatable
  • IComparable<T> (1)
  • IComparable

(1) We support both the T of expected and actual when they're not the same type

We are not planning to add special-cased support for JSON.NET, as we don't special case anything that isn't part of the core framework itself. Third party libraries are expected to either conform to the comparison systems provided by .NET, or the testers are expected to use their own custom logic when the third party libraries aren't written to comply, as is the case with JSON.NET.

@gurustron
Copy link
Author

gurustron commented May 15, 2023

@bradwilson please check out the linked SO question. JValue implements IComparable, the problem here is that it throws and the error is swallowed (maybe a more correct behavior would be to return false in this case?), so the JValue is compared as IEnumerable, but it is an empty IEnumerable from the library point of view.

We are not planning to add special-cased support for JSON.NET, as we don't special case anything that isn't part of the core framework itself.

Totally agree with this.

@bradwilson
Copy link
Member

Hmm, I think if I changed the behavior, it would be to propagate the exception. Assuming "exception" means "not equal" isn't correct, IMO, because what if you were using Assert.NotEqual? Any exception would cause the code to unnecessarily pass.

I want to review this since I'm already catching it, and I assume I had a good reason for it. 😄

@bradwilson
Copy link
Member

The commit that changed this is more than 6 years old: xunit/assert.xunit@6349e0c

This is the associated PR: xunit/assert.xunit#13

No reasoning there. Maybe @hughbe will remember? $10 says it was added for JSON.NET. 😂

@bradwilson
Copy link
Member

Still poking around here, and I've determined that with the 2.5.0 assertion library, IComparable never comes into play because IEnumerable always takes precedence:

https://github.com/xunit/assert.xunit/blob/b4e17c53b3c1eb97d69146f275387611563bd395/EqualityAsserts.cs#L137-L146

So even removing the try/catch would have no impact any more.

@gurustron
Copy link
Author

@bradwilson thank you!

Assuming "exception" means "not equal" isn't correct, IMO, because what if you were using Assert.NotEqual?

Yes, I agree that this is also not the clearest/cleanest solution (though an argument can be made here - if two things can't be compared they are definitely not equal 😊).

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

No branches or pull requests

2 participants