tpierrain/NFluent

Providing an `IEqualityComparer` for comparison

MiniKeb opened this issue · 1 comments

If I write a method that return an object with a type from a library, I can't add or modify the Equals() method's of this type.
This imply that I won't be able to compare by value rather than by reference and my assertion will failed.

Expected Behavior

It would be nice if I could define my own IEqualityComparer :

public class CustomComparer : IEqualityComparer<Item>
{
    public bool Equals(Item x, Item y)
    {
        if (ReferenceEquals(null, x) || ReferenceEquals(null, y)) return false;
        if (ReferenceEquals(x, y)) return true;
        return x.Name == y.Name && x.Number == y.Number;
    }

    public int GetHashCode(Item obj)
    {
        return HashCode.Combine(obj.Name, obj.Number);
    }
}

And use it in my test :

var items = sut.MyMethod(withParameter).ToArray();

var expected = new[]
{
    new Item
    {
        Name = "ItemA",
        Number = 111
    },
    new Item
    {
        Name = "ItemB",
        Number = 222
    }
};

Check.That(items).ContainsExactly(expected, new CustomComparer());
//OR
Check.RegisterEqualityComparer<Item>(new CustomComparer()) 
Check.That(items).ContainsExactly(expected);

Thanks for your feedback.
I have a working prototype that supports the register approach. As such, once a comparer is registered it is used for every relevant check.
Therefore you can also unregister it.
This looks like this:

Check.RegisterComparer<Item>(new CustomComparer());
Check.That(items).ContainsExactly(expected);

The recommended pattern is

try
{
  var previous = Check.RegisterComparer<Item>(new CustomComparer());
  Check.That(items).ContainsExactly(expected);
}
finally
{
 // restore previous comparer
  Check.RegisterComparer<Item>(previous);
}

Note that this feature requires some caching logic as searching for comparers will slow every test, so this requires extra work. But the feature will be available in the V3.0

expect a new beta in the coming days