diff --git a/src/Moq/IInvocation.cs b/src/Moq/IInvocation.cs index c2982b920..9104d41ae 100644 --- a/src/Moq/IInvocation.cs +++ b/src/Moq/IInvocation.cs @@ -41,5 +41,10 @@ public interface IInvocation /// Optional exception if the method invocation results in an exception being thrown. /// Exception Exception { get; } + + /// + /// A number representing the order of this invocation in time with respect to all other invocations + /// + long SequenceNumber { get; } } } \ No newline at end of file diff --git a/src/Moq/IVerifyResult.cs b/src/Moq/IVerifyResult.cs new file mode 100644 index 000000000..753176278 --- /dev/null +++ b/src/Moq/IVerifyResult.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Moq +{ + /// + /// A collection of invocations verified by a call to mock.Verify() or one of its variations + /// + /// The type being mocked and verified + public interface IVerifyResult : IReadOnlyList where T: class + { + /// + /// The mock that was verified + /// + Mock Mock { get; } + } +} diff --git a/src/Moq/Invocation.cs b/src/Moq/Invocation.cs index 9b8a237f2..ba25eec14 100644 --- a/src/Moq/Invocation.cs +++ b/src/Moq/Invocation.cs @@ -6,7 +6,7 @@ using System.Diagnostics; using System.Reflection; using System.Text; - +using System.Threading; using Moq.Async; namespace Moq @@ -20,6 +20,8 @@ abstract class Invocation : IInvocation object result; Setup matchingSetup; bool verified; + long sequenceNumber; + static long globalSequenceNumber = 0;//ONLY access with Interlocked.Increment() /// /// Initializes a new instance of the class. @@ -36,8 +38,11 @@ protected Invocation(Type proxyType, MethodInfo method, params object[] argument this.arguments = arguments; this.method = method; this.proxyType = proxyType; + this.sequenceNumber = Interlocked.Increment(ref globalSequenceNumber); } + public long SequenceNumber => this.sequenceNumber; + /// /// Gets the method of the invocation. /// diff --git a/src/Moq/Mock.cs b/src/Moq/Mock.cs index 958494f17..a782288c9 100644 --- a/src/Moq/Mock.cs +++ b/src/Moq/Mock.cs @@ -313,7 +313,7 @@ internal void Verify(Func predicate, HashSet verifiedMocks) } } - internal static void Verify(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static IEnumerable Verify(Mock mock, LambdaExpression expression, Times times, string failMessage) { Guard.NotNull(times, nameof(times)); @@ -326,6 +326,7 @@ internal static void Verify(Mock mock, LambdaExpression expression, Times times, part.SetupEvaluatedSuccessfully(invocation); invocation.MarkAsVerified(); } + return invocationsToBeMarkedAsVerified.Select(pair => (IInvocation)pair.Item1); } else { @@ -333,7 +334,7 @@ internal static void Verify(Mock mock, LambdaExpression expression, Times times, } } - internal static void VerifyGet(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static IEnumerable VerifyGet(Mock mock, LambdaExpression expression, Times times, string failMessage) { Guard.NotNull(expression, nameof(expression)); @@ -343,31 +344,31 @@ internal static void VerifyGet(Mock mock, LambdaExpression expression, Times tim Guard.CanRead(property); } - Mock.Verify(mock, expression, times, failMessage); + return Mock.Verify(mock, expression, times, failMessage); } - internal static void VerifySet(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static IEnumerable VerifySet(Mock mock, LambdaExpression expression, Times times, string failMessage) { Guard.NotNull(expression, nameof(expression)); Guard.IsAssignmentToPropertyOrIndexer(expression, nameof(expression)); - Mock.Verify(mock, expression, times, failMessage); + return Mock.Verify(mock, expression, times, failMessage); } - internal static void VerifyAdd(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static IEnumerable VerifyAdd(Mock mock, LambdaExpression expression, Times times, string failMessage) { Guard.NotNull(expression, nameof(expression)); Guard.IsEventAdd(expression, nameof(expression)); - Mock.Verify(mock, expression, times, failMessage); + return Mock.Verify(mock, expression, times, failMessage); } - internal static void VerifyRemove(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static IEnumerable VerifyRemove(Mock mock, LambdaExpression expression, Times times, string failMessage) { Guard.NotNull(expression, nameof(expression)); Guard.IsEventRemove(expression, nameof(expression)); - Mock.Verify(mock, expression, times, failMessage); + return Mock.Verify(mock, expression, times, failMessage); } internal static void VerifyNoOtherCalls(Mock mock) diff --git a/src/Moq/Mock`1.cs b/src/Moq/Mock`1.cs index d9e697875..77f4ba4bf 100644 --- a/src/Moq/Mock`1.cs +++ b/src/Moq/Mock`1.cs @@ -705,9 +705,10 @@ public ISetupConditionResult When(Func condition) /// mock.Verify(proc => proc.Execute("ping")); /// /// - public void Verify(Expression> expression) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression) { - Mock.Verify(this, expression, Times.AtLeastOnce(), null); + return new VerifyResult(this, Mock.Verify(this, expression, Times.AtLeastOnce(), null)); } /// @@ -719,9 +720,10 @@ public void Verify(Expression> expression) /// /// The invocation was not called the number of times specified by . /// - public void Verify(Expression> expression, Times times) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, Times times) { - Mock.Verify(this, expression, times, null); + return new VerifyResult(this, Mock.Verify(this, expression, times, null)); } /// @@ -733,9 +735,10 @@ public void Verify(Expression> expression, Times times) /// /// The invocation was not called the number of times specified by . /// - public void Verify(Expression> expression, Func times) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, Func times) { - Verify(expression, times()); + return Verify(expression, times()); } /// @@ -746,9 +749,10 @@ public void Verify(Expression> expression, Func times) /// Expression to verify. /// Message to show if verification fails. /// The invocation was not performed on the mock. - public void Verify(Expression> expression, string failMessage) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, string failMessage) { - Mock.Verify(this, expression, Times.AtLeastOnce(), failMessage); + return new VerifyResult(this, Mock.Verify(this, expression, Times.AtLeastOnce(), failMessage)); } /// @@ -762,9 +766,10 @@ public void Verify(Expression> expression, string failMessage) /// /// The invocation was not called the number of times specified by . /// - public void Verify(Expression> expression, Times times, string failMessage) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, Times times, string failMessage) { - Mock.Verify(this, expression, times, failMessage); + return new VerifyResult(this, Mock.Verify(this, expression, times, failMessage)); } /// @@ -778,9 +783,10 @@ public void Verify(Expression> expression, Times times, string failMes /// /// The invocation was not called the number of times specified by . /// - public void Verify(Expression> expression, Func times, string failMessage) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, Func times, string failMessage) { - Mock.Verify(this, expression, times(), failMessage); + return new VerifyResult(this, Mock.Verify(this, expression, times(), failMessage)); } /// @@ -802,9 +808,10 @@ public void Verify(Expression> expression, Func times, string f /// mock.Verify(warehouse => warehouse.HasInventory(TALISKER, 50)); /// /// - public void Verify(Expression> expression) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression) { - Mock.Verify(this, expression, Times.AtLeastOnce(), null); + return new VerifyResult(this, Mock.Verify(this, expression, Times.AtLeastOnce(), null)); } /// @@ -817,9 +824,10 @@ public void Verify(Expression> expression) /// /// The invocation was not called the number of times specified by . /// - public void Verify(Expression> expression, Times times) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, Times times) { - Mock.Verify(this, expression, times, null); + return new VerifyResult(this, Mock.Verify(this, expression, times, null)); } /// @@ -832,9 +840,10 @@ public void Verify(Expression> expression, Times times /// /// The invocation was not called the number of times specified by . /// - public void Verify(Expression> expression, Func times) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, Func times) { - Mock.Verify(this, expression, times(), null); + return new VerifyResult(this, Mock.Verify(this, expression, times(), null)); } /// @@ -848,9 +857,10 @@ public void Verify(Expression> expression, Func /// /// The invocation was not called the number times specified by . /// - public void Verify(Expression> expression, Func times, string failMessage) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, Func times, string failMessage) { - Mock.Verify(this, expression, times(), failMessage); + return new VerifyResult(this, Mock.Verify(this, expression, times(), failMessage)); } /// @@ -874,9 +884,10 @@ public void Verify(Expression> expression, Func /// "When filling orders, inventory has to be checked"); /// /// - public void Verify(Expression> expression, string failMessage) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, string failMessage) { - Mock.Verify(this, expression, Times.AtLeastOnce(), failMessage); + return new VerifyResult(this, Mock.Verify(this, expression, Times.AtLeastOnce(), failMessage)); } /// @@ -890,9 +901,10 @@ public void Verify(Expression> expression, string fail /// /// The invocation was not called the number times specified by . /// - public void Verify(Expression> expression, Times times, string failMessage) + /// A list of matching invocations + public IVerifyResult Verify(Expression> expression, Times times, string failMessage) { - Mock.Verify(this, expression, times, failMessage); + return new VerifyResult(this, Mock.Verify(this, expression, times, failMessage)); } /// @@ -912,12 +924,13 @@ public void Verify(Expression> expression, Times times /// ... // exercise mock /// /// // Will throw if the test code didn't retrieve the IsClosed property. - /// mock.VerifyGet(warehouse => warehouse.IsClosed); + /// new VerifyResult(this, mock.VerifyGet(warehouse => warehouse.IsClosed)); /// /// - public void VerifyGet(Expression> expression) + /// A list of matching invocations + public IVerifyResult VerifyGet(Expression> expression) { - Mock.VerifyGet(this, expression, Times.AtLeastOnce(), null); + return new VerifyResult(this, Mock.VerifyGet(this, expression, Times.AtLeastOnce(), null)); } /// @@ -931,9 +944,10 @@ public void VerifyGet(Expression> expression) /// /// The invocation was not called the number times specified by . /// - public void VerifyGet(Expression> expression, Times times) + /// A list of matching invocations + public IVerifyResult VerifyGet(Expression> expression, Times times) { - Mock.VerifyGet(this, expression, times, null); + return new VerifyResult(this, Mock.VerifyGet(this, expression, times, null)); } /// @@ -947,9 +961,10 @@ public void VerifyGet(Expression> expression, Time /// /// The invocation was not called the number times specified by . /// - public void VerifyGet(Expression> expression, Func times) + /// A list of matching invocations + public IVerifyResult VerifyGet(Expression> expression, Func times) { - VerifyGet(this, expression, times(), null); + return new VerifyResult(this, VerifyGet(this, expression, times(), null)); } /// @@ -961,9 +976,10 @@ public void VerifyGet(Expression> expression, Func /// Type of the property to verify. Typically omitted as it can be inferred from the expression's return type. /// /// The invocation was not performed on the mock. - public void VerifyGet(Expression> expression, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyGet(Expression> expression, string failMessage) { - Mock.VerifyGet(this, expression, Times.AtLeastOnce(), failMessage); + return new VerifyResult(this, Mock.VerifyGet(this, expression, Times.AtLeastOnce(), failMessage)); } /// @@ -978,9 +994,10 @@ public void VerifyGet(Expression> expression, stri /// /// The invocation was not called the number times specified by . /// - public void VerifyGet(Expression> expression, Times times, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyGet(Expression> expression, Times times, string failMessage) { - Mock.VerifyGet(this, expression, times, failMessage); + return new VerifyResult(this, Mock.VerifyGet(this, expression, times, failMessage)); } /// @@ -995,9 +1012,10 @@ public void VerifyGet(Expression> expression, Time /// /// The invocation was not called the number times specified by . /// - public void VerifyGet(Expression> expression, Func times, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyGet(Expression> expression, Func times, string failMessage) { - VerifyGet(this, expression, times(), failMessage); + return new VerifyResult(this, VerifyGet(this, expression, times(), failMessage)); } /// @@ -1014,15 +1032,16 @@ public void VerifyGet(Expression> expression, Func /// ... // exercise mock /// /// // Will throw if the test code didn't set the IsClosed property. - /// mock.VerifySet(warehouse => warehouse.IsClosed = true); + /// new VerifyResult(this, mock.VerifySet(warehouse => warehouse.IsClosed = true)); /// /// - public void VerifySet(Action setterExpression) + /// A list of matching invocations + public IVerifyResult VerifySet(Action setterExpression) { Guard.NotNull(setterExpression, nameof(setterExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, this.ConstructorArguments); - Mock.VerifySet(this, expression, Times.AtLeastOnce(), null); + return new VerifyResult(this, Mock.VerifySet(this, expression, Times.AtLeastOnce(), null)); } /// @@ -1033,12 +1052,13 @@ public void VerifySet(Action setterExpression) /// /// The invocation was not called the number of times specified by . /// - public void VerifySet(Action setterExpression, Times times) + /// A list of matching invocations + public IVerifyResult VerifySet(Action setterExpression, Times times) { Guard.NotNull(setterExpression, nameof(setterExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, this.ConstructorArguments); - Mock.VerifySet(this, expression, times, null); + return new VerifyResult(this, Mock.VerifySet(this, expression, times, null)); } /// @@ -1049,12 +1069,13 @@ public void VerifySet(Action setterExpression, Times times) /// /// The invocation was not called the number of times specified by . /// - public void VerifySet(Action setterExpression, Func times) + /// A list of matching invocations + public IVerifyResult VerifySet(Action setterExpression, Func times) { Guard.NotNull(setterExpression, nameof(setterExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, this.ConstructorArguments); - Mock.VerifySet(this, expression, times(), null); + return new VerifyResult(this, Mock.VerifySet(this, expression, times(), null)); } /// @@ -1076,12 +1097,13 @@ public void VerifySet(Action setterExpression, Func times) /// "Warehouse should always be closed after the action"); /// /// - public void VerifySet(Action setterExpression, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifySet(Action setterExpression, string failMessage) { Guard.NotNull(setterExpression, nameof(setterExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, this.ConstructorArguments); - Mock.VerifySet(this, expression, Times.AtLeastOnce(), failMessage); + return new VerifyResult(this, Mock.VerifySet(this, expression, Times.AtLeastOnce(), failMessage)); } /// @@ -1093,12 +1115,13 @@ public void VerifySet(Action setterExpression, string failMessage) /// /// The invocation was not called the number of times specified by . /// - public void VerifySet(Action setterExpression, Times times, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifySet(Action setterExpression, Times times, string failMessage) { Guard.NotNull(setterExpression, nameof(setterExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, this.ConstructorArguments); - Mock.VerifySet(this, expression, times, failMessage); + return new VerifyResult(this, Mock.VerifySet(this, expression, times, failMessage)); } /// @@ -1110,12 +1133,13 @@ public void VerifySet(Action setterExpression, Times times, string failMessag /// /// The invocation was not called the number of times specified by . /// - public void VerifySet(Action setterExpression, Func times, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifySet(Action setterExpression, Func times, string failMessage) { Guard.NotNull(setterExpression, nameof(setterExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, this.ConstructorArguments); - Mock.VerifySet(this, expression, times(), failMessage); + return new VerifyResult(this, Mock.VerifySet(this, expression, times(), failMessage)); } /// @@ -1135,12 +1159,13 @@ public void VerifySet(Action setterExpression, Func times, string fail /// mock.VerifyAdd(warehouse => warehouse.OnClosed += It.IsAny<EventHandler>()); /// /// - public void VerifyAdd(Action addExpression) + /// A list of matching invocations + public IVerifyResult VerifyAdd(Action addExpression) { Guard.NotNull(addExpression, nameof(addExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(addExpression, this.ConstructorArguments); - Mock.VerifyAdd(this, expression, Times.AtLeastOnce(), null); + return new VerifyResult(this, Mock.VerifyAdd(this, expression, Times.AtLeastOnce(), null)); } /// @@ -1151,12 +1176,13 @@ public void VerifyAdd(Action addExpression) /// /// The invocation was not called the number of times specified by . /// - public void VerifyAdd(Action addExpression, Times times) + /// A list of matching invocations + public IVerifyResult VerifyAdd(Action addExpression, Times times) { Guard.NotNull(addExpression, nameof(addExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(addExpression, this.ConstructorArguments); - Mock.VerifyAdd(this, expression, times, null); + return new VerifyResult(this, Mock.VerifyAdd(this, expression, times, null)); } /// @@ -1167,12 +1193,13 @@ public void VerifyAdd(Action addExpression, Times times) /// /// The invocation was not called the number of times specified by . /// - public void VerifyAdd(Action addExpression, Func times) + /// A list of matching invocations + public IVerifyResult VerifyAdd(Action addExpression, Func times) { Guard.NotNull(addExpression, nameof(addExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(addExpression, this.ConstructorArguments); - Mock.VerifyAdd(this, expression, times(), null); + return new VerifyResult(this, Mock.VerifyAdd(this, expression, times(), null)); } /// @@ -1181,12 +1208,13 @@ public void VerifyAdd(Action addExpression, Func times) /// Expression to verify. /// Message to show if verification fails. /// The invocation was not performed on the mock. - public void VerifyAdd(Action addExpression, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyAdd(Action addExpression, string failMessage) { Guard.NotNull(addExpression, nameof(addExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(addExpression, this.ConstructorArguments); - Mock.VerifyAdd(this, expression, Times.AtLeastOnce(), failMessage); + return new VerifyResult(this, Mock.VerifyAdd(this, expression, Times.AtLeastOnce(), failMessage)); } /// @@ -1198,12 +1226,13 @@ public void VerifyAdd(Action addExpression, string failMessage) /// /// The invocation was not called the number of times specified by . /// - public void VerifyAdd(Action addExpression, Times times, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyAdd(Action addExpression, Times times, string failMessage) { Guard.NotNull(addExpression, nameof(addExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(addExpression, this.ConstructorArguments); - Mock.VerifyAdd(this, expression, times, failMessage); + return new VerifyResult(this, Mock.VerifyAdd(this, expression, times, failMessage)); } /// @@ -1215,12 +1244,13 @@ public void VerifyAdd(Action addExpression, Times times, string failMessage) /// /// The invocation was not called the number of times specified by . /// - public void VerifyAdd(Action addExpression, Func times, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyAdd(Action addExpression, Func times, string failMessage) { Guard.NotNull(addExpression, nameof(addExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(addExpression, this.ConstructorArguments); - Mock.VerifyAdd(this, expression, times(), failMessage); + return new VerifyResult(this, Mock.VerifyAdd(this, expression, times(), failMessage)); } /// @@ -1240,12 +1270,13 @@ public void VerifyAdd(Action addExpression, Func times, string failMes /// mock.VerifyRemove(warehouse => warehouse.OnClose -= It.IsAny<EventHandler>()); /// /// - public void VerifyRemove(Action removeExpression) + /// A list of matching invocations + public IVerifyResult VerifyRemove(Action removeExpression) { Guard.NotNull(removeExpression, nameof(removeExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(removeExpression, this.ConstructorArguments); - Mock.VerifyRemove(this, expression, Times.AtLeastOnce(), null); + return new VerifyResult(this, Mock.VerifyRemove(this, expression, Times.AtLeastOnce(), null)); } /// @@ -1256,12 +1287,13 @@ public void VerifyRemove(Action removeExpression) /// /// The invocation was not called the number of times specified by . /// - public void VerifyRemove(Action removeExpression, Times times) + /// A list of matching invocations + public IVerifyResult VerifyRemove(Action removeExpression, Times times) { Guard.NotNull(removeExpression, nameof(removeExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(removeExpression, this.ConstructorArguments); - Mock.VerifyRemove(this, expression, times, null); + return new VerifyResult(this, Mock.VerifyRemove(this, expression, times, null)); } /// @@ -1272,12 +1304,13 @@ public void VerifyRemove(Action removeExpression, Times times) /// /// The invocation was not called the number of times specified by . /// - public void VerifyRemove(Action removeExpression, Func times) + /// A list of matching invocations + public IVerifyResult VerifyRemove(Action removeExpression, Func times) { Guard.NotNull(removeExpression, nameof(removeExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(removeExpression, this.ConstructorArguments); - Mock.VerifyRemove(this, expression, times(), null); + return new VerifyResult(this, Mock.VerifyRemove(this, expression, times(), null)); } /// @@ -1286,12 +1319,13 @@ public void VerifyRemove(Action removeExpression, Func times) /// Expression to verify. /// Message to show if verification fails. /// The invocation was not performed on the mock. - public void VerifyRemove(Action removeExpression, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyRemove(Action removeExpression, string failMessage) { Guard.NotNull(removeExpression, nameof(removeExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(removeExpression, this.ConstructorArguments); - Mock.VerifyRemove(this, expression, Times.AtLeastOnce(), failMessage); + return new VerifyResult(this, Mock.VerifyRemove(this, expression, Times.AtLeastOnce(), failMessage)); } /// @@ -1303,12 +1337,13 @@ public void VerifyRemove(Action removeExpression, string failMessage) /// /// The invocation was not called the number of times specified by . /// - public void VerifyRemove(Action removeExpression, Times times, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyRemove(Action removeExpression, Times times, string failMessage) { Guard.NotNull(removeExpression, nameof(removeExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(removeExpression, this.ConstructorArguments); - Mock.VerifyRemove(this, expression, times, failMessage); + return new VerifyResult(this, Mock.VerifyRemove(this, expression, times, failMessage)); } /// @@ -1320,12 +1355,13 @@ public void VerifyRemove(Action removeExpression, Times times, string failMes /// /// The invocation was not called the number of times specified by . /// - public void VerifyRemove(Action removeExpression, Func times, string failMessage) + /// A list of matching invocations + public IVerifyResult VerifyRemove(Action removeExpression, Func times, string failMessage) { Guard.NotNull(removeExpression, nameof(removeExpression)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(removeExpression, this.ConstructorArguments); - Mock.VerifyRemove(this, expression, times(), failMessage); + return new VerifyResult(this, Mock.VerifyRemove(this, expression, times(), failMessage)); } /// diff --git a/src/Moq/Protected/IProtectedAsMock.cs b/src/Moq/Protected/IProtectedAsMock.cs index 878faaf3b..17e0148a6 100644 --- a/src/Moq/Protected/IProtectedAsMock.cs +++ b/src/Moq/Protected/IProtectedAsMock.cs @@ -2,6 +2,7 @@ // All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq.Expressions; @@ -115,7 +116,8 @@ public interface IProtectedAsMock : IFluentInterface /// /// Message to include in the thrown if verification fails. /// The specified invocation did not occur (or did not occur the specified number of times). - void Verify(Expression> expression, Times? times = null, string failMessage = null); + /// A list of matching invocations + IVerifyResult Verify(Expression> expression, Times? times = null, string failMessage = null); /// /// Verifies that a specific invocation matching the given expression was performed on the mock. @@ -129,7 +131,8 @@ public interface IProtectedAsMock : IFluentInterface /// /// Message to include in the thrown if verification fails. /// The specified invocation did not occur (or did not occur the specified number of times). - void Verify(Expression> expression, Times? times = null, string failMessage = null); + /// A list of matching invocations + IVerifyResult Verify(Expression> expression, Times? times = null, string failMessage = null); /// /// Verifies that a property was set on the mock. @@ -143,7 +146,8 @@ public interface IProtectedAsMock : IFluentInterface /// /// The invocation was not called the number of times specified by . /// - void VerifySet(Action setterExpression, Times? times = null, string failMessage = null); + /// A list of matching invocations + IVerifyResult VerifySet(Action setterExpression, Times? times = null, string failMessage = null); /// /// Verifies that a property was read on the mock. @@ -156,6 +160,7 @@ public interface IProtectedAsMock : IFluentInterface /// /// Message to include in the thrown if verification fails. /// The specified invocation did not occur (or did not occur the specified number of times). - void VerifyGet(Expression> expression, Times? times = null, string failMessage = null); + /// A list of matching invocations + IVerifyResult VerifyGet(Expression> expression, Times? times = null, string failMessage = null); } } diff --git a/src/Moq/Protected/IProtectedMock.cs b/src/Moq/Protected/IProtectedMock.cs index 11a448e9e..ae5f99300 100644 --- a/src/Moq/Protected/IProtectedMock.cs +++ b/src/Moq/Protected/IProtectedMock.cs @@ -2,6 +2,7 @@ // All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. using System; +using System.Collections.Generic; using System.ComponentModel; using Moq.Language; @@ -182,7 +183,8 @@ IProtectedAsMock As() /// The number of times a method is allowed to be called. /// The optional arguments for the invocation. If argument matchers are used, /// remember to use rather than . - void Verify(string methodName, Times times, params object[] args); + /// A list of matching invocations + IVerifyResult Verify(string methodName, Times times, params object[] args); /// /// Specifies a verify for a void method with the given , @@ -196,7 +198,8 @@ IProtectedAsMock As() /// The number of times a method is allowed to be called. /// The optional arguments for the invocation. If argument matchers are used, /// remember to use rather than . - void Verify(string methodName, Type[] genericTypeArguments, Times times, params object[] args); + /// A list of matching invocations + IVerifyResult Verify(string methodName, Type[] genericTypeArguments, Times times, params object[] args); /// /// Specifies a verify for a void method with the given , @@ -210,7 +213,8 @@ IProtectedAsMock As() /// Should the parameter types match exactly types that were provided /// The optional arguments for the invocation. If argument matchers are used, /// remember to use rather than . - void Verify(string methodName, Times times, bool exactParameterMatch, params object[] args); + /// A list of matching invocations + IVerifyResult Verify(string methodName, Times times, bool exactParameterMatch, params object[] args); /// /// Specifies a verify for a void method with the given , @@ -225,7 +229,8 @@ IProtectedAsMock As() /// Should the parameter types match exactly types that were provided /// The optional arguments for the invocation. If argument matchers are used, /// remember to use rather than . - void Verify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args); + /// A list of matching invocations + IVerifyResult Verify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args); /// /// Specifies a verify for an invocation on a property or a non void method with the given @@ -238,7 +243,8 @@ IProtectedAsMock As() /// remember to use rather than . /// The number of times a method is allowed to be called. /// The type of return value from the expression. - void Verify(string methodName, Times times, params object[] args); + /// A list of matching invocations + IVerifyResult Verify(string methodName, Times times, params object[] args); /// /// Specifies a verify for an invocation on a property or a non void method with the given @@ -252,7 +258,8 @@ IProtectedAsMock As() /// remember to use rather than . /// The number of times a method is allowed to be called. /// The type of return value from the expression. - void Verify(string methodName, Type[] genericTypeArguments, Times times, params object[] args); + /// A list of matching invocations + IVerifyResult Verify(string methodName, Type[] genericTypeArguments, Times times, params object[] args); /// /// Specifies a verify for an invocation on a property or a non void method with the given @@ -266,7 +273,8 @@ IProtectedAsMock As() /// remember to use rather than . /// The number of times a method is allowed to be called. /// The type of return value from the expression. - void Verify(string methodName, Times times, bool exactParameterMatch, params object[] args); + /// A list of matching invocations + IVerifyResult Verify(string methodName, Times times, bool exactParameterMatch, params object[] args); /// /// Specifies a verify for an invocation on a property or a non void method with the given @@ -281,7 +289,8 @@ IProtectedAsMock As() /// remember to use rather than . /// The number of times a method is allowed to be called. /// The type of return value from the expression. - void Verify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args); + /// A list of matching invocations + IVerifyResult Verify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args); /// /// Specifies a verify for an invocation on a property getter with the given @@ -292,8 +301,9 @@ IProtectedAsMock As() /// The name of the property. /// The number of times a method is allowed to be called. /// The type of the property. + /// A list of matching invocations // TODO should receive args to support indexers - void VerifyGet(string propertyName, Times times); + IVerifyResult VerifyGet(string propertyName, Times times); /// /// Specifies a setup for an invocation on a property setter with the given @@ -306,8 +316,9 @@ IProtectedAsMock As() /// The property value. /// The type of the property. If argument matchers are used, /// remember to use rather than . + /// A list of matching invocations // TODO should receive args to support indexers - void VerifySet(string propertyName, Times times, object value); + IVerifyResult VerifySet(string propertyName, Times times, object value); #endregion } diff --git a/src/Moq/Protected/ProtectedAsMock.cs b/src/Moq/Protected/ProtectedAsMock.cs index c3d61024f..4cdb8f8b5 100644 --- a/src/Moq/Protected/ProtectedAsMock.cs +++ b/src/Moq/Protected/ProtectedAsMock.cs @@ -2,6 +2,7 @@ // All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; @@ -153,7 +154,7 @@ public ISetupSequentialAction SetupSequence(Expression> expressi return new SetupSequencePhrase(setup); } - public void Verify(Expression> expression, Times? times = null, string failMessage = null) + public IVerifyResult Verify(Expression> expression, Times? times = null, string failMessage = null) { Guard.NotNull(expression, nameof(expression)); @@ -167,10 +168,10 @@ public void Verify(Expression> expression, Times? times = null, throw new ArgumentException(ex.Message, nameof(expression)); } - Mock.Verify(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage); + return new VerifyResult(this.mock, Mock.Verify(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage)); } - public void Verify(Expression> expression, Times? times = null, string failMessage = null) + public IVerifyResult Verify(Expression> expression, Times? times = null, string failMessage = null) { Guard.NotNull(expression, nameof(expression)); @@ -184,18 +185,18 @@ public void Verify(Expression> expression, Times throw new ArgumentException(ex.Message, nameof(expression)); } - Mock.Verify(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage); + return new VerifyResult(this.mock, Mock.Verify(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage)); } - public void VerifySet(Action setterExpression, Times? times = null, string failMessage = null) + public IVerifyResult VerifySet(Action setterExpression, Times? times = null, string failMessage = null) { Guard.NotNull(setterExpression, nameof(setterExpression)); var rewrittenExpression = ReconstructAndReplaceSetter(setterExpression); - Mock.VerifySet(mock, rewrittenExpression, times.HasValue ? times.Value : Times.AtLeastOnce(), failMessage); + return new VerifyResult(mock, Mock.VerifySet(mock, rewrittenExpression, times.HasValue ? times.Value : Times.AtLeastOnce(), failMessage)); } - public void VerifyGet(Expression> expression, Times? times = null, string failMessage = null) + public IVerifyResult VerifyGet(Expression> expression, Times? times = null, string failMessage = null) { Guard.NotNull(expression, nameof(expression)); @@ -209,7 +210,7 @@ public void VerifyGet(Expression> expression throw new ArgumentException(ex.Message, nameof(expression)); } - Mock.VerifyGet(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage); + return new VerifyResult(this.mock, Mock.VerifyGet(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage)); } LambdaExpression ReconstructAndReplaceSetter(Action setterExpression) diff --git a/src/Moq/Protected/ProtectedMock.cs b/src/Moq/Protected/ProtectedMock.cs index d6c8e808f..7d6b60bbd 100644 --- a/src/Moq/Protected/ProtectedMock.cs +++ b/src/Moq/Protected/ProtectedMock.cs @@ -201,29 +201,29 @@ ISetupSequentialResult InternalSetupSequence(string methodOrPr #region Verify - public void Verify(string methodName, Times times, object[] args) + public IVerifyResult Verify(string methodName, Times times, object[] args) { - this.InternalVerify(methodName, null, times, false, args); + return this.InternalVerify(methodName, null, times, false, args); } - public void Verify(string methodName, Type[] genericTypeArguments, Times times, params object[] args) + public IVerifyResult Verify(string methodName, Type[] genericTypeArguments, Times times, params object[] args) { Guard.NotNull(genericTypeArguments, nameof(genericTypeArguments)); - this.InternalVerify(methodName, genericTypeArguments, times, false, args); + return this.InternalVerify(methodName, genericTypeArguments, times, false, args); } - public void Verify(string methodName, Times times, bool exactParameterMatch, object[] args) + public IVerifyResult Verify(string methodName, Times times, bool exactParameterMatch, object[] args) { - this.InternalVerify(methodName, null, times, exactParameterMatch, args); + return this.InternalVerify(methodName, null, times, exactParameterMatch, args); } - public void Verify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) + public IVerifyResult Verify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) { Guard.NotNull(genericTypeArguments, nameof(genericTypeArguments)); - this.InternalVerify(methodName, genericTypeArguments, times, exactParameterMatch, args); + return this.InternalVerify(methodName, genericTypeArguments, times, exactParameterMatch, args); } - void InternalVerify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) + IVerifyResult InternalVerify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) { Guard.NotNullOrEmpty(methodName, nameof(methodName)); @@ -231,32 +231,32 @@ void InternalVerify(string methodName, Type[] genericTypeArguments, Times times, ThrowIfMethodMissing(methodName, method, args); ThrowIfPublicMethod(method, typeof(T).Name); - Mock.Verify(mock, GetMethodCall(method, args), times, null); + return new VerifyResult(mock, Mock.Verify(mock, GetMethodCall(method, args), times, null)); } - public void Verify(string methodName, Times times, object[] args) + public IVerifyResult Verify(string methodName, Times times, object[] args) { - this.InternalVerify(methodName, null, times, false, args); + return this.InternalVerify(methodName, null, times, false, args); } - public void Verify(string methodName, Type[] genericTypeArguments, Times times, params object[] args) + public IVerifyResult Verify(string methodName, Type[] genericTypeArguments, Times times, params object[] args) { Guard.NotNull(genericTypeArguments, nameof(genericTypeArguments)); - this.InternalVerify(methodName, genericTypeArguments, times, false, args); + return this.InternalVerify(methodName, genericTypeArguments, times, false, args); } - public void Verify(string methodName, Times times, bool exactParameterMatch, object[] args) + public IVerifyResult Verify(string methodName, Times times, bool exactParameterMatch, object[] args) { - this.InternalVerify(methodName, null, times, exactParameterMatch, args); + return this.InternalVerify(methodName, null, times, exactParameterMatch, args); } - public void Verify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) + public IVerifyResult Verify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) { Guard.NotNull(genericTypeArguments, nameof(genericTypeArguments)); - this.InternalVerify(methodName, genericTypeArguments, times, exactParameterMatch, args); + return this.InternalVerify(methodName, genericTypeArguments, times, exactParameterMatch, args); } - void InternalVerify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) + IVerifyResult InternalVerify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) { Guard.NotNullOrEmpty(methodName, nameof(methodName)); @@ -265,19 +265,18 @@ void InternalVerify(string methodName, Type[] genericTypeArguments, Tim { ThrowIfPublicGetter(property, typeof(T).Name); // TODO should consider property indexers - Mock.VerifyGet(mock, GetMemberAccess(property), times, null); - return; + return new VerifyResult(mock, Mock.VerifyGet(mock, GetMemberAccess(property), times, null)); } var method = GetMethod(methodName, genericTypeArguments, exactParameterMatch, args); ThrowIfMethodMissing(methodName, method, args); ThrowIfPublicMethod(method, typeof(T).Name); - Mock.Verify(mock, GetMethodCall(method, args), times, null); + return new VerifyResult(mock, Mock.Verify(mock, GetMethodCall(method, args), times, null)); } // TODO should receive args to support indexers - public void VerifyGet(string propertyName, Times times) + public IVerifyResult VerifyGet(string propertyName, Times times) { Guard.NotNullOrEmpty(propertyName, nameof(propertyName)); @@ -287,11 +286,11 @@ public void VerifyGet(string propertyName, Times times) Guard.CanRead(property); // TODO should consider property indexers - Mock.VerifyGet(mock, GetMemberAccess(property), times, null); + return new VerifyResult(mock, Mock.VerifyGet(mock, GetMemberAccess(property), times, null)); } // TODO should receive args to support indexers - public void VerifySet(string propertyName, Times times, object value) + public IVerifyResult VerifySet(string propertyName, Times times, object value) { Guard.NotNullOrEmpty(propertyName, nameof(propertyName)); @@ -303,7 +302,7 @@ public void VerifySet(string propertyName, Times times, object value) var expression = GetSetterExpression(property, ToExpressionArg(property.PropertyType, value)); // TODO should consider property indexers // TODO should receive the parameter here - Mock.VerifySet(mock, expression, times, null); + return new VerifyResult(mock, Mock.VerifySet(mock, expression, times, null)); } #endregion diff --git a/src/Moq/VerifyResult.cs b/src/Moq/VerifyResult.cs new file mode 100644 index 000000000..bd86fe744 --- /dev/null +++ b/src/Moq/VerifyResult.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Moq +{ + class VerifyResult : List, IVerifyResult where T : class + { + public Mock Mock { get; } + + public VerifyResult(Mock mock, IEnumerable invocations) : base(invocations) + { + this.Mock = mock; + } + } +}