From c9c09339e785d34cc4b7f45f2c826d561d4f04d4 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Fri, 13 Aug 2010 00:35:04 -0500 Subject: [PATCH 01/24] Adding mark down file --- readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 readme.md diff --git a/readme.md b/readme.md new file mode 100644 index 00000000..246340fb --- /dev/null +++ b/readme.md @@ -0,0 +1,9 @@ +Rhino Mocks +====================================================================== + +_Current Version: 3.6.0.0_ + +## Links/Resources + +* [Rhino Mocks Wiki](http://www.ayende.com/wiki/Rhino+Mocks.ashx "Rhino Mocks Wiki") +* [Rhino MOcks 4.0 Planning](http://nhprof.uservoice.com/pages/28152-rhino-mocks-4-0 "Rhino 4.0 Planning") \ No newline at end of file From fcb2edc41c34221ff1cdf62aa5aea38c26df6885 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Sun, 29 Aug 2010 08:06:22 -0500 Subject: [PATCH 02/24] Upgrading solution and projects to Visual Studio 2010 --- .../Rhino.Mocks.GettingStarted.csproj | 170 ++-- .../Rhino.Mocks.Tests.Model.csproj | 174 ++-- Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj | 925 +++++++++--------- Rhino.Mocks.sln | 136 +-- Rhino.Mocks/Rhino.Mocks.csproj | 39 +- Rhino.Mocks/Rhino.Mocks.csproj.user | 121 +-- 6 files changed, 851 insertions(+), 714 deletions(-) diff --git a/Rhino.Mocks.GettingStarted/Rhino.Mocks.GettingStarted.csproj b/Rhino.Mocks.GettingStarted/Rhino.Mocks.GettingStarted.csproj index 029226d2..6e111351 100644 --- a/Rhino.Mocks.GettingStarted/Rhino.Mocks.GettingStarted.csproj +++ b/Rhino.Mocks.GettingStarted/Rhino.Mocks.GettingStarted.csproj @@ -1,73 +1,111 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {59F8A3E2-80C5-4250-909A-16741DF81B23} - Library - Properties - Rhino.Mocks.GettingStarted - Rhino.Mocks.GettingStarted - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\SharedLibs\nunit.framework.dll - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - - - - - - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8} - Rhino.Mocks - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {59F8A3E2-80C5-4250-909A-16741DF81B23} + Library + Properties + Rhino.Mocks.GettingStarted + Rhino.Mocks.GettingStarted + v3.5 + 512 + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + False + ..\SharedLibs\nunit.framework.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8} + Rhino.Mocks + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + --> \ No newline at end of file diff --git a/Rhino.Mocks.Tests.Model/Rhino.Mocks.Tests.Model.csproj b/Rhino.Mocks.Tests.Model/Rhino.Mocks.Tests.Model.csproj index 4f47b36e..75a2a79e 100644 --- a/Rhino.Mocks.Tests.Model/Rhino.Mocks.Tests.Model.csproj +++ b/Rhino.Mocks.Tests.Model/Rhino.Mocks.Tests.Model.csproj @@ -1,75 +1,113 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {3078B943-10A5-41FA-A68A-7C4FC98506A0} - Library - Properties - Rhino.Mocks.Tests.Model - Rhino.Mocks.Tests.Model - v3.5 - 512 - true - ..\ayende-open-source.snk - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - 1607 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - - - - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8} - Rhino.Mocks 3.5 - - - - - ayende-open-source.snk - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {3078B943-10A5-41FA-A68A-7C4FC98506A0} + Library + Properties + Rhino.Mocks.Tests.Model + Rhino.Mocks.Tests.Model + v3.5 + 512 + true + ..\ayende-open-source.snk + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + 1607 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8} + Rhino.Mocks 3.5 + + + + + ayende-open-source.snk + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + --> \ No newline at end of file diff --git a/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj b/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj index 5decf81c..99bdf4bf 100644 --- a/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj +++ b/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj @@ -1,455 +1,472 @@ - - - Local - 9.0.30729 - 2.0 - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20} - Debug - AnyCPU - Rhino.Mocks.Tests - JScript - Grid - IE50 - false - Library - Rhino.Mocks.Tests - OnBuildSuccess - true - ..\ayende-open-source.snk - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - v3.5 - - - bin\debug\ - false - 285212672 - false - TRACE;DEBUG;DOTNET35 - true - 4096 - false - false - false - false - false - 4 - false - Full - 1607 - - - ..\..\Build\Tests\Release\ - false - 285212672 - false - TRACE;dotNet2 - false - 4096 - false - true - false - false - false - 4 - - - Program - C:\Program Files\MbUnit\MbUnit.GUI.exe - D:\OSS\rhino-tools\rhino-mocks\Rhino.Mocks.Tests\bin\debug\Rhino.Mocks.Tests.dll - - - Auto - AnyCPU - - - - False - ..\SharedLibs\Castle.Core.dll - - - False - ..\SharedLibs\Castle.DynamicProxy2.dll - - - False - ..\SharedLibs\Interop.ADODB.dll - - - False - ..\SharedLibs\Interop.MSHTML.dll - - - False - ..\SharedLibs\Microsoft.Practices.Unity.dll - - - False - ..\SharedLibs\Rhino.Mocks.CPP.Interfaces.dll - - - False - ..\SharedLibs\Scripting.dll - - - System - - - - 3.5 - - - System.Data - - - System.EnterpriseServices - - - 3.0 - - - System.Web - - - - System.XML - - - False - ..\SharedLibs\xunit.dll - - - False - ..\SharedLibs\xunit.extensions.dll - - - - - - Code - - - - Code - - - - Code - - - Code - - - Code - - - - Code - - - Code - - - Code - - - - - - - - - - - - - - - - - - Component - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - - Code - - - Code - - - Code - - - Code - - - Code - - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - - Code - - - - Code - - - - - - - - - - - - - - - - - - Code - - - Code - - - - - - - - - - - - Code - - - Code - - - - - {3078B943-10A5-41FA-A68A-7C4FC98506A0} - Rhino.Mocks.Tests.Model - - - Rhino.Mocks - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8} - {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - - - - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - - - ayende-open-source.snk - - - + + + + Local + 9.0.30729 + 2.0 + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20} + Debug + AnyCPU + Rhino.Mocks.Tests + JScript + Grid + IE50 + false + Library + Rhino.Mocks.Tests + OnBuildSuccess + true + ..\ayende-open-source.snk + false + v3.5 + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + bin\debug\ + false + 285212672 + false + TRACE;DEBUG;DOTNET35 + true + 4096 + false + false + false + false + false + 4 + false + Full + 1607 + AllRules.ruleset + + + ..\..\Build\Tests\Release\ + false + 285212672 + false + TRACE;dotNet2 + false + 4096 + false + true + false + false + false + 4 + AllRules.ruleset + + + Program + C:\Program Files\MbUnit\MbUnit.GUI.exe + D:\OSS\rhino-tools\rhino-mocks\Rhino.Mocks.Tests\bin\debug\Rhino.Mocks.Tests.dll + + + Auto + AnyCPU + + + + False + ..\SharedLibs\Castle.Core.dll + + + False + ..\SharedLibs\Castle.DynamicProxy2.dll + + + False + ..\SharedLibs\Interop.ADODB.dll + + + False + ..\SharedLibs\Interop.MSHTML.dll + + + False + ..\SharedLibs\Microsoft.Practices.Unity.dll + + + False + ..\SharedLibs\Rhino.Mocks.CPP.Interfaces.dll + + + False + ..\SharedLibs\Scripting.dll + + + System + + + + 3.5 + + + System.Data + + + System.EnterpriseServices + + + 3.0 + + + System.Web + + + + System.XML + + + False + ..\SharedLibs\xunit.dll + + + False + ..\SharedLibs\xunit.extensions.dll + + + + + + Code + + + + Code + + + + Code + + + Code + + + Code + + + + Code + + + Code + + + Code + + + + + + + + + + + + + + + + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + + Code + + + Code + + + Code + + + Code + + + Code + + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + + Code + + + + Code + + + + + + + + + + + + + + + + + + Code + + + Code + + + + + + + + + + + + Code + + + Code + + + + + {3078B943-10A5-41FA-A68A-7C4FC98506A0} + Rhino.Mocks.Tests.Model + + + Rhino.Mocks + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + false + + + + + ayende-open-source.snk + + + \ No newline at end of file diff --git a/Rhino.Mocks.sln b/Rhino.Mocks.sln index f59b9696..a2d0f467 100644 --- a/Rhino.Mocks.sln +++ b/Rhino.Mocks.sln @@ -1,68 +1,68 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhino.Mocks.Tests", "Rhino.Mocks.Tests\Rhino.Mocks.Tests.csproj", "{C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhino.Mocks", "Rhino.Mocks\Rhino.Mocks.csproj", "{1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhino.Mocks.Tests.Model", "Rhino.Mocks.Tests.Model\Rhino.Mocks.Tests.Model.csproj", "{3078B943-10A5-41FA-A68A-7C4FC98506A0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhino.Mocks.GettingStarted", "Rhino.Mocks.GettingStarted\Rhino.Mocks.GettingStarted.csproj", "{59F8A3E2-80C5-4250-909A-16741DF81B23}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|Win32 = Debug|Win32 - Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Win32.ActiveCfg = Debug|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Any CPU.Build.0 = Release|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Win32.ActiveCfg = Release|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Win32.ActiveCfg = Debug|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Any CPU.Build.0 = Release|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Win32.ActiveCfg = Release|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Win32.ActiveCfg = Debug|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Any CPU.Build.0 = Release|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Win32.ActiveCfg = Release|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Any CPU.Build.0 = Debug|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Win32.ActiveCfg = Debug|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Any CPU.ActiveCfg = Release|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Any CPU.Build.0 = Release|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Win32.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(TextTemplating) = postSolution - TextTemplating = 1 - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhino.Mocks.Tests", "Rhino.Mocks.Tests\Rhino.Mocks.Tests.csproj", "{C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhino.Mocks", "Rhino.Mocks\Rhino.Mocks.csproj", "{1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhino.Mocks.Tests.Model", "Rhino.Mocks.Tests.Model\Rhino.Mocks.Tests.Model.csproj", "{3078B943-10A5-41FA-A68A-7C4FC98506A0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhino.Mocks.GettingStarted", "Rhino.Mocks.GettingStarted\Rhino.Mocks.GettingStarted.csproj", "{59F8A3E2-80C5-4250-909A-16741DF81B23}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Debug|Win32.ActiveCfg = Debug|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Any CPU.Build.0 = Release|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C63839EC-BEF3-4DCD-BE23-B6DA21E8BE20}.Release|Win32.ActiveCfg = Release|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Debug|Win32.ActiveCfg = Debug|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Any CPU.Build.0 = Release|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {1E8FECC7-9E9B-4275-A938-D956F5E5D4F8}.Release|Win32.ActiveCfg = Release|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Debug|Win32.ActiveCfg = Debug|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Any CPU.Build.0 = Release|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3078B943-10A5-41FA-A68A-7C4FC98506A0}.Release|Win32.ActiveCfg = Release|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Debug|Win32.ActiveCfg = Debug|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Any CPU.Build.0 = Release|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {59F8A3E2-80C5-4250-909A-16741DF81B23}.Release|Win32.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(TextTemplating) = postSolution + TextTemplating = 1 + EndGlobalSection +EndGlobal diff --git a/Rhino.Mocks/Rhino.Mocks.csproj b/Rhino.Mocks/Rhino.Mocks.csproj index 42b9f001..bb77e4a8 100644 --- a/Rhino.Mocks/Rhino.Mocks.csproj +++ b/Rhino.Mocks/Rhino.Mocks.csproj @@ -1,4 +1,5 @@ - + + Local 9.0.30729 @@ -18,10 +19,25 @@ ..\ayende-open-source.snk - 2.0 + 3.5 v3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true bin\debug\ @@ -40,6 +56,7 @@ 4 true 1607 + AllRules.ruleset bin\Release\ @@ -57,6 +74,7 @@ 4 pdbonly Rhino.Mocks.XML + AllRules.ruleset @@ -294,5 +312,22 @@ + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + \ No newline at end of file diff --git a/Rhino.Mocks/Rhino.Mocks.csproj.user b/Rhino.Mocks/Rhino.Mocks.csproj.user index 5a2e8d60..3ae98b11 100644 --- a/Rhino.Mocks/Rhino.Mocks.csproj.user +++ b/Rhino.Mocks/Rhino.Mocks.csproj.user @@ -1,57 +1,66 @@ - - - 7.10.3077 - Debug - AnyCPU - D:\Code\rhino-mocks\vendor\;D:\Code\rhino-mocks\vendor\net-1.1\;C:\Code\rhino-mocks\vendor\net-1.1\ - - - - - 0 - ProjectFiles - 0 - - - false - false - false - false - false - - - Project - - - - - - - - - - - false - - - false - false - false - false - false - - - Project - - - - - - - - - - - false - + + + + 7.10.3077 + Debug + AnyCPU + D:\Code\rhino-mocks\vendor\;D:\Code\rhino-mocks\vendor\net-1.1\;C:\Code\rhino-mocks\vendor\net-1.1\ + + + + + 0 + ProjectFiles + 0 + + + + + + + en-US + false + + + false + false + false + false + false + + + Project + + + + + + + + + + + false + + + false + false + false + false + false + + + Project + + + + + + + + + + + false + \ No newline at end of file From 0f195513160933306ab8f28b7d75388b623fd22d Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Mon, 6 Sep 2010 00:57:02 -0500 Subject: [PATCH 03/24] Adding ConsoleLogger - new IExpectationLogger --- Rhino.Mocks/Impl/ConsoleLogger.cs | 51 +++++++++++++++++++++++++++++++ Rhino.Mocks/Rhino.Mocks.csproj | 1 + 2 files changed, 52 insertions(+) create mode 100644 Rhino.Mocks/Impl/ConsoleLogger.cs diff --git a/Rhino.Mocks/Impl/ConsoleLogger.cs b/Rhino.Mocks/Impl/ConsoleLogger.cs new file mode 100644 index 00000000..2d6eab8a --- /dev/null +++ b/Rhino.Mocks/Impl/ConsoleLogger.cs @@ -0,0 +1,51 @@ +using System; +using Castle.Core.Interceptor; +using Rhino.Mocks.Interfaces; +using Rhino.Mocks.Utilities; + +namespace Rhino.Mocks.Impl +{ + + /// + /// Write rhino mocks log info to the console + /// + public class ConsoleLogger : IExpectationLogger + { + #region IExpectationLogger Members + + /// + /// Logs the expectation as is was recorded + /// + /// The invocation. + /// The expectation. + public void LogRecordedExpectation(IInvocation invocation, IExpectation expectation) + { + string methodCall = MethodCallUtil.StringPresentation(invocation, invocation.Method, invocation.Arguments); + Console.WriteLine(string.Format("Recorded expectation: {0}", methodCall)); + } + + /// + /// Logs the expectation as it was recorded + /// + /// The invocation. + /// The expectation. + public void LogReplayedExpectation(IInvocation invocation, IExpectation expectation) + { + string methodCall = MethodCallUtil.StringPresentation(invocation, invocation.Method, invocation.Arguments); + Console.WriteLine(string.Format("Replayed expectation: {0}", methodCall)); + } + + /// + /// Logs the unexpected method call. + /// + /// The invocation. + /// The message. + public void LogUnexpectedMethodCall(IInvocation invocation, string message) + { + string methodCall = MethodCallUtil.StringPresentation(invocation, invocation.Method, invocation.Arguments); + Console.WriteLine(string.Format("{1}: {0}", methodCall, message)); + } + + #endregion + } +} \ No newline at end of file diff --git a/Rhino.Mocks/Rhino.Mocks.csproj b/Rhino.Mocks/Rhino.Mocks.csproj index bb77e4a8..8d8f6238 100644 --- a/Rhino.Mocks/Rhino.Mocks.csproj +++ b/Rhino.Mocks/Rhino.Mocks.csproj @@ -147,6 +147,7 @@ Code + From 29513c6dd01cd3442e70bc834b6276b92c38eafb Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Fri, 13 Aug 2010 00:29:32 -0500 Subject: [PATCH 04/24] Created failing test around Arg constraint --- Rhino.Mocks.Tests/ArgConstraintTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Rhino.Mocks.Tests/ArgConstraintTests.cs b/Rhino.Mocks.Tests/ArgConstraintTests.cs index 34ba7fca..f51360ea 100644 --- a/Rhino.Mocks.Tests/ArgConstraintTests.cs +++ b/Rhino.Mocks.Tests/ArgConstraintTests.cs @@ -454,9 +454,23 @@ public void ImplicitlyConverted_parameter_is_properly_compared_when_using_IsLess Assert.Equal(null, stub.GetUser(3)); } + [Fact] + public void Can_use_partial_constraints_API() + { + // Arrange + var stub = MockRepository.GenerateStub(); + + stub.Stub(x => x.GetUserId(Arg.Is.Equal("Tim"), "Barcz")).Return(12); + + // Act & Assert + Assert.Equal(12, stub.GetUserId("Tim","Barcz")); + + } + public interface ITestService { string GetUser(long id); + int GetUserId(string firstName, string lastName); } } } From e9dae8ac857a87bd18446f46f828a9cb18fc15b2 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Sun, 5 Sep 2010 23:45:19 -0500 Subject: [PATCH 05/24] beginning to make refactoring changes around expectation builder --- Rhino.Mocks.Tests/ArgConstraintTests.cs | 33 ++++++++-- Rhino.Mocks/Impl/RecordMockState.cs | 84 ++++++++++++++----------- 2 files changed, 75 insertions(+), 42 deletions(-) diff --git a/Rhino.Mocks.Tests/ArgConstraintTests.cs b/Rhino.Mocks.Tests/ArgConstraintTests.cs index f51360ea..fb579b5e 100644 --- a/Rhino.Mocks.Tests/ArgConstraintTests.cs +++ b/Rhino.Mocks.Tests/ArgConstraintTests.cs @@ -454,23 +454,48 @@ public void ImplicitlyConverted_parameter_is_properly_compared_when_using_IsLess Assert.Equal(null, stub.GetUser(3)); } + public interface ITestService + { + string GetUser(long id); + int GetUserId(string firstName, string lastName); + } + } + + public class ArgConstraintTests2 + { + [Fact] public void Can_use_partial_constraints_API() { // Arrange var stub = MockRepository.GenerateStub(); - stub.Stub(x => x.GetUserId(Arg.Is.Equal("Tim"), "Barcz")).Return(12); + //stub.Stub(x => x.GetUser(1)).Return("tim").Repeat.Once(); + stub.Stub(x => x.GetUser(Arg.Is.Anything)).Return("barcz"); - // Act & Assert - Assert.Equal(12, stub.GetUserId("Tim","Barcz")); + + Console.WriteLine(stub.GetUser(1)); + Console.WriteLine(stub.GetUser(1)); + + // stub.Stub(x => x.GetUserId("Tim", "Barcz")).Return(12); + //stub.Stub(x => + // x.GetUserId( + // Arg.Is.Equal("Tim"), + // "Barcz")) + // .Return(12); + + // Act & Assert + //Assert.Equal(12, stub.GetUserId("Tim","Barcz")); + //Assert.NotNull(stub); } + public interface ITestService { string GetUser(long id); int GetUserId(string firstName, string lastName); } - } + + } } diff --git a/Rhino.Mocks/Impl/RecordMockState.cs b/Rhino.Mocks/Impl/RecordMockState.cs index edca3f76..ae8ce417 100644 --- a/Rhino.Mocks/Impl/RecordMockState.cs +++ b/Rhino.Mocks/Impl/RecordMockState.cs @@ -48,7 +48,8 @@ public class RecordMockState : IMockState private readonly IMockedObject mockedObject; private int methodCallsCount = 0; private IExpectation lastExpectation; - private bool lastCallWasPropertyBehavior; + private bool lastCallWasPropertyBehavior; + private ExpectationBuilder expectationBuilder; #endregion @@ -145,6 +146,7 @@ public RecordMockState(IMockedObject mockedObject, MockRepository repository) Validate.IsNotNull(repository, "repository"); this.repository = repository; this.mockedObject = mockedObject; + expectationBuilder = new ExpectationBuilder(); } #endregion @@ -169,11 +171,11 @@ public object MethodCall(IInvocation invocation, MethodInfo method, params objec // Has the Arg class been used? if (ArgManager.HasBeenUsed) { - expectation = BuildParamExpectation(invocation, method); + expectation = expectationBuilder.BuildParamExpectation(invocation, method); } else { - expectation = BuildDefaultExpectation(invocation, method, args); + expectation = expectationBuilder.BuildDefaultExpectation(invocation, method, args); } repository.Recorder.Record(mockedObject, method, expectation); LastExpectation = expectation; @@ -296,40 +298,6 @@ private Exception InvalidOperationOnRecord() return new InvalidOperationException(string.Format("This action is invalid when the mock object {0}is in record state.", mockedTypes)); } - private IExpectation BuildDefaultExpectation(IInvocation invocation, MethodInfo method, object[] args) - { - ParameterInfo[] parameters = method.GetParameters(); - if (!Array.Exists(parameters, delegate(ParameterInfo p) { return p.IsOut; })) - { - return new ArgsEqualExpectation(invocation, args, GetDefaultCallCountRangeExpectation()); - } - - //The value of an incoming out parameter variable is ignored - AbstractConstraint[] constraints = new AbstractConstraint[parameters.Length]; - for (int i = 0; i < parameters.Length; i++) - { - constraints[i] = parameters[i].IsOut ? Is.Anything() : Is.Equal(args[i]); - } - return new ConstraintsExpectation(invocation, constraints, GetDefaultCallCountRangeExpectation()); - } - - /// - /// Get the default call count range expectation - /// - /// - protected virtual Range GetDefaultCallCountRangeExpectation() - { - return new Range(1, 1); - } - - private static IExpectation BuildParamExpectation(IInvocation invocation, MethodInfo method) - { - ArgManager.CheckMethodSignature(method); - IExpectation expectation = new ConstraintsExpectation(invocation, ArgManager.GetAllConstraints(), new Range(1, null)); - expectation.OutRefParams = ArgManager.GetAllReturnValues(); - return expectation; - } - #endregion #region Internal @@ -344,5 +312,45 @@ internal IMockedObject Proxy } #endregion - } + } + + /// + /// Responsible for building expectations + /// + public class ExpectationBuilder + { + public IExpectation BuildDefaultExpectation(IInvocation invocation, MethodInfo method, object[] args) + { + var parameters = method.GetParameters(); + if (!Array.Exists(parameters, p => p.IsOut)) + { + return new ArgsEqualExpectation(invocation, args, GetDefaultCallCountRangeExpectation()); + } + + //The value of an incoming out parameter variable is ignored + var constraints = new AbstractConstraint[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + { + constraints[i] = parameters[i].IsOut ? Is.Anything() : Is.Equal(args[i]); + } + return new ConstraintsExpectation(invocation, constraints, GetDefaultCallCountRangeExpectation()); + } + + public IExpectation BuildParamExpectation(IInvocation invocation, MethodInfo method) + { + ArgManager.CheckMethodSignature(method); + var expectation = new ConstraintsExpectation(invocation, ArgManager.GetAllConstraints(), new Range(1, null)); + expectation.OutRefParams = ArgManager.GetAllReturnValues(); + return expectation; + } + + /// + /// Get the default call count range expectation + /// + /// + protected virtual Range GetDefaultCallCountRangeExpectation() + { + return new Range(1, 1); + } + } } From e7e9ed97f6044bc4f60d944ee3a3caae2d97f65d Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Sun, 5 Sep 2010 23:56:36 -0500 Subject: [PATCH 06/24] Refactored out a new ExpectationBuilder class --- Rhino.Mocks/Impl/ExpectationBuilder.cs | 54 +++++++++++++++++++++++++ Rhino.Mocks/Impl/RecordMockState.cs | 55 ++++++-------------------- Rhino.Mocks/Rhino.Mocks.csproj | 1 + 3 files changed, 66 insertions(+), 44 deletions(-) create mode 100644 Rhino.Mocks/Impl/ExpectationBuilder.cs diff --git a/Rhino.Mocks/Impl/ExpectationBuilder.cs b/Rhino.Mocks/Impl/ExpectationBuilder.cs new file mode 100644 index 00000000..1a7e79da --- /dev/null +++ b/Rhino.Mocks/Impl/ExpectationBuilder.cs @@ -0,0 +1,54 @@ +using System; +using System.Reflection; +using Castle.Core.Interceptor; +using Rhino.Mocks.Constraints; +using Rhino.Mocks.Expectations; +using Rhino.Mocks.Interfaces; + +namespace Rhino.Mocks.Impl +{ + /// + /// Responsible for building expectations + /// + public class ExpectationBuilder + { + /// + /// Builds the default expectation. + /// + /// The invocation. + /// The method. + /// The args. + /// The call call range expectation. + /// + public IExpectation BuildDefaultExpectation(IInvocation invocation, MethodInfo method, object[] args, Func callCallRangeExpectation) + { + var parameters = method.GetParameters(); + if (!Array.Exists(parameters, p => p.IsOut)) + { + return new ArgsEqualExpectation(invocation, args, callCallRangeExpectation()); + } + + //The value of an incoming out parameter variable is ignored + var constraints = new AbstractConstraint[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + { + constraints[i] = parameters[i].IsOut ? Is.Anything() : Is.Equal(args[i]); + } + return new ConstraintsExpectation(invocation, constraints, callCallRangeExpectation()); + } + + /// + /// Builds the param expectation. + /// + /// The invocation. + /// The method. + /// + public IExpectation BuildParamExpectation(IInvocation invocation, MethodInfo method) + { + ArgManager.CheckMethodSignature(method); + var expectation = new ConstraintsExpectation(invocation, ArgManager.GetAllConstraints(), new Range(1, null)); + expectation.OutRefParams = ArgManager.GetAllReturnValues(); + return expectation; + } + } +} \ No newline at end of file diff --git a/Rhino.Mocks/Impl/RecordMockState.cs b/Rhino.Mocks/Impl/RecordMockState.cs index ae8ce417..d33ebc2c 100644 --- a/Rhino.Mocks/Impl/RecordMockState.cs +++ b/Rhino.Mocks/Impl/RecordMockState.cs @@ -29,9 +29,7 @@ using System; using System.Reflection; -using Castle.Core.Interceptor; -using Rhino.Mocks.Constraints; -using Rhino.Mocks.Expectations; +using Castle.Core.Interceptor; using Rhino.Mocks.Interfaces; using Rhino.Mocks.Utilities; @@ -175,7 +173,7 @@ public object MethodCall(IInvocation invocation, MethodInfo method, params objec } else { - expectation = expectationBuilder.BuildDefaultExpectation(invocation, method, args); + expectation = expectationBuilder.BuildDefaultExpectation(invocation, method, args, GetDefaultCallCountRangeExpectation); } repository.Recorder.Record(mockedObject, method, expectation); LastExpectation = expectation; @@ -296,6 +294,15 @@ private Exception InvalidOperationOnRecord() } return new InvalidOperationException(string.Format("This action is invalid when the mock object {0}is in record state.", mockedTypes)); + } + + /// + /// Get the default call count range expectation + /// + /// + protected virtual Range GetDefaultCallCountRangeExpectation() + { + return new Range(1, 1); } #endregion @@ -313,44 +320,4 @@ internal IMockedObject Proxy #endregion } - - /// - /// Responsible for building expectations - /// - public class ExpectationBuilder - { - public IExpectation BuildDefaultExpectation(IInvocation invocation, MethodInfo method, object[] args) - { - var parameters = method.GetParameters(); - if (!Array.Exists(parameters, p => p.IsOut)) - { - return new ArgsEqualExpectation(invocation, args, GetDefaultCallCountRangeExpectation()); - } - - //The value of an incoming out parameter variable is ignored - var constraints = new AbstractConstraint[parameters.Length]; - for (var i = 0; i < parameters.Length; i++) - { - constraints[i] = parameters[i].IsOut ? Is.Anything() : Is.Equal(args[i]); - } - return new ConstraintsExpectation(invocation, constraints, GetDefaultCallCountRangeExpectation()); - } - - public IExpectation BuildParamExpectation(IInvocation invocation, MethodInfo method) - { - ArgManager.CheckMethodSignature(method); - var expectation = new ConstraintsExpectation(invocation, ArgManager.GetAllConstraints(), new Range(1, null)); - expectation.OutRefParams = ArgManager.GetAllReturnValues(); - return expectation; - } - - /// - /// Get the default call count range expectation - /// - /// - protected virtual Range GetDefaultCallCountRangeExpectation() - { - return new Range(1, 1); - } - } } diff --git a/Rhino.Mocks/Rhino.Mocks.csproj b/Rhino.Mocks/Rhino.Mocks.csproj index 8d8f6238..15982853 100644 --- a/Rhino.Mocks/Rhino.Mocks.csproj +++ b/Rhino.Mocks/Rhino.Mocks.csproj @@ -148,6 +148,7 @@ + From 3cb29be2e4f9d9e87b590a4fb4e1abeadc206eed Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Mon, 6 Sep 2010 01:59:39 -0500 Subject: [PATCH 07/24] Adding expectations class diagram --- Rhino.Mocks/Expectations/Expectations.cd | 40 ++++++++++++++++++++++++ Rhino.Mocks/Rhino.Mocks.csproj | 1 + 2 files changed, 41 insertions(+) create mode 100644 Rhino.Mocks/Expectations/Expectations.cd diff --git a/Rhino.Mocks/Expectations/Expectations.cd b/Rhino.Mocks/Expectations/Expectations.cd new file mode 100644 index 00000000..85313ffa --- /dev/null +++ b/Rhino.Mocks/Expectations/Expectations.cd @@ -0,0 +1,40 @@ + + + + + + BQAABAAYAoYgCLBAgAAoQCAEAgIAAIAAIABQPBQCJDQ= + Expectations\AbstractExpectation.cs + + + + + + + AQAAAAAAAIAAAAAAgAAAAAAAAAAAAKAAAAAQAAAAAEA= + Expectations\ConstraintsExpectation.cs + + + + + + AQAAAAAAAIAAAAAAgAAAAAAAAIAAAIAAAAAAAAAAAAA= + Expectations\AnyArgsExpectation.cs + + + + + + AQAAAAAAAIAAAAAAgAAAAAAAAAAAEIAgAAAAIAAAAAA= + Expectations\ArgsEqualExpectation.cs + + + + + + AQBAAAAAAIAAAAAAgAAAAAAAAAAAAIAAAEAAAAAAAAA= + Expectations\CallbackExpectation.cs + + + + \ No newline at end of file diff --git a/Rhino.Mocks/Rhino.Mocks.csproj b/Rhino.Mocks/Rhino.Mocks.csproj index 15982853..8c77114c 100644 --- a/Rhino.Mocks/Rhino.Mocks.csproj +++ b/Rhino.Mocks/Rhino.Mocks.csproj @@ -310,6 +310,7 @@ + From e91e65526bd2adb205936b2e1929c7009175073e Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Mon, 6 Sep 2010 02:09:00 -0500 Subject: [PATCH 08/24] Modifying Validate class to remove string parameter --- Rhino.Mocks/Impl/Validate.cs | 54 ++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/Rhino.Mocks/Impl/Validate.cs b/Rhino.Mocks/Impl/Validate.cs index 4856e8b4..99ef5f81 100644 --- a/Rhino.Mocks/Impl/Validate.cs +++ b/Rhino.Mocks/Impl/Validate.cs @@ -27,8 +27,10 @@ #endregion -using System; -using Rhino.Mocks.Interfaces; +using System; +using System.Linq.Expressions; +using Rhino.Mocks.Interfaces; +using System.Reflection; using System.Collections; namespace Rhino.Mocks.Impl @@ -51,7 +53,28 @@ public static void IsNotNull(object obj, string name) { if (obj == null) throw new ArgumentNullException(name); - } + } + + /// + /// Validates that the passed argument is not null + /// + /// + /// The reference. + public static void IsNotNull(Expression> reference) + { + if (reference.Body.GetConstantValue() == null) throw new ArgumentNullException(GetParameterName(reference)); + } + + /// + /// Validates that the passed argument is not null + /// + /// + /// The reference. + /// The message. + public static void IsNotNull(Expression> reference, string message) + { + if (reference.Body.GetConstantValue() == null) throw new ArgumentNullException(GetParameterName(reference), message); + } /// /// Validate that the arguments are equal. @@ -132,7 +155,32 @@ private static bool SafeEquals(object expected, object actual) //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); + } + + private static string GetParameterName(Expression reference) + { + var lambda = reference as LambdaExpression; + var member = lambda.Body as MemberExpression; + + return member.Member.Name; + } + + private static T GetConstantValue(this Expression expression) + { + if (expression.NodeType == ExpressionType.Constant) + return (T)(((ConstantExpression)expression).Value); + + if (expression.NodeType == ExpressionType.MemberAccess) + { + var memberExpr = (MemberExpression)expression; + var memberInfo = memberExpr.Member as FieldInfo; + if (memberInfo != null) + return (T)memberInfo.GetValue(memberExpr.Expression.GetConstantValue()); + } + + return Expression.Lambda>(Expression.Convert(expression, typeof(T)), new ParameterExpression[0]).Compile()(); } + #endregion } } From 93f4ad856158346cf95a06c602167c4bde56c697 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Mon, 6 Sep 2010 02:15:54 -0500 Subject: [PATCH 09/24] Adding in test for new Validate.IsNotNull method --- Rhino.Mocks.Tests/Impl/ValidateTests.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Rhino.Mocks.Tests/Impl/ValidateTests.cs b/Rhino.Mocks.Tests/Impl/ValidateTests.cs index 80420389..4e0db248 100644 --- a/Rhino.Mocks.Tests/Impl/ValidateTests.cs +++ b/Rhino.Mocks.Tests/Impl/ValidateTests.cs @@ -51,6 +51,16 @@ public void IsNotNullWhenNullThrows() () => Validate.IsNotNull(null, "test")); } + [Fact] + public void IsNotNull_throws_exception_when_argument_is_null() + { + string sample = null; + + Assert.Throws( + "Value cannot be null.\r\nParameter name:sample", + () => Validate.IsNotNull(() => sample)); + } + [Fact] public void ArgsEqualWhenNoArgs() { From 7d4aec0add78e4b922f665f668cf0cbbf1c2fef8 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Mon, 6 Sep 2010 20:49:16 -0500 Subject: [PATCH 10/24] Adding generic Log message to IExceptionLogger interface and implementors --- Rhino.Mocks/Impl/ConsoleLogger.cs | 9 +++++++++ Rhino.Mocks/Impl/NullLogger.cs | 13 +++++++++++-- Rhino.Mocks/Impl/TextWriterExpectationLogger.cs | 14 ++++++++++++-- .../Impl/TraceWriterExpectationLogger.cs | 15 ++++++++++++--- ...raceWriterWithStackTraceExpectationWriter.cs | 17 ++++++++++++++--- Rhino.Mocks/Interfaces/IExpectationLogger.cs | 11 +++++++++-- 6 files changed, 67 insertions(+), 12 deletions(-) diff --git a/Rhino.Mocks/Impl/ConsoleLogger.cs b/Rhino.Mocks/Impl/ConsoleLogger.cs index 2d6eab8a..3e55826a 100644 --- a/Rhino.Mocks/Impl/ConsoleLogger.cs +++ b/Rhino.Mocks/Impl/ConsoleLogger.cs @@ -13,6 +13,15 @@ public class ConsoleLogger : IExpectationLogger { #region IExpectationLogger Members + /// + /// Logs the message + /// + /// The message. + public void Log(string message) + { + Console.WriteLine(message); + } + /// /// Logs the expectation as is was recorded /// diff --git a/Rhino.Mocks/Impl/NullLogger.cs b/Rhino.Mocks/Impl/NullLogger.cs index 4f8f98d6..58801e41 100644 --- a/Rhino.Mocks/Impl/NullLogger.cs +++ b/Rhino.Mocks/Impl/NullLogger.cs @@ -1,3 +1,4 @@ +using System; using Castle.Core.Interceptor; using Rhino.Mocks.Interfaces; @@ -7,8 +8,16 @@ namespace Rhino.Mocks.Impl /// Doesn't log anything, just makes happy noises /// public class NullLogger : IExpectationLogger - { - /// + { + /// + /// Logs the message + /// + /// The message. + public void Log(string message) + { + } + + /// /// Logs the expectation as is was recorded /// /// The invocation. diff --git a/Rhino.Mocks/Impl/TextWriterExpectationLogger.cs b/Rhino.Mocks/Impl/TextWriterExpectationLogger.cs index 3408eb83..00cb4e53 100644 --- a/Rhino.Mocks/Impl/TextWriterExpectationLogger.cs +++ b/Rhino.Mocks/Impl/TextWriterExpectationLogger.cs @@ -22,8 +22,18 @@ public class TextWriterExpectationLogger : IExpectationLogger public TextWriterExpectationLogger(TextWriter writer) { this.writer = writer; - } - /// + } + + /// + /// Logs the message + /// + /// The message. + public void Log(string message) + { + writer.WriteLine(message); + } + + /// /// Logs the expectation as it was recorded /// /// The invocation. diff --git a/Rhino.Mocks/Impl/TraceWriterExpectationLogger.cs b/Rhino.Mocks/Impl/TraceWriterExpectationLogger.cs index 10e10352..ca3743d4 100644 --- a/Rhino.Mocks/Impl/TraceWriterExpectationLogger.cs +++ b/Rhino.Mocks/Impl/TraceWriterExpectationLogger.cs @@ -36,9 +36,18 @@ public TraceWriterExpectationLogger(bool logRecorded, bool logReplayed, bool log _logUnexpected = logUnexpected; } - #region IExpectationLogger Members - - /// + #region IExpectationLogger Members + + /// + /// Logs the message + /// + /// The message. + public void Log(string message) + { + Trace.WriteLine(message); + } + + /// /// Logs the expectation as is was recorded /// /// The invocation. diff --git a/Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs b/Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs index b1ca4036..1e1aca4c 100644 --- a/Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs +++ b/Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs @@ -1,3 +1,5 @@ +using System; + namespace Rhino.Mocks.Impl { using System.Diagnostics; @@ -14,9 +16,18 @@ public class TraceWriterWithStackTraceExpectationWriter : IExpectationLogger /// /// Allows to redirect output to a different location. /// - public TextWriter AlternativeWriter; - - /// + public TextWriter AlternativeWriter; + + /// + /// Logs the message + /// + /// The message. + public void Log(string message) + { + WriteLine(message); + } + + /// /// Logs the expectation as is was recorded /// /// The invocation. diff --git a/Rhino.Mocks/Interfaces/IExpectationLogger.cs b/Rhino.Mocks/Interfaces/IExpectationLogger.cs index 2e61f29f..1b844424 100644 --- a/Rhino.Mocks/Interfaces/IExpectationLogger.cs +++ b/Rhino.Mocks/Interfaces/IExpectationLogger.cs @@ -33,8 +33,15 @@ namespace Rhino.Mocks.Interfaces /// /// Log expectations - allows to see what is going on inside Rhino Mocks /// - public interface IExpectationLogger - { + public interface IExpectationLogger + { + + /// + /// Logs the message + /// + /// The message. + void Log(string message); + /// /// Logs the expectation as is was recorded /// From 6ddd1ad480dca5c61574259f8ed9bda5fcbfc900 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Mon, 6 Sep 2010 21:30:16 -0500 Subject: [PATCH 11/24] using new Validate method (very small tweak) --- Rhino.Mocks/Expectations/ConstraintsExpectation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rhino.Mocks/Expectations/ConstraintsExpectation.cs b/Rhino.Mocks/Expectations/ConstraintsExpectation.cs index 1f462fe5..8ed5e020 100644 --- a/Rhino.Mocks/Expectations/ConstraintsExpectation.cs +++ b/Rhino.Mocks/Expectations/ConstraintsExpectation.cs @@ -52,7 +52,7 @@ public class ConstraintsExpectation : AbstractExpectation /// Number of method calls for this expectations public ConstraintsExpectation(IInvocation invocation,AbstractConstraint[] constraints, Range expectedRange) : base(invocation, expectedRange) { - Validate.IsNotNull(constraints, "constraints"); + Validate.IsNotNull(()=>constraints); this.constraints = constraints; ConstraintsMatchMethod(); } @@ -64,7 +64,7 @@ public ConstraintsExpectation(IInvocation invocation,AbstractConstraint[] constr /// Constraints. public ConstraintsExpectation(IExpectation expectation, AbstractConstraint[] constraints) : base(expectation) { - Validate.IsNotNull(constraints, "constraints"); + Validate.IsNotNull(() => constraints); this.constraints = constraints; ConstraintsMatchMethod(); } From 4b2f916d2a2607188d2cdccf5aef6798aff1d516 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Mon, 6 Sep 2010 21:30:36 -0500 Subject: [PATCH 12/24] adding some logging --- Rhino.Mocks/Impl/RecordMockState.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Rhino.Mocks/Impl/RecordMockState.cs b/Rhino.Mocks/Impl/RecordMockState.cs index d33ebc2c..7bf13739 100644 --- a/Rhino.Mocks/Impl/RecordMockState.cs +++ b/Rhino.Mocks/Impl/RecordMockState.cs @@ -175,6 +175,7 @@ public object MethodCall(IInvocation invocation, MethodInfo method, params objec { expectation = expectationBuilder.BuildDefaultExpectation(invocation, method, args, GetDefaultCallCountRangeExpectation); } + RhinoMocks.Logger.Log(string.Format("{0} -> {1} ", expectation.ErrorMessage, expectation.GetType())); repository.Recorder.Record(mockedObject, method, expectation); LastExpectation = expectation; methodCallsCount++; From d458e607d636feeb29397d01f96388d656340923 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Tue, 7 Sep 2010 17:14:03 -0500 Subject: [PATCH 13/24] Fixing little 'hitch' in TraceWriterWithStackTraceExpectationWriter (was causing a failing test) --- Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs b/Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs index 1e1aca4c..4ed705ba 100644 --- a/Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs +++ b/Rhino.Mocks/Impl/TraceWriterWithStackTraceExpectationWriter.cs @@ -24,7 +24,7 @@ public class TraceWriterWithStackTraceExpectationWriter : IExpectationLogger /// The message. public void Log(string message) { - WriteLine(message); + Debug.WriteLine(message); } /// From b2f15b6d173f92583edc8248c4881a928e585c34 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sat, 18 Sep 2010 23:30:48 -0500 Subject: [PATCH 14/24] Failing tests: stub returning delegate twice --- .../FieldsProblem/FieldProblem_KeithD.cs | 41 +++++++++++++++++++ Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj | 1 + 2 files changed, 42 insertions(+) create mode 100644 Rhino.Mocks.Tests/FieldsProblem/FieldProblem_KeithD.cs diff --git a/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_KeithD.cs b/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_KeithD.cs new file mode 100644 index 00000000..498494f5 --- /dev/null +++ b/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_KeithD.cs @@ -0,0 +1,41 @@ +namespace Rhino.Mocks.Tests.FieldsProblem +{ + using System; + using Xunit; + + public class FieldProblem_KeithD + { + [Fact] + public void CanStubReturningAnonymousDelegateTwice() + { + var foo = MockRepository.GenerateMock(); + + foo.Stub(x => x.Bar(0)).Return(() => 2); + foo.Stub(x => x.Bar(1)).Return(() => 4); + + Assert.Equal(2, foo.Bar(0)()); + Assert.Equal(4, foo.Bar(1)()); + } + + [Fact] + public void CanStubReturningNonAnonymousDelegateTwice() + { + var foo = MockRepository.GenerateMock(); + + foo.Stub(x => x.Bar(0)).Return(Return2); + foo.Stub(x => x.Bar(1)).Return(Return4); + + Assert.Equal(2, foo.Bar(0)()); + Assert.Equal(4, foo.Bar(1)()); + } + + public interface IFoo + { + Func Bar(int baz); + } + + private static int Return2() { return 2; } + + private static int Return4() { return 4; } + } +} diff --git a/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj b/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj index 99bdf4bf..b8f89280 100644 --- a/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj +++ b/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj @@ -175,6 +175,7 @@ + From 4d1054fcd86eaf42873e2800198828c353db0bfb Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 19 Sep 2010 12:47:09 -0500 Subject: [PATCH 15/24] Failing test: mocked delegate's Target should not include the delegate type in ImplementedTypes --- .../FieldsProblem/FieldProblem_KeithD.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_KeithD.cs b/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_KeithD.cs index 498494f5..5b2f8775 100644 --- a/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_KeithD.cs +++ b/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_KeithD.cs @@ -1,10 +1,22 @@ namespace Rhino.Mocks.Tests.FieldsProblem { using System; + using Rhino.Mocks.Interfaces; using Xunit; public class FieldProblem_KeithD { + [Fact] + public void ImplementedTypesOfTargetOfMockedDelegateDoesNotContainDelegateType() + { + var mockDelegate = MockRepository.GenerateMock(); + + var mockTarget = mockDelegate.Target as IMockedObject; + + Assert.NotNull(mockTarget); + Assert.DoesNotContain(typeof(EventHandler), mockTarget.ImplementedTypes); + } + [Fact] public void CanStubReturningAnonymousDelegateTwice() { From 5b337e8cfa02ce67d9a9d196e7bfb601c1a237ba Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 19 Sep 2010 12:48:16 -0500 Subject: [PATCH 16/24] Mocked delegate's Target no longer includes the delegate type in ImplementedTypes --- Rhino.Mocks/MockRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rhino.Mocks/MockRepository.cs b/Rhino.Mocks/MockRepository.cs index 1b92521d..64ea200c 100644 --- a/Rhino.Mocks/MockRepository.cs +++ b/Rhino.Mocks/MockRepository.cs @@ -785,7 +785,7 @@ private object MockDelegate(CreateMockState mockStateFactory, Type type) object proxy; - ProxyInstance proxyInstance = new ProxyInstance(this, type); + ProxyInstance proxyInstance = new ProxyInstance(this); RhinoInterceptor interceptor = new RhinoInterceptor(this, proxyInstance,invocationVisitorsFactory.CreateStandardInvocationVisitors(proxyInstance, this)); Type[] types = new Type[] { typeof(IMockedObject) }; From 5535896fbead0d4ce6b6d2e2aff95974fee58e2e Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Tue, 21 Sep 2010 13:46:18 -0500 Subject: [PATCH 17/24] Combining several parital files that made up MockRepository into a singulr file/class --- Rhino.Mocks/Impl/RecordMockState.cs | 624 ++++++++++---------- Rhino.Mocks/MockRepository.cs | 234 +++++++- Rhino.Mocks/MockRepositoryRecordPlayback.cs | 30 - Rhino.Mocks/Rhino.Mocks.csproj | 1 - 4 files changed, 543 insertions(+), 346 deletions(-) diff --git a/Rhino.Mocks/Impl/RecordMockState.cs b/Rhino.Mocks/Impl/RecordMockState.cs index 7bf13739..1c159037 100644 --- a/Rhino.Mocks/Impl/RecordMockState.cs +++ b/Rhino.Mocks/Impl/RecordMockState.cs @@ -1,300 +1,300 @@ -#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.Reflection; +#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.Reflection; using Castle.Core.Interceptor; -using Rhino.Mocks.Interfaces; -using Rhino.Mocks.Utilities; - -namespace Rhino.Mocks.Impl -{ - /// - /// Records all the expectations for a mock - /// - public class RecordMockState : IMockState - { - #region Variables - - private MockRepository repository; - private readonly IMockedObject mockedObject; - private int methodCallsCount = 0; - private IExpectation lastExpectation; +using Rhino.Mocks.Interfaces; +using Rhino.Mocks.Utilities; + +namespace Rhino.Mocks.Impl +{ + /// + /// Records all the expectations for a mock + /// + public class RecordMockState : IMockState + { + #region Variables + + private MockRepository repository; + private readonly IMockedObject mockedObject; + private int methodCallsCount = 0; + private IExpectation lastExpectation; private bool lastCallWasPropertyBehavior; - private ExpectationBuilder expectationBuilder; - - #endregion - - #region Properties - - /// - /// Gets the last expectation. - /// - public IExpectation LastExpectation - { - get { return lastExpectation; } - set - { - lastCallWasPropertyBehavior = false; - lastExpectation = value; - } - } - - /// - /// Gets the total method calls count. - /// - public int MethodCallsCount - { - get { return methodCallsCount; } - } - - /// - /// Get the options for the last method call - /// - public IMethodOptions GetLastMethodOptions() - { - if(lastCallWasPropertyBehavior) - { - string message = - @"You are trying to set an expectation on a property that was defined to use PropertyBehavior. -Instead of writing code such as this: mockObject.Stub(x => x.SomeProperty).Return(42); -You can use the property directly to achieve the same result: mockObject.SomeProperty = 42;"; - throw new InvalidOperationException(message); - } - if (LastExpectation == null) - throw new InvalidOperationException("There is no matching last call on this object. Are you sure that the last call was a virtual or interface method call?"); - return new MethodOptions(repository, this, mockedObject, LastExpectation); - } - - /// - /// Get the options for the last method call - /// - public IMethodOptions LastMethodOptions - { - get { return GetLastMethodOptions(); } - } - - /// - /// Set the exception to throw when Verify is called. - /// This is used to report exception that may have happened but where caught in the code. - /// This way, they are reported anyway when Verify() is called. - /// - public void SetExceptionToThrowOnVerify(Exception ex) - { - //not implementing this, since there is never a call to Verify() anyway. - } - - /// - /// This method is called to indicate that a property behavior call. - /// This is done so we generate good error message in the common case of people using - /// Stubbed properties with Return(). - /// - public void NotifyCallOnPropertyBehavior() - { - LastExpectation = null; - lastCallWasPropertyBehavior = true; - } - - /// - /// Gets the matching verify state for this state - /// - public IMockState VerifyState - { - get { throw InvalidOperationOnRecord(); } - } - - #endregion - - #region C'tor - - /// - /// Creates a new instance. - /// - /// Repository. - /// The proxy that generates the method calls - public RecordMockState(IMockedObject mockedObject, MockRepository repository) - { - Validate.IsNotNull(mockedObject, "proxy"); - Validate.IsNotNull(repository, "repository"); - this.repository = repository; - this.mockedObject = mockedObject; - expectationBuilder = new ExpectationBuilder(); - } - - #endregion - - #region Methods - - /// - /// Add a method call for this state' mock. - /// - /// The invocation for this method - /// The method that was called - /// The arguments this method was called with - public object MethodCall(IInvocation invocation, MethodInfo method, params object[] args) - { - try - { - AssertPreviousMethodIsClose(); - repository.lastMockedObject = mockedObject; - MockRepository.lastRepository = repository; - IExpectation expectation; - - // Has the Arg class been used? - if (ArgManager.HasBeenUsed) - { - expectation = expectationBuilder.BuildParamExpectation(invocation, method); - } - else - { - expectation = expectationBuilder.BuildDefaultExpectation(invocation, method, args, GetDefaultCallCountRangeExpectation); - } - RhinoMocks.Logger.Log(string.Format("{0} -> {1} ", expectation.ErrorMessage, expectation.GetType())); - repository.Recorder.Record(mockedObject, method, expectation); - LastExpectation = expectation; - methodCallsCount++; - RhinoMocks.Logger.LogRecordedExpectation(invocation, expectation); - object returnValue; - if (TryCreateReturnValue(expectation, out returnValue)) - return returnValue; - return ReturnValueUtil.DefaultValue(method.ReturnType, invocation); - } - finally - { - // Consume the Arg constraints only once, and reset it after each call. - // this is in the finally block to make sure that an exeption does not - // make subsequent unit tests fail. - ArgManager.Clear(); - } - } - - private bool TryCreateReturnValue(IExpectation expectation, out object returnValue) - { - returnValue = null; - - //use already created instance if any - if (mockedObject.DependentMocks != null && mockedObject.DependentMocks.Count > 0) - { - foreach (IMockedObject dependentMock in mockedObject.DependentMocks) - { - if (dependentMock.ImplementedTypes != null && dependentMock.ImplementedTypes.Length > 0) - { - foreach (Type type in dependentMock.ImplementedTypes) - { - if (type == expectation.Method.ReturnType) - { - returnValue = dependentMock.MockedObjectInstance; - return true; - } - } - } - } - return false; - } - //create new instance - try - { - returnValue = Repository.DynamicMock(expectation.Method.ReturnType); - } - catch (Exception) - { - // couldn't create mock object for it, we fall back to returning a default value - returnValue = null; - return false; - } - - mockedObject.DependentMocks.Add(MockRepository.GetMockedObject(returnValue)); - - expectation.ReturnValue = returnValue; - expectation.AllowTentativeReturn = true; - - return true; - } - - /// - /// Verify that we can move to replay state and move - /// to the reply state. - /// - public virtual IMockState Replay() - { - AssertPreviousMethodIsClose(); - return DoReplay(); - } - - /// - /// Verify that we can move to replay state and move - /// to the reply state. - /// - protected virtual IMockState DoReplay() - { - return new ReplayMockState(this); - } - - /// - /// Verify that this mock expectations have passed. - /// - public virtual void Verify() - { - throw InvalidOperationOnRecord(); - } - - /// - /// Gets a mock state that match the original mock state of the object. - /// - public virtual IMockState BackToRecord() - { - return new RecordMockState(mockedObject, repository); - } - - #endregion - - #region Private Methods - - /// - /// Asserts the previous method is closed (had an expectation set on it so we can replay it correctly) - /// - protected virtual void AssertPreviousMethodIsClose() - { - if (LastExpectation != null && !LastExpectation.ActionsSatisfied) - throw new InvalidOperationException("Previous method '" + LastExpectation.ErrorMessage + "' requires a return value or an exception to throw."); - } - - private Exception InvalidOperationOnRecord() - { - // Format the mock types into a string for display in the exception message, - // using the pattern {Namespace.IType1, Namespace.IType2}. - string mockedTypes = string.Empty; - if (this.mockedObject.ImplementedTypes.Length > 0) { - mockedTypes = string.Format("{{{0}}} ", string.Join(", ", Array.ConvertAll(this.mockedObject.ImplementedTypes, delegate(Type ty) { return ty.FullName; }))); - } - - return new InvalidOperationException(string.Format("This action is invalid when the mock object {0}is in record state.", mockedTypes)); + private ExpectationBuilder expectationBuilder; + + #endregion + + #region Properties + + /// + /// Gets the last expectation. + /// + public IExpectation LastExpectation + { + get { return lastExpectation; } + set + { + lastCallWasPropertyBehavior = false; + lastExpectation = value; + } + } + + /// + /// Gets the total method calls count. + /// + public int MethodCallsCount + { + get { return methodCallsCount; } + } + + /// + /// Get the options for the last method call + /// + public IMethodOptions GetLastMethodOptions() + { + if(lastCallWasPropertyBehavior) + { + string message = + @"You are trying to set an expectation on a property that was defined to use PropertyBehavior. +Instead of writing code such as this: mockObject.Stub(x => x.SomeProperty).Return(42); +You can use the property directly to achieve the same result: mockObject.SomeProperty = 42;"; + throw new InvalidOperationException(message); + } + if (LastExpectation == null) + throw new InvalidOperationException("There is no matching last call on this object. Are you sure that the last call was a virtual or interface method call?"); + return new MethodOptions(repository, this, mockedObject, LastExpectation); + } + + /// + /// Get the options for the last method call + /// + public IMethodOptions LastMethodOptions + { + get { return GetLastMethodOptions(); } + } + + /// + /// Set the exception to throw when Verify is called. + /// This is used to report exception that may have happened but where caught in the code. + /// This way, they are reported anyway when Verify() is called. + /// + public void SetExceptionToThrowOnVerify(Exception ex) + { + //not implementing this, since there is never a call to Verify() anyway. + } + + /// + /// This method is called to indicate that a property behavior call. + /// This is done so we generate good error message in the common case of people using + /// Stubbed properties with Return(). + /// + public void NotifyCallOnPropertyBehavior() + { + LastExpectation = null; + lastCallWasPropertyBehavior = true; + } + + /// + /// Gets the matching verify state for this state + /// + public IMockState VerifyState + { + get { throw InvalidOperationOnRecord(); } + } + + #endregion + + #region C'tor + + /// + /// Creates a new instance. + /// + /// Repository. + /// The proxy that generates the method calls + public RecordMockState(IMockedObject mockedObject, MockRepository repository) + { + Validate.IsNotNull(mockedObject, "proxy"); + Validate.IsNotNull(repository, "repository"); + this.repository = repository; + this.mockedObject = mockedObject; + expectationBuilder = new ExpectationBuilder(); + } + + #endregion + + #region Methods + + /// + /// Add a method call for this state' mock. + /// + /// The invocation for this method + /// The method that was called + /// The arguments this method was called with + public object MethodCall(IInvocation invocation, MethodInfo method, params object[] args) + { + try + { + AssertPreviousMethodIsClose(); + repository.lastMockedObject = mockedObject; + MockRepository.lastRepository = repository; + IExpectation expectation; + + // Has the Arg class been used? + if (ArgManager.HasBeenUsed) + { + expectation = expectationBuilder.BuildParamExpectation(invocation, method); + } + else + { + expectation = expectationBuilder.BuildDefaultExpectation(invocation, method, args, GetDefaultCallCountRangeExpectation); + } + RhinoMocks.Logger.Log(string.Format("{0} -> {1} ", expectation.ErrorMessage, expectation.GetType())); + repository.Recorder.Record(mockedObject, method, expectation); + LastExpectation = expectation; + methodCallsCount++; + RhinoMocks.Logger.LogRecordedExpectation(invocation, expectation); + object returnValue; + if (TryCreateReturnValue(expectation, out returnValue)) + return returnValue; + return ReturnValueUtil.DefaultValue(method.ReturnType, invocation); + } + finally + { + // Consume the Arg constraints only once, and reset it after each call. + // this is in the finally block to make sure that an exeption does not + // make subsequent unit tests fail. + ArgManager.Clear(); + } + } + + private bool TryCreateReturnValue(IExpectation expectation, out object returnValue) + { + returnValue = null; + + //use already created instance if any + if (mockedObject.DependentMocks != null && mockedObject.DependentMocks.Count > 0) + { + foreach (IMockedObject dependentMock in mockedObject.DependentMocks) + { + if (dependentMock.ImplementedTypes != null && dependentMock.ImplementedTypes.Length > 0) + { + foreach (Type type in dependentMock.ImplementedTypes) + { + if (type == expectation.Method.ReturnType) + { + returnValue = dependentMock.MockedObjectInstance; + return true; + } + } + } + } + return false; + } + //create new instance + try + { + returnValue = Repository.DynamicMock(expectation.Method.ReturnType); + } + catch (Exception) + { + // couldn't create mock object for it, we fall back to returning a default value + returnValue = null; + return false; + } + + mockedObject.DependentMocks.Add(MockRepository.GetMockedObject(returnValue)); + + expectation.ReturnValue = returnValue; + expectation.AllowTentativeReturn = true; + + return true; + } + + /// + /// Verify that we can move to replay state and move + /// to the reply state. + /// + public virtual IMockState Replay() + { + AssertPreviousMethodIsClose(); + return DoReplay(); + } + + /// + /// Verify that we can move to replay state and move + /// to the reply state. + /// + protected virtual IMockState DoReplay() + { + return new ReplayMockState(this); + } + + /// + /// Verify that this mock expectations have passed. + /// + public virtual void Verify() + { + throw InvalidOperationOnRecord(); + } + + /// + /// Gets a mock state that match the original mock state of the object. + /// + public virtual IMockState BackToRecord() + { + return new RecordMockState(mockedObject, repository); + } + + #endregion + + #region Private Methods + + /// + /// Asserts the previous method is closed (had an expectation set on it so we can replay it correctly) + /// + protected virtual void AssertPreviousMethodIsClose() + { + if (LastExpectation != null && !LastExpectation.ActionsSatisfied) + throw new InvalidOperationException("Previous method '" + LastExpectation.ErrorMessage + "' requires a return value or an exception to throw."); + } + + private Exception InvalidOperationOnRecord() + { + // Format the mock types into a string for display in the exception message, + // using the pattern {Namespace.IType1, Namespace.IType2}. + string mockedTypes = string.Empty; + if (this.mockedObject.ImplementedTypes.Length > 0) { + mockedTypes = string.Format("{{{0}}} ", string.Join(", ", Array.ConvertAll(this.mockedObject.ImplementedTypes, delegate(Type ty) { return ty.FullName; }))); + } + + return new InvalidOperationException(string.Format("This action is invalid when the mock object {0}is in record state.", mockedTypes)); } /// @@ -304,21 +304,21 @@ private Exception InvalidOperationOnRecord() protected virtual Range GetDefaultCallCountRangeExpectation() { return new Range(1, 1); - } - - #endregion - - #region Internal - internal MockRepository Repository - { - get { return repository; } - } - - internal IMockedObject Proxy - { - get { return mockedObject; } - } - - #endregion + } + + #endregion + + #region Internal + internal MockRepository Repository + { + get { return repository; } + } + + internal IMockedObject Proxy + { + get { return mockedObject; } + } + + #endregion } -} +} diff --git a/Rhino.Mocks/MockRepository.cs b/Rhino.Mocks/MockRepository.cs index 64ea200c..2a664424 100644 --- a/Rhino.Mocks/MockRepository.cs +++ b/Rhino.Mocks/MockRepository.cs @@ -107,7 +107,7 @@ namespace Rhino.Mocks /// /// Creates proxied instances of types. /// - public partial class MockRepository + public class MockRepository { /// /// Delegate: CreateMockState @@ -1070,8 +1070,236 @@ protected internal static void SetExceptionToBeThrownOnVerify(object proxy, Expe repository.proxies[proxy].SetExceptionToThrowOnVerify(expectationViolationException); } - #endregion - + #endregion + + #region AAA Methods (formerly MockRepositoryAAA.cs) + /* MockRepositoryAAA.cs contains further definitions on MockRepository. MockRepository right now is too large of a class and allowing + * to exist as partials "masks" the problems of this growing class". The items in this reagion are transplants from the other file location + */ + + // Static methods for working with RhinoMocks using AAA syntax + + /// 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; + } + + + #endregion + + #region Mock Repository using (formerly part of MockRepositoryRecordPlayback.cs) + /* Much like the "AAA Methods ..." region block above, the code in this region was in it's own file + * which masked the problem of the growing file" + */ + + // + // Adds optional new usage: + // using(mockRepository.Record()) { + // Expect.Call(mock.Method()).Return(retVal); + // } + // using(mockRepository.Playback()) { + // // Execute code + // } + // N.B. mockRepository.ReplayAll() and mockRepository.VerifyAll() + // calls are taken care of by Record/Playback + // + + /// + /// + /// + public IDisposable Record() + { + return new RecordModeChanger(this); + } + + /// + /// + /// + public IDisposable Playback() + { + return new PlaybackModeChanger(this); + } + + #endregion + /// /// 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. diff --git a/Rhino.Mocks/MockRepositoryRecordPlayback.cs b/Rhino.Mocks/MockRepositoryRecordPlayback.cs index c3036947..19bc7030 100644 --- a/Rhino.Mocks/MockRepositoryRecordPlayback.cs +++ b/Rhino.Mocks/MockRepositoryRecordPlayback.cs @@ -31,36 +31,6 @@ namespace Rhino.Mocks { - /// - /// Adds optional new usage: - /// using(mockRepository.Record()) { - /// Expect.Call(mock.Method()).Return(retVal); - /// } - /// using(mockRepository.Playback()) { - /// // Execute code - /// } - /// N.B. mockRepository.ReplayAll() and mockRepository.VerifyAll() - /// calls are taken care of by Record/Playback - /// - public partial class MockRepository - { - /// - /// - /// - public IDisposable Record() - { - return new RecordModeChanger(this); - } - - /// - /// - /// - public IDisposable Playback() - { - return new PlaybackModeChanger(this); - } - } - internal class PlaybackModeChanger : IDisposable { private readonly MockRepository m_repository; diff --git a/Rhino.Mocks/Rhino.Mocks.csproj b/Rhino.Mocks/Rhino.Mocks.csproj index 8c77114c..5ce3d93d 100644 --- a/Rhino.Mocks/Rhino.Mocks.csproj +++ b/Rhino.Mocks/Rhino.Mocks.csproj @@ -182,7 +182,6 @@ - From da89c216187313be55ae5f1e9124820db8266bb7 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Tue, 21 Sep 2010 13:46:52 -0500 Subject: [PATCH 18/24] File is no longer needed due to previous commit --- Rhino.Mocks/MockRepositoryAAA.cs | 191 ------------------------------- 1 file changed, 191 deletions(-) delete mode 100644 Rhino.Mocks/MockRepositoryAAA.cs diff --git a/Rhino.Mocks/MockRepositoryAAA.cs b/Rhino.Mocks/MockRepositoryAAA.cs deleted file mode 100644 index e751a3cb..00000000 --- a/Rhino.Mocks/MockRepositoryAAA.cs +++ /dev/null @@ -1,191 +0,0 @@ -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 From 18a152c3877ca7b01f939db96c77b6383af7460a Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Tue, 21 Sep 2010 13:51:09 -0500 Subject: [PATCH 19/24] Adding in marker interface which is more descriptive that IDisposable and allows for logical grouping of mode changers --- Rhino.Mocks/MockRepositoryRecordPlayback.cs | 22 ++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Rhino.Mocks/MockRepositoryRecordPlayback.cs b/Rhino.Mocks/MockRepositoryRecordPlayback.cs index 19bc7030..0e665072 100644 --- a/Rhino.Mocks/MockRepositoryRecordPlayback.cs +++ b/Rhino.Mocks/MockRepositoryRecordPlayback.cs @@ -31,7 +31,7 @@ namespace Rhino.Mocks { - internal class PlaybackModeChanger : IDisposable + internal class PlaybackModeChanger : IModeChanger { private readonly MockRepository m_repository; @@ -67,7 +67,7 @@ internal static bool ExceptionWasThrownAndDisposableActionShouldNotBeCalled() } } - internal class RecordModeChanger : IDisposable + internal class RecordModeChanger : IModeChanger { private readonly MockRepository m_repository; @@ -82,5 +82,21 @@ public void Dispose() return; m_repository.ReplayAll(); } - } + } + + /// + /// Interface which allows for the optional usage: + /// using(mockRepository.Record()) { + /// Expect.Call(mock.Method()).Return(retVal); + /// } + /// using(mockRepository.Playback()) { + /// // Execute code + /// } + /// N.B. mockRepository.ReplayAll() and mockRepository.VerifyAll() + /// calls are taken care of by Record/Playback + /// + public interface IModeChanger : IDisposable + { + + } } \ No newline at end of file From 61dc509201111222f410fe3381849907803a5f6b Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Wed, 22 Sep 2010 07:00:03 -0700 Subject: [PATCH 20/24] Changing Record() and Playback() options to use new IModeChanger interfaces --- Rhino.Mocks/MockRepository.cs | 2562 ++++++++++++++++----------------- 1 file changed, 1281 insertions(+), 1281 deletions(-) diff --git a/Rhino.Mocks/MockRepository.cs b/Rhino.Mocks/MockRepository.cs index 2a664424..53a16e40 100644 --- a/Rhino.Mocks/MockRepository.cs +++ b/Rhino.Mocks/MockRepository.cs @@ -1,1075 +1,1075 @@ -#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.Collections.Generic; -using System.Collections.Specialized; -using System.Reflection; -using System.Text; -using Castle.Core.Interceptor; -using Castle.DynamicProxy; -using Rhino.Mocks.Exceptions; -using Rhino.Mocks.Generated; -using Rhino.Mocks.Impl; -using Rhino.Mocks.Impl.Invocation; -using Rhino.Mocks.Impl.RemotingMock; -using Rhino.Mocks.Interfaces; -using Rhino.Mocks.MethodRecorders; - -namespace Rhino.Mocks -{ - /* - * class: MockRepository - * The MockRepository is the main interaction point with Rhino Mocks. - * - * Common usage pattern is to create the on [SetUp] - * and then create mock objects using either or - * and setup expectations on the mock object(s) by - * callling their methods. A call to would move the mock - * object(s) to replay state, a call to is made from the - * [TearDown] method. - * - * Thread Safety: - * MockRepository is capable of verifying in multiply threads, but recording in multiply threads - * is not recommended. If you need to do so you _must_ use the and - * methods and not and - * 's various methods. - * - * Code Sample: - * - * (start code) - * MockRepository mocks; - * - * [SetUp] - * public void Setup() - * { - * mocks = new MockRepository(); - * } - * - * [Test] - * public void CallMethodOnObject() - * { - * - * IDemo demo = (IDemo)mocks.CreateMock(typeof(IDemo)); - * // Setting up an expectation for a call to IDemo.VoidNoArg - * demo.VoidNoArg(); - * mocks.ReplayAll(); - * // Fullifying the expectation for call to IDemo.VoidNoArg - * demo.VoidNoArg(); - * } - * - * [TearDown] - * public void Teardown() - * { - * mocks.VerifyAll(); - * } - * (end) - * - * Class Responsbilities: - * - * - Create and manage mock object throughout their life time - * - * See Also: - * - - * - - * - - * - - */ - - /// - /// Creates proxied instances of types. - /// - public class MockRepository - { - /// - /// Delegate: CreateMockState - /// This is used internally to cleanly handle the creation of different - /// RecordMockStates. - /// - protected delegate IMockState CreateMockState(IMockedObject mockedObject); - - #region Variables - - /* - * Variable: generatorMap - * A static variable that is used to hold a map of Types to ProxyGenerators - * - */ - - /// - /// This is a map of types to ProxyGenerators. - /// - private static readonly IDictionary generatorMap = new Dictionary(); - - /* - * Variable: lastRepository - * A static variable that is used to hold the repository that last had a method call - * on one of its mock objects. - * - */ - - /// - /// This is used to record the last repository that has a method called on it. - /// - internal static MockRepository lastRepository; - - /* - * Var: lastProxy - * The last proxy that had a method call for _this_ repository - */ - - /// - /// this is used to get to the last proxy on this repository. - /// - internal IMockedObject lastMockedObject; - - private static readonly DelegateTargetInterfaceCreator delegateTargetInterfaceCreator = - new DelegateTargetInterfaceCreator(); - - /// - /// For mock delegates, maps the proxy instance from intercepted invocations - /// back to the delegate that was originally returned to client code, if any. - /// - protected IDictionary delegateProxies; - - /// - /// All the proxies in the mock repositories - /// - protected ProxyStateDictionary proxies; - - private readonly Stack recorders; - private readonly IMethodRecorder rootRecorder; - /// - /// This is here because we can't put it in any of the recorders, since repeatable methods - /// have no orderring, and if we try to handle them using the usual manner, we would get into - /// wierd situations where repeatable method that was defined in an orderring block doesn't - /// exists until we enter this block. - /// - private readonly ProxyMethodExpectationsDictionary repeatableMethods; - - private ProxyGenerationOptions proxyGenerationOptions; - private InvocationVisitorsFactory invocationVisitorsFactory; - - #endregion - - #region Properties - - /* - * Property: Recorder - * Gets the current recorder for the repository. - */ - - /// - /// Gets the recorder. - /// - /// - internal IMethodRecorder Recorder - { - get { return recorders.Peek() as IMethodRecorder; } - } - - #endregion - - #region c'tors - - /* function: MockRepository - * Create a new instance of MockRepository - */ - - /// - /// Creates a new instance. - /// - public MockRepository() - { - proxyGenerationOptions = new ProxyGenerationOptions - { - AttributesToAddToGeneratedTypes = - { - new __ProtectAttribute() - } - }; - recorders = new Stack(); - repeatableMethods = new ProxyMethodExpectationsDictionary(); - rootRecorder = new UnorderedMethodRecorder(repeatableMethods); - recorders.Push(rootRecorder); - proxies = new ProxyStateDictionary(); - delegateProxies = new Hashtable(MockedObjectsEquality.Instance); - invocationVisitorsFactory = new InvocationVisitorsFactory(); - - // clean up Arg data to avoid the static data to be carried from one unit test - // to another. - ArgManager.Clear(); - } - - - #endregion - - #region Methods - - /* - * Method: Ordered - * Moves the _entire_ to use ordered recording. - * - * This call is only valid during the recording phase. - * This call affects all mock objects that were created from this repository. - * - * The orderring is ended when the returned IDisposable's Dispose() method is called. - * (start code) - * [Test] - * public void CallMethodOnObject() - * { - * IDemo demo = (IDemo)mocks.CreateMock(typeof(IDemo)); - * //Moving to ordered mocking. - * using(mocks.Ordered() - * { - * demo.VoidNoArg(); - * demo.IntNoArg(); - * } - * //Must exit the ordering before calling - * mocks.ReplayAll(); - * //If we would try to call them in any other order, the test would fail - * demo.VoidNoArg(); - * demo.IntNoArg(); - * } - * (end) - * - */ - - /// - /// Move the repository to ordered mode - /// - public IDisposable Ordered() - { - return new RecorderChanger(this, Recorder, new OrderedMethodRecorder(Recorder, repeatableMethods)); - } - - /* - * Method: Unordered - * Moves the _entire_ to use unordered recording (the default). - * - * This call is only valid during the recording phase. - * This call affects all mock objects that were created from this repository. - * - * (start code) - * [Test] - * public void CallMethodOnObject() - * { - * IDemo demo = (IDemo)mocks.CreateMock(typeof(IDemo)); - * //Moving to ordered mocking. - * using(mocks.Ordered() - * { - * demo.VoidNoArg(); - * using(mocks.Unordered() - * { - * demo.VoidNoArg(); - * demo.IntNoArg(); - * } - * demo.IntNoArg(); - * } - * //Must exit the ordering before calling - * mocks.ReplayAll(); - * //The expectations we set up is: - * // 1. demo.VoidNoArgs(); - * // 2. in any order: - * // 1. demo.VoidNoArg(); - * // 2. demo.IntNoArg(); - * // 3. demo.IntNoArg(); - * demo.VoidNoArg(); - * demo.IntNoArg(); - * demo.VoidNoArg(); - * demo.IntNoArg(); - * } - */ - - /// - /// Move the repository to un-ordered mode - /// - public IDisposable Unordered() - { - return new RecorderChanger(this, Recorder, new UnorderedMethodRecorder(Recorder, repeatableMethods)); - } - - /* - * Method: CreateMock - * Create a mock object 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 specified type. - /// - /// Type. - /// Arguments for the class' constructor, if mocking a concrete class - [Obsolete("Use StrictMock instead")] - public object CreateMock(Type type, params object[] argumentsForConstructor) - { - return StrictMock(type, argumentsForConstructor); - } - - /// - /// Creates a strict mock for the specified type. - /// - /// Type. - /// Arguments for the class' constructor, if mocking a concrete class - public object StrictMock(Type type, params object[] argumentsForConstructor) - { - if (ShouldUseRemotingProxy(type, argumentsForConstructor)) - return RemotingMock(type, CreateRecordState); - return StrictMultiMock(type, new Type[0], argumentsForConstructor); - } - - /// - /// Creates a remoting mock for the specified type. - /// - /// Type. - /// Arguments for the class' constructor, if mocking a concrete class - [Obsolete("Use StrictMockWithRemoting instead")] - public object CreateMockWithRemoting(Type type, params object[] argumentsForConstructor) - { - return StrictMockWithRemoting(type, argumentsForConstructor); - } - - /// - /// Creates a strict remoting mock for the specified type. - /// - /// Type. - /// Arguments for the class' constructor, if mocking a concrete class - public object StrictMockWithRemoting(Type type, params object[] argumentsForConstructor) - { - return RemotingMock(type, CreateRecordState); - } - - /// - /// Creates a remoting mock for the specified type. - /// - /// - /// Arguments for the class' constructor, if mocking a concrete class - /// - [Obsolete("Use StrictMockWithRemoting instead")] - public T CreateMockWithRemoting(params object[] argumentsForConstructor) - { - return StrictMockWithRemoting(argumentsForConstructor); - } - - /// - /// Creates a strict remoting mock for the specified type. - /// - /// - /// Arguments for the class' constructor, if mocking a concrete class - /// - public T StrictMockWithRemoting(params object[] argumentsForConstructor) - { - return (T)RemotingMock(typeof(T), CreateRecordState); - } - - /// - /// Creates a mock from several types, with strict semantics. - /// Only may be a class. - /// - [Obsolete("Use StrictMultiMock instead")] - public object CreateMultiMock(Type mainType, params Type[] extraTypes) - { - return StrictMultiMock(mainType, extraTypes); - } - - /// - /// Creates a strict mock from several types, with strict semantics. - /// Only may be a class. - /// - public object StrictMultiMock(Type mainType, params Type[] extraTypes) - { - return StrictMultiMock(mainType, extraTypes, new object[0]); - } - - /// - /// Creates a mock from several types, with strict semantics. - /// Only may be a class. - /// - /// The main type to mock. - /// Extra interface types to mock. - /// Arguments for the class' constructor, if mocking a concrete class. - [Obsolete("Use StrictMultiMock instead")] - public object CreateMultiMock(Type mainType, Type[] extraTypes, params object[] argumentsForConstructor) - { - return StrictMultiMock(mainType, extraTypes, argumentsForConstructor); - } - - /// - /// Creates a strict mock from several types, with strict semantics. - /// Only may be a class. - /// - /// The main type to mock. - /// Extra interface types to mock. - /// 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); - } - - /// - /// Creates a mock from several types, with dynamic semantics. - /// Only may be a class. - /// - /// The main type to mock. - /// Extra interface types to mock. - public object DynamicMultiMock(Type mainType, params Type[] extraTypes) - { - return DynamicMultiMock(mainType, extraTypes, new object[0]); - } - - /// - /// Creates a mock from several types, with dynamic semantics. - /// Only may be a class. - /// - /// The main type to mock. - /// Extra interface types to mock. - /// Arguments for the class' constructor, if mocking a concrete class. - public object DynamicMultiMock(Type mainType, Type[] extraTypes, params object[] argumentsForConstructor) - { - return CreateMockObject(mainType, CreateDynamicRecordState, extraTypes, argumentsForConstructor); - } - - /* - * Method: DynamicMock - * Create a mock object with dynamic semantics. - * Dynamic semantics means that any call that wasn't explicitly recorded is accepted and a - * null or zero is returned (if there is a return value). - */ - - /// 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) - { - if (ShouldUseRemotingProxy(type, argumentsForConstructor)) - return RemotingMock(type, CreateDynamicRecordState); - return DynamicMultiMock(type, new Type[0], argumentsForConstructor); - } - - /// 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) - { - return RemotingMock(type, CreateDynamicRecordState); - } - - /// Creates a dynamic mock for the specified type. - /// - /// Arguments for the class' constructor, if mocking a concrete class - /// - public T DynamicMockWithRemoting(params object[] argumentsForConstructor) - { - return (T)RemotingMock(typeof(T), CreateDynamicRecordState); - } - - /// 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) - { - return PartialMultiMock(type, new Type[0], argumentsForConstructor); - } - - /// 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) - { - return PartialMultiMock(type, extraTypes, new object[0]); - } - - /// Creates a mock object that defaults to calling the class methods. - /// Type. - /// Extra interface types to mock. - /// Arguments for the class' constructor. - public object PartialMultiMock(Type type, Type[] extraTypes, params object[] argumentsForConstructor) - { - if (type.IsInterface) - throw new InvalidOperationException("Can't create a partial mock from an interface"); - List extraTypesWithMarker = new List(extraTypes); - extraTypesWithMarker.Add(typeof(IPartialMockMarker)); - return CreateMockObject(type, CreatePartialRecordState, extraTypesWithMarker.ToArray(), argumentsForConstructor); - } - - /// 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 - /// Creates the mock state for this proxy - private object RemotingMock(Type type, CreateMockState factory) - { - ProxyInstance rhinoProxy = new ProxyInstance(this, type); - RhinoInterceptor interceptor = new RhinoInterceptor(this, rhinoProxy,invocationVisitorsFactory.CreateStandardInvocationVisitors(rhinoProxy, this)); - object transparentProxy = new RemotingMockGenerator().CreateRemotingMock(type, interceptor, rhinoProxy); - IMockState value = factory(rhinoProxy); - proxies.Add(transparentProxy, value); - return transparentProxy; - } - - /// - /// 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) - { - ReplayCore(obj, true); - } - - /// - /// Cause the mock state to change to replay, any further call is compared to the - /// ones that were called in the record state. - /// - /// the object to move to replay state - /// - protected internal void ReplayCore(object obj, bool checkInsideOrdering) - { - if (checkInsideOrdering) - NotInsideOrderring(); - - IsMockObjectFromThisRepository(obj); - ClearLastProxy(obj); - IMockState state = proxies[obj]; - proxies[obj] = state.Replay(); - foreach (IMockedObject dependentMock in GetMockedObject(obj).DependentMocks) - { - ReplayCore(dependentMock, checkInsideOrdering); - } - } - - /// 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); - } - - /// - /// Move the mocked object back to record state. - /// Optionally, can delete all current expectations, but allows more granularity about how - /// it would behave with regard to the object state. - /// - public void BackToRecord(object obj, BackToRecordOptions options) - { - IsMockObjectFromThisRepository(obj); - - if ((options & BackToRecordOptions.Expectations) == BackToRecordOptions.Expectations) - { - foreach (IExpectation expectation in rootRecorder.GetAllExpectationsForProxy(obj)) - { - rootRecorder.RemoveExpectation(expectation); - } - rootRecorder.RemoveAllRepeatableExpectationsForProxy(obj); - } - - GetMockedObject(obj).ClearState(options); - - proxies[obj] = proxies[obj].BackToRecord(); - foreach (IMockedObject dependentMock in GetMockedObject(obj).DependentMocks) - { - BackToRecord(dependentMock, options); - } - } - - /* - * Method: Verify - * Verifies that all expectations has been met for a single mock object. - * After calling this method and action taken on the mock object would result in an - * exception even if the object is a dynamic mock. - */ - - /// - /// Verify that all the expectations for this object were fulfilled. - /// - /// the object to verify the expectations for - public void Verify(object obj) - { - IsMockObjectFromThisRepository(obj); - try - { - proxies[obj].Verify(); - foreach (IMockedObject dependentMock in GetMockedObject(obj).DependentMocks) - { - Verify(dependentMock); - } - } - finally - { - //This is needed because there might be an exception in verifying - //and I still need the mock state to move to verified. - proxies[obj] = proxies[obj].VerifyState; - } - } - - /* - * Method: LastMethodCall - * Gets the method options for the last call on mockedInstance - */ - - /// - /// Get the method options for the last call on - /// mockedInstance. - /// - /// The mock object - /// Method options for the last call - internal IMethodOptions LastMethodCall(object mockedInstance) - { - object mock = GetMockObjectFromInvocationProxy(mockedInstance); - IsMockObjectFromThisRepository(mock); - return proxies[mock].GetLastMethodOptions(); - } - - #endregion - - #region Implementation Details - - /* - * Method: MethodCall - * Handles a method call for a mock object. - */ - - internal object MethodCall(IInvocation invocation, object proxy, MethodInfo method, object[] args) - { - //This can happen only if a vritual method call originated from - //the constructor, before Rhino Mocks knows about the existance - //of this proxy. Those type of calls will be ignored and not count - //as expectations, since there is not way to relate them to the - //proper state. - if (proxies.ContainsKey(proxy) == false) - { - //We allow calls to virtual methods from the ctor only for partial mocks. - if (proxy is IPartialMockMarker) - { - invocation.Proceed(); - return invocation.ReturnValue; - } - return null; - } - IMockState state = proxies[proxy]; - GetMockedObject(proxy).MethodCall(method, args); - return state.MethodCall(invocation, method, args); - } - - /// - /// Maps an invocation proxy back to the mock object instance that was originally - /// returned to client code which might have been a delegate to this proxy. - /// - /// The mock object proxy from the intercepted invocation - /// The mock object - internal object GetMockObjectFromInvocationProxy(object invocationProxy) - { - object proxy = delegateProxies[invocationProxy]; - if (proxy != null) return proxy; - return invocationProxy; - } - - private IMockState CreateRecordState(IMockedObject mockedObject) - { - return new RecordMockState(mockedObject, this); - } - - private IMockState CreateDynamicRecordState(IMockedObject mockedObject) - { - return new RecordDynamicMockState(mockedObject, this); - } - - private IMockState CreatePartialRecordState(IMockedObject mockedObject) - { - return new RecordPartialMockState(mockedObject, this); - } - - private void NotInsideOrderring() - { - if (Recorder != rootRecorder) - throw new InvalidOperationException( - "Can't start replaying because Ordered or Unordered properties were call and not yet disposed."); - } - - private void ClearLastProxy(object obj) - { - if (GetMockedObjectOrNull(obj) == lastMockedObject) - lastMockedObject = null; - } - - 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); - ProxyInstance proxyInstance = new ProxyInstance(this, implementedTypesForGenericInvocationDiscoverability.ToArray()); - RhinoInterceptor interceptor = new RhinoInterceptor(this, proxyInstance,invocationVisitorsFactory.CreateStandardInvocationVisitors(proxyInstance, this)); - ArrayList types = new ArrayList(); - types.AddRange(extras); - types.Add(typeof(IMockedObject)); - object proxy; - try - { - proxyGenerationOptions = ProxyGenerationOptions.Default; - proxy = GetProxyGenerator(type).CreateClassProxy(type, (Type[])types.ToArray(typeof(Type)), - proxyGenerationOptions, - argumentsForConstructor, interceptor); - } - catch (MissingMethodException mme) - { - throw new MissingMethodException("Can't find a constructor with matching arguments", mme); - } - catch (TargetInvocationException tie) - { - throw new Exception("Exception in constructor: " + tie.InnerException, tie.InnerException); - } - IMockedObject mockedObject = (IMockedObject)proxy; - mockedObject.ConstructorArguments = argumentsForConstructor; - IMockState value = mockStateFactory(mockedObject); - proxies.Add(proxy, value); - GC.SuppressFinalize(proxy);//avoid issues with expectations created/validated on the finalizer thread - return proxy; - } - - private object MockInterface(CreateMockState mockStateFactory, Type type, Type[] extras) - { - object proxy; - List implementedTypesForGenericInvocationDiscoverability = new List(extras); - implementedTypesForGenericInvocationDiscoverability.Add(type); - ProxyInstance proxyInstance = new ProxyInstance(this, - implementedTypesForGenericInvocationDiscoverability - .ToArray()); - RhinoInterceptor interceptor = new RhinoInterceptor(this, proxyInstance,invocationVisitorsFactory.CreateStandardInvocationVisitors(proxyInstance, this)); - - List types = new List(); - types.AddRange(extras); - types.Add(typeof(IMockedObject)); - proxy = - GetProxyGenerator(type).CreateInterfaceProxyWithoutTarget(type, types.ToArray(), proxyGenerationOptions, interceptor); - IMockState value = mockStateFactory((IMockedObject)proxy); - proxies.Add(proxy, value); - return proxy; - } - - private object MockDelegate(CreateMockState mockStateFactory, Type type) - { - if (typeof(Delegate).Equals(type)) - throw new InvalidOperationException("Cannot mock the Delegate base type."); - - object proxy; - - ProxyInstance proxyInstance = new ProxyInstance(this); - RhinoInterceptor interceptor = new RhinoInterceptor(this, proxyInstance,invocationVisitorsFactory.CreateStandardInvocationVisitors(proxyInstance, this)); - - Type[] types = new Type[] { typeof(IMockedObject) }; - var delegateTargetInterface = delegateTargetInterfaceCreator.GetDelegateTargetInterface(type); - object target = GetProxyGenerator(type).CreateInterfaceProxyWithoutTarget( - delegateTargetInterface, - types, proxyGenerationOptions, interceptor); - - proxy = Delegate.CreateDelegate(type, target, delegateTargetInterface.Name+ ".Invoke"); - delegateProxies.Add(target, proxy); - - IMockState value = mockStateFactory(GetMockedObject(proxy)); - proxies.Add(proxy, value); - return proxy; - } - - /// 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) - { - foreach (Type extraType in extras) - { - if (!extraType.IsInterface) - { - throw new ArgumentException("Extra types must all be interfaces", "extras"); - } - } - - if (type.IsInterface) - { - if (argumentsForConstructor != null && argumentsForConstructor.Length > 0) - { - throw new ArgumentException( - "Constructor arguments should not be supplied when mocking an interface", - "argumentsForConstructor"); - } - return MockInterface(factory, type, extras); - } - else if (typeof(Delegate).IsAssignableFrom(type)) - { - if (argumentsForConstructor != null && argumentsForConstructor.Length > 0) - { - throw new ArgumentException("Constructor arguments should not be supplied when mocking a delegate", - "argumentsForConstructor"); - } - return MockDelegate(factory, type); - } - else - return MockClass(factory, type, extras, argumentsForConstructor); - } - - private void IsMockObjectFromThisRepository(object obj) - { - if (proxies.ContainsKey(obj) == false) - throw new ObjectNotMockFromThisRepositoryException( - "The object is not a mock object that belong to this repository."); - } - - /// - /// Method: GetMockedObject - /// Get an IProxy from a mocked object instance, or throws if the - /// object is not a mock object. - /// - protected internal static IMockedObject GetMockedObject(object mockedInstance) - { - IMockedObject mockedObj = GetMockedObjectOrNull(mockedInstance); - if (mockedObj == null) - throw new InvalidOperationException("The object '" + mockedInstance + - "' is not a mocked object."); - return mockedObj; - } - - /// - /// Method: GetMockedObjectOrNull - /// Get an IProxy from a mocked object instance, or null if the - /// object is not a mock object. - /// - protected internal static IMockedObject GetMockedObjectOrNull(object mockedInstance) - { - Delegate mockedDelegate = mockedInstance as Delegate; - - if (mockedDelegate != null) - { - mockedInstance = mockedDelegate.Target; - } - - // must be careful not to call any methods on mocked objects, - // or it may cause infinite recursion - if (mockedInstance is IMockedObject) - { - return (IMockedObject)mockedInstance; - } - - if (RemotingMockGenerator.IsRemotingProxy(mockedInstance)) - { - return RemotingMockGenerator.GetMockedObjectFromProxy(mockedInstance); - } - - return null; - } - - /// Pops the recorder. - internal void PopRecorder() - { - if (recorders.Count > 1) - recorders.Pop(); - } - - /// Pushes the recorder. - /// New recorder. - internal void PushRecorder(IMethodRecorder newRecorder) - { - recorders.Push(newRecorder); - } - - #endregion - - #region Convenience Methods - - /// - /// All the mock objects in this repository will be moved - /// to record state. - /// - public void BackToRecordAll() - { - BackToRecordAll(BackToRecordOptions.All); - } - - /// - /// All the mock objects in this repository will be moved - /// to record state. - /// - public void BackToRecordAll(BackToRecordOptions options) - { - if (proxies.Count == 0) - return; - foreach (object key in new ArrayList(proxies.Keys)) - { - BackToRecord(key, options); - } - } - - /* - * Method: ReplayAll - * Moves all the mock objects in the repository to replay state. - * - * Note: - * This method will skip any mock object that you've manually moved to replay state - * by calling - */ - - /// - /// Replay all the mocks from this repository - /// - public void ReplayAll() - { - if (proxies.Count == 0) - return; - foreach (object key in new ArrayList(proxies.Keys)) - { - if (proxies[key] is RecordMockState) - Replay(key); - } - } - - /* - * Method: VerifyAll - * Verifies that all the expectations on all mock objects in the repository are met. - * - * Note: - * This method skip any mock objects that you've manually verified using - * - * Exception safety: - * If an unexpected exception has been thrown (which would fail the test) and the Repository - * still have unsatisfied expectations, this method will cause _another_ exception, that may - * mask the real cause. - * If this happens to you, you may need to avoid the using statement until you figure out what is wrong: - * The using statement: - * (start code) - * using(MockRepository mocks = new MockRepository()) - * { - * // Some action that cause an unexpected exception - * // which would cause unsatisfied expectation and cause - * // VerifyAll() to fail. - * } - * (end) - * - * The unrolled using statement: - * (start code) - * MockRepository mocks = new MockRepository()) - * //The afore mentioned action - * mocks.VerifyAll()//won't occur if an exception is thrown - * (end) - * - * This way you can get the real exception from the unit testing framework. - */ - - /// - /// Verify all the mocks from this repository - /// - public void VerifyAll() - { - if (lastRepository == this) - lastRepository = null; - if (proxies.Keys.Count == 0) - return; - StringCollection validationErrors = new StringCollection(); - foreach (object key in new ArrayList(proxies.Keys)) - { - if (proxies[key] is VerifiedMockState) - continue; - try - { - Verify(key); - } - catch (ExpectationViolationException e) - { - validationErrors.Add(e.Message); - } - } - if (validationErrors.Count == 0) - return; - if (validationErrors.Count == 1) - throw new ExpectationViolationException(validationErrors[0]); - StringBuilder sb = new StringBuilder(); - foreach (string validationError in validationErrors) - { - sb.AppendLine(validationError); - } - throw new ExpectationViolationException(sb.ToString()); - } - - /// - /// Gets the replayer for this repository. - /// - /// - internal IMethodRecorder Replayer - { - get { return rootRecorder; } - } - - /// - /// Gets the last proxy which had a method call. - /// - internal static IMockedObject LastMockedObject - { - get - { - if (lastRepository == null) - return null; - return lastRepository.lastMockedObject; - } - } - - /// - /// Gets the proxy generator for a specific type. Having a single ProxyGenerator - /// with multiple types linearly degrades the performance so this implementation - /// keeps one ProxyGenerator per type. - /// - protected virtual ProxyGenerator GetProxyGenerator(Type type) - { - if (!generatorMap.ContainsKey(type)) - { - generatorMap[type] = new ProxyGenerator(); - } - - return generatorMap[type]; - } - - - - /// 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) - return; - repository.proxies[proxy].SetExceptionToThrowOnVerify(expectationViolationException); - } - +#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.Collections.Generic; +using System.Collections.Specialized; +using System.Reflection; +using System.Text; +using Castle.Core.Interceptor; +using Castle.DynamicProxy; +using Rhino.Mocks.Exceptions; +using Rhino.Mocks.Generated; +using Rhino.Mocks.Impl; +using Rhino.Mocks.Impl.Invocation; +using Rhino.Mocks.Impl.RemotingMock; +using Rhino.Mocks.Interfaces; +using Rhino.Mocks.MethodRecorders; + +namespace Rhino.Mocks +{ + /* + * class: MockRepository + * The MockRepository is the main interaction point with Rhino Mocks. + * + * Common usage pattern is to create the on [SetUp] + * and then create mock objects using either or + * and setup expectations on the mock object(s) by + * callling their methods. A call to would move the mock + * object(s) to replay state, a call to is made from the + * [TearDown] method. + * + * Thread Safety: + * MockRepository is capable of verifying in multiply threads, but recording in multiply threads + * is not recommended. If you need to do so you _must_ use the and + * methods and not and + * 's various methods. + * + * Code Sample: + * + * (start code) + * MockRepository mocks; + * + * [SetUp] + * public void Setup() + * { + * mocks = new MockRepository(); + * } + * + * [Test] + * public void CallMethodOnObject() + * { + * + * IDemo demo = (IDemo)mocks.CreateMock(typeof(IDemo)); + * // Setting up an expectation for a call to IDemo.VoidNoArg + * demo.VoidNoArg(); + * mocks.ReplayAll(); + * // Fullifying the expectation for call to IDemo.VoidNoArg + * demo.VoidNoArg(); + * } + * + * [TearDown] + * public void Teardown() + * { + * mocks.VerifyAll(); + * } + * (end) + * + * Class Responsbilities: + * + * - Create and manage mock object throughout their life time + * + * See Also: + * - + * - + * - + * - + */ + + /// + /// Creates proxied instances of types. + /// + public class MockRepository + { + /// + /// Delegate: CreateMockState + /// This is used internally to cleanly handle the creation of different + /// RecordMockStates. + /// + protected delegate IMockState CreateMockState(IMockedObject mockedObject); + + #region Variables + + /* + * Variable: generatorMap + * A static variable that is used to hold a map of Types to ProxyGenerators + * + */ + + /// + /// This is a map of types to ProxyGenerators. + /// + private static readonly IDictionary generatorMap = new Dictionary(); + + /* + * Variable: lastRepository + * A static variable that is used to hold the repository that last had a method call + * on one of its mock objects. + * + */ + + /// + /// This is used to record the last repository that has a method called on it. + /// + internal static MockRepository lastRepository; + + /* + * Var: lastProxy + * The last proxy that had a method call for _this_ repository + */ + + /// + /// this is used to get to the last proxy on this repository. + /// + internal IMockedObject lastMockedObject; + + private static readonly DelegateTargetInterfaceCreator delegateTargetInterfaceCreator = + new DelegateTargetInterfaceCreator(); + + /// + /// For mock delegates, maps the proxy instance from intercepted invocations + /// back to the delegate that was originally returned to client code, if any. + /// + protected IDictionary delegateProxies; + + /// + /// All the proxies in the mock repositories + /// + protected ProxyStateDictionary proxies; + + private readonly Stack recorders; + private readonly IMethodRecorder rootRecorder; + /// + /// This is here because we can't put it in any of the recorders, since repeatable methods + /// have no orderring, and if we try to handle them using the usual manner, we would get into + /// wierd situations where repeatable method that was defined in an orderring block doesn't + /// exists until we enter this block. + /// + private readonly ProxyMethodExpectationsDictionary repeatableMethods; + + private ProxyGenerationOptions proxyGenerationOptions; + private InvocationVisitorsFactory invocationVisitorsFactory; + + #endregion + + #region Properties + + /* + * Property: Recorder + * Gets the current recorder for the repository. + */ + + /// + /// Gets the recorder. + /// + /// + internal IMethodRecorder Recorder + { + get { return recorders.Peek() as IMethodRecorder; } + } + + #endregion + + #region c'tors + + /* function: MockRepository + * Create a new instance of MockRepository + */ + + /// + /// Creates a new instance. + /// + public MockRepository() + { + proxyGenerationOptions = new ProxyGenerationOptions + { + AttributesToAddToGeneratedTypes = + { + new __ProtectAttribute() + } + }; + recorders = new Stack(); + repeatableMethods = new ProxyMethodExpectationsDictionary(); + rootRecorder = new UnorderedMethodRecorder(repeatableMethods); + recorders.Push(rootRecorder); + proxies = new ProxyStateDictionary(); + delegateProxies = new Hashtable(MockedObjectsEquality.Instance); + invocationVisitorsFactory = new InvocationVisitorsFactory(); + + // clean up Arg data to avoid the static data to be carried from one unit test + // to another. + ArgManager.Clear(); + } + + + #endregion + + #region Methods + + /* + * Method: Ordered + * Moves the _entire_ to use ordered recording. + * + * This call is only valid during the recording phase. + * This call affects all mock objects that were created from this repository. + * + * The orderring is ended when the returned IDisposable's Dispose() method is called. + * (start code) + * [Test] + * public void CallMethodOnObject() + * { + * IDemo demo = (IDemo)mocks.CreateMock(typeof(IDemo)); + * //Moving to ordered mocking. + * using(mocks.Ordered() + * { + * demo.VoidNoArg(); + * demo.IntNoArg(); + * } + * //Must exit the ordering before calling + * mocks.ReplayAll(); + * //If we would try to call them in any other order, the test would fail + * demo.VoidNoArg(); + * demo.IntNoArg(); + * } + * (end) + * + */ + + /// + /// Move the repository to ordered mode + /// + public IDisposable Ordered() + { + return new RecorderChanger(this, Recorder, new OrderedMethodRecorder(Recorder, repeatableMethods)); + } + + /* + * Method: Unordered + * Moves the _entire_ to use unordered recording (the default). + * + * This call is only valid during the recording phase. + * This call affects all mock objects that were created from this repository. + * + * (start code) + * [Test] + * public void CallMethodOnObject() + * { + * IDemo demo = (IDemo)mocks.CreateMock(typeof(IDemo)); + * //Moving to ordered mocking. + * using(mocks.Ordered() + * { + * demo.VoidNoArg(); + * using(mocks.Unordered() + * { + * demo.VoidNoArg(); + * demo.IntNoArg(); + * } + * demo.IntNoArg(); + * } + * //Must exit the ordering before calling + * mocks.ReplayAll(); + * //The expectations we set up is: + * // 1. demo.VoidNoArgs(); + * // 2. in any order: + * // 1. demo.VoidNoArg(); + * // 2. demo.IntNoArg(); + * // 3. demo.IntNoArg(); + * demo.VoidNoArg(); + * demo.IntNoArg(); + * demo.VoidNoArg(); + * demo.IntNoArg(); + * } + */ + + /// + /// Move the repository to un-ordered mode + /// + public IDisposable Unordered() + { + return new RecorderChanger(this, Recorder, new UnorderedMethodRecorder(Recorder, repeatableMethods)); + } + + /* + * Method: CreateMock + * Create a mock object 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 specified type. + /// + /// Type. + /// Arguments for the class' constructor, if mocking a concrete class + [Obsolete("Use StrictMock instead")] + public object CreateMock(Type type, params object[] argumentsForConstructor) + { + return StrictMock(type, argumentsForConstructor); + } + + /// + /// Creates a strict mock for the specified type. + /// + /// Type. + /// Arguments for the class' constructor, if mocking a concrete class + public object StrictMock(Type type, params object[] argumentsForConstructor) + { + if (ShouldUseRemotingProxy(type, argumentsForConstructor)) + return RemotingMock(type, CreateRecordState); + return StrictMultiMock(type, new Type[0], argumentsForConstructor); + } + + /// + /// Creates a remoting mock for the specified type. + /// + /// Type. + /// Arguments for the class' constructor, if mocking a concrete class + [Obsolete("Use StrictMockWithRemoting instead")] + public object CreateMockWithRemoting(Type type, params object[] argumentsForConstructor) + { + return StrictMockWithRemoting(type, argumentsForConstructor); + } + + /// + /// Creates a strict remoting mock for the specified type. + /// + /// Type. + /// Arguments for the class' constructor, if mocking a concrete class + public object StrictMockWithRemoting(Type type, params object[] argumentsForConstructor) + { + return RemotingMock(type, CreateRecordState); + } + + /// + /// Creates a remoting mock for the specified type. + /// + /// + /// Arguments for the class' constructor, if mocking a concrete class + /// + [Obsolete("Use StrictMockWithRemoting instead")] + public T CreateMockWithRemoting(params object[] argumentsForConstructor) + { + return StrictMockWithRemoting(argumentsForConstructor); + } + + /// + /// Creates a strict remoting mock for the specified type. + /// + /// + /// Arguments for the class' constructor, if mocking a concrete class + /// + public T StrictMockWithRemoting(params object[] argumentsForConstructor) + { + return (T)RemotingMock(typeof(T), CreateRecordState); + } + + /// + /// Creates a mock from several types, with strict semantics. + /// Only may be a class. + /// + [Obsolete("Use StrictMultiMock instead")] + public object CreateMultiMock(Type mainType, params Type[] extraTypes) + { + return StrictMultiMock(mainType, extraTypes); + } + + /// + /// Creates a strict mock from several types, with strict semantics. + /// Only may be a class. + /// + public object StrictMultiMock(Type mainType, params Type[] extraTypes) + { + return StrictMultiMock(mainType, extraTypes, new object[0]); + } + + /// + /// Creates a mock from several types, with strict semantics. + /// Only may be a class. + /// + /// The main type to mock. + /// Extra interface types to mock. + /// Arguments for the class' constructor, if mocking a concrete class. + [Obsolete("Use StrictMultiMock instead")] + public object CreateMultiMock(Type mainType, Type[] extraTypes, params object[] argumentsForConstructor) + { + return StrictMultiMock(mainType, extraTypes, argumentsForConstructor); + } + + /// + /// Creates a strict mock from several types, with strict semantics. + /// Only may be a class. + /// + /// The main type to mock. + /// Extra interface types to mock. + /// 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); + } + + /// + /// Creates a mock from several types, with dynamic semantics. + /// Only may be a class. + /// + /// The main type to mock. + /// Extra interface types to mock. + public object DynamicMultiMock(Type mainType, params Type[] extraTypes) + { + return DynamicMultiMock(mainType, extraTypes, new object[0]); + } + + /// + /// Creates a mock from several types, with dynamic semantics. + /// Only may be a class. + /// + /// The main type to mock. + /// Extra interface types to mock. + /// Arguments for the class' constructor, if mocking a concrete class. + public object DynamicMultiMock(Type mainType, Type[] extraTypes, params object[] argumentsForConstructor) + { + return CreateMockObject(mainType, CreateDynamicRecordState, extraTypes, argumentsForConstructor); + } + + /* + * Method: DynamicMock + * Create a mock object with dynamic semantics. + * Dynamic semantics means that any call that wasn't explicitly recorded is accepted and a + * null or zero is returned (if there is a return value). + */ + + /// 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) + { + if (ShouldUseRemotingProxy(type, argumentsForConstructor)) + return RemotingMock(type, CreateDynamicRecordState); + return DynamicMultiMock(type, new Type[0], argumentsForConstructor); + } + + /// 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) + { + return RemotingMock(type, CreateDynamicRecordState); + } + + /// Creates a dynamic mock for the specified type. + /// + /// Arguments for the class' constructor, if mocking a concrete class + /// + public T DynamicMockWithRemoting(params object[] argumentsForConstructor) + { + return (T)RemotingMock(typeof(T), CreateDynamicRecordState); + } + + /// 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) + { + return PartialMultiMock(type, new Type[0], argumentsForConstructor); + } + + /// 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) + { + return PartialMultiMock(type, extraTypes, new object[0]); + } + + /// Creates a mock object that defaults to calling the class methods. + /// Type. + /// Extra interface types to mock. + /// Arguments for the class' constructor. + public object PartialMultiMock(Type type, Type[] extraTypes, params object[] argumentsForConstructor) + { + if (type.IsInterface) + throw new InvalidOperationException("Can't create a partial mock from an interface"); + List extraTypesWithMarker = new List(extraTypes); + extraTypesWithMarker.Add(typeof(IPartialMockMarker)); + return CreateMockObject(type, CreatePartialRecordState, extraTypesWithMarker.ToArray(), argumentsForConstructor); + } + + /// 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 + /// Creates the mock state for this proxy + private object RemotingMock(Type type, CreateMockState factory) + { + ProxyInstance rhinoProxy = new ProxyInstance(this, type); + RhinoInterceptor interceptor = new RhinoInterceptor(this, rhinoProxy,invocationVisitorsFactory.CreateStandardInvocationVisitors(rhinoProxy, this)); + object transparentProxy = new RemotingMockGenerator().CreateRemotingMock(type, interceptor, rhinoProxy); + IMockState value = factory(rhinoProxy); + proxies.Add(transparentProxy, value); + return transparentProxy; + } + + /// + /// 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) + { + ReplayCore(obj, true); + } + + /// + /// Cause the mock state to change to replay, any further call is compared to the + /// ones that were called in the record state. + /// + /// the object to move to replay state + /// + protected internal void ReplayCore(object obj, bool checkInsideOrdering) + { + if (checkInsideOrdering) + NotInsideOrderring(); + + IsMockObjectFromThisRepository(obj); + ClearLastProxy(obj); + IMockState state = proxies[obj]; + proxies[obj] = state.Replay(); + foreach (IMockedObject dependentMock in GetMockedObject(obj).DependentMocks) + { + ReplayCore(dependentMock, checkInsideOrdering); + } + } + + /// 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); + } + + /// + /// Move the mocked object back to record state. + /// Optionally, can delete all current expectations, but allows more granularity about how + /// it would behave with regard to the object state. + /// + public void BackToRecord(object obj, BackToRecordOptions options) + { + IsMockObjectFromThisRepository(obj); + + if ((options & BackToRecordOptions.Expectations) == BackToRecordOptions.Expectations) + { + foreach (IExpectation expectation in rootRecorder.GetAllExpectationsForProxy(obj)) + { + rootRecorder.RemoveExpectation(expectation); + } + rootRecorder.RemoveAllRepeatableExpectationsForProxy(obj); + } + + GetMockedObject(obj).ClearState(options); + + proxies[obj] = proxies[obj].BackToRecord(); + foreach (IMockedObject dependentMock in GetMockedObject(obj).DependentMocks) + { + BackToRecord(dependentMock, options); + } + } + + /* + * Method: Verify + * Verifies that all expectations has been met for a single mock object. + * After calling this method and action taken on the mock object would result in an + * exception even if the object is a dynamic mock. + */ + + /// + /// Verify that all the expectations for this object were fulfilled. + /// + /// the object to verify the expectations for + public void Verify(object obj) + { + IsMockObjectFromThisRepository(obj); + try + { + proxies[obj].Verify(); + foreach (IMockedObject dependentMock in GetMockedObject(obj).DependentMocks) + { + Verify(dependentMock); + } + } + finally + { + //This is needed because there might be an exception in verifying + //and I still need the mock state to move to verified. + proxies[obj] = proxies[obj].VerifyState; + } + } + + /* + * Method: LastMethodCall + * Gets the method options for the last call on mockedInstance + */ + + /// + /// Get the method options for the last call on + /// mockedInstance. + /// + /// The mock object + /// Method options for the last call + internal IMethodOptions LastMethodCall(object mockedInstance) + { + object mock = GetMockObjectFromInvocationProxy(mockedInstance); + IsMockObjectFromThisRepository(mock); + return proxies[mock].GetLastMethodOptions(); + } + + #endregion + + #region Implementation Details + + /* + * Method: MethodCall + * Handles a method call for a mock object. + */ + + internal object MethodCall(IInvocation invocation, object proxy, MethodInfo method, object[] args) + { + //This can happen only if a vritual method call originated from + //the constructor, before Rhino Mocks knows about the existance + //of this proxy. Those type of calls will be ignored and not count + //as expectations, since there is not way to relate them to the + //proper state. + if (proxies.ContainsKey(proxy) == false) + { + //We allow calls to virtual methods from the ctor only for partial mocks. + if (proxy is IPartialMockMarker) + { + invocation.Proceed(); + return invocation.ReturnValue; + } + return null; + } + IMockState state = proxies[proxy]; + GetMockedObject(proxy).MethodCall(method, args); + return state.MethodCall(invocation, method, args); + } + + /// + /// Maps an invocation proxy back to the mock object instance that was originally + /// returned to client code which might have been a delegate to this proxy. + /// + /// The mock object proxy from the intercepted invocation + /// The mock object + internal object GetMockObjectFromInvocationProxy(object invocationProxy) + { + object proxy = delegateProxies[invocationProxy]; + if (proxy != null) return proxy; + return invocationProxy; + } + + private IMockState CreateRecordState(IMockedObject mockedObject) + { + return new RecordMockState(mockedObject, this); + } + + private IMockState CreateDynamicRecordState(IMockedObject mockedObject) + { + return new RecordDynamicMockState(mockedObject, this); + } + + private IMockState CreatePartialRecordState(IMockedObject mockedObject) + { + return new RecordPartialMockState(mockedObject, this); + } + + private void NotInsideOrderring() + { + if (Recorder != rootRecorder) + throw new InvalidOperationException( + "Can't start replaying because Ordered or Unordered properties were call and not yet disposed."); + } + + private void ClearLastProxy(object obj) + { + if (GetMockedObjectOrNull(obj) == lastMockedObject) + lastMockedObject = null; + } + + 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); + ProxyInstance proxyInstance = new ProxyInstance(this, implementedTypesForGenericInvocationDiscoverability.ToArray()); + RhinoInterceptor interceptor = new RhinoInterceptor(this, proxyInstance,invocationVisitorsFactory.CreateStandardInvocationVisitors(proxyInstance, this)); + ArrayList types = new ArrayList(); + types.AddRange(extras); + types.Add(typeof(IMockedObject)); + object proxy; + try + { + proxyGenerationOptions = ProxyGenerationOptions.Default; + proxy = GetProxyGenerator(type).CreateClassProxy(type, (Type[])types.ToArray(typeof(Type)), + proxyGenerationOptions, + argumentsForConstructor, interceptor); + } + catch (MissingMethodException mme) + { + throw new MissingMethodException("Can't find a constructor with matching arguments", mme); + } + catch (TargetInvocationException tie) + { + throw new Exception("Exception in constructor: " + tie.InnerException, tie.InnerException); + } + IMockedObject mockedObject = (IMockedObject)proxy; + mockedObject.ConstructorArguments = argumentsForConstructor; + IMockState value = mockStateFactory(mockedObject); + proxies.Add(proxy, value); + GC.SuppressFinalize(proxy);//avoid issues with expectations created/validated on the finalizer thread + return proxy; + } + + private object MockInterface(CreateMockState mockStateFactory, Type type, Type[] extras) + { + object proxy; + List implementedTypesForGenericInvocationDiscoverability = new List(extras); + implementedTypesForGenericInvocationDiscoverability.Add(type); + ProxyInstance proxyInstance = new ProxyInstance(this, + implementedTypesForGenericInvocationDiscoverability + .ToArray()); + RhinoInterceptor interceptor = new RhinoInterceptor(this, proxyInstance,invocationVisitorsFactory.CreateStandardInvocationVisitors(proxyInstance, this)); + + List types = new List(); + types.AddRange(extras); + types.Add(typeof(IMockedObject)); + proxy = + GetProxyGenerator(type).CreateInterfaceProxyWithoutTarget(type, types.ToArray(), proxyGenerationOptions, interceptor); + IMockState value = mockStateFactory((IMockedObject)proxy); + proxies.Add(proxy, value); + return proxy; + } + + private object MockDelegate(CreateMockState mockStateFactory, Type type) + { + if (typeof(Delegate).Equals(type)) + throw new InvalidOperationException("Cannot mock the Delegate base type."); + + object proxy; + + ProxyInstance proxyInstance = new ProxyInstance(this); + RhinoInterceptor interceptor = new RhinoInterceptor(this, proxyInstance,invocationVisitorsFactory.CreateStandardInvocationVisitors(proxyInstance, this)); + + Type[] types = new Type[] { typeof(IMockedObject) }; + var delegateTargetInterface = delegateTargetInterfaceCreator.GetDelegateTargetInterface(type); + object target = GetProxyGenerator(type).CreateInterfaceProxyWithoutTarget( + delegateTargetInterface, + types, proxyGenerationOptions, interceptor); + + proxy = Delegate.CreateDelegate(type, target, delegateTargetInterface.Name+ ".Invoke"); + delegateProxies.Add(target, proxy); + + IMockState value = mockStateFactory(GetMockedObject(proxy)); + proxies.Add(proxy, value); + return proxy; + } + + /// 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) + { + foreach (Type extraType in extras) + { + if (!extraType.IsInterface) + { + throw new ArgumentException("Extra types must all be interfaces", "extras"); + } + } + + if (type.IsInterface) + { + if (argumentsForConstructor != null && argumentsForConstructor.Length > 0) + { + throw new ArgumentException( + "Constructor arguments should not be supplied when mocking an interface", + "argumentsForConstructor"); + } + return MockInterface(factory, type, extras); + } + else if (typeof(Delegate).IsAssignableFrom(type)) + { + if (argumentsForConstructor != null && argumentsForConstructor.Length > 0) + { + throw new ArgumentException("Constructor arguments should not be supplied when mocking a delegate", + "argumentsForConstructor"); + } + return MockDelegate(factory, type); + } + else + return MockClass(factory, type, extras, argumentsForConstructor); + } + + private void IsMockObjectFromThisRepository(object obj) + { + if (proxies.ContainsKey(obj) == false) + throw new ObjectNotMockFromThisRepositoryException( + "The object is not a mock object that belong to this repository."); + } + + /// + /// Method: GetMockedObject + /// Get an IProxy from a mocked object instance, or throws if the + /// object is not a mock object. + /// + protected internal static IMockedObject GetMockedObject(object mockedInstance) + { + IMockedObject mockedObj = GetMockedObjectOrNull(mockedInstance); + if (mockedObj == null) + throw new InvalidOperationException("The object '" + mockedInstance + + "' is not a mocked object."); + return mockedObj; + } + + /// + /// Method: GetMockedObjectOrNull + /// Get an IProxy from a mocked object instance, or null if the + /// object is not a mock object. + /// + protected internal static IMockedObject GetMockedObjectOrNull(object mockedInstance) + { + Delegate mockedDelegate = mockedInstance as Delegate; + + if (mockedDelegate != null) + { + mockedInstance = mockedDelegate.Target; + } + + // must be careful not to call any methods on mocked objects, + // or it may cause infinite recursion + if (mockedInstance is IMockedObject) + { + return (IMockedObject)mockedInstance; + } + + if (RemotingMockGenerator.IsRemotingProxy(mockedInstance)) + { + return RemotingMockGenerator.GetMockedObjectFromProxy(mockedInstance); + } + + return null; + } + + /// Pops the recorder. + internal void PopRecorder() + { + if (recorders.Count > 1) + recorders.Pop(); + } + + /// Pushes the recorder. + /// New recorder. + internal void PushRecorder(IMethodRecorder newRecorder) + { + recorders.Push(newRecorder); + } + + #endregion + + #region Convenience Methods + + /// + /// All the mock objects in this repository will be moved + /// to record state. + /// + public void BackToRecordAll() + { + BackToRecordAll(BackToRecordOptions.All); + } + + /// + /// All the mock objects in this repository will be moved + /// to record state. + /// + public void BackToRecordAll(BackToRecordOptions options) + { + if (proxies.Count == 0) + return; + foreach (object key in new ArrayList(proxies.Keys)) + { + BackToRecord(key, options); + } + } + + /* + * Method: ReplayAll + * Moves all the mock objects in the repository to replay state. + * + * Note: + * This method will skip any mock object that you've manually moved to replay state + * by calling + */ + + /// + /// Replay all the mocks from this repository + /// + public void ReplayAll() + { + if (proxies.Count == 0) + return; + foreach (object key in new ArrayList(proxies.Keys)) + { + if (proxies[key] is RecordMockState) + Replay(key); + } + } + + /* + * Method: VerifyAll + * Verifies that all the expectations on all mock objects in the repository are met. + * + * Note: + * This method skip any mock objects that you've manually verified using + * + * Exception safety: + * If an unexpected exception has been thrown (which would fail the test) and the Repository + * still have unsatisfied expectations, this method will cause _another_ exception, that may + * mask the real cause. + * If this happens to you, you may need to avoid the using statement until you figure out what is wrong: + * The using statement: + * (start code) + * using(MockRepository mocks = new MockRepository()) + * { + * // Some action that cause an unexpected exception + * // which would cause unsatisfied expectation and cause + * // VerifyAll() to fail. + * } + * (end) + * + * The unrolled using statement: + * (start code) + * MockRepository mocks = new MockRepository()) + * //The afore mentioned action + * mocks.VerifyAll()//won't occur if an exception is thrown + * (end) + * + * This way you can get the real exception from the unit testing framework. + */ + + /// + /// Verify all the mocks from this repository + /// + public void VerifyAll() + { + if (lastRepository == this) + lastRepository = null; + if (proxies.Keys.Count == 0) + return; + StringCollection validationErrors = new StringCollection(); + foreach (object key in new ArrayList(proxies.Keys)) + { + if (proxies[key] is VerifiedMockState) + continue; + try + { + Verify(key); + } + catch (ExpectationViolationException e) + { + validationErrors.Add(e.Message); + } + } + if (validationErrors.Count == 0) + return; + if (validationErrors.Count == 1) + throw new ExpectationViolationException(validationErrors[0]); + StringBuilder sb = new StringBuilder(); + foreach (string validationError in validationErrors) + { + sb.AppendLine(validationError); + } + throw new ExpectationViolationException(sb.ToString()); + } + + /// + /// Gets the replayer for this repository. + /// + /// + internal IMethodRecorder Replayer + { + get { return rootRecorder; } + } + + /// + /// Gets the last proxy which had a method call. + /// + internal static IMockedObject LastMockedObject + { + get + { + if (lastRepository == null) + return null; + return lastRepository.lastMockedObject; + } + } + + /// + /// Gets the proxy generator for a specific type. Having a single ProxyGenerator + /// with multiple types linearly degrades the performance so this implementation + /// keeps one ProxyGenerator per type. + /// + protected virtual ProxyGenerator GetProxyGenerator(Type type) + { + if (!generatorMap.ContainsKey(type)) + { + generatorMap[type] = new ProxyGenerator(); + } + + return generatorMap[type]; + } + + + + /// 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) + return; + repository.proxies[proxy].SetExceptionToThrowOnVerify(expectationViolationException); + } + #endregion #region AAA Methods (formerly MockRepositoryAAA.cs) @@ -1285,7 +1285,7 @@ private static T CreateMockInReplay(Func createMock) /// /// /// - public IDisposable Record() + public IModeChanger Record() { return new RecordModeChanger(this); } @@ -1293,217 +1293,217 @@ public IDisposable Record() /// /// /// - public IDisposable Playback() + public IModeChanger Playback() { return new PlaybackModeChanger(this); } #endregion - /// - /// 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")] - public T CreateMock(params object[] argumentsForConstructor) - { - return StrictMock(argumentsForConstructor); - } - - /// - /// 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) - { - if (ShouldUseRemotingProxy(typeof(T), argumentsForConstructor)) - return (T)RemotingMock(typeof(T), CreateRecordState); - return (T)CreateMockObject(typeof(T), CreateRecordState, new Type[0], argumentsForConstructor); - } - - private static bool ShouldUseRemotingProxy(Type type, object[] argumentsForConstructor) - { - return typeof(MarshalByRefObject).IsAssignableFrom(type) && - (argumentsForConstructor == null || argumentsForConstructor.Length == 0); - } - - /* - * Method: DynamicMock - * Create a mock object of type T with dynamic semantics. - * Dynamic semantics means that any call that wasn't explicitly recorded is accepted and a - * null or zero is returned (if there is a return value). - */ - - /// - /// Creates a dynamic mock for the specified type. - /// - /// Arguments for the class' constructor, if mocking a concrete class - public T DynamicMock(params object[] argumentsForConstructor) - where T : class - { - if (ShouldUseRemotingProxy(typeof(T), argumentsForConstructor)) - return (T)RemotingMock(typeof(T), CreateDynamicRecordState); - return (T)CreateMockObject(typeof(T), CreateDynamicRecordState, new Type[0], argumentsForConstructor); - } - - /// - /// Creates a mock object from several types. - /// - [Obsolete("Use StrictMultiMock instead")] - public T CreateMultiMock(params Type[] extraTypes) - { - return StrictMultiMock(extraTypes); - } - - /// - /// Creates a strict mock object from several types. - /// - public T StrictMultiMock(params Type[] extraTypes) - { - return (T)StrictMultiMock(typeof(T), extraTypes); - } - - /// - /// Create a mock object from several types with dynamic semantics. - /// - public T DynamicMultiMock(params Type[] extraTypes) - { - return (T)DynamicMultiMock(typeof(T), extraTypes); - } - - /// - /// Create a mock object from several types with partial semantics. - /// - public T PartialMultiMock(params Type[] extraTypes) - { - return (T)PartialMultiMock(typeof(T), extraTypes); - } - - /// - /// Create a mock object from several types with strict semantics. - /// - /// Extra interface types to mock. - /// Arguments for the class' constructor, if mocking a concrete class - [Obsolete("Use StrictMultiMock instead")] - public T CreateMultiMock(Type[] extraTypes, params object[] argumentsForConstructor) - { - return StrictMultiMock(extraTypes, argumentsForConstructor); - } - - - /// - /// Create a strict mock object from several types with strict semantics. - /// - /// Extra interface types to mock. - /// Arguments for the class' constructor, if mocking a concrete class - public T StrictMultiMock(Type[] extraTypes, params object[] argumentsForConstructor) - { - return (T)StrictMultiMock(typeof(T), extraTypes, argumentsForConstructor); - } - - /// - /// Create a mock object from several types with dynamic semantics. - /// - /// Extra interface types to mock. - /// Arguments for the class' constructor, if mocking a concrete class - public T DynamicMultiMock(Type[] extraTypes, params object[] argumentsForConstructor) - { - return (T)DynamicMultiMock(typeof(T), extraTypes, argumentsForConstructor); - } - - /// - /// Create a mock object from several types with partial semantics. - /// - /// Extra interface types to mock. - /// Arguments for the class' constructor, if mocking a concrete class - public T PartialMultiMock(Type[] extraTypes, params object[] argumentsForConstructor) - { - return (T)PartialMultiMock(typeof(T), extraTypes, argumentsForConstructor); - } - - /* - * 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. - * - */ - - /// - /// Create a mock object with from a class that defaults to calling the class methods - /// - /// Arguments for the class' constructor, if mocking a concrete class - public T PartialMock(params object[] argumentsForConstructor) where T : class - { - return (T)PartialMock(typeof(T), argumentsForConstructor); - } - - /// - /// Create a stub object, one that has properties and events ready for use, and - /// can have methods called on it. It requires an explicit step in order to create - /// an expectation for a stub. - /// - /// The arguments for constructor. - public T Stub(params object[] argumentsForConstructor) - { - return (T)Stub(typeof(T), argumentsForConstructor); - } - - /// - /// Create a stub object, one that has properties and events ready for use, and - /// can have methods called on it. It requires an explicit step in order to create - /// an expectation for a stub. - /// - /// The type. - /// The arguments for constructor. - /// The stub - public object Stub(Type type, params object[] argumentsForConstructor) - { - CreateMockState createStub = mockedObject => new StubRecordMockState(mockedObject, this); - if (ShouldUseRemotingProxy(type, argumentsForConstructor)) - return RemotingMock(type, createStub); - return CreateMockObject(type, createStub, new Type[0], argumentsForConstructor); - } - - /// - /// Returns true if the passed mock is currently in replay mode. - /// - /// The mock to test. - /// True if the mock is in replay mode, false otherwise. - public bool IsInReplayMode(object mock) - { - if (mock == null) - throw new ArgumentNullException("mock"); - - if (proxies.ContainsKey(mock)) - { - return proxies[mock] is ReplayMockState; - } - - throw new ArgumentException(mock + " is not a mock.", "mock"); - } - - /// - /// Determines whether the specified proxy is a stub. - /// - /// The proxy. - protected internal static bool IsStub(object proxy) - { - MockRepository repository = GetMockedObject(proxy).Repository; - IMockState mockState = repository.proxies[proxy]; - return mockState is StubRecordMockState || mockState is StubReplayMockState; - } - - /// - /// Register a call on a prperty behavior - /// - /// - protected internal void RegisterPropertyBehaviorOn(IMockedObject instance) - { - lastRepository = this; - lastMockedObject = instance; - proxies[instance].NotifyCallOnPropertyBehavior(); - } - } -} + /// + /// 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")] + public T CreateMock(params object[] argumentsForConstructor) + { + return StrictMock(argumentsForConstructor); + } + + /// + /// 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) + { + if (ShouldUseRemotingProxy(typeof(T), argumentsForConstructor)) + return (T)RemotingMock(typeof(T), CreateRecordState); + return (T)CreateMockObject(typeof(T), CreateRecordState, new Type[0], argumentsForConstructor); + } + + private static bool ShouldUseRemotingProxy(Type type, object[] argumentsForConstructor) + { + return typeof(MarshalByRefObject).IsAssignableFrom(type) && + (argumentsForConstructor == null || argumentsForConstructor.Length == 0); + } + + /* + * Method: DynamicMock + * Create a mock object of type T with dynamic semantics. + * Dynamic semantics means that any call that wasn't explicitly recorded is accepted and a + * null or zero is returned (if there is a return value). + */ + + /// + /// Creates a dynamic mock for the specified type. + /// + /// Arguments for the class' constructor, if mocking a concrete class + public T DynamicMock(params object[] argumentsForConstructor) + where T : class + { + if (ShouldUseRemotingProxy(typeof(T), argumentsForConstructor)) + return (T)RemotingMock(typeof(T), CreateDynamicRecordState); + return (T)CreateMockObject(typeof(T), CreateDynamicRecordState, new Type[0], argumentsForConstructor); + } + + /// + /// Creates a mock object from several types. + /// + [Obsolete("Use StrictMultiMock instead")] + public T CreateMultiMock(params Type[] extraTypes) + { + return StrictMultiMock(extraTypes); + } + + /// + /// Creates a strict mock object from several types. + /// + public T StrictMultiMock(params Type[] extraTypes) + { + return (T)StrictMultiMock(typeof(T), extraTypes); + } + + /// + /// Create a mock object from several types with dynamic semantics. + /// + public T DynamicMultiMock(params Type[] extraTypes) + { + return (T)DynamicMultiMock(typeof(T), extraTypes); + } + + /// + /// Create a mock object from several types with partial semantics. + /// + public T PartialMultiMock(params Type[] extraTypes) + { + return (T)PartialMultiMock(typeof(T), extraTypes); + } + + /// + /// Create a mock object from several types with strict semantics. + /// + /// Extra interface types to mock. + /// Arguments for the class' constructor, if mocking a concrete class + [Obsolete("Use StrictMultiMock instead")] + public T CreateMultiMock(Type[] extraTypes, params object[] argumentsForConstructor) + { + return StrictMultiMock(extraTypes, argumentsForConstructor); + } + + + /// + /// Create a strict mock object from several types with strict semantics. + /// + /// Extra interface types to mock. + /// Arguments for the class' constructor, if mocking a concrete class + public T StrictMultiMock(Type[] extraTypes, params object[] argumentsForConstructor) + { + return (T)StrictMultiMock(typeof(T), extraTypes, argumentsForConstructor); + } + + /// + /// Create a mock object from several types with dynamic semantics. + /// + /// Extra interface types to mock. + /// Arguments for the class' constructor, if mocking a concrete class + public T DynamicMultiMock(Type[] extraTypes, params object[] argumentsForConstructor) + { + return (T)DynamicMultiMock(typeof(T), extraTypes, argumentsForConstructor); + } + + /// + /// Create a mock object from several types with partial semantics. + /// + /// Extra interface types to mock. + /// Arguments for the class' constructor, if mocking a concrete class + public T PartialMultiMock(Type[] extraTypes, params object[] argumentsForConstructor) + { + return (T)PartialMultiMock(typeof(T), extraTypes, argumentsForConstructor); + } + + /* + * 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. + * + */ + + /// + /// Create a mock object with from a class that defaults to calling the class methods + /// + /// Arguments for the class' constructor, if mocking a concrete class + public T PartialMock(params object[] argumentsForConstructor) where T : class + { + return (T)PartialMock(typeof(T), argumentsForConstructor); + } + + /// + /// Create a stub object, one that has properties and events ready for use, and + /// can have methods called on it. It requires an explicit step in order to create + /// an expectation for a stub. + /// + /// The arguments for constructor. + public T Stub(params object[] argumentsForConstructor) + { + return (T)Stub(typeof(T), argumentsForConstructor); + } + + /// + /// Create a stub object, one that has properties and events ready for use, and + /// can have methods called on it. It requires an explicit step in order to create + /// an expectation for a stub. + /// + /// The type. + /// The arguments for constructor. + /// The stub + public object Stub(Type type, params object[] argumentsForConstructor) + { + CreateMockState createStub = mockedObject => new StubRecordMockState(mockedObject, this); + if (ShouldUseRemotingProxy(type, argumentsForConstructor)) + return RemotingMock(type, createStub); + return CreateMockObject(type, createStub, new Type[0], argumentsForConstructor); + } + + /// + /// Returns true if the passed mock is currently in replay mode. + /// + /// The mock to test. + /// True if the mock is in replay mode, false otherwise. + public bool IsInReplayMode(object mock) + { + if (mock == null) + throw new ArgumentNullException("mock"); + + if (proxies.ContainsKey(mock)) + { + return proxies[mock] is ReplayMockState; + } + + throw new ArgumentException(mock + " is not a mock.", "mock"); + } + + /// + /// Determines whether the specified proxy is a stub. + /// + /// The proxy. + protected internal static bool IsStub(object proxy) + { + MockRepository repository = GetMockedObject(proxy).Repository; + IMockState mockState = repository.proxies[proxy]; + return mockState is StubRecordMockState || mockState is StubReplayMockState; + } + + /// + /// Register a call on a prperty behavior + /// + /// + protected internal void RegisterPropertyBehaviorOn(IMockedObject instance) + { + lastRepository = this; + lastMockedObject = instance; + proxies[instance].NotifyCallOnPropertyBehavior(); + } + } +} From 79914b4a6f70c3eb1caec46c0834b5fdead65ceb Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Wed, 22 Sep 2010 07:43:57 -0700 Subject: [PATCH 21/24] Created AsMockObject() extension method which MockRepository.GetMockObject now delegates to - working to simplify surface area in MockRepository). Same process was done for MockRepository.GetMockedObjectOrNull() --- Rhino.Mocks/MockRepository.cs | 27 ++--------------- Rhino.Mocks/RhinoMocksExtensions.cs | 45 +++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/Rhino.Mocks/MockRepository.cs b/Rhino.Mocks/MockRepository.cs index 53a16e40..53553c0d 100644 --- a/Rhino.Mocks/MockRepository.cs +++ b/Rhino.Mocks/MockRepository.cs @@ -855,11 +855,7 @@ private void IsMockObjectFromThisRepository(object obj) /// protected internal static IMockedObject GetMockedObject(object mockedInstance) { - IMockedObject mockedObj = GetMockedObjectOrNull(mockedInstance); - if (mockedObj == null) - throw new InvalidOperationException("The object '" + mockedInstance + - "' is not a mocked object."); - return mockedObj; + return mockedInstance.AsMockObject(); } /// @@ -869,26 +865,7 @@ protected internal static IMockedObject GetMockedObject(object mockedInstance) /// protected internal static IMockedObject GetMockedObjectOrNull(object mockedInstance) { - Delegate mockedDelegate = mockedInstance as Delegate; - - if (mockedDelegate != null) - { - mockedInstance = mockedDelegate.Target; - } - - // must be careful not to call any methods on mocked objects, - // or it may cause infinite recursion - if (mockedInstance is IMockedObject) - { - return (IMockedObject)mockedInstance; - } - - if (RemotingMockGenerator.IsRemotingProxy(mockedInstance)) - { - return RemotingMockGenerator.GetMockedObjectFromProxy(mockedInstance); - } - - return null; + return mockedInstance.AsMockObjectOrNull(); } /// Pops the recorder. diff --git a/Rhino.Mocks/RhinoMocksExtensions.cs b/Rhino.Mocks/RhinoMocksExtensions.cs index 5e796b6c..7f546959 100644 --- a/Rhino.Mocks/RhinoMocksExtensions.cs +++ b/Rhino.Mocks/RhinoMocksExtensions.cs @@ -30,7 +30,8 @@ using System; using System.Collections.Generic; using Rhino.Mocks.Exceptions; -using Rhino.Mocks.Generated; +using Rhino.Mocks.Generated; +using Rhino.Mocks.Impl.RemotingMock; using Rhino.Mocks.Interfaces; @@ -482,7 +483,47 @@ private VoidType() } } - #endregion + #endregion + + internal static IMockedObject AsMockObject(this object mockedInstance) + { + IMockedObject mockedObj = mockedInstance.AsMockObjectOrNull(); + if (mockedObj == null) + throw new InvalidOperationException("The object '" + mockedInstance + + "' is not a mocked object."); + return mockedObj; + } + + /// + /// Method: GetMockedObjectOrNull + /// Get an IProxy from a mocked object instance, or null if the + /// object is not a mock object. + /// + internal static IMockedObject AsMockObjectOrNull(this object mockedInstance) + { + Delegate mockedDelegate = mockedInstance as Delegate; + + if (mockedDelegate != null) + { + mockedInstance = mockedDelegate.Target; + } + + // must be careful not to call any methods on mocked objects, + // or it may cause infinite recursion + if (mockedInstance is IMockedObject) + { + return (IMockedObject)mockedInstance; + } + + if (RemotingMockGenerator.IsRemotingProxy(mockedInstance)) + { + return RemotingMockGenerator.GetMockedObjectFromProxy(mockedInstance); + } + + return null; + } + + } } #endif From da77754eb2031341a74bef2d34f443f18f76e393 Mon Sep 17 00:00:00 2001 From: TimBarcz Date: Mon, 11 Oct 2010 08:56:16 -0500 Subject: [PATCH 22/24] Adding internalsVisibleAttribute to allow for test assembly to see into target assembly --- default.ps1 | 3 ++- psake_ext.ps1 | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/default.ps1 b/default.ps1 index 905210c6..c9f2b6cd 100644 --- a/default.ps1 +++ b/default.ps1 @@ -30,7 +30,8 @@ task Init -depends Clean { -company "Hibernating Rhinos" ` -product "Rhino Mocks $version" ` -version $version ` - -copyright "Hibernating Rhinos & Ayende Rahien 2004 - 2009" + -copyright "Hibernating Rhinos & Ayende Rahien 2004 - 2009" ` + -internalsVisibleTo "Rhino.Mocks.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001009d1cf4b75b7218b141ac64c15450141b1e5f41f6a302ac717ab9761fa6ae2c3ee0c354c22d0a60ac59de41fa285d572e7cf33c320aa7ff877e2b7da1792fcc6aa4eb0b4d8294a2f74cb14d03fb9b091f751d6dc49e626d74601692c99eab7718ed76a40c36d39af842be378b677e6e4eae973f643d7065241ad86ecc156d81ab" Generate-Assembly-Info ` -file "$base_dir\Rhino.Mocks.Tests\Properties\AssemblyInfo.cs" ` diff --git a/psake_ext.ps1 b/psake_ext.ps1 index f4b3da93..4ab77468 100644 --- a/psake_ext.ps1 +++ b/psake_ext.ps1 @@ -14,7 +14,8 @@ param( [string]$product, [string]$copyright, [string]$version, - [string]$file = $(throw "file is a required parameter.") + [string]$file = $(throw "file is a required parameter."), + [string]$internalsVisibleTo ) $commit = Get-Git-Commit $asmInfo = "using System; @@ -33,6 +34,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyInformationalVersionAttribute(""$version / $commit"")] [assembly: AssemblyFileVersionAttribute(""$version"")] [assembly: AssemblyDelaySignAttribute(false)] +[assembly: InternalsVisibleTo(""$internalsVisibleTo"")] " $dir = [System.IO.Path]::GetDirectoryName($file) From e707bdfddabb49b573e41afad82403e89c99ab2c Mon Sep 17 00:00:00 2001 From: andriniaina Date: Mon, 28 Jan 2013 16:42:59 +0100 Subject: [PATCH 23/24] Fixed ref parameters on COM interfaces The value of a variable used as a ref parameter should be used as a constraint on an expectation even when if it is marked with an InteropServices.OutAttribute --- .../FieldsProblem/FieldProblem_Andri.cs | 68 +++++++++++++++++++ Rhino.Mocks/Impl/RecordMockState.cs | 2 +- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs diff --git a/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs b/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs new file mode 100644 index 00000000..2e63f153 --- /dev/null +++ b/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs @@ -0,0 +1,68 @@ +#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 +namespace Rhino.Mocks.Tests.FieldsProblem +{ + using System; + using Xunit; + using Rhino.Mocks.Constraints; + + + public class FieldProblem_Andri + { + public class AndriTest + { + /// + /// The value of a variable used as a ref parameter should be used as a constraint on an expectation + /// even when if it is marked with an InteropServices.OutAttribute + /// + [Fact] + public void OutByRefTest() + { + MockRepository mockery = new MockRepository(); + IFoo mockFoo = mockery.StrictMock(); + int three = 3; + int six = 6; + using (mockery.Record()) + { + SetupResult.For(mockFoo.foo(ref three)).OutRef(six).Return(true); + } + + Assert.Throws(() => mockFoo.foo(ref six)); + } + } + + #region Nested type: IFoo + + public interface IFoo + { + bool foo([System.Runtime.InteropServices.Out] [System.Runtime.InteropServices.In] ref int fooSquared); + } + + #endregion + } +} \ No newline at end of file diff --git a/Rhino.Mocks/Impl/RecordMockState.cs b/Rhino.Mocks/Impl/RecordMockState.cs index edca3f76..aa282add 100644 --- a/Rhino.Mocks/Impl/RecordMockState.cs +++ b/Rhino.Mocks/Impl/RecordMockState.cs @@ -308,7 +308,7 @@ private IExpectation BuildDefaultExpectation(IInvocation invocation, MethodInfo AbstractConstraint[] constraints = new AbstractConstraint[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { - constraints[i] = parameters[i].IsOut ? Is.Anything() : Is.Equal(args[i]); + constraints[i] = parameters[i].IsOut && !parameters[i].IsIn ? Is.Anything() : Is.Equal(args[i]); } return new ConstraintsExpectation(invocation, constraints, GetDefaultCallCountRangeExpectation()); } From 00f886ab39aca3df77c0ae318f8ec69c8a36775a Mon Sep 17 00:00:00 2001 From: andri Date: Thu, 30 May 2013 23:21:30 +0200 Subject: [PATCH 24/24] Fixed ref parameters on COM interfaces --- Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs | 2 +- Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj | 1 + Rhino.Mocks/Impl/ExpectationBuilder.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs b/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs index 2e63f153..014cc468 100644 --- a/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs +++ b/Rhino.Mocks.Tests/FieldsProblem/FieldProblem_Andri.cs @@ -65,4 +65,4 @@ public interface IFoo #endregion } -} \ No newline at end of file +} diff --git a/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj b/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj index b8f89280..728243d9 100644 --- a/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj +++ b/Rhino.Mocks.Tests/Rhino.Mocks.Tests.csproj @@ -173,6 +173,7 @@ Code + diff --git a/Rhino.Mocks/Impl/ExpectationBuilder.cs b/Rhino.Mocks/Impl/ExpectationBuilder.cs index 1a7e79da..1cc2914a 100644 --- a/Rhino.Mocks/Impl/ExpectationBuilder.cs +++ b/Rhino.Mocks/Impl/ExpectationBuilder.cs @@ -32,7 +32,7 @@ public IExpectation BuildDefaultExpectation(IInvocation invocation, MethodInfo m var constraints = new AbstractConstraint[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { - constraints[i] = parameters[i].IsOut ? Is.Anything() : Is.Equal(args[i]); + constraints[i] = parameters[i].IsOut && !parameters[i].IsIn ? Is.Anything() : Is.Equal(args[i]); } return new ConstraintsExpectation(invocation, constraints, callCallRangeExpectation()); }