tpierrain/NFluent

Handling of double.NaNs is inconsistent

bacar opened this issue · 4 comments

bacar commented

Bug Type
Please pick one:

  • a check failed to detect an error (false negative), i.e. a test is green while it should be red.
  • a check raised a non existing error (false positive), i.e a test is red while it should be green.
  • an error message is invalid/incomplete (please provide samples)
  • a ran into an exception.
  • other.

Describe the bug

Consider the test below with failures described in comments.

It is confounding that:

  • 5 passes while 1 and 6 do not (IsEqualTo does not behave like Equals)
  • 1 & 6 fail while 2 and 8 do not (double and double? comparison of NaN is inconsistent)
  • 6 fails while 7 passes. (inconsistent behaviour across ostensibly simliar NFluent overloads / it is not obvious or discoverable how the behaviour should differ). I am using this as a workaround for the above issues now.

To Reproduce

    [Test]
    public void Check_NaNs()
    {
        CheckIt(double.NaN); // succeeds 2.7.2, fails 3.0.2 -- 1
        CheckIt((double?)Double.NaN); // 2

        CheckIt2(double.NaN); // 3
        CheckIt2((double?)Double.NaN); // 4

        Check.That(double.NaN.Equals(double.NaN)).IsTrue(); // 5

        Check.That(double.NaN).IsEqualTo(double.NaN); // fails in both 2.7.2 and 3.0.2 - 6
        Check.That(double.NaN).IsEqualTo<double>(double.NaN); // 7
        
        Check.That((double?)double.NaN).IsEqualTo((double?)double.NaN); // 8
        Check.That((double?)double.NaN).IsEqualTo<double?>(double.NaN); // 9
    }

    private static void CheckIt<T>(T t) => Check.That(t).IsEqualTo(t);
    private static void CheckIt2<T>(T t) => Check.That(t).IsEqualTo<T>(t);

Expected behavior

IMO all the cases above should pass, given double.NaN.Equals(double.NaN). No other doubles for which Equals passes fails IsEqualTo.

IsNan() is a useful standalone check for explicit NaN checks in test, but not ideal for a parameterized test (e.g.: to test your serialisation library can round trip doubles, including NaN).

Desktop (please complete the following information):

  • NFluent version: 3.0.2
  • Net Version: Net Fwmk 4.8
dupdob commented

I need to dig to understand why : double.Nan != double.Nan while double.Nan.Equals(double.Nan). But the BCL code is pretty explicit about ensuring NaN == NaN.
So I assume this should be the default behavior.

bacar commented

NaN != NaN per the IEEE 754 floating point spec - which .net respects for == (but does its own thing for Equals)
Given NFluent's IsEqualTo seems to be a more generous "are these things equivalent in sense" check, I think it's more meaningful to follow Equals?

dupdob commented

Net behavior is documented here, but not justified: https://learn.microsoft.com/fr-fr/dotnet/api/system.double.nan?view=net-8.0

Especially why Equals and Compare consider NaN as equals.

bacar commented

https://stackoverflow.com/a/4934316 is fairly informative on why