2025-03-11 15:30:07 +08:00

114 lines
5.2 KiB
C#

// ***********************************************************************
// Copyright (c) 2017 Unity Technologies. All rights reserved.
//
// Licensed under the ##LICENSENAME##.
// See LICENSE.md file in the project root for full license information.
// ***********************************************************************
using NUnit.Framework;
using System.Collections.Generic;
namespace Autodesk.Fbx.UnitTests
{
internal static class EqualityTester<T>
{
// T.Equals(T), T.Equals(base(T), ...
static List<System.Reflection.MethodInfo> s_Equals = new List<System.Reflection.MethodInfo>();
// operator== (T, T), operator== (base(T), base(T), ...
static List<System.Reflection.MethodInfo> s_op_Equality = new List<System.Reflection.MethodInfo>();
// operator!= (T, T), operator== (base(T), base(T), ...
static List<System.Reflection.MethodInfo> s_op_Inequality = new List<System.Reflection.MethodInfo>();
static EqualityTester() {
// For T and its base classes B1, B2, ...
// get the following functions so we can test equality:
// bool Equals(U)
// static bool operator == (U, U)
// static bool operator != (U, U)
var U = typeof(T);
do {
// Get all the methods, look for Equals(U), op_Equality(U,U), and op_Inequality(U,U)
var methods = U.GetMethods();
foreach(var method in methods) {
if (method.Name == "Equals") {
var parms = method.GetParameters();
if (parms.Length == 1 && parms[0].ParameterType == U) {
s_Equals.Add(method);
}
} else if (method.Name == "op_Equality") {
var parms = method.GetParameters();
if (parms.Length == 2 && parms[0].ParameterType == U && parms[1].ParameterType == U) {
s_op_Equality.Add(method);
}
} else if (method.Name == "op_Inequality") {
var parms = method.GetParameters();
if (parms.Length == 2 && parms[0].ParameterType == U && parms[1].ParameterType == U) {
s_op_Inequality.Add(method);
}
}
}
// Repeat on the base type, if there is one.
U = U.BaseType;
} while (U != null);
}
/* Instances of this class definitely don't cast to T. */
class WrongClass { };
/*
* Test all the equality and hashing functions on type T.
*
* 'a' is an arbitrary non-null instance of class T.
*
* 'b' should be a different non-null instance.
*
* 'acopy' should be equal, but not reference-equal, to 'a' (unless the
* notion of equality for this type is reference equality)
*/
public static void TestEquality(T a, T b, T acopy) {
// Test Equals(object) on a.
Assert.IsTrue(a.Equals((object) acopy));
Assert.IsFalse(a.Equals((object) b));
Assert.IsFalse(a.Equals((object) new WrongClass()));
// Test all the Equals functions on a.
// a.Equals(a) is true
// a.Equals(b) is false
// a.Equals(null) is false and doesn't throw an exception
foreach(var equals in s_Equals) {
Assert.IsTrue(Invoker.Invoke<bool>(equals, a, a));
Assert.IsTrue(Invoker.Invoke<bool>(equals, a, acopy));
Assert.IsFalse(Invoker.Invoke<bool>(equals, a, b));
Assert.IsFalse(Invoker.Invoke<bool>(equals, a, null));
}
// test operator== in various cases including null handling
foreach(var equals in s_op_Equality) {
Assert.IsTrue(Invoker.InvokeStatic<bool>(equals, a, a));
Assert.IsTrue(Invoker.InvokeStatic<bool>(equals, a, acopy));
Assert.IsFalse(Invoker.InvokeStatic<bool>(equals, a, b));
Assert.IsFalse(Invoker.InvokeStatic<bool>(equals, a, null));
Assert.IsFalse(Invoker.InvokeStatic<bool>(equals, null, b));
Assert.IsTrue(Invoker.InvokeStatic<bool>(equals, null, null));
}
// test operator!= in the same cases; should always return ! the answer
foreach(var equals in s_op_Inequality) {
Assert.IsTrue(!Invoker.InvokeStatic<bool>(equals, a, a));
Assert.IsTrue(!Invoker.InvokeStatic<bool>(equals, a, acopy));
Assert.IsFalse(!Invoker.InvokeStatic<bool>(equals, a, b));
Assert.IsFalse(!Invoker.InvokeStatic<bool>(equals, a, null));
Assert.IsFalse(!Invoker.InvokeStatic<bool>(equals, null, b));
Assert.IsTrue(!Invoker.InvokeStatic<bool>(equals, null, null));
}
// test hashing. This is very minimal: just testing that two
// instances that test equal have equal hash code.
Assert.AreEqual(a.GetHashCode(), acopy.GetHashCode());
}
}
}