Skip to content

Commit 80bd7eb

Browse files
authored
Merge pull request #256 from sebasijan/ignore-collection-count
ignore collection count
2 parents f578c61 + 4f44ee9 commit 80bd7eb

File tree

4 files changed

+211
-1
lines changed

4 files changed

+211
-1
lines changed

Compare-NET-Objects-Tests/IgnoreTests.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Dynamic;
4+
using System.Linq;
35
using KellermanSoftware.CompareNetObjects;
46
using KellermanSoftware.CompareNetObjectsTests.TestClasses;
57
using KellermanSoftware.CompareNetObjectsTests.TestClasses.IgnoreExample;
@@ -137,5 +139,56 @@ public void IgnoreDerivedClassPropertyUsingIgnoreProperty()
137139
result = compare.Compare(derive2FromOfficer1, derive2FromOfficer2);
138140
Assert.IsFalse(result.AreEqual);
139141
}
140-
}
142+
143+
144+
[Test]
145+
public void IgnoreReadonlyCollection()
146+
{
147+
var coll1 = new List<int>
148+
{
149+
1, 2, 3, 4, 5
150+
}.AsReadOnly();
151+
var coll2 = new List<int>
152+
{
153+
1, 2, 3, 4, 5, 6
154+
}.AsReadOnly();
155+
var compareLogic = new CompareLogic
156+
{
157+
Config = new ComparisonConfig
158+
{
159+
MaxDifferences = int.MaxValue,
160+
CompareReadOnly = false
161+
}
162+
};
163+
164+
var result = compareLogic.Compare(coll1, coll2);
165+
Assert.AreEqual(result.Differences.Count, 0);
166+
167+
var obj1 = new
168+
{
169+
Name = "test",
170+
Collection = coll1
171+
};
172+
var obj2 = new
173+
{
174+
Name = "test",
175+
Collection = coll2
176+
};
177+
178+
result = compareLogic.Compare(obj1, obj2);
179+
Assert.AreEqual(result.Differences.Count, 0);
180+
181+
compareLogic = new CompareLogic
182+
{
183+
Config = new ComparisonConfig
184+
{
185+
MaxDifferences = int.MaxValue,
186+
CompareReadOnly = true
187+
}
188+
};
189+
190+
result = compareLogic.Compare(obj1, obj2);
191+
Assert.AreEqual(result.Differences.Count, 1);
192+
}
193+
}
141194
}

Compare-NET-Objects/RootComparerFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ private static RootComparer BuildRootComparer()
4141
_rootComparer.TypeComparers.Add(new DoubleComparer(_rootComparer));
4242
_rootComparer.TypeComparers.Add(new PointerComparer(_rootComparer));
4343
_rootComparer.TypeComparers.Add(new SimpleTypeComparer(_rootComparer));
44+
_rootComparer.TypeComparers.Add(new ReadOnlyCollectionComparer(_rootComparer));
4445
_rootComparer.TypeComparers.Add(new ListComparer(_rootComparer));
4546

4647
#if NETFULL || NETSTANDARD2_0 || NETSTANDARD2_1
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using KellermanSoftware.CompareNetObjects.IgnoreOrderTypes;
2+
using System;
3+
using System.Collections;
4+
using System.Collections.Generic;
5+
using System.Collections.ObjectModel;
6+
using System.Globalization;
7+
using System.Linq;
8+
using System.Text;
9+
10+
namespace KellermanSoftware.CompareNetObjects.TypeComparers
11+
{
12+
/// <summary>
13+
/// Logic to compare two ReadOnlyCollections.
14+
/// </summary>
15+
public class ReadOnlyCollectionComparer : BaseTypeComparer
16+
{
17+
/// <summary>
18+
/// The main constructor.
19+
/// </summary>
20+
public ReadOnlyCollectionComparer(RootComparer rootComparer) : base(rootComparer)
21+
{
22+
23+
}
24+
25+
/// <summary>
26+
/// Returns true if both objects are ReadOnlyCollections.
27+
/// </summary>
28+
/// <param name="type1">The type of the first object</param>
29+
/// <param name="type2">The type of the second object</param>
30+
/// <returns></returns>
31+
public override bool IsTypeMatch(Type type1, Type type2)
32+
{
33+
return TypeHelper.IsReadOnlyCollection(type1) && TypeHelper.IsReadOnlyCollection(type2);
34+
}
35+
36+
/// <summary>
37+
/// Compare two ReadOnlyCollections.
38+
/// </summary>
39+
public override void CompareType(CompareParms parms)
40+
{
41+
if (!parms.Config.CompareReadOnly)
42+
return;
43+
44+
try
45+
{
46+
parms.Result.AddParent(parms.Object1);
47+
parms.Result.AddParent(parms.Object2);
48+
49+
Type t1 = parms.Object1.GetType();
50+
Type t2 = parms.Object2.GetType();
51+
52+
//Check if the class type should be excluded based on the configuration
53+
if (ExcludeLogic.ShouldExcludeClass(parms.Config, t1, t2))
54+
return;
55+
56+
parms.Object1Type = t1;
57+
parms.Object2Type = t2;
58+
59+
bool countsDifferent = CollectionsDifferentCount(parms);
60+
61+
if (parms.Result.ExceededDifferences)
62+
return;
63+
64+
if (parms.Config.IgnoreCollectionOrder)
65+
{
66+
IgnoreOrderLogic logic = new IgnoreOrderLogic(RootComparer);
67+
logic.CompareEnumeratorIgnoreOrder(parms, countsDifferent);
68+
}
69+
else
70+
{
71+
CompareItems(parms);
72+
}
73+
}
74+
finally
75+
{
76+
parms.Result.RemoveParent(parms.Object1);
77+
parms.Result.RemoveParent(parms.Object2);
78+
}
79+
}
80+
81+
private void CompareItems(CompareParms parms)
82+
{
83+
int count = 0;
84+
85+
IEnumerator enumerator1 = ((ICollection)parms.Object1).GetEnumerator();
86+
IEnumerator enumerator2 = ((ICollection)parms.Object2).GetEnumerator();
87+
88+
while (enumerator1.MoveNext() && enumerator2.MoveNext())
89+
{
90+
string currentBreadCrumb = AddBreadCrumb(parms.Config, parms.BreadCrumb, string.Empty, string.Empty, count);
91+
92+
CompareParms childParms = new CompareParms
93+
{
94+
Result = parms.Result,
95+
Config = parms.Config,
96+
ParentObject1 = parms.Object1,
97+
ParentObject2 = parms.Object2,
98+
Object1 = enumerator1.Current,
99+
Object2 = enumerator2.Current,
100+
BreadCrumb = currentBreadCrumb
101+
};
102+
103+
RootComparer.Compare(childParms);
104+
105+
if (parms.Result.ExceededDifferences)
106+
return;
107+
108+
count++;
109+
}
110+
}
111+
112+
private bool CollectionsDifferentCount(CompareParms parms)
113+
{
114+
//Get count by reflection since we can't cast it to HashSet<>
115+
int count1 = ((ICollection)parms.Object1).Count;
116+
int count2 = ((ICollection)parms.Object2).Count;
117+
118+
//Objects must be the same length
119+
if (count1 != count2)
120+
{
121+
Difference difference = new Difference
122+
{
123+
ParentObject1 = parms.ParentObject1,
124+
ParentObject2 = parms.ParentObject2,
125+
PropertyName = parms.BreadCrumb,
126+
Object1Value = count1.ToString(CultureInfo.InvariantCulture),
127+
Object2Value = count2.ToString(CultureInfo.InvariantCulture),
128+
ChildPropertyName = "Count",
129+
Object1 = parms.Object1,
130+
Object2 = parms.Object2
131+
};
132+
133+
AddDifference(parms.Result, difference);
134+
135+
return true;
136+
}
137+
138+
return false;
139+
}
140+
}
141+
}

Compare-NET-Objects/TypeHelper.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#if !NETSTANDARD
1212
using System.Data;
1313
using System.Drawing;
14+
using System.Runtime.CompilerServices;
1415
#endif
1516

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

121+
/// <summary>
122+
/// True if the type is a System.Collections.ObjectModel.ReadOnlyCollection
123+
/// </summary>
124+
/// <param name="type"></param>
125+
/// <returns></returns>
126+
public static bool IsReadOnlyCollection(Type type)
127+
{
128+
if (type == null)
129+
return false;
130+
131+
return (type.Namespace == "System.Collections.ObjectModel"
132+
&& type.Name == "ReadOnlyCollection`1");
133+
}
134+
120135
/// <summary>
121136
/// Returns true if it is a struct
122137
/// </summary>

0 commit comments

Comments
 (0)