/// <summary> /// Compare the properties, fields of a class /// </summary> /// <param name="expected"></param> /// <param name="actual"></param> /// <param name="breadCrumb"></param> private void CompareClass(object expected, object actual, string breadCrumb) { try { _parents.Add(expected); _parents.Add(actual); Type t1 = expected.GetType(); //We ignore the class name if (ElementsToIgnore.Contains(t1.Name)) { return; } //Compare the properties if (CompareProperties) { PerformCompareProperties(t1, expected, actual, breadCrumb); } //Compare the fields if (CompareFields) { PerformCompareFields(t1, expected, actual, breadCrumb); } } finally { _parents.Remove(expected); _parents.Remove(actual); } }
/// <summary> /// Compare the properties, fields of a class /// </summary> /// <param name="object1"></param> /// <param name="object2"></param> /// <param name="breadCrumb"></param> private void CompareClass(object object1, object object2, string breadCrumb) { try { _parents.Add(object1); _parents.Add(object2); Type t1 = object1.GetType(); //We ignore the class name if (ElementsToIgnore.Contains(t1.Name) || IgnoredByAttribute(t1)) { return; } //Compare the properties if (CompareProperties) { PerformCompareProperties(t1, object1, object2, breadCrumb); } //Compare the fields if (CompareFields) { PerformCompareFields(t1, object1, object2, breadCrumb); } } finally { _parents.Remove(object1); _parents.Remove(object2); } }
/// <summary> /// Compare the fields of a class /// </summary> /// <param name="t1"></param> /// <param name="object1"></param> /// <param name="object2"></param> /// <param name="breadCrumb"></param> private void PerformCompareFields(Type t1, object object1, object object2, string breadCrumb) { object objectValue1; object objectValue2; string currentCrumb; FieldInfo[] currentFields; if (ComparePrivateFields) { currentFields = t1.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); } else { currentFields = t1.GetFields(); //Default is public instance } foreach (var item in currentFields) { //Skip if this is a shallow compare if (!CompareChildren && IsChildType(item.FieldType)) { continue; } //If we should ignore it, skip it if (ElementsToIgnore.Contains(item.Name)) { continue; } objectValue1 = item.GetValue(object1); objectValue2 = item.GetValue(object2); bool object1IsParent = objectValue1 != null && (objectValue1 == object1 || _parents.Contains(objectValue1)); bool object2IsParent = objectValue2 != null && (objectValue2 == object2 || _parents.Contains(objectValue2)); //Skip fields that point to the parent if (IsClass(item.FieldType) && (object1IsParent || object2IsParent)) { continue; } currentCrumb = AddBreadCrumb(breadCrumb, item.Name, string.Empty, -1); Compare(objectValue1, objectValue2, currentCrumb); if (Differences.Count >= MaxDifferences) { return; } } }
private void CompareDataRow(object expected, object actual, string breadCrumb) { DataRow dataRow1 = expected as DataRow; DataRow dataRow2 = actual as DataRow; if (dataRow1 == null) //This should never happen, null check happens one level up { throw new ArgumentNullException("expected"); } if (dataRow2 == null) //This should never happen, null check happens one level up { throw new ArgumentNullException("actual"); } for (int i = 0; i < dataRow1.Table.Columns.Count; i++) { //If we should ignore it, skip it if (ElementsToIgnore.Contains(dataRow1.Table.Columns[i].ColumnName)) { continue; } //If we should ignore read only, skip it if (!CompareReadOnly && dataRow1.Table.Columns[i].ReadOnly) { continue; } //Both are null if (dataRow1.IsNull(i) && dataRow2.IsNull(i)) { continue; } string currentBreadCrumb = AddBreadCrumb(breadCrumb, string.Empty, string.Empty, dataRow1.Table.Columns[i].ColumnName); //Check if one of them is null if (dataRow1.IsNull(i)) { Differences.Add(string.Format("expected{0} == null && actual{0} != null ((null),{1})", currentBreadCrumb, cStr(actual))); return; } if (dataRow2.IsNull(i)) { Differences.Add(string.Format("expected{0} != null && actual{0} == null ({1},(null))", currentBreadCrumb, cStr(expected))); return; } Compare(dataRow1[i], dataRow2[i], currentBreadCrumb); if (Differences.Count >= MaxDifferences) { return; } } }
private void CompareDataTable(object expected, object actual, string breadCrumb) { DataTable dataTable1 = expected as DataTable; DataTable dataTable2 = actual as DataTable; if (dataTable1 == null) //This should never happen, null check happens one level up { throw new ArgumentNullException("expected"); } if (dataTable2 == null) //This should never happen, null check happens one level up { throw new ArgumentNullException("actual"); } //If we should ignore it, skip it if (ElementsToIgnore.Contains(dataTable1.TableName)) { return; } //There must be the same amount of rows in the datatable if (dataTable1.Rows.Count != dataTable2.Rows.Count) { Differences.Add(string.Format("expected{0}.Rows.Count != actual{0}.Rows.Count ({1},{2})", breadCrumb, dataTable1.Rows.Count, dataTable2.Rows.Count)); if (Differences.Count >= MaxDifferences) { return; } } //There must be the same amount of columns in the datatable if (dataTable1.Columns.Count != dataTable2.Columns.Count) { Differences.Add(string.Format("expected{0}.Columns.Count != actual{0}.Columns.Count ({1},{2})", breadCrumb, dataTable1.Columns.Count, dataTable2.Columns.Count)); if (Differences.Count >= MaxDifferences) { return; } } for (int i = 0; i < dataTable1.Rows.Count; i++) { string currentBreadCrumb = AddBreadCrumb(breadCrumb, "Rows", string.Empty, i); CompareDataRow(dataTable1.Rows[i], dataTable2.Rows[i], currentBreadCrumb); if (Differences.Count >= MaxDifferences) { return; } } }
private bool SkipElementForType(Type type, string elementName) { if (TypeSpecificCompareOptions.ContainsKey(type)) { return(TypeSpecificCompareOptions[type].ElementsToIgnore.Contains(elementName)); } return(ElementsToIgnore.Contains(elementName)); }
/// <summary> /// Compare the fields of a class /// </summary> /// <param name="t1"></param> /// <param name="object1"></param> /// <param name="object2"></param> /// <param name="breadCrumb"></param> private void PerformCompareFields(Type t1, object object1, object object2, bool structCompare, string breadCrumb) { IEnumerable <FieldInfo> currentFields = GetFieldInfo(t1); foreach (FieldInfo item in currentFields) { //Ignore invalid struct fields if (structCompare && !ValidStructSubType(item.FieldType)) { continue; } //Skip if this is a shallow compare if (!CompareChildren && IsChildType(item.FieldType)) { continue; } //If we should ignore it, skip it if (ElementsToIgnore.Contains(item.Name) || IgnoredByAttribute(item.FieldType) || IgnoredByAttribute(item.GetCustomAttributes(true)) ) { continue; } object objectValue1 = item.GetValue(object1); object objectValue2 = item.GetValue(object2); bool object1IsParent = objectValue1 != null && (objectValue1 == object1 || _parents.Contains(objectValue1)); bool object2IsParent = objectValue2 != null && (objectValue2 == object2 || _parents.Contains(objectValue2)); //Skip fields that point to the parent if (IsClass(item.FieldType) && (object1IsParent || object2IsParent)) { continue; } string currentCrumb = AddBreadCrumb(breadCrumb, item.Name, string.Empty, -1); Compare(objectValue1, objectValue2, currentCrumb); if (Differences.Count >= MaxDifferences) { return; } } }
void PerformCompareFields(Type t1, object object1, object object2, string breadCrumb) { IEnumerable <FieldInfo> currentFields = GetFieldInfo(t1); foreach (FieldInfo item in currentFields) { if (!CompareChildren && IsChildType(item.FieldType)) { continue; } if (ElementsToIgnore.Contains(item.Name) || IgnoredByAttribute(item.FieldType)) { continue; } object objectValue1 = item.GetValue(object1); object objectValue2 = item.GetValue(object2); bool object1IsParent = objectValue1 != null && (objectValue1 == object1 || _parents.Contains(objectValue1)); bool object2IsParent = objectValue2 != null && (objectValue2 == object2 || _parents.Contains(objectValue2)); if (IsClass(item.FieldType) && (object1IsParent || object2IsParent)) { continue; } string currentCrumb = AddBreadCrumb(breadCrumb, item.Name, string.Empty, -1); Compare(objectValue1, objectValue2, currentCrumb); if (Differences.Count >= MaxDifferences) { return; } } }
/// <summary> /// Compare the properties, fields of a class /// </summary> /// <param name="object1"></param> /// <param name="object2"></param> /// <param name="breadCrumb"></param> private void CompareClass(object object1, object object2, string breadCrumb) { try { _parents.Add(object1); _parents.Add(object2); Type t1 = object1.GetType(); //We ignore the class name if (ElementsToIgnore.Contains(t1.Name)) { return; } if (TypesToIgnore.Contains(t1)) { return; } if (CompareChildrenForType(t1)) { // Compare the properties, if allowed for this object type if (ComparePropertiesForType(t1)) { PerformCompareProperties(t1, object1, object2, breadCrumb); } // Compare the fields, if allowed for this object type if (CompareFieldsForType(t1)) { PerformCompareFields(t1, object1, object2, breadCrumb); } } } finally { _parents.Remove(object1); _parents.Remove(object2); } }
/// <summary> /// Compare the properties of a class /// </summary> /// <param name="t1"></param> /// <param name="expected"></param> /// <param name="actual"></param> /// <param name="breadCrumb"></param> private void PerformCompareProperties(Type t1, object expected, object actual, string breadCrumb) { object objectValue1; object objectValue2; string currentCrumb; PropertyInfo[] currentProperties; if (ComparePrivateProperties) { currentProperties = t1.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); } else { currentProperties = t1.GetProperties(BindingFlags.Public | BindingFlags.Instance); } foreach (PropertyInfo info in currentProperties) { //If we can't read it, skip it if (info.CanRead == false) { continue; } //Skip if this is a shallow compare if (!CompareChildren && IsChildType(info.PropertyType)) { continue; } //If we should ignore it, skip it if (ElementsToIgnore.Contains(info.Name)) { continue; } //If we should ignore read only, skip it if (!CompareReadOnly && info.CanWrite == false) { continue; } if (!IsValidIndexer(info, expected, actual, breadCrumb)) { objectValue1 = info.GetValue(expected, null); objectValue2 = info.GetValue(actual, null); } else { CompareIndexer(info, expected, actual, breadCrumb); continue;; } bool expectedIsParent = objectValue1 != null && (objectValue1 == expected || _parents.Contains(objectValue1)); bool actualIsParent = objectValue2 != null && (objectValue2 == actual || _parents.Contains(objectValue2)); //Skip properties where both point to the corresponding parent if (IsClass(info.PropertyType) && (expectedIsParent && actualIsParent)) { continue; } currentCrumb = AddBreadCrumb(breadCrumb, info.Name, string.Empty, -1); Compare(objectValue1, objectValue2, currentCrumb); if (Differences.Count >= MaxDifferences) { return; } } }
/// <summary> /// Compare the properties of a class /// </summary> /// <param name="t1"></param> /// <param name="object1"></param> /// <param name="object2"></param> /// <param name="breadCrumb"></param> private void PerformCompareProperties(Type t1, object object1, object object2, string breadCrumb) { IEnumerable <PropertyInfo> currentProperties = GetPropertyInfo(t1); foreach (PropertyInfo info in currentProperties) { //If we can't read it, skip it if (info.CanRead == false) { continue; } //Skip if this is a shallow compare if (!CompareChildren && IsChildType(info.PropertyType)) { continue; } //If we should ignore it, skip it if (ElementsToIgnore.Contains(info.Name) || IgnoredByAttribute(info.PropertyType)) { continue; } //If we should ignore read only, skip it if (!CompareReadOnly && info.CanWrite == false) { continue; } object objectValue1; object objectValue2; if (!IsValidIndexer(info, breadCrumb)) { objectValue1 = info.GetValue(object1, null); objectValue2 = info.GetValue(object2, null); } else { CompareIndexer(info, object1, object2, breadCrumb); continue; } bool object1IsParent = objectValue1 != null && (objectValue1 == object1 || _parents.Contains(objectValue1)); bool object2IsParent = objectValue2 != null && (objectValue2 == object2 || _parents.Contains(objectValue2)); //Skip properties where both point to the corresponding parent if ((IsClass(info.PropertyType) || IsStruct(info.PropertyType)) && (object1IsParent && object2IsParent)) { continue; } string currentCrumb = AddBreadCrumb(breadCrumb, info.Name, string.Empty, -1); Compare(objectValue1, objectValue2, currentCrumb); if (Differences.Count >= MaxDifferences) { return; } } }
/// <summary> /// Compare the properties of a class /// </summary> /// <param name="t1"></param> /// <param name="object1"></param> /// <param name="object2"></param> /// <param name="breadCrumb"></param> private void PerformCompareProperties(Type t1, object object1, object object2, bool structCompare, string breadCrumb) { IEnumerable <PropertyInfo> currentProperties = GetPropertyInfo(t1); foreach (PropertyInfo info in currentProperties) { //Ignore invalid struct fields if (structCompare && !ValidStructSubType(info.PropertyType)) { continue; } //If we can't read it, skip it if (info.CanRead == false) { continue; } //Skip if this is a shallow compare if (!CompareChildren && IsChildType(info.PropertyType)) { continue; } //If we should ignore it, skip it if (ElementsToIgnore.Contains(info.Name) || IgnoredByAttribute(info.PropertyType) || // November 25, 2012 // Added the ability to // ignore by attributes on // fields/properties. IgnoredByAttribute(info.GetCustomAttributes(true))) { continue; } //If we should ignore read only, skip it if (!CompareReadOnly && info.CanWrite == false) { continue; } //If we ignore types then we must get correct PropertyInfo object PropertyInfo secondObjectInfo = null; if (IgnoreObjectTypes) { var secondObjectPropertyInfos = GetPropertyInfo(object2.GetType()); foreach (var propertyInfo in secondObjectPropertyInfos) { if (propertyInfo.Name != info.Name) { continue; } secondObjectInfo = propertyInfo; break; } } else { secondObjectInfo = info; } object objectValue1; object objectValue2; if (!IsValidIndexer(info, breadCrumb)) { objectValue1 = info.GetValue(object1, null); objectValue2 = secondObjectInfo != null?secondObjectInfo.GetValue(object2, null) : null; } else { CompareIndexer(info, object1, object2, breadCrumb); continue; } bool object1IsParent = objectValue1 != null && (objectValue1 == object1 || _parents.Contains(objectValue1)); bool object2IsParent = objectValue2 != null && (objectValue2 == object2 || _parents.Contains(objectValue2)); //Skip properties where both point to the corresponding parent if ((IsClass(info.PropertyType) || IsStruct(info.PropertyType)) && (object1IsParent && object2IsParent)) { continue; } string currentCrumb = AddBreadCrumb(breadCrumb, info.Name, string.Empty, -1); Compare(objectValue1, objectValue2, currentCrumb); if (Differences.Count >= MaxDifferences) { return; } } }
/// <summary> /// Compare the properties of a class /// </summary> /// <param name="t1"></param> /// <param name="object1"></param> /// <param name="object2"></param> /// <param name="breadCrumb"></param> private void PerformCompareProperties(Type t1, object object1, object object2, string breadCrumb) { PropertyInfo[] currentProperties; if (ComparePrivateProperties && !CompareStaticProperties) { currentProperties = t1.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); } else if (ComparePrivateProperties) { currentProperties = t1.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); } else if (!CompareStaticProperties) { currentProperties = t1.GetProperties(BindingFlags.Public | BindingFlags.Instance); } else { currentProperties = t1.GetProperties(); //Default is public instance and static } foreach (PropertyInfo info in currentProperties) { //If we can't read it, skip it if (info.CanRead == false) { continue; } //Skip if this is a shallow compare if (!CompareChildren && IsChildType(info.PropertyType)) { continue; } //If we should ignore it, skip it if (ElementsToIgnore.Contains(info.Name)) { continue; } //If we should ignore read only, skip it if (!CompareReadOnly && info.CanWrite == false) { continue; } object objectValue1; object objectValue2; if (!IsValidIndexer(info, breadCrumb)) { objectValue1 = info.GetValue(object1, null); objectValue2 = info.GetValue(object2, null); } else { CompareIndexer(info, object1, object2, breadCrumb); continue; } bool object1IsParent = objectValue1 != null && (objectValue1 == object1 || _parents.Contains(objectValue1)); bool object2IsParent = objectValue2 != null && (objectValue2 == object2 || _parents.Contains(objectValue2)); //Skip properties where both point to the corresponding parent if ((IsClass(info.PropertyType) || IsStruct(info.PropertyType)) && (object1IsParent && object2IsParent)) { continue; } string currentCrumb = AddBreadCrumb(breadCrumb, info.Name, string.Empty, -1); Compare(objectValue1, objectValue2, currentCrumb); if (Differences.Count >= MaxDifferences) { return; } } }