using NUnit.Framework; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace TestUtils { public static class AssertUtils { /// /// "Глубокое" сравнение двух объектов по значению их свойств /// /// /// /// /// public static bool AllPropertiesEqualTo(this T a, T b) { if (a == null) return b == null; if (b == null) return a == null; if (IsCollection(a.GetType())) return EqualsAsCollection(a, b); if (a.GetType().IsPrimitive) return a.Equals(b); var props = a.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); return props.All(x => x.EqualsOn(a, b)); } public static bool EqualsOn(this PropertyInfo prop, T a, T b) { object valueA = prop.GetValue(a); object valueB = prop.GetValue(b); if (valueA == null && valueB == null) return true; if (valueA == null || valueB == null) { ThrowOnPropertyInequality(prop, valueA, valueB); } if (IsCollection(prop.PropertyType)) { return prop.EqualsAsCollectionOn(a, b); } if (!valueA.Equals(valueB) && !valueA.AllPropertiesEqualTo(valueB)) { ThrowOnPropertyInequality(prop, valueA, valueB); } return true; } private static void ThrowOnPropertyInequality(PropertyInfo prop, object expectedValue, object actualValue) { var msg = string.Format("\"{0}\" is not equal. Expected: {1} Actual: {2}", prop.Name, expectedValue ?? "", actualValue ?? ""); throw new AssertionException(msg); } public static bool EqualsAsCollectionOn(this PropertyInfo prop, T a, T b) { return EqualsAsCollection(prop.GetValue(a), prop.GetValue(b)); } public static bool EqualsAsCollection(T a, T b) { IEnumerable enumerableA = (IEnumerable) a; IEnumerable enumerableB = (IEnumerable) b; var iterA = enumerableA.GetEnumerator(); var iterB = enumerableB.GetEnumerator(); while (iterA.MoveNext()) { if (!iterB.MoveNext()) return false; if (!iterA.Current.AllPropertiesEqualTo(iterB.Current)) return false; } if (iterB.MoveNext()) { return false; } return true; } public static bool IsCollection(Type type) { return typeof(IEnumerable).IsAssignableFrom(type); } public static bool IsTrue(this T input, Predicate predicate) { return predicate(input); } } }