diff --git a/Rhino.Mocks.Tests/Impl/ValidateTests.cs b/Rhino.Mocks.Tests/Impl/ValidateTests.cs
index 80420389..7defdf89 100644
--- a/Rhino.Mocks.Tests/Impl/ValidateTests.cs
+++ b/Rhino.Mocks.Tests/Impl/ValidateTests.cs
@@ -36,7 +36,64 @@ namespace Rhino.Mocks.Tests.Impl
{
public class ValidateTests
- {
+ {
+ private class AllObjectsCreatedEqualEqualityComparerImpl : IEqualityComparer
+ {
+ #region Implementation of IEqualityComparer
+
+ ///
+ /// Determines whether the specified objects are equal.
+ ///
+ ///
+ /// true if the specified objects are equal; otherwise, false.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// and are of different types and neither one can handle comparisons with the other.
+ ///
+ public bool Equals(object x, object y)
+ {
+ return true;
+ }
+
+ ///
+ /// Returns a hash code for the specified object.
+ ///
+ ///
+ /// A hash code for the specified object.
+ ///
+ /// The for which a hash code is to be returned.
+ /// The type of is a reference type and is null.
+ ///
+ public int GetHashCode(object obj)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+
+ [Fact]
+ public void ValidateUseEqualityComparerIfNotNull()
+ {
+ string string1 = "string1";
+ string string2 = "string2";
+
+ Assert.False(Validate.AreEqual(string1, string2));
+
+ try
+ {
+ // Implementation isn't important here. Just want to know that it gets called
+ Validate.EqualityComparer = new AllObjectsCreatedEqualEqualityComparerImpl();
+
+ Assert.True(Validate.AreEqual(string1, string2));
+ }
+ finally
+ {
+ Validate.EqualityComparer = null;
+ }
+ }
+
[Fact]
public void IsNotNullWhenNotNull()
{
diff --git a/Rhino.Mocks/Impl/Validate.cs b/Rhino.Mocks/Impl/Validate.cs
index 4856e8b4..19047fe3 100644
--- a/Rhino.Mocks/Impl/Validate.cs
+++ b/Rhino.Mocks/Impl/Validate.cs
@@ -1,138 +1,150 @@
-#region license
-// Copyright (c) 2005 - 2007 Ayende Rahien (ayende@ayende.com)
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Ayende Rahien nor the names of its
-// contributors may be used to endorse or promote products derived from this
-// software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-
-using System;
-using Rhino.Mocks.Interfaces;
-using System.Collections;
-
-namespace Rhino.Mocks.Impl
-{
- ///
- /// Validate arguments for methods
- ///
- public static class Validate
- {
- ///
- /// Validate that the passed argument is not null.
- ///
- /// The object to validate
- /// The name of the argument
- ///
- /// If the obj is null, an ArgumentNullException with the passed name
- /// is thrown.
- ///
- public static void IsNotNull(object obj, string name)
- {
- if (obj == null)
- throw new ArgumentNullException(name);
- }
-
- ///
- /// Validate that the arguments are equal.
- ///
- /// Expected args.
- /// Actual Args.
- public static bool ArgsEqual(object[] expectedArgs, object[] actualArgs)
- {
- return RecursiveCollectionEqual(expectedArgs, actualArgs);
- }
-
- ///
- /// Validate that the two arguments are equals, including validation for
- /// when the arguments are collections, in which case it will validate their values.
- ///
- public static bool AreEqual(object expectedArg, object actualArg)
- {
- return RecursiveCollectionEqual(new object[] { expectedArg }, new object[] { actualArg });
- }
-
- #region Implementation
-
- private static bool RecursiveCollectionEqual(ICollection expectedArgs, ICollection actualArgs)
- {
- if(expectedArgs == null && actualArgs == null)
- return true;
- if(expectedArgs==null || actualArgs==null)
- return false;
-
- if (expectedArgs.Count != actualArgs.Count)
- return false;
-
- IEnumerator expectedArgsEnumerator = expectedArgs.GetEnumerator();
- IEnumerator actualArgsEnumerator = actualArgs.GetEnumerator();
- while (expectedArgsEnumerator.MoveNext()
- && actualArgsEnumerator.MoveNext())
- {
- object expected = expectedArgsEnumerator.Current;
- object actual = actualArgsEnumerator.Current;
-
- if (expected == null)
- {
- if (actual == null)
- continue;
- else
- return false;
- }
-
- if (SafeEquals(expected, actual))
- continue;
-
- if (expected is ICollection)
- {
- if (!RecursiveCollectionEqual(expected as ICollection, actual as ICollection))
- return false;
-
- continue;
- }
- return false;
- }
- return true;
- }
-
- ///
- /// This method is safe for use even if any of the objects is a mocked object
- /// that override equals.
- ///
- private static bool SafeEquals(object expected, object actual)
- {
- IMockedObject expectedMock = expected as IMockedObject;
- IMockedObject actualMock = actual as IMockedObject;
- //none are mocked object
- if (expectedMock == null && actualMock == null)
- {
- return expected.Equals(actual);
- }
- //if any of them is a mocked object, use mocks equality
- //this may not be what the user is expecting, but it is needed, because
- //otherwise we get into endless loop.
- return MockedObjectsEquality.Instance.Equals(expected,actual);
- }
- #endregion
- }
-}
+#region license
+// Copyright (c) 2005 - 2007 Ayende Rahien (ayende@ayende.com)
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Ayende Rahien nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+
+using System;
+using Rhino.Mocks.Interfaces;
+using System.Collections;
+
+namespace Rhino.Mocks.Impl
+{
+ ///
+ /// Validate arguments for methods
+ ///
+ public static class Validate
+ {
+ ///
+ /// Gets or sets the equality comparer tha is used for testing the equality of two instances.
+ ///
+ /// If this is null then default equality is used.
+ /// The equality comparer.
+ public static IEqualityComparer EqualityComparer { get; set; }
+
+ ///
+ /// Validate that the passed argument is not null.
+ ///
+ /// The object to validate
+ /// The name of the argument
+ ///
+ /// If the obj is null, an ArgumentNullException with the passed name
+ /// is thrown.
+ ///
+ public static void IsNotNull(object obj, string name)
+ {
+ if (obj == null)
+ throw new ArgumentNullException(name);
+ }
+
+ ///
+ /// Validate that the arguments are equal.
+ ///
+ /// Expected args.
+ /// Actual Args.
+ public static bool ArgsEqual(object[] expectedArgs, object[] actualArgs)
+ {
+ return RecursiveCollectionEqual(expectedArgs, actualArgs);
+ }
+
+ ///
+ /// Validate that the two arguments are equals, including validation for
+ /// when the arguments are collections, in which case it will validate their values.
+ ///
+ public static bool AreEqual(object expectedArg, object actualArg)
+ {
+ return RecursiveCollectionEqual(new object[] { expectedArg }, new object[] { actualArg });
+ }
+
+ #region Implementation
+
+ private static bool RecursiveCollectionEqual(ICollection expectedArgs, ICollection actualArgs)
+ {
+ if (expectedArgs == null && actualArgs == null)
+ return true;
+ if (expectedArgs == null || actualArgs == null)
+ return false;
+
+ if (expectedArgs.Count != actualArgs.Count)
+ return false;
+
+ IEnumerator expectedArgsEnumerator = expectedArgs.GetEnumerator();
+ IEnumerator actualArgsEnumerator = actualArgs.GetEnumerator();
+ while (expectedArgsEnumerator.MoveNext()
+ && actualArgsEnumerator.MoveNext())
+ {
+ object expected = expectedArgsEnumerator.Current;
+ object actual = actualArgsEnumerator.Current;
+
+ if (expected == null)
+ {
+ if (actual == null)
+ continue;
+ else
+ return false;
+ }
+
+ if (SafeEquals(expected, actual))
+ continue;
+
+ if (expected is ICollection)
+ {
+ if (!RecursiveCollectionEqual(expected as ICollection, actual as ICollection))
+ return false;
+
+ continue;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ ///
+ /// This method is safe for use even if any of the objects is a mocked object
+ /// that override equals.
+ ///
+ private static bool SafeEquals(object expected, object actual)
+ {
+ IMockedObject expectedMock = expected as IMockedObject;
+ IMockedObject actualMock = actual as IMockedObject;
+ //none are mocked object
+ if (expectedMock == null && actualMock == null)
+ {
+ if (EqualityComparer != null)
+ {
+ return EqualityComparer.Equals(expected, actual);
+ }
+
+ return expected.Equals(actual);
+ }
+ //if any of them is a mocked object, use mocks equality
+ //this may not be what the user is expecting, but it is needed, because
+ //otherwise we get into endless loop.
+ return MockedObjectsEquality.Instance.Equals(expected, actual);
+ }
+ #endregion
+ }
+}