From 48c6aa654f94907d4b19c8b2275c9e8d824f88e5 Mon Sep 17 00:00:00 2001 From: alexbestul Date: Mon, 2 Oct 2017 15:01:28 -0500 Subject: [PATCH] Add support for void sequences (#463) --- CHANGELOG.md | 7 ++ Source/Language/ISetupSequentialAction.cs | 94 +++++++++++++++ Source/SequenceExtensions.cs | 11 ++ Source/SetupSequentialActionContext.cs | 107 ++++++++++++++++++ .../SequentialActionExtensionsFixture.cs | 83 ++++++++++++++ 5 files changed, 302 insertions(+) create mode 100644 Source/Language/ISetupSequentialAction.cs create mode 100644 Source/SetupSequentialActionContext.cs create mode 100644 UnitTests/SequentialActionExtensionsFixture.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d4cb0b8e..aa700574a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). +## Unreleased + +#### Added + +* Support for sequential setup of `void` methods (@alexbestul, #463) + + ## 4.7.137 (2017-09-30) #### Changed diff --git a/Source/Language/ISetupSequentialAction.cs b/Source/Language/ISetupSequentialAction.cs new file mode 100644 index 000000000..9ba546293 --- /dev/null +++ b/Source/Language/ISetupSequentialAction.cs @@ -0,0 +1,94 @@ +//Copyright (c) 2007. Clarius Consulting, Manas Technology Solutions, InSTEDD +//https://github.com/moq/moq4 +//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 Clarius Consulting, Manas Technology Solutions or InSTEDD 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. + +//[This is the BSD license, see +// http://www.opensource.org/licenses/bsd-license.php] + +using System; + +namespace Moq.Language +{ + /// + /// Defines the Pass and Throws verbs for sequence setups + /// on void methods. + /// + public interface ISetupSequentialAction + { + /// + /// Configures the next call in the sequence to do nothing. + /// + /// + /// The following code configures the first call to Execute() + /// to do nothing, and the second call to throw an exception. + /// + /// mock.SetupSequence(m => m.Execute()) + /// .Pass() + /// .Throws<InvalidOperationException>(); + /// + /// + ISetupSequentialAction Pass(); + + /// + /// Configures the next call in the sequence to throw an exception. + /// + /// + /// The following code configures the first call to Execute() + /// to do nothing, and the second call to throw an exception. + /// + /// mock.SetupSequence(m => m.Execute()) + /// .Pass() + /// .Throws<InvalidOperationException>(); + /// + /// + ISetupSequentialAction Throws() + where TException : Exception, new(); + + /// + /// Configures the next call in the sequence to throw an exception. + /// + /// + /// The following code configures the first call to Execute() + /// to do nothing, and the second call to throw an exception. + /// + /// mock.SetupSequence(m => m.Execute()) + /// .Pass() + /// .Throws(new InvalidOperationException()); + /// + /// + ISetupSequentialAction Throws(Exception exception); + } +} diff --git a/Source/SequenceExtensions.cs b/Source/SequenceExtensions.cs index 7fad011ee..6196d0996 100644 --- a/Source/SequenceExtensions.cs +++ b/Source/SequenceExtensions.cs @@ -23,6 +23,17 @@ public static ISetupSequentialResult SetupSequence( return new SetupSequentialContext(mock, expression); } + /// + /// Performs a sequence of actions, one per call. + /// + public static ISetupSequentialAction SetupSequence( + this Mock mock, + Expression> expression) + where TMock : class + { + return new SetupSequentialActionContext(mock, expression); + } + /// /// Return a sequence of tasks, once per call. /// diff --git a/Source/SetupSequentialActionContext.cs b/Source/SetupSequentialActionContext.cs new file mode 100644 index 000000000..0f24822da --- /dev/null +++ b/Source/SetupSequentialActionContext.cs @@ -0,0 +1,107 @@ +//Copyright (c) 2007. Clarius Consulting, Manas Technology Solutions, InSTEDD +//https://github.com/moq/moq4 +//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 Clarius Consulting, Manas Technology Solutions or InSTEDD 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. + +//[This is the BSD license, see +// http://www.opensource.org/licenses/bsd-license.php] + +using System; +using System.Linq.Expressions; +using Moq.Language; +using Moq.Language.Flow; + +namespace Moq +{ + internal sealed class SetupSequentialActionContext : ISetupSequentialAction + where TMock : class + { + private int currentStep; + private int expectationsCount; + private Mock mock; + private Expression> expression; + private readonly Action callbackAction; + + public SetupSequentialActionContext( + Mock mock, + Expression> expression) + { + this.mock = mock; + this.expression = expression; + this.callbackAction = () => currentStep++; + } + + public ISetupSequentialAction Pass() + { + var setup = this.GetSetup(); + setup.Callback(DoNothing); + this.EndSetup(setup); + return this; + } + + private static void DoNothing() { } + + public ISetupSequentialAction Throws() where TException : Exception, new() + { + var setup = this.GetSetup(); + setup.Throws(); + this.EndSetup(setup); + return this; + } + + public ISetupSequentialAction Throws(Exception exception) + { + var setup = this.GetSetup(); + setup.Throws(exception); + this.EndSetup(setup); + return this; + } + + private void EndSetup(ICallback callback) + { + callback.Callback(callbackAction); + } + + private ISetup GetSetup() + { + var expectationStep = this.expectationsCount; + this.expectationsCount++; + + return this.mock + .When(() => currentStep == expectationStep) + .Setup(expression); + } + } +} diff --git a/UnitTests/SequentialActionExtensionsFixture.cs b/UnitTests/SequentialActionExtensionsFixture.cs new file mode 100644 index 000000000..1c600047b --- /dev/null +++ b/UnitTests/SequentialActionExtensionsFixture.cs @@ -0,0 +1,83 @@ +//Copyright (c) 2007. Clarius Consulting, Manas Technology Solutions, InSTEDD +//https://github.com/moq/moq4 +//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 Clarius Consulting, Manas Technology Solutions or InSTEDD 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. + +//[This is the BSD license, see +// http://www.opensource.org/licenses/bsd-license.php] + +using System; +using Xunit; + +namespace Moq.Tests +{ + public class SequentialActionExtensionsFixture + { + [Fact] + public void PerformSequence() + { + var mock = new Mock(); + + mock.SetupSequence(m => m.Do()) + .Pass() + .Throws() + .Throws(new ArgumentException()); + + mock.Object.Do(); + Assert.Throws(() => mock.Object.Do()); + Assert.Throws(() => mock.Object.Do()); + } + + [Fact] + public void PerformSequenceWithThrowFirst() + { + var mock = new Mock(); + + mock.SetupSequence(m => m.Do()) + .Throws() + .Pass() + .Throws(new ArgumentException()); + + Assert.Throws(() => mock.Object.Do()); + mock.Object.Do(); + Assert.Throws(() => mock.Object.Do()); + } + + public interface IFoo + { + void Do(); + } + } +}