/// <summary> /// Returns the exception to be thrown when <see cref="Mock.Verify"/> finds no invocations (or the wrong number of invocations) that match the specified expectation. /// </summary> internal static MockException NoMatchingCalls( Mock rootMock, LambdaExpression expression, string failMessage, Times times, int callCount) { var message = new StringBuilder(); message.AppendLine(times.GetExceptionMessage(failMessage, expression.PartialMatcherAwareEval().ToStringFixed(), callCount)) .AppendLine(Resources.PerformedInvocations) .AppendLine(); var visitedMocks = new HashSet <Mock>(); var mocks = new Queue <Mock>(); mocks.Enqueue(rootMock); while (mocks.Any()) { var mock = mocks.Dequeue(); if (visitedMocks.Contains(mock)) { continue; } visitedMocks.Add(mock); message.AppendLine(mock == rootMock ? $" {mock} ({expression.Parameters[0].Name}):" : $" {mock}:"); var invocations = mock.MutableInvocations.ToArray(); if (invocations.Any()) { message.AppendLine(); foreach (var invocation in invocations) { message.Append($" {invocation}"); if (invocation.Method.ReturnType != typeof(void) && Unwrap.ResultIfCompletedTask(invocation.ReturnValue) is IMocked mocked) { var innerMock = mocked.Mock; mocks.Enqueue(innerMock); message.Append($" => {innerMock}"); } message.AppendLine(); } } else { message.AppendLine($" {Resources.NoInvocationsPerformed}"); } message.AppendLine(); } return(new MockException(MockExceptionReasons.NoMatchingCalls, message.TrimEnd().AppendLine().ToString())); }
/// <summary> /// Recursively unwraps the result of completed <see cref="Task{TResult}"/> or <see cref="ValueTask{TResult}"/> instances. /// If the given value is not a task, the value itself is returned. /// </summary> /// <param name="obj">The value to be unwrapped.</param> public static object ResultIfCompletedTask(object obj) { if (obj != null) { var objType = obj.GetType(); if (objType.IsGenericType) { var genericTypeDefinition = objType.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(Task <>) || genericTypeDefinition == typeof(ValueTask <>)) { var isCompleted = (bool)objType.GetProperty("IsCompleted").GetValue(obj, null); if (isCompleted) { try { var innerObj = objType.GetProperty("Result").GetValue(obj, null); return(Unwrap.ResultIfCompletedTask(innerObj)); } catch { // We end up here when the task has completed, but not successfully; // e.g. when an exception was thrown. There's no return value to unwrap, // so fall through. } } } } } return(obj); }
public bool ReturnsInnerMock(out Mock mock) { if (this.TryGetReturnValue(out var returnValue) && Unwrap.ResultIfCompletedTask(returnValue) is IMocked mocked) { mock = mocked.Mock; return(true); }
public InnerMockSetup(Expression originalExpression, Mock mock, InvocationShape expectation, object returnValue) : base(originalExpression, mock, expectation) { Debug.Assert(Unwrap.ResultIfCompletedTask(returnValue) is IMocked); this.returnValue = returnValue; this.MarkAsVerifiable(); }
public bool?ReturnsMock(out Mock mock) { if (this.TryGetReturnValue(out var returnValue)) { if (Unwrap.ResultIfCompletedTask(returnValue) is IMocked mocked) { mock = mocked.Mock; return(true); } else { mock = null; return(false); } } else { mock = null; return(null); } }
/// <summary> /// Recursively unwraps the result of completed <see cref="Task{TResult}"/> or <see cref="ValueTask{TResult}"/> instances. /// If the given value is not a task, the value itself is returned. /// </summary> /// <param name="obj">The value to be unwrapped.</param> public static object ResultIfCompletedTask(object obj) { if (obj != null) { var objType = obj.GetType(); if (objType.IsGenericType) { var genericTypeDefinition = objType.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(Task <>) || genericTypeDefinition == typeof(ValueTask <>)) { var isCompleted = (bool)objType.GetProperty("IsCompleted").GetValue(obj, null); if (isCompleted) { var innerObj = objType.GetProperty("Result").GetValue(obj, null); return(Unwrap.ResultIfCompletedTask(innerObj)); } } } } return(obj); }