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);
}
}
}