views:

117

answers:

2

Hello,

I am trying to compare the contents of 2 collections in a unit test in .NET using MSTEST. To make things simple, instead of having to .Sort() and then loop through the collection and compare items one at a time, I've found the new and very cool .Intersect Extension method.

It seems to work great by doing:

         Assert.AreEqual(expected.Count, actual.Intersect(expected).Count)

However, now that I have a test which needs to be case-sensitive, it breaks. I've tried sending Intersect's second parameter StringComparer.Ordinal,StringComparer.InvariantCulture, and StringComparer.CurrentCulture... no luck..

Anyone experience this before?

thanks!

EDIT: here is the data:

 Actual:
    (0) "FOO"   String
    (1) "foo"   String
    (2) "Foo"   String
    (3) "fOo"   String
    (4) "foO"   String
    (5) "BAR"   String
    (6) "BAR"   String
    (7) "BAZ"   String
    (8) "baz"   String
    (9) "foo"   String

 Expected:

    (0) "FOO"   String
    (1) "foo"   String
    (2) "Foo"   String
    (3) "fOo"   String
    (4) "foO"   String
    (5) "BAR"   String
    (6) "BAR"   String
    (7) "BAZ"   String
    (8) "baz"   String
    (9) "foo"   String

 actual.Intersect(expected, StringComparer.CurrentCulture)

    (0) "FOO"   String
    (1) "foo"   String
    (2) "Foo"   String
    (3) "fOo"   String
    (4) "foO"   String
    (5) "BAR"   String
    (6) "BAZ"   String
    (7) "baz"   String

It seems to be removing a matching duplicate 'foo', and a matching duplicate 'BAZ'. Perhaps there is a better way to assert collections are matching?

_EDIT2: I think Intersect() removes duplicates, which is why this is breaking. I Found the CollectionAssert Class. This is exactly what I needed! Thanks! _

+1  A: 

Implement an IEqualityComparer like so:

Class StringCaseInsensitiveComparer
    Implements IEqualityComparer(Of String)
    Public Function Equals(ByVal s1 As String, ByVal s2 As String) As Boolean
        Return s1.ToLower() = s2.ToLower()
    End Function
    Public Function GetHashCode(ByVal s As String) As Integer
        Return s.GetHashCode()
    End Function
End Class

Then, call this overload of Intersect:

Dim first As IEnumerable(Of TSource)
Dim second As IEnumerable(Of TSource)
Dim comparer As IEqualityComparer(Of TSource)
Dim returnValue As IEnumerable(Of TSource)

passing it an instance of the comparer that you just made.

Brett Widmeier
Thanks - I figured out I should be using CollectionAssert. But going back to the original problem - shouldn't the InvariantCulture and CurrentCulture comparers do exactly what you are doing here? They say in their documentation 'does a case sensitive compare'..
dferraro
Sorry, instead try using StringComparer.InvariantCultureIgnoreCase, StringComparer.OrdinalIgnoreCase, or StringComparer.CurrentCultureIgnoreCase.
Brett Widmeier
I realized that the issue isn't about case sensitivity - if you look at the above data, it seems that intersect() is filtering out duplicates. This is the issue
dferraro
@dferraro: intersect does filter them out, in a sense. I explained a bit in my response.
Ahmad Mageed
+2  A: 

For testing purposes use CollectionAssert.AreEqual(actual, expected)

You were looking for SequenceEqual, not Intersect. Intersect returns the intersection of two sequences, ie. the items shared between them. Using Intersect on { 1, 2, 3 } and { 3, 4, 5 } would return 3. SequenceEqual would return false.

Had you not found CollectionAssert you could've used:

Assert.IsTrue(actual.SequenceEqual(expected))
Ahmad Mageed
Thanks for the reply. I did look at the MSDN doc you posted.. one thing to note, SequenceEqual seems to compare references... not actual values... so I think SequenceEqual still would have failed without implementing IComparable. Still good to know though! thanks again
dferraro
@dferraro np... for a collection of strings or ints etc. you can use it directly and the default equality comparer is used for the values of the given type. For a custom class it would need an `IEqualityComparer` to determine just how to compare the objects.
Ahmad Mageed