EqualityTester.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // ***********************************************************************
  2. // Copyright (c) 2017 Unity Technologies. All rights reserved.
  3. //
  4. // Licensed under the ##LICENSENAME##.
  5. // See LICENSE.md file in the project root for full license information.
  6. // ***********************************************************************
  7. using NUnit.Framework;
  8. using System.Collections.Generic;
  9. namespace Autodesk.Fbx.UnitTests
  10. {
  11. public static class EqualityTester<T>
  12. {
  13. // T.Equals(T), T.Equals(base(T), ...
  14. static List<System.Reflection.MethodInfo> s_Equals = new List<System.Reflection.MethodInfo>();
  15. // operator== (T, T), operator== (base(T), base(T), ...
  16. static List<System.Reflection.MethodInfo> s_op_Equality = new List<System.Reflection.MethodInfo>();
  17. // operator!= (T, T), operator== (base(T), base(T), ...
  18. static List<System.Reflection.MethodInfo> s_op_Inequality = new List<System.Reflection.MethodInfo>();
  19. static EqualityTester() {
  20. // For T and its base classes B1, B2, ...
  21. // get the following functions so we can test equality:
  22. // bool Equals(U)
  23. // static bool operator == (U, U)
  24. // static bool operator != (U, U)
  25. var U = typeof(T);
  26. do {
  27. // Get all the methods, look for Equals(U), op_Equality(U,U), and op_Inequality(U,U)
  28. var methods = U.GetMethods();
  29. foreach(var method in methods) {
  30. if (method.Name == "Equals") {
  31. var parms = method.GetParameters();
  32. if (parms.Length == 1 && parms[0].ParameterType == U) {
  33. s_Equals.Add(method);
  34. }
  35. } else if (method.Name == "op_Equality") {
  36. var parms = method.GetParameters();
  37. if (parms.Length == 2 && parms[0].ParameterType == U && parms[1].ParameterType == U) {
  38. s_op_Equality.Add(method);
  39. }
  40. } else if (method.Name == "op_Inequality") {
  41. var parms = method.GetParameters();
  42. if (parms.Length == 2 && parms[0].ParameterType == U && parms[1].ParameterType == U) {
  43. s_op_Inequality.Add(method);
  44. }
  45. }
  46. }
  47. // Repeat on the base type, if there is one.
  48. U = U.BaseType;
  49. } while (U != null);
  50. #if ENABLE_COVERAGE_TEST
  51. // Register the calls we make through reflection.
  52. var testEquality = typeof(EqualityTester<T>).GetMethod("TestEquality");
  53. foreach(var equals in s_Equals) { CoverageTester.RegisterReflectionCall(testEquality, equals); }
  54. foreach(var equals in s_op_Equality) { CoverageTester.RegisterReflectionCall(testEquality, equals); }
  55. foreach(var equals in s_op_Inequality) { CoverageTester.RegisterReflectionCall(testEquality, equals); }
  56. #endif
  57. }
  58. /* Instances of this class definitely don't cast to T. */
  59. class WrongClass { };
  60. /*
  61. * Test all the equality and hashing functions on type T.
  62. *
  63. * 'a' is an arbitrary non-null instance of class T.
  64. *
  65. * 'b' should be a different non-null instance.
  66. *
  67. * 'acopy' should be equal, but not reference-equal, to 'a' (unless the
  68. * notion of equality for this type is reference equality)
  69. */
  70. public static void TestEquality(T a, T b, T acopy) {
  71. // Test Equals(object) on a.
  72. Assert.IsTrue(a.Equals((object) acopy));
  73. Assert.IsFalse(a.Equals((object) b));
  74. Assert.IsFalse(a.Equals((object) new WrongClass()));
  75. // Test all the Equals functions on a.
  76. // a.Equals(a) is true
  77. // a.Equals(b) is false
  78. // a.Equals(null) is false and doesn't throw an exception
  79. foreach(var equals in s_Equals) {
  80. Assert.IsTrue(Invoker.Invoke<bool>(equals, a, a));
  81. Assert.IsTrue(Invoker.Invoke<bool>(equals, a, acopy));
  82. Assert.IsFalse(Invoker.Invoke<bool>(equals, a, b));
  83. Assert.IsFalse(Invoker.Invoke<bool>(equals, a, null));
  84. }
  85. // test operator== in various cases including null handling
  86. foreach(var equals in s_op_Equality) {
  87. Assert.IsTrue(Invoker.InvokeStatic<bool>(equals, a, a));
  88. Assert.IsTrue(Invoker.InvokeStatic<bool>(equals, a, acopy));
  89. Assert.IsFalse(Invoker.InvokeStatic<bool>(equals, a, b));
  90. Assert.IsFalse(Invoker.InvokeStatic<bool>(equals, a, null));
  91. Assert.IsFalse(Invoker.InvokeStatic<bool>(equals, null, b));
  92. Assert.IsTrue(Invoker.InvokeStatic<bool>(equals, null, null));
  93. }
  94. // test operator!= in the same cases; should always return ! the answer
  95. foreach(var equals in s_op_Inequality) {
  96. Assert.IsTrue(!Invoker.InvokeStatic<bool>(equals, a, a));
  97. Assert.IsTrue(!Invoker.InvokeStatic<bool>(equals, a, acopy));
  98. Assert.IsFalse(!Invoker.InvokeStatic<bool>(equals, a, b));
  99. Assert.IsFalse(!Invoker.InvokeStatic<bool>(equals, a, null));
  100. Assert.IsFalse(!Invoker.InvokeStatic<bool>(equals, null, b));
  101. Assert.IsTrue(!Invoker.InvokeStatic<bool>(equals, null, null));
  102. }
  103. // test hashing. This is very minimal: just testing that two
  104. // instances that test equal have equal hash code.
  105. Assert.AreEqual(a.GetHashCode(), acopy.GetHashCode());
  106. }
  107. }
  108. }