nunit / nunit

NUnit Framework
https://nunit.org/
MIT License
2.5k stars 728 forks source link

CollectionAssert.AreEquivalent throws exception with tuples of reference types that don't implement IComparable. #3884

Closed MarkWithall closed 3 years ago

MarkWithall commented 3 years ago

CollectionAssert.AreEquivalent throws System.InvalidOperationException with tuples of reference types that don't implement IComparable.

NUnit version: 3.13.2 (works in 3.13.1)

Possibly broken by #3831.

The following example demonstrates the issue:

[Test]
public void Test()
{
    object a = new();
    object b = new();
    object c = new();
    object d = new();
    var actual = new[] {(a, b), (c, d)};
    var expected = new[] {(c, d), (a, b)};
    CollectionAssert.AreEquivalent(expected, actual);
}

Exception:

System.InvalidOperationException : Failed to compare two elements in the array.
  ----> System.ArgumentException : At least one object must implement IComparable.
   at System.Array.SorterObjectArray.IntrospectiveSort(Int32 left, Int32 length)
   at System.Array.Sort(Array keys, Array items, Int32 index, Int32 length, IComparer comparer)
   at System.Collections.ArrayList.Sort(Int32 index, Int32 count, IComparer comparer)
   at System.Collections.ArrayList.Sort()
   at NUnit.Framework.Constraints.CollectionTally..ctor(NUnitEqualityComparer comparer, IEnumerable c)
   at NUnit.Framework.Constraints.CollectionItemsEqualConstraint.Tally(IEnumerable c)
   at NUnit.Framework.Constraints.CollectionEquivalentConstraint.Matches(IEnumerable actual)
   at NUnit.Framework.Constraints.CollectionEquivalentConstraint.ApplyTo[TActual](TActual actual)
   at NUnit.Framework.Assert.That[TActual](TActual actual, IResolveConstraint expression, String message, Object[] args)
   at NUnit.Framework.CollectionAssert.AreEquivalent(IEnumerable expected, IEnumerable actual, String message, Object[] args)
   at NUnit.Framework.CollectionAssert.AreEquivalent(IEnumerable expected, IEnumerable actual)
--ArgumentException
   at System.Collections.Comparer.Compare(Object a, Object b)
   at System.Collections.Generic.ObjectComparer`1.Compare(T x, T y)
   at System.ValueTuple`2.System.IComparable.CompareTo(Object other)
   at System.Collections.Comparer.Compare(Object a, Object b)
   at System.Array.SorterObjectArray.SwapIfGreater(Int32 a, Int32 b)
   at System.Array.SorterObjectArray.IntroSort(Int32 lo, Int32 hi, Int32 depthLimit)
   at System.Array.SorterObjectArray.IntrospectiveSort(Int32 left, Int32 length)

Assert.That(actual, Is.EquivalentTo(expected)); also fails in the same way.

Replacing object with a class that implements IComparable works as expected.

mikkelbu commented 3 years ago

This have also been reported in #3841, so closing this as a duplicate.