/// <summary>Assert by deep recursive value equality compare.</summary> public static void IsNotStructuralEqual(this object actual, object expected, string message = "") { message = string.IsNullOrEmpty(message) ? string.Empty : ", " + message; if (object.ReferenceEquals(actual, expected)) { throw new AssertException("actual is same reference" + message); } if (actual == null) { return; } if (expected == null) { return; } if (actual.GetType() != expected.GetType()) { return; } EqualInfo r = StructuralEqual(actual, expected, new[] { actual.GetType().Name }); // root type if (r.IsEquals) { throw new AssertException("is structural equal" + message); } }
private static EqualInfo SequenceEqual(IEnumerable leftEnumerable, IEnumerable rightEnumarable, IEnumerable <string> names) { IEnumerator le = leftEnumerable.GetEnumerator(); using (le as IDisposable) { IEnumerator re = rightEnumarable.GetEnumerator(); using (re as IDisposable) { var index = 0; while (true) { object lValue = null; object rValue = null; var lMove = le.MoveNext(); var rMove = re.MoveNext(); if (lMove) { lValue = le.Current; } if (rMove) { rValue = re.Current; } if (lMove && rMove) { EqualInfo result = StructuralEqual(lValue, rValue, names.Concat(new[] { "[" + index + "]" })); if (!result.IsEquals) { return(result); } } if ((lMove == true && rMove == false) || (lMove == false && rMove == true)) { return(new EqualInfo { IsEquals = false, Left = lValue, Right = rValue, Names = names.Concat(new[] { "[" + index + "]" }) }); } if (lMove == false && rMove == false) { break; } index++; } } } return(new EqualInfo { IsEquals = true, Left = leftEnumerable, Right = rightEnumarable, Names = names }); }
/// <summary>Assert by deep recursive value equality compare.</summary> public static void IsStructuralEqual(this object actual, object expected, string message = "") { message = string.IsNullOrEmpty(message) ? string.Empty : ", " + message; if (object.ReferenceEquals(actual, expected)) { return; } if (actual == null) { throw new AssertException("actual is null" + message); } if (expected == null) { throw new AssertException("actual is not null" + message); } if (actual.GetType() != expected.GetType()) { var msg = string.Format( "expected type is {0} but actual type is {1}{2}", expected.GetType().Name, actual.GetType().Name, message); throw new AssertException(msg); } EqualInfo r = StructuralEqual(actual, expected, new[] { actual.GetType().Name }); // root type if (!r.IsEquals) { var msg = string.Format( "is not structural equal, failed at {0}, actual = {1} expected = {2}{3}", string.Join(".", r.Names), r.Left, r.Right, message); throw new AssertException(msg); } }
private static EqualInfo StructuralEqual(object left, object right, IEnumerable <string> names) { // type and basic checks if (object.ReferenceEquals(left, right)) { return(new EqualInfo { IsEquals = true, Left = left, Right = right, Names = names }); } if (left == null || right == null) { return(new EqualInfo { IsEquals = false, Left = left, Right = right, Names = names }); } Type lType = left.GetType(); Type rType = right.GetType(); if (lType != rType) { return(new EqualInfo { IsEquals = false, Left = left, Right = right, Names = names }); } Type type = left.GetType(); // not object(int, string, etc...) if (Type.GetTypeCode(type) != TypeCode.Object) { return(new EqualInfo { IsEquals = left.Equals(right), Left = left, Right = right, Names = names }); } // is sequence if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(type)) { return(SequenceEqual((IEnumerable)left, (IEnumerable)right, names)); } // IEquatable<T> Type equatable = typeof(IEquatable <>).MakeGenericType(type); if (equatable.GetTypeInfo().IsAssignableFrom(type)) { var result = (bool)equatable.GetTypeInfo().GetMethod("Equals").Invoke(left, new[] { right }); return(new EqualInfo { IsEquals = result, Left = left, Right = right, Names = names }); } // is object FieldInfo[] fields = left.GetType().GetTypeInfo().GetFields(BindingFlags.Instance | BindingFlags.Public); IEnumerable <PropertyInfo> properties = left.GetType().GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public) .Where(x => x.GetGetMethod(false) != null && x.GetIndexParameters().Length == 0); IEnumerable <MemberInfo> members = fields.Cast <MemberInfo>().Concat(properties); foreach (dynamic mi in members) { IEnumerable <string> concatNames = names.Concat(new[] { (string)mi.Name }); object lv = mi.GetValue(left); object rv = mi.GetValue(right); EqualInfo result = StructuralEqual(lv, rv, concatNames); if (!result.IsEquals) { return(result); } } return(new EqualInfo { IsEquals = true, Left = left, Right = right, Names = names }); }