Skip to content

Commit

Permalink
Merge pull request #256 from sebasijan/ignore-collection-count
Browse files Browse the repository at this point in the history
ignore collection count
  • Loading branch information
GregFinzer authored Mar 18, 2022
2 parents f578c61 + 4f44ee9 commit 80bd7eb
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 1 deletion.
55 changes: 54 additions & 1 deletion Compare-NET-Objects-Tests/IgnoreTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using KellermanSoftware.CompareNetObjects;
using KellermanSoftware.CompareNetObjectsTests.TestClasses;
using KellermanSoftware.CompareNetObjectsTests.TestClasses.IgnoreExample;
Expand Down Expand Up @@ -137,5 +139,56 @@ public void IgnoreDerivedClassPropertyUsingIgnoreProperty()
result = compare.Compare(derive2FromOfficer1, derive2FromOfficer2);
Assert.IsFalse(result.AreEqual);
}
}


[Test]
public void IgnoreReadonlyCollection()
{
var coll1 = new List<int>
{
1, 2, 3, 4, 5
}.AsReadOnly();
var coll2 = new List<int>
{
1, 2, 3, 4, 5, 6
}.AsReadOnly();
var compareLogic = new CompareLogic
{
Config = new ComparisonConfig
{
MaxDifferences = int.MaxValue,
CompareReadOnly = false
}
};

var result = compareLogic.Compare(coll1, coll2);
Assert.AreEqual(result.Differences.Count, 0);

var obj1 = new
{
Name = "test",
Collection = coll1
};
var obj2 = new
{
Name = "test",
Collection = coll2
};

result = compareLogic.Compare(obj1, obj2);
Assert.AreEqual(result.Differences.Count, 0);

compareLogic = new CompareLogic
{
Config = new ComparisonConfig
{
MaxDifferences = int.MaxValue,
CompareReadOnly = true
}
};

result = compareLogic.Compare(obj1, obj2);
Assert.AreEqual(result.Differences.Count, 1);
}
}
}
1 change: 1 addition & 0 deletions Compare-NET-Objects/RootComparerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ private static RootComparer BuildRootComparer()
_rootComparer.TypeComparers.Add(new DoubleComparer(_rootComparer));
_rootComparer.TypeComparers.Add(new PointerComparer(_rootComparer));
_rootComparer.TypeComparers.Add(new SimpleTypeComparer(_rootComparer));
_rootComparer.TypeComparers.Add(new ReadOnlyCollectionComparer(_rootComparer));
_rootComparer.TypeComparers.Add(new ListComparer(_rootComparer));

#if NETFULL || NETSTANDARD2_0 || NETSTANDARD2_1
Expand Down
141 changes: 141 additions & 0 deletions Compare-NET-Objects/TypeComparers/ReadOnlyCollectionComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using KellermanSoftware.CompareNetObjects.IgnoreOrderTypes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;

namespace KellermanSoftware.CompareNetObjects.TypeComparers
{
/// <summary>
/// Logic to compare two ReadOnlyCollections.
/// </summary>
public class ReadOnlyCollectionComparer : BaseTypeComparer
{
/// <summary>
/// The main constructor.
/// </summary>
public ReadOnlyCollectionComparer(RootComparer rootComparer) : base(rootComparer)
{

}

/// <summary>
/// Returns true if both objects are ReadOnlyCollections.
/// </summary>
/// <param name="type1">The type of the first object</param>
/// <param name="type2">The type of the second object</param>
/// <returns></returns>
public override bool IsTypeMatch(Type type1, Type type2)
{
return TypeHelper.IsReadOnlyCollection(type1) && TypeHelper.IsReadOnlyCollection(type2);
}

/// <summary>
/// Compare two ReadOnlyCollections.
/// </summary>
public override void CompareType(CompareParms parms)
{
if (!parms.Config.CompareReadOnly)
return;

try
{
parms.Result.AddParent(parms.Object1);
parms.Result.AddParent(parms.Object2);

Type t1 = parms.Object1.GetType();
Type t2 = parms.Object2.GetType();

//Check if the class type should be excluded based on the configuration
if (ExcludeLogic.ShouldExcludeClass(parms.Config, t1, t2))
return;

parms.Object1Type = t1;
parms.Object2Type = t2;

bool countsDifferent = CollectionsDifferentCount(parms);

if (parms.Result.ExceededDifferences)
return;

if (parms.Config.IgnoreCollectionOrder)
{
IgnoreOrderLogic logic = new IgnoreOrderLogic(RootComparer);
logic.CompareEnumeratorIgnoreOrder(parms, countsDifferent);
}
else
{
CompareItems(parms);
}
}
finally
{
parms.Result.RemoveParent(parms.Object1);
parms.Result.RemoveParent(parms.Object2);
}
}

private void CompareItems(CompareParms parms)
{
int count = 0;

IEnumerator enumerator1 = ((ICollection)parms.Object1).GetEnumerator();
IEnumerator enumerator2 = ((ICollection)parms.Object2).GetEnumerator();

while (enumerator1.MoveNext() && enumerator2.MoveNext())
{
string currentBreadCrumb = AddBreadCrumb(parms.Config, parms.BreadCrumb, string.Empty, string.Empty, count);

CompareParms childParms = new CompareParms
{
Result = parms.Result,
Config = parms.Config,
ParentObject1 = parms.Object1,
ParentObject2 = parms.Object2,
Object1 = enumerator1.Current,
Object2 = enumerator2.Current,
BreadCrumb = currentBreadCrumb
};

RootComparer.Compare(childParms);

if (parms.Result.ExceededDifferences)
return;

count++;
}
}

private bool CollectionsDifferentCount(CompareParms parms)
{
//Get count by reflection since we can't cast it to HashSet<>
int count1 = ((ICollection)parms.Object1).Count;
int count2 = ((ICollection)parms.Object2).Count;

//Objects must be the same length
if (count1 != count2)
{
Difference difference = new Difference
{
ParentObject1 = parms.ParentObject1,
ParentObject2 = parms.ParentObject2,
PropertyName = parms.BreadCrumb,
Object1Value = count1.ToString(CultureInfo.InvariantCulture),
Object2Value = count2.ToString(CultureInfo.InvariantCulture),
ChildPropertyName = "Count",
Object1 = parms.Object1,
Object2 = parms.Object2
};

AddDifference(parms.Result, difference);

return true;
}

return false;
}
}
}
15 changes: 15 additions & 0 deletions Compare-NET-Objects/TypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#if !NETSTANDARD
using System.Data;
using System.Drawing;
using System.Runtime.CompilerServices;
#endif

namespace KellermanSoftware.CompareNetObjects
Expand Down Expand Up @@ -117,6 +118,20 @@ public static bool IsImmutableArray(Type type)
&& type.Name == "ImmutableArray`1";
}

/// <summary>
/// True if the type is a System.Collections.ObjectModel.ReadOnlyCollection
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static bool IsReadOnlyCollection(Type type)
{
if (type == null)
return false;

return (type.Namespace == "System.Collections.ObjectModel"
&& type.Name == "ReadOnlyCollection`1");
}

/// <summary>
/// Returns true if it is a struct
/// </summary>
Expand Down

0 comments on commit 80bd7eb

Please sign in to comment.