Skip to content

Instantly share code, notes, and snippets.

@mjul
Last active December 16, 2015 22:39
Show Gist options
  • Select an option

  • Save mjul/5508125 to your computer and use it in GitHub Desktop.

Select an option

Save mjul/5508125 to your computer and use it in GitHub Desktop.
Test Helper for Equals and GetHashCode, checking that the Equals relation is an equivalence relation, meaning that it is Reflexive, Transitive and Symmetrical. Also tests equality operator overloading.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
namespace TestHelpers
{
public class EqualityTesting
{
/// <summary>
/// Check that Equals and GetHashCode are well behaved with Value semantics.
/// Given three equal but different instances and a number of unequal instances,
/// verify the Equals behaves correctly:
/// The Equals relation must be Reflexive, Transitive and Symmetrical.
/// </summary>
/// <typeparam name="T">The type under test.</typeparam>
/// <param name="a">An instance</param>
/// <param name="b">Another instance, with the same values as a.</param>
/// <param name="c">Another instance, with the same values as a and b.</param>
/// <param name="unequalInstances">These should not equal a, b and c.
/// It is recommended to supply one per property on the type T,
/// and have only one property per instance differ from the values of the
/// same properties on a, b and c.</param>
public static void TestEqualsAndGetHashCode<T>(T a, T b, T c, params T[] unequalInstances)
{
// Reflexive
Assert.AreEqual(a, a, "Expected A=A");
// Transitivity
Assert.AreEqual(a, b, "Expected A=B");
Assert.AreEqual(b, c, "Expected B=C");
Assert.AreEqual(a, c, "Expected A=C");
// Symmetrical
Assert.AreEqual(b, a, "Expected B=A");
Assert.AreNotEqual(a, null, "Expected a != null");
Assert.AreNotEqual(null, a, "Expected null != a");
var otherType = new Object();
Assert.AreNotEqual(a, otherType, "Expected a != object of other type.");
for (int i = 0; i < unequalInstances.Length; i++)
{
T unequalInstance = unequalInstances[i];
Assert.AreNotEqual(a, unequalInstance, "Expected a != unequal instances (index {0})", i);
Assert.DoesNotThrow(() => unequalInstance.GetHashCode(), "Expected GetHashCode to not raise exception for unequal instances (index {0})", i);
}
Assert.AreEqual(a.GetHashCode(), b.GetHashCode(), "Expected equal hashcode when objects are equal.");
}
public static void TestEqualityOperators<T>(T a, T b, T c, params T[] unequalInstances)
{
// we don't know if the operators are defined on generic type T, so we use dynamic
dynamic da = a;
dynamic db = b;
dynamic dc = c;
// Reflexive
// ReSharper disable EqualExpressionComparison
Assert.IsTrue(da == da, "Expected A=A");
// ReSharper restore EqualExpressionComparison
// Transitivity
Assert.IsTrue(da == db, "Expected A=B");
Assert.IsTrue(db == dc, "Expected B=C");
Assert.IsTrue(da == dc, "Expected A=C");
// Symmetrical
Assert.IsTrue(db == da, "Expected B=A");
Assert.IsTrue(da != null, "Expected a != null");
Assert.IsTrue(null != da, "Expected null != a");
Assert.IsFalse(da == null, "Expected not (A == null)");
Assert.IsFalse(null == da, "Expected not (null == A)");
var otherType = new Object();
Assert.AreNotEqual(a, otherType, "Expected a != object of other type.");
for (int i = 0; i < unequalInstances.Length; i++)
{
dynamic unequal = unequalInstances[i];
Assert.IsTrue(da != unequal, "Expected a != unequal instances (index {0})", i);
}
}
}
}
public class Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public override int GetHashCode()
{
return X;
}
public override bool Equals(object obj)
{
if (null == obj) return false;
if (!(obj.GetType().Equals(GetType()))) return false;
var other = (Point) obj;
if (other.X != this.X) return false;
if (other.Y != this.Y) return false;
return true;
}
}
[TestFixture]
public class PointTest
{
[Test]
public void EqualsAndGetHashCode_MustBeEquivalenceRelation()
{
var a = new Point(1, 0);
var b = new Point(1, 0);
var c = new Point(1, 0);
var unequalX = new Point(10, 0);
var unequalY = new Point(0, 10);
EqualityTesting.TestEqualsAndGetHashCode(a,b,c, unequalX, unequalY);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment