diff --git a/Rhino.Mocks.Tests/MultiMocksWithAAA.cs b/Rhino.Mocks.Tests/MultiMocksWithAAA.cs new file mode 100644 index 00000000..3952c26e --- /dev/null +++ b/Rhino.Mocks.Tests/MultiMocksWithAAA.cs @@ -0,0 +1,461 @@ +#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 System.Collections; +using System.ComponentModel; +using System.IO; +using System.Text; +using System.Xml; + +using MbUnit.Framework; +using Rhino.Mocks.Exceptions; +using Rhino.Mocks.Interfaces; + +namespace Rhino.Mocks.Tests +{ + [TestFixture] + public class MultiMocksAAA + { + [Test, Description("Tests that AAA can be used easily with Multi-Mocks")] + public void CanCreateADynamicMultiMockFromTwoInterfacesGenericAndAssertWasCalled() + { + IDemo demo = MockRepository.GenerateMock(); + IEditableObject editable = demo as IEditableObject; + + demo.ReturnIntNoArgs(); + editable.BeginEdit(); + editable.CancelEdit(); // we don't care about this + editable.EndEdit(); + + demo.AssertWasCalled(x => x.ReturnIntNoArgs()); + editable.AssertWasCalled(x => x.BeginEdit()); + editable.AssertWasCalled(x => x.EndEdit()); + + // Double check all expectations were verified + editable.VerifyAllExpectations(); + } + + #region CanCreateAStrictMultiMockFromTwoInterfaces + [Test] + public void CanCreateAStrictMultiMockFromTwoInterfacesNonGeneric() + { + IDemo demo = (IDemo)MockRepository.GenerateStrictMock(typeof(IDemo), new Type[]{typeof(IDisposable)}); + CanCreateAStrictMultiMockFromTwoInterfacesCommon(demo); + } + + [Test] + public void CanCreateAStrictMultiMockFromTwoInterfacesGeneric() + { + IDemo demo = MockRepository.GenerateStrictMock(); + CanCreateAStrictMultiMockFromTwoInterfacesCommon(demo); + } + + private static void CanCreateAStrictMultiMockFromTwoInterfacesCommon(IDemo demo) + { + demo.Expect(x => x.ReturnIntNoArgs()).Return(1); + IDisposable disposable = demo as IDisposable; + Assert.IsNotNull(disposable); + disposable.Expect(x => x.Dispose()); + + Assert.AreEqual(1, demo.ReturnIntNoArgs()); + disposable.Dispose(); + + demo.VerifyAllExpectations(); + } + #endregion + + #region ClearStrictCollectionAndDisposesIt + [Test] + public void ClearStrictCollectionAndDisposesItNonGeneric() + { + CollectionBase collection = (CollectionBase)MockRepository.GenerateStrictMock(typeof(CollectionBase), new Type[]{typeof(IDisposable)}); + ClearStrictCollectionAndDisposesItCommon(collection); + } + + [Test] + public void ClearStrictCollectionAndDisposesItGeneric() + { + CollectionBase collection = MockRepository.GenerateStrictMock(); + ClearStrictCollectionAndDisposesItCommon(collection); + } + + private static void ClearStrictCollectionAndDisposesItCommon(CollectionBase collection) + { + collection.Expect(x => x.Clear()); + ((IDisposable)collection).Expect(x => x.Dispose()); + + CleanCollection(collection); + collection.VerifyAllExpectations(); + } + + private static void CleanCollection(CollectionBase collection) + { + collection.Clear(); + IDisposable disposable = collection as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + #endregion + + #region CanCreateAStrictMultiMockFromClassAndTwoInterfacesNonGeneric + [Test] + public void CanCreateAStrictMultiMockFromClassAndTwoInterfacesNonGeneric() + { + XmlReader reader = (XmlReader)MockRepository.GenerateStrictMock(typeof(XmlReader), new Type[]{typeof(ICloneable), typeof(IHasXmlNode)}); + + CanCreateAStrictMultiMockFromClassAndTwoInterfacesCommon(reader); + } + + [Test] + public void CanCreateAStrictMultiMockFromClassAndTwoInterfacesGeneric() + { + XmlReader reader = MockRepository.GenerateStrictMock(); + + CanCreateAStrictMultiMockFromClassAndTwoInterfacesCommon(reader); + } + + private static void CanCreateAStrictMultiMockFromClassAndTwoInterfacesCommon(XmlReader reader) + { + reader.Expect(x => x.AttributeCount).Return(3); + + ICloneable cloneable = reader as ICloneable; + Assert.IsNotNull(cloneable); + cloneable.Expect(x => x.Clone()).Return(reader); + + IHasXmlNode hasXmlNode = reader as IHasXmlNode; + Assert.IsNotNull(hasXmlNode); + + XmlNode node = new XmlDocument(); + hasXmlNode.Expect(x => x.GetNode()).Return(node); + + Assert.AreEqual(3, reader.AttributeCount); + Assert.AreEqual(node, hasXmlNode.GetNode()); + + Assert.AreSame(cloneable, cloneable.Clone()); + + reader.VerifyAllExpectations(); + } + #endregion + + #region CanCreateAStrictMultiMockWithConstructorArgs + [Test] + public void CanCreateAStrictMultiMockWithConstructorArgsNonGeneric() + { + + StringBuilder stringBuilder = new StringBuilder(); + IFormatProvider formatProvider = (IFormatProvider)MockRepository.GenerateStrictMock(typeof(IFormatProvider), new Type[0]); + + StringWriter mockedWriter = (StringWriter)MockRepository.GenerateStrictMock( + typeof(StringWriter), + new Type[] { typeof(IDataErrorInfo) }, + stringBuilder, + formatProvider + ); + + CommonConstructorArgsTest(stringBuilder, formatProvider, mockedWriter, MockType.Strict); + } + + [Test] + public void CanCreateAStrictMultiMockWithConstructorArgsGeneric() + { + + StringBuilder stringBuilder = new StringBuilder(); + IFormatProvider formatProvider = MockRepository.GenerateStrictMock(); + + StringWriter mockedWriter = MockRepository.GenerateStrictMock( + stringBuilder, + formatProvider + ); + + CommonConstructorArgsTest(stringBuilder, formatProvider, mockedWriter, MockType.Strict); + } + + #endregion + + #region CanCreateADynamicMultiMockFromTwoInterfacesNonGeneric + [Test] + public void CanCreateADynamicMultiMockFromTwoInterfacesNonGeneric() + { + object o = MockRepository.GenerateMock(typeof(IDemo), new Type[]{typeof(IEditableObject)}); + + IDemo demo = o as IDemo; + IEditableObject editable = o as IEditableObject; + + CanCreateADynamicMultiMockFromTwoInterfacesCommon(demo, editable); + } + + [Test] + public void CanCreateADynamicMultiMockFromTwoInterfacesGeneric() + { + IDemo demo = MockRepository.GenerateMock(); + IEditableObject editable = demo as IEditableObject; + + CanCreateADynamicMultiMockFromTwoInterfacesCommon(demo, editable); + } + + private static void CanCreateADynamicMultiMockFromTwoInterfacesCommon(IDemo demo, IEditableObject editable) + { + Assert.IsNotNull(demo, "IDemo null"); + Assert.IsNotNull(editable, "IEditableObject null"); + + // Set expectation on one member on each interface + + demo.Expect(x => demo.ReadOnly).Return("foo"); + editable.Expect(x => x.BeginEdit()); + + // Drive two members on each interface to check dynamic nature + + Assert.AreEqual("foo", demo.ReadOnly); + demo.VoidNoArgs(); + + editable.BeginEdit(); + editable.EndEdit(); + + demo.VerifyAllExpectations(); + } + #endregion + + #region CanCreateADynamicMultiMockWithConstructorArgs + [Test(Description = "Tests that we can dynamic multi-mock a class with constructor arguments")] + public void CanCreateADynamicMultiMockWithConstructorArgsNonGeneric() + { + StringBuilder stringBuilder = new StringBuilder(); + IFormatProvider formatProvider = (IFormatProvider)MockRepository.GenerateStrictMock(typeof(IFormatProvider), new Type[0]); + + StringWriter mockedWriter = (StringWriter)MockRepository.GenerateMock( + typeof(StringWriter), + new Type[] { typeof(IDataErrorInfo) }, + stringBuilder, + formatProvider + ); + CommonConstructorArgsTest(stringBuilder, formatProvider, mockedWriter, MockType.Dynamic); + } + + [Test(Description = "Tests that we can dynamic generic multi-mock a class with constructor arguments")] + public void CanCreateADynamicMultiMockWithConstructorArgsGeneric() + { + StringBuilder stringBuilder = new StringBuilder(); + IFormatProvider formatProvider = MockRepository.GenerateStrictMock(); + + StringWriter mockedWriter = MockRepository.GenerateMock( + stringBuilder, + formatProvider + ); + CommonConstructorArgsTest(stringBuilder, formatProvider, mockedWriter, MockType.Dynamic); + } + + #endregion + + #region CanCreateAPartialMultiMockFromClassAndTwoInterfacesNonGeneric + [Test] + public void CanCreateAPartialMultiMockFromClassAndTwoInterfacesNonGeneric() + { + XmlReader reader = (XmlReader)MockRepository.GeneratePartialMock(typeof(XmlReader), new Type[]{typeof(ICloneable), typeof(IHasXmlNode)}); + + CanCreateAPartialMultiMockFromClassAndTwoInterfacesCommon(reader); + } + + [Test] + public void CanCreateAPartialMultiMockFromClassAndTwoInterfacesGeneric() + { + XmlReader reader = MockRepository.GeneratePartialMock(); + + CanCreateAPartialMultiMockFromClassAndTwoInterfacesCommon(reader); + } + + private static void CanCreateAPartialMultiMockFromClassAndTwoInterfacesCommon(XmlReader reader) + { + reader.Expect(x => x.AttributeCount).Return(3); + + ICloneable cloneable = reader as ICloneable; + Assert.IsNotNull(cloneable); + + cloneable.Expect(x => x.Clone()).Return(reader); + + IHasXmlNode hasXmlNode = reader as IHasXmlNode; + Assert.IsNotNull(hasXmlNode); + + XmlNode node = new XmlDocument(); + hasXmlNode.Expect(x => x.GetNode()).Return(node); + + Assert.AreEqual(3, reader.AttributeCount); + Assert.AreEqual(node, hasXmlNode.GetNode()); + + Assert.AreSame(cloneable, cloneable.Clone()); + + reader.VerifyAllExpectations(); + } + #endregion + + #region CanConstructAPartialMultiMockWithConstructorArgs + [Test(Description = "Tests that we can partial multi-mock a class with constructor arguments")] + public void CanCreateAPartialMultiMockWithConstructorArgsNonGeneric() + { + StringBuilder stringBuilder = new StringBuilder(); + IFormatProvider formatProvider = (IFormatProvider)MockRepository.GenerateStrictMock(typeof(IFormatProvider), new Type[0]); + + StringWriter mockedWriter = (StringWriter)MockRepository.GeneratePartialMock( + typeof(StringWriter), + new Type[] { typeof(IDataErrorInfo) }, + stringBuilder, + formatProvider + ); + + CommonConstructorArgsTest(stringBuilder, formatProvider, mockedWriter, MockType.Partial); + } + + [Test(Description = "Tests that we can partial generic multi-mock a class with constructor arguments")] + public void CanCreateAPartialMultiMockWithConstructorArgsGeneric() + { + StringBuilder stringBuilder = new StringBuilder(); + IFormatProvider formatProvider = MockRepository.GenerateStrictMock(); + + StringWriter mockedWriter = MockRepository.GeneratePartialMock( + stringBuilder, + formatProvider + ); + + CommonConstructorArgsTest(stringBuilder, formatProvider, mockedWriter, MockType.Partial); + } + #endregion + + #region Check cannot create multi mocks using extra classes + [Test] + [ExpectedException(typeof(ArgumentException))] + public void CannotMultiMockUsingClassesAsExtras() + { + MockRepository.GenerateStrictMock(typeof(XmlReader), new Type[]{typeof(XmlWriter)}); + } + #endregion + + #region RepeatedInterfaceMultiMocks + public interface IMulti + { + void OriginalMethod1(); + void OriginalMethod2(); + } + public class MultiClass : IMulti + { + // NON-virtual method + public void OriginalMethod1() { } + // VIRTUAL method + public virtual void OriginalMethod2() { } + } + public interface ISpecialMulti : IMulti + { + void ExtraMethod(); + } + + [Test(Description = "Tests that MultiMocks can mock class hierarchies where interfaces are repeated")] + public void RepeatedInterfaceMultiMocks() + { + object o = MockRepository.GenerateStrictMock(typeof(MultiClass), new Type[]{typeof(ISpecialMulti)}); + + Assert.IsTrue(o is MultiClass, "Object should be MultiClass"); + Assert.IsTrue(o is IMulti, "Object should be IMulti"); + Assert.IsTrue(o is ISpecialMulti, "Object should be ISpecialMulti"); + } + #endregion + + #region CommonConstructorArgsTest + private enum MockType { Strict, Dynamic, Partial } + + // Helper class to provide a common set of tests for constructor-args based + // multi-mocks testing. Exercises a mocked StringWriter (which should also be an IDataErrorInfo) + // constructed with a mocked IFormatProvider. The test checks the semantics + // of the mocked StringWriter to compare it with the expected semantics. + private static void CommonConstructorArgsTest(StringBuilder stringBuilder, IFormatProvider formatProvider, StringWriter mockedWriter, MockType mockType) + { + string stringToWrite = "The original string"; + string stringToWriteLine = "Extra bit"; + + IDataErrorInfo errorInfo = mockedWriter as IDataErrorInfo; + Assert.IsNotNull(errorInfo); + + // Configure expectations for mocked writer + mockedWriter.Stub(x => x.FormatProvider).Return(formatProvider).CallOriginalMethod(OriginalCallOptions.CreateExpectation); + mockedWriter.Expect(x => x.Write((string) null)).IgnoreArguments().CallOriginalMethod(OriginalCallOptions.CreateExpectation); + mockedWriter.Expect(x => x.Flush()).Repeat.Any().CallOriginalMethod(OriginalCallOptions.CreateExpectation); + mockedWriter.Expect(x => x.Close()); + + + // Configure expectations for object through interface + errorInfo.Expect(x => x.Error).Return(null).Repeat.Once(); + errorInfo.Expect(x => x.Error).Return("error!!!").Repeat.Once(); + + // Ensure that arguments arrived okay + // Is the format provider correct + Assert.AreSame(formatProvider, mockedWriter.FormatProvider, "FormatProvider"); + // Does writing to the writer forward to our stringbuilder from the constructor? + mockedWriter.Write(stringToWrite); + mockedWriter.Flush(); + + // Let's see what mode our mock is running in. + // We have not configured WriteLine at all, so: + // a) if we're running as a strict mock, it'll fail + // b) if we're running as a dynamic mock, it'll no-op + // c) if we're running as a partial mock, it'll work + try + { + mockedWriter.WriteLine(stringToWriteLine); + } + catch (ExpectationViolationException) + { + // We're operating strictly. + Assert.AreEqual(MockType.Strict, mockType); + } + + string expectedStringBuilderContents = null; + switch (mockType) + { + case MockType.Dynamic: + case MockType.Strict: + // The writeline won't have done anything + expectedStringBuilderContents = stringToWrite; + break; + case MockType.Partial: + // The writeline will have worked + expectedStringBuilderContents = stringToWrite + stringToWriteLine + Environment.NewLine; + break; + } + + Assert.AreEqual(expectedStringBuilderContents, stringBuilder.ToString()); + + // Satisfy expectations. + mockedWriter.Close(); + Assert.IsNull(errorInfo.Error, "Error should be null"); + Assert.AreEqual("error!!!", errorInfo.Error, "Should have gotten an error"); + + if (MockType.Strict != mockType) + mockedWriter.VerifyAllExpectations(); + } + #endregion + } +} diff --git a/Rhino.Mocks.Tests/PartialMockTestsAAA.cs b/Rhino.Mocks.Tests/PartialMockTestsAAA.cs new file mode 100644 index 00000000..6e49bd07 --- /dev/null +++ b/Rhino.Mocks.Tests/PartialMockTestsAAA.cs @@ -0,0 +1,101 @@ +#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 MbUnit.Framework; +using Rhino.Mocks.Exceptions; + +namespace Rhino.Mocks.Tests +{ + [TestFixture] + public class PartialMockTestsAAA + { + private AbstractClass abs; + + [SetUp] + public void SetUp() + { + abs = (AbstractClass) MockRepository.GeneratePartialMock(typeof (AbstractClass), new Type[] {}); + } + + [Test] + public void AutomaticallCallBaseMethodIfNoExpectationWasSet() + { + Assert.AreEqual(1, abs.Increment()); + Assert.AreEqual(6, abs.Add(5)); + Assert.AreEqual(6, abs.Count); + abs.VerifyAllExpectations(); + } + + [Test] + public void CanMockVirtualMethods() + { + abs.Expect(x => x.Increment()).Return(5); + abs.Expect(x => x.Add(2)).Return(3); + + Assert.AreEqual(5, abs.Increment()); + Assert.AreEqual(3, abs.Add(2)); + Assert.AreEqual(0, abs.Count); + abs.VerifyAllExpectations(); + } + + [Test] + public void CanMockAbstractMethods() + { + abs.Expect(x => x.Decrement()).Return(5); + Assert.AreEqual(5, abs.Decrement()); + Assert.AreEqual(0, abs.Count); + abs.VerifyAllExpectations(); + } + + [Test] + [ExpectedException(typeof (InvalidOperationException), "Can't create a partial mock from an interface")] + public void CantCreatePartialMockFromInterfaces() + { + MockRepository.GeneratePartialMock(); + } + + [Test] + [ExpectedException(typeof (ExpectationViolationException), "AbstractClass.Decrement(); Expected #0, Actual #1.")] + public void CallAnAbstractMethodWithoutSettingExpectation() + { + abs.Decrement(); + } + + [Test] + public void CanMockWithCtorParams() + { + var withParameters = MockRepository.GeneratePartialMock(1); + withParameters.Expect(x => x.Int).Return(4); + Assert.AreEqual(4, withParameters.Int); + withParameters.VerifyAllExpectations(); + } + } +} \ No newline at end of file diff --git a/Rhino.Mocks.Tests/Rhino.Mocks.Tests 3.5.csproj b/Rhino.Mocks.Tests/Rhino.Mocks.Tests 3.5.csproj index 4db85dff..5fad1bb3 100644 --- a/Rhino.Mocks.Tests/Rhino.Mocks.Tests 3.5.csproj +++ b/Rhino.Mocks.Tests/Rhino.Mocks.Tests 3.5.csproj @@ -83,6 +83,14 @@ False ..\..\SharedLibs\Castle\Castle.DynamicProxy2.dll + + False + ..\..\SharedLibs\Interop\Interop.ADODB.dll + + + False + ..\..\SharedLibs\Interop\Interop.MSHTML.dll + False ..\..\SharedLibs\Tools\MbUnit\MbUnit.Framework.dll @@ -144,6 +152,8 @@ Code + + @@ -397,30 +407,6 @@ {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8} {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - {2A75196C-D9EB-4129-B803-931327F72D5C} - 2 - 8 - 0 - tlbimp - False - - - {3050F1C5-98B5-11CF-BB82-00AA00BDCE0B} - 4 - 0 - 0 - tlbimp - False - - - {420B2830-E718-11CF-893D-00A0C9054228} - 1 - 0 - 0 - tlbimp - False - @@ -447,5 +433,15 @@ false + + + {420B2830-E718-11CF-893D-00A0C9054228} + 1 + 0 + 0 + tlbimp + False + + \ No newline at end of file diff --git a/Rhino.Mocks.Tests/default.build b/Rhino.Mocks.Tests/default.build index e5693703..200e3a48 100644 --- a/Rhino.Mocks.Tests/default.build +++ b/Rhino.Mocks.Tests/default.build @@ -15,7 +15,7 @@ - + diff --git a/Rhino.Mocks/MockRepository.cs b/Rhino.Mocks/MockRepository.cs index 72b93edd..fe6a6641 100644 --- a/Rhino.Mocks/MockRepository.cs +++ b/Rhino.Mocks/MockRepository.cs @@ -428,6 +428,7 @@ public object CreateMultiMock(Type mainType, Type[] extraTypes, params object[] /// Arguments for the class' constructor, if mocking a concrete class. public object StrictMultiMock(Type mainType, Type[] extraTypes, params object[] argumentsForConstructor) { + if (argumentsForConstructor == null) argumentsForConstructor = new object[0]; return CreateMockObject(mainType, CreateRecordState, extraTypes, argumentsForConstructor); } @@ -461,9 +462,7 @@ public object DynamicMultiMock(Type mainType, Type[] extraTypes, params object[] * null or zero is returned (if there is a return value). */ - /// - /// Creates a dynamic mock for the specified type. - /// + /// Creates a dynamic mock for the specified type. /// Type. /// Arguments for the class' constructor, if mocking a concrete class public object DynamicMock(Type type, params object[] argumentsForConstructor) @@ -473,9 +472,7 @@ public object DynamicMock(Type type, params object[] argumentsForConstructor) return DynamicMultiMock(type, new Type[0], argumentsForConstructor); } - /// - /// Creates a dynamic mock for the specified type. - /// + /// Creates a dynamic mock for the specified type. /// Type. /// Arguments for the class' constructor, if mocking a concrete class public object DynamicMockWithRemoting(Type type, params object[] argumentsForConstructor) @@ -483,9 +480,7 @@ public object DynamicMockWithRemoting(Type type, params object[] argumentsForCon return RemotingMock(type, CreateDynamicRecordState); } - /// - /// Creates a dynamic mock for the specified type. - /// + /// Creates a dynamic mock for the specified type. /// /// Arguments for the class' constructor, if mocking a concrete class /// @@ -494,16 +489,7 @@ public T DynamicMockWithRemoting(params object[] argumentsForConstructor) return (T)RemotingMock(typeof(T), CreateDynamicRecordState); } - /* - * Method: PartialMock - * Create a mock object with from a class that defaults to calling the class methods - * if no expectation is set on the method. - * - */ - - /// - /// Creates a mock object that defaults to calling the class methods. - /// + /// Creates a mock object that defaults to calling the class methods if no expectation is set on the method. /// Type. /// Arguments for the class' constructor. public object PartialMock(Type type, params object[] argumentsForConstructor) @@ -511,9 +497,7 @@ public object PartialMock(Type type, params object[] argumentsForConstructor) return PartialMultiMock(type, new Type[0], argumentsForConstructor); } - /// - /// Creates a mock object that defaults to calling the class methods. - /// + /// Creates a mock object that defaults to calling the class methods. /// Type. /// Extra interface types to mock. public object PartialMultiMock(Type type, params Type[] extraTypes) @@ -521,9 +505,7 @@ public object PartialMultiMock(Type type, params Type[] extraTypes) return PartialMultiMock(type, extraTypes, new object[0]); } - /// - /// Creates a mock object that defaults to calling the class methods. - /// + /// Creates a mock object that defaults to calling the class methods. /// Type. /// Extra interface types to mock. /// Arguments for the class' constructor. @@ -536,9 +518,7 @@ public object PartialMultiMock(Type type, Type[] extraTypes, params object[] arg return CreateMockObject(type, CreatePartialRecordState, extraTypesWithMarker.ToArray(), argumentsForConstructor); } - /// - /// Creates a mock object using remoting proxies - /// + /// Creates a mock object using remoting proxies /// Type to mock - must be MarshalByRefObject /// Mock object /// Proxy mock can mock non-virtual methods, but not static methods @@ -553,17 +533,11 @@ private object RemotingMock(Type type, CreateMockState factory) return transparentProxy; } - - /* - * Method: Replay - * Moves a single mock object to the replay state. - * This method *cannot* be called from inside an ordering. - */ - /// /// Cause the mock state to change to replay, any further call is compared to the /// ones that were called in the record state. /// + /// This method *cannot* be called from inside an ordering. /// the object to move to replay state public void Replay(object obj) { @@ -591,23 +565,8 @@ protected internal void ReplayCore(object obj, bool checkInsideOrdering) } } - /* - * Method: BackToRecord - * - * Moves the mocked object back to record state. - * This works on mock objects regardless of state. - * You can (and it's recommended) to run before you use this method, but it's not neccecary. - * - * Note: - * This will remove all the current expectations from the mock repository. - * - * - */ - - /// - /// Move the mocked object back to record state. - /// Will delete all current expectations! - /// + /// Move the mocked object back to record state.You can (and it's recommended) to run {Verify()} before you use this method. + /// Will delete all current expectations! public void BackToRecord(object obj) { BackToRecord(obj, BackToRecordOptions.All); @@ -760,16 +719,13 @@ private void ClearLastProxy(object obj) lastMockedObject = null; } - private object MockClass(CreateMockState mockStateFactory, Type type, Type[] extras, - object[] argumentsForConstructor) + private object MockClass(CreateMockState mockStateFactory, Type type, Type[] extras, object[] argumentsForConstructor) { if (type.IsSealed) throw new NotSupportedException("Can't create mocks of sealed classes"); List implementedTypesForGenericInvocationDiscoverability = new List(extras); implementedTypesForGenericInvocationDiscoverability.Add(type); - RhinoInterceptor interceptor = new RhinoInterceptor(this, new ProxyInstance(this, - implementedTypesForGenericInvocationDiscoverability - .ToArray())); + RhinoInterceptor interceptor = new RhinoInterceptor(this, new ProxyInstance(this, implementedTypesForGenericInvocationDiscoverability.ToArray())); ArrayList types = new ArrayList(); types.AddRange(extras); types.Add(typeof(IMockedObject)); @@ -839,17 +795,13 @@ private object MockDelegate(CreateMockState mockStateFactory, Type type) return proxy; } - /// - /// This is provided to allow advance extention functionality, where Rhino Mocks standard - /// functionality is not enough. - /// + /// This is provided to allow advance extention functionality, where Rhino Mocks standard functionality is not enough. /// The type to mock /// Delegate that create the first state of the mocked object (usualy the record state). /// Additional types to be implemented, this can be only interfaces /// optional arguments for the constructor /// - protected object CreateMockObject(Type type, CreateMockState factory, Type[] extras, - params object[] argumentsForConstructor) + protected object CreateMockObject(Type type, CreateMockState factory, Type[] extras, params object[] argumentsForConstructor) { foreach (Type extraType in extras) { @@ -932,18 +884,14 @@ protected internal static IMockedObject GetMockedObjectOrNull(object mockedInsta return null; } - /// - /// Pops the recorder. - /// + /// Pops the recorder. internal void PopRecorder() { if (recorders.Count > 1) recorders.Pop(); } - /// - /// Pushes the recorder. - /// + /// Pushes the recorder. /// New recorder. internal void PushRecorder(IMethodRecorder newRecorder) { @@ -1067,11 +1015,6 @@ public void VerifyAll() throw new ExpectationViolationException(sb.ToString()); } - /* - * Property: Replayer - * The replayer for the repository. - */ - /// /// Gets the replayer for this repository. /// @@ -1081,11 +1024,6 @@ internal IMethodRecorder Replayer get { return rootRecorder; } } - /* - * Property: LastProxy - * The last mock object that was called on *any* repository. - */ - /// /// Gets the last proxy which had a method call. /// @@ -1116,12 +1054,8 @@ protected virtual ProxyGenerator GetProxyGenerator(Type type) - /// - /// Set the exception to be thrown when verified is called. - /// - protected internal static void SetExceptionToBeThrownOnVerify(object proxy, - ExpectationViolationException - expectationViolationException) + /// Set the exception to be thrown when verified is called. + protected internal static void SetExceptionToBeThrownOnVerify(object proxy, ExpectationViolationException expectationViolationException) { MockRepository repository = GetMockedObject(proxy).Repository; if (repository.proxies.ContainsKey(proxy) == false) @@ -1131,15 +1065,9 @@ protected internal static void SetExceptionToBeThrownOnVerify(object proxy, #endregion - /* - * Method: CreateMock - * Create a mock object of type T with strict semantics. - * Strict semantics means that any call that wasn't explicitly recorded is considered an - * error and would cause an exception to be thrown. - */ - /// - /// Creates a mock for the spesified type. + /// Creates a mock for the spesified type with strict mocking semantics. + /// Strict semantics means that any call that wasn't explicitly recorded is considered an error and would cause an exception to be thrown. /// /// Arguments for the class' constructor, if mocking a concrete class [Obsolete("Use StrictMock instead")] @@ -1149,7 +1077,8 @@ public T CreateMock(params object[] argumentsForConstructor) } /// - /// Creates a strict mock for the spesified type. + /// Creates a mock for the spesified type with strict mocking semantics. + /// Strict semantics means that any call that wasn't explicitly recorded is considered an error and would cause an exception to be thrown. /// /// Arguments for the class' constructor, if mocking a concrete class public T StrictMock(params object[] argumentsForConstructor) @@ -1293,7 +1222,7 @@ public T Stub(params object[] argumentsForConstructor) /// /// The type. /// The arguments for constructor. - /// + /// The stub public object Stub(Type type, params object[] argumentsForConstructor) { CreateMockState createStub = mockedObject => new StubRecordMockState(mockedObject, this); @@ -1302,30 +1231,6 @@ public object Stub(Type type, params object[] argumentsForConstructor) return CreateMockObject(type, createStub, new Type[0], argumentsForConstructor); } - /// - /// Generates a stub without mock repository - /// - /// The arguments for constructor. - /// - public static T GenerateStub(params object[] argumentsForConstructor) - where T : class - { - return (T)GenerateStub(typeof(T), argumentsForConstructor); - } - - /// - /// Generates the stub without mock repository - /// - /// The type. - /// The arguments for constructor. - public static object GenerateStub(Type type, params object[] argumentsForConstructor) - { - MockRepository repository = new MockRepository(); - object stub = repository.Stub(type, argumentsForConstructor); - repository.Replay(stub); - return stub; - } - /// /// Returns true if the passed mock is currently in replay mode. /// @@ -1344,41 +1249,6 @@ public bool IsInReplayMode(object mock) throw new ArgumentException(mock + " is not a mock.", "mock"); } - /// - /// Generate a mock object without needing the mock repository - /// - public static T GenerateMock(params object[] argumentsForConstructor) - where T : class - { - MockRepository repository = new MockRepository(); - T mock = repository.DynamicMock(argumentsForConstructor); - repository.Replay(mock); - return mock; - } - - /// - /// Generate a mock object with dynamic replay semantics and remoting without needing the mock repository - /// - public static T GenerateDynamicMockWithRemoting(params object[] argumentsForConstructor) - { - MockRepository repository = new MockRepository(); - T mock = repository.DynamicMockWithRemoting(argumentsForConstructor); - repository.Replay(mock); - return mock; - } - - /// - /// Generate a mock object with strict replay semantics and remoting without needing the mock repository - /// - public static T GenerateStrictMockWithRemoting(params object[] argumentsForConstructor) - where T : class - { - MockRepository repository = new MockRepository(); - T mock = repository.StrictMockWithRemoting(argumentsForConstructor); - repository.Replay(mock); - return mock; - } - /// /// Determines whether the specified proxy is a stub. /// diff --git a/Rhino.Mocks/MockRepositoryAAA.cs b/Rhino.Mocks/MockRepositoryAAA.cs new file mode 100644 index 00000000..c3a714cb --- /dev/null +++ b/Rhino.Mocks/MockRepositoryAAA.cs @@ -0,0 +1,191 @@ +using System; + +namespace Rhino.Mocks +{ + // Static methods for working with RhinoMocks using AAA syntax + public partial class MockRepository + { + /// Generates a stub without needing a + /// Arguments for 's constructor + /// The of stub to create. + /// The stub + /// + public static T GenerateStub(params object[] argumentsForConstructor) where T : class + { + return CreateMockInReplay(repo => (T)repo.Stub(typeof(T), argumentsForConstructor)); + } + + /// Generates a stub without needing a + /// The of stub. + /// Arguments for the 's constructor. + /// The stub + /// + public static object GenerateStub(Type type, params object[] argumentsForConstructor) + { + return CreateMockInReplay(repo => repo.Stub(type, argumentsForConstructor)); + } + + /// Generate a mock object without needing a + /// type of mock object to create. + /// Arguments for 's constructor + /// the mock object + /// + public static T GenerateMock(params object[] argumentsForConstructor) where T : class + { + return CreateMockInReplay(r => r.DynamicMock(argumentsForConstructor)); + } + + /// Generate a multi-mock object without needing a + /// The typeof object to generate a mock for. + /// A second interface to generate a multi-mock for. + /// Arguments for 's constructor + /// the multi-mock object + /// + public static T GenerateMock(params object[] argumentsForConstructor) + { + return (T) GenerateMock(typeof (T), new Type[] {typeof (TMultiMockInterface1)}, argumentsForConstructor); + } + + /// Generate a multi-mock object without without needing a + /// The typeof object to generate a mock for. + /// An interface to generate a multi-mock for. + /// A second interface to generate a multi-mock for. + /// Arguments for 's constructor + /// the multi-mock object + /// + public static T GenerateMock(params object[] argumentsForConstructor) + { + return (T) GenerateMock(typeof (T), new Type[] {typeof (TMultiMockInterface1), typeof (TMultiMockInterface2)}, argumentsForConstructor); + } + + /// Creates a multi-mock without without needing a + /// The type of mock to create, this can be a class + /// Any extra interfaces to add to the multi-mock, these can only be interfaces. + /// Arguments for 's constructor + /// the multi-mock object + /// + public static object GenerateMock(Type type, Type[] extraTypes, params object[] argumentsForConstructor) + { + return CreateMockInReplay(r => r.DynamicMultiMock(type, extraTypes, argumentsForConstructor)); + } + + ///Creates a strict mock without without needing a + ///Any arguments required for the 's constructor + ///The type of mock object to create. + ///The mock object with strict replay semantics + /// + public static T GenerateStrictMock(params object[] argumentsForConstructor) + { + return CreateMockInReplay(r => r.StrictMock(argumentsForConstructor)); + } + + ///Creates a strict multi-mock without needing a + ///Any arguments required for the 's constructor + ///The type of mock object to create, this can be a class. + ///An interface to generate a multi-mock for, this must be an interface! + ///The multi-mock object with strict replay semantics + /// + public static T GenerateStrictMock(params object[] argumentsForConstructor) + { + return (T)GenerateStrictMock(typeof(T), new Type[] { typeof(TMultiMockInterface1) }, argumentsForConstructor); + } + + ///Creates a strict multi-mock without needing a + ///Any arguments required for the 's constructor + ///The type of mock object to create, this can be a class. + ///An interface to generate a multi-mock for, this must be an interface! + ///A second interface to generate a multi-mock for, this must be an interface! + ///The multi-mock object with strict replay semantics + /// + public static T GenerateStrictMock(params object[] argumentsForConstructor) + { + return (T)GenerateStrictMock(typeof(T), new Type[] { typeof(TMultiMockInterface1), typeof(TMultiMockInterface2) }, argumentsForConstructor); + } + + ///Creates a strict multi-mock without needing a + ///The type of mock object to create, this can be a class + ///Any extra interfaces to generate a multi-mock for, these must be interaces! + ///Any arguments for the 's constructor + ///The strict multi-mock object + /// + public static object GenerateStrictMock(Type type, Type[] extraTypes, params object[] argumentsForConstructor) + { + if (extraTypes == null) extraTypes = new Type[0]; + if (argumentsForConstructor == null) argumentsForConstructor = new object[0]; + + return CreateMockInReplay(r => r.StrictMultiMock(type, extraTypes, argumentsForConstructor)); + } + + /// + /// + /// + /// + /// + public static T GeneratePartialMock(params object[] argumentsForConstructor) + { + return (T)GeneratePartialMock(typeof(T), new Type[0], argumentsForConstructor); + } + + /// + /// + /// + /// + /// + /// + public static T GeneratePartialMock(params object[] argumentsForConstructor) + { + return (T)GeneratePartialMock(typeof(T), new Type[] { typeof(TMultiMockInterface1) }, argumentsForConstructor); + } + + /// + /// + /// + /// + /// + /// + /// + public static T GeneratePartialMock(params object[] argumentsForConstructor) + { + return (T)GeneratePartialMock(typeof(T), new Type[] { typeof(TMultiMockInterface1), typeof(TMultiMockInterface2) }, argumentsForConstructor); + } + + /// + /// + /// + /// + /// + /// + public static object GeneratePartialMock(Type type, Type[] extraTypes, params object[] argumentsForConstructor) + { + return CreateMockInReplay(r => r.PartialMultiMock(type, extraTypes, argumentsForConstructor)); + } + + /// + /// Generate a mock object with dynamic replay semantics and remoting without needing the mock repository + /// + public static T GenerateDynamicMockWithRemoting(params object[] argumentsForConstructor) + { + return CreateMockInReplay(r => r.DynamicMockWithRemoting(argumentsForConstructor)); + } + + /// + /// Generate a mock object with strict replay semantics and remoting without needing the mock repository + /// + public static T GenerateStrictMockWithRemoting(params object[] argumentsForConstructor) where T : class + { + return CreateMockInReplay(r => r.StrictMockWithRemoting(argumentsForConstructor)); + } + + /// Helper method to create a mock object without a repository instance and put the object back into replay mode. + /// The type of mock object to create + /// A delegate that uses a mock repository instance to create the underlying mock + /// The mock object in the replay mode. + private static T CreateMockInReplay(Func createMock) + { + var repository = new MockRepository(); + var mockObject = createMock(repository); + repository.Replay(mockObject); + return mockObject; + } + } +} \ No newline at end of file diff --git a/Rhino.Mocks/Rhino.Mocks 3.5.csproj b/Rhino.Mocks/Rhino.Mocks 3.5.csproj index e59545ad..1d95d15b 100644 --- a/Rhino.Mocks/Rhino.Mocks 3.5.csproj +++ b/Rhino.Mocks/Rhino.Mocks 3.5.csproj @@ -144,6 +144,7 @@ + diff --git a/Rhino.Mocks/RhinoMocksExtensions.cs b/Rhino.Mocks/RhinoMocksExtensions.cs index 039e17a1..51355735 100644 --- a/Rhino.Mocks/RhinoMocksExtensions.cs +++ b/Rhino.Mocks/RhinoMocksExtensions.cs @@ -29,6 +29,7 @@ #if DOTNET35 using System; using System.Collections.Generic; +using System.Linq.Expressions; using Rhino.Mocks.Exceptions; using Rhino.Mocks.Generated; using Rhino.Mocks.Interfaces; @@ -202,7 +203,7 @@ public static IList GetArgumentsForCallsMadeOn(this T mock, Action< /// var argsForCalls = foo54.GetArgumentsForCallsMadeOn(x => x.DoSomething(0)) /// /// - public static IList GetArgumentsForCallsMadeOn(this T mock, Action action, Action> setupConstraints) + public static IList GetArgumentsForCallsMadeOn(this T mock, Action action, Action> setupConstraints) { return GetExpectationsToVerify(mock, action, setupConstraints).ArgumentsForAllCalls; } @@ -213,7 +214,7 @@ public static IList GetArgumentsForCallsMadeOn(this T mock, Action< /// /// The mock. /// The action. - public static void AssertWasCalled(this T mock, Action action) + public static void AssertWasCalled(this T mock, Action action) { AssertWasCalled(mock, action, DefaultConstraintSetup); } @@ -230,7 +231,7 @@ private static void DefaultConstraintSetup(IMethodOptions options) /// The mock. /// The action. /// The setup constraints. - public static void AssertWasCalled(this T mock, Action action, Action> setupConstraints) + public static void AssertWasCalled(this T mock, Action action, Action> setupConstraints) { ExpectationVerificationInformation verificationInformation = GetExpectationsToVerify(mock, action, setupConstraints); @@ -280,7 +281,7 @@ public static void AssertWasCalled(this T mock, Func action, Actio /// /// The mock. /// The action. - public static void AssertWasNotCalled(this T mock, Action action) + public static void AssertWasNotCalled(this T mock, Action action) { AssertWasNotCalled(mock, action, DefaultConstraintSetup); } @@ -344,8 +345,8 @@ private static ExpectationVerificationInformation GetExpectationsToVerify(T m "Cannot assert on an object that is not in replay mode. Did you forget to call ReplayAll() ?"); } - var mockToRecordExpectation = - (T)mocks.DynamicMock(FindAppropriteType(mockedObject), mockedObject.ConstructorArguments); + var mockToRecordExpectation = + (T)mocks.DynamicMock(FindAppropriteType(mockedObject), mockedObject.ConstructorArguments); action(mockToRecordExpectation); AssertExactlySingleExpectaton(mocks, mockToRecordExpectation); @@ -375,16 +376,16 @@ private static ExpectationVerificationInformation GetExpectationsToVerify(T m /// /// The mocked obj. /// - private static Type FindAppropriteType(IMockedObject mockedObj) + private static Type FindAppropriteType(IMockedObject mockedObj) { foreach (var type in mockedObj.ImplementedTypes) { - if(type.IsClass) + if(type.IsClass && typeof(T).IsAssignableFrom(type)) return type; } foreach (var type in mockedObj.ImplementedTypes) { - if(type.Assembly==typeof(IMockedObject).Assembly) + if(type.Assembly==typeof(IMockedObject).Assembly || !typeof(T).IsAssignableFrom(type)) continue; return type; } @@ -449,15 +450,24 @@ public static void Raise(this TEventSource mockObject, ActionTODO: Make this better! It currently breaks down when mocking classes or + /// ABC's that call other virtual methods which are getting intercepted too. I wish + /// we could just walk Expression{Action{Action{T}} to assert only a single + /// method is being made. + /// + /// The workaround is to not call foo.AssertWasCalled .. rather foo.VerifyAllExpectations() + /// The type of mock object + /// The mock repository + /// The actual mock object to assert expectations on. private static void AssertExactlySingleExpectaton(MockRepository mocks, T mockToRecordExpectation) { if (mocks.Replayer.GetAllExpectationsForProxy(mockToRecordExpectation).Count == 0) throw new InvalidOperationException( "No expectations were setup to be verified, ensure that the method call in the action is a virtual (C#) / overridable (VB.Net) method call"); - if (mocks.Replayer.GetAllExpectationsForProxy(mockToRecordExpectation).Count > 1) - throw new InvalidOperationException( - "You can only use a single expectation on AssertWasCalled(), use separate calls to AssertWasCalled() if you want to verify several expectations"); + if (mocks.Replayer.GetAllExpectationsForProxy(mockToRecordExpectation).Count > 1) + throw new InvalidOperationException( + "You can only use a single expectation on AssertWasCalled(), use separate calls to AssertWasCalled() if you want to verify several expectations"); } #region Nested type: VoidType