using System; using System.Reflection; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Nuri.Test.Helpers { public static class Equality { private static readonly string[] _ReservedProperties = { "SyncRoot" }; public static void EnsureMatchByProperties(this object expected, object actual) { ensureNotNull(expected, actual); Type expectedType = expected.GetType(); Type actualType = actual.GetType(); Assert.AreEqual(expectedType, actualType); if (expectedType.IsArray) { Array expectedArray = expected as System.Array; Array actualArray = actual as System.Array; Console.WriteLine(">>>*** digging into array " + expectedType.Name); for (int i = 0; i < expectedArray.Length; i++) { Console.WriteLine(" --- --- ---"); EnsureMatchByProperties(expectedArray.GetValue(i), actualArray.GetValue(i)); } Console.WriteLine("<<<*** digging out from array " + expectedType.Name); } else { ensurePropertiesMatch(expected, actual, expectedType, actualType); } } public static void EnsureMatchByFields(this object expected, object actual, params string[] exclusionList) { ensureNotNull(expected, actual); Type expectedType = expected.GetType(); Type actualType = actual.GetType(); Assert.AreEqual(expectedType, actualType); if (expectedType.IsArray) { Array expectedArray = expected as System.Array; Array actualArray = actual as System.Array; Console.WriteLine(">>>*** digging into array " + expectedType.Name); for (int i = 0; i < expectedArray.Length; i++) { Console.WriteLine(" --- --- ---"); expectedArray.GetValue(i).EnsureMatchByFields(actualArray.GetValue(i)); } Console.WriteLine("<<<*** digging out from array " + expectedType.Name); } else { ensureFieldsMatch(expected, actual, exclusionList); } } private static void ensurePropertiesMatch(object expected, object actual, Type expectedType, Type actualType) { BindingFlags propertyExtractionOptions = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.GetProperty; foreach (PropertyInfo expectedProp in expectedType.GetProperties()) { if (expectedProp.CanRead && !_ReservedProperties.Contains(expectedProp.Name)) { if (expectedProp.PropertyType.IsValueType || expectedProp.PropertyType == typeof(String)) { object expectedValue = expectedType.InvokeMember(expectedProp.Name, propertyExtractionOptions, null, expected, null); object actualValue = actualType.InvokeMember(expectedProp.Name, propertyExtractionOptions, null, actual, null); if (expectedValue == null && actualValue == null) { Console.WriteLine("{0}: null == null", expectedProp.Name); continue; } if (expectedValue == null || actualValue == null) { Assert.Fail(expectedProp.Name + ": Expected Or Actual is null! (but not both)"); break; } Console.Write("{0}: {1} == {2} ?", expectedProp.Name, expectedValue.ToString(), actualValue.ToString()); Assert.AreEqual(expectedValue, actualValue, "Value of property doesn't match in " + expectedProp.Name); Console.WriteLine(" true."); } else if (expectedProp.PropertyType.IsClass) { object expectedObject = expectedType.InvokeMember(expectedProp.Name, propertyExtractionOptions, null, expected, null); object actualObject = actualType.InvokeMember(expectedProp.Name, propertyExtractionOptions, null, actual, null); if (expectedObject != null && actualObject != null) { Console.WriteLine(">>>>>>>> digging into " + expectedProp.Name); EnsureMatchByProperties(expectedObject, actualObject); Console.WriteLine("<<<<<<<< back from dig of " + expectedProp.Name); } } } } } private static void ensureFieldsMatch(object expected, object actual, params string[] exclusionList) { Type expectedType = expected.GetType(); Type actualType = actual.GetType(); BindingFlags filedExtractionOptions = BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; foreach (FieldInfo expectedField in expectedType.GetFields(filedExtractionOptions)) { if (!exclusionList.Contains(expectedField.Name)) { if (expectedField.FieldType.IsValueType || expectedField.FieldType == typeof(String)) { object expectedValue = expectedType.InvokeMember(expectedField.Name, filedExtractionOptions, null, expected, null); object actualValue = actualType.InvokeMember(expectedField.Name, filedExtractionOptions, null, actual, null); if (actual == null && expectedValue == null) { Console.WriteLine("{0}: null == null", expectedField.Name); continue; } if (expectedValue == null || actualValue == null) { Assert.Fail(expectedField.Name + ": Expected Or Actual is null! (but not both)"); break; } Console.Write("{0}: {1} == {2} ?", expectedField.Name, expectedValue.ToString(), actualValue.ToString()); Assert.AreEqual(expectedValue, actualValue, "Value of filed doesn't match in " + expectedField.Name); Console.WriteLine(" true."); } else if (expectedField.FieldType.IsClass) { object expectedObject = expectedType.InvokeMember(expectedField.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, expected, null); object actualObject = actualType.InvokeMember(expectedField.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, actual, null); if (expectedObject != null && actualObject != null) { Console.WriteLine(">>>>>>>> digging into " + expectedField.Name); expectedObject.EnsureMatchByFields(actualObject); Console.WriteLine("<<<<<<<< back from dig" + expectedField.Name); } } } } } private static void ensureNotNull(params object[] parameters) { foreach (object obj in parameters) if (obj == null) { throw new ArgumentNullException("at least one parameter is null"); } } } }
|