From 013f0f566000bc144eb732daead73688feaebfa9 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Sun, 17 Jan 2021 18:54:50 +0100 Subject: [PATCH 1/4] `.Returns` callback validation fails for task `.Result` setups --- tests/Moq.Tests/SetupTaskResultFixture.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Moq.Tests/SetupTaskResultFixture.cs b/tests/Moq.Tests/SetupTaskResultFixture.cs index 5b73b1ed9..5950730a9 100644 --- a/tests/Moq.Tests/SetupTaskResultFixture.cs +++ b/tests/Moq.Tests/SetupTaskResultFixture.cs @@ -101,6 +101,15 @@ public async Task Setup__completed_Task__Returns() Assert.Same(Friend, friend); } + [Fact] + public async Task Setup__completed_Task__Returns_callback() + { + var person = new Mock(); + person.Setup(p => p.GetFriendTaskAsync().Result).Returns(() => Friend); + var friend = await person.Object.GetFriendTaskAsync(); + Assert.Same(Friend, friend); + } + [Fact] public async Task Setup__completed_Task__Throws() { @@ -119,6 +128,15 @@ public async Task Setup__completed_ValueTask__Returns() Assert.Same(Friend, friend); } + [Fact] + public async Task Setup__completed_ValueTask__Returns_callback() + { + var person = new Mock(); + person.Setup(p => p.GetFriendValueTaskAsync().Result).Returns(()=> Friend); + var friend = await person.Object.GetFriendValueTaskAsync(); + Assert.Same(Friend, friend); + } + [Fact] public async Task Setup__completed_ValueTask__Throws() { From 22237a6ce049270aa1c1752220f8b34487a97dc1 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Sun, 17 Jan 2021 19:40:40 +0100 Subject: [PATCH 2/4] Lower expected return type (if needed) during validation --- src/Moq/MethodCall.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Moq/MethodCall.cs b/src/Moq/MethodCall.cs index 02209c4e4..0d8a8c315 100644 --- a/src/Moq/MethodCall.cs +++ b/src/Moq/MethodCall.cs @@ -310,7 +310,8 @@ void ValidateCallback(Delegate callback) throw new ArgumentException(Resources.InvalidReturnsCallbackNotADelegateWithReturnType); } - var expectedReturnType = this.Method.ReturnType; + var expectedReturnType = this.Expectation.HasResultExpression(out var awaitable) ? awaitable.ResultType + : this.Method.ReturnType; if (!expectedReturnType.IsAssignableFrom(actualReturnType)) { From c13c0eb711ca8cce1c261bee0c0fa5dfe29d53bb Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Sun, 17 Jan 2021 19:44:47 +0100 Subject: [PATCH 3/4] Improve validation error formatting --- src/Moq/MethodCall.cs | 6 ++++-- src/Moq/Properties/Resources.Designer.cs | 2 +- src/Moq/Properties/Resources.resx | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Moq/MethodCall.cs b/src/Moq/MethodCall.cs index 0d8a8c315..276674970 100644 --- a/src/Moq/MethodCall.cs +++ b/src/Moq/MethodCall.cs @@ -13,6 +13,8 @@ using Moq.Behaviors; using Moq.Properties; +using TypeNameFormatter; + namespace Moq { internal sealed partial class MethodCall : SetupWithOutParameterSupport @@ -322,8 +324,8 @@ void ValidateCallback(Delegate callback) string.Format( CultureInfo.CurrentCulture, Resources.InvalidCallbackReturnTypeMismatch, - expectedReturnType, - actualReturnType)); + expectedReturnType.GetFormattedName(), + actualReturnType.GetFormattedName())); } } } diff --git a/src/Moq/Properties/Resources.Designer.cs b/src/Moq/Properties/Resources.Designer.cs index 7fce6d353..24df7ac44 100644 --- a/src/Moq/Properties/Resources.Designer.cs +++ b/src/Moq/Properties/Resources.Designer.cs @@ -187,7 +187,7 @@ internal static string InvalidCallbackParameterMismatch { } /// - /// Looks up a localized string similar to Invalid callback. Setup on method with return type ({0}) cannot invoke callback with return type ({1}).. + /// Looks up a localized string similar to Invalid callback. Setup on method with return type '{0}' cannot invoke callback with return type '{1}'.. /// internal static string InvalidCallbackReturnTypeMismatch { get { diff --git a/src/Moq/Properties/Resources.resx b/src/Moq/Properties/Resources.resx index 09e0223ca..4ecfacf05 100644 --- a/src/Moq/Properties/Resources.resx +++ b/src/Moq/Properties/Resources.resx @@ -285,7 +285,7 @@ Remember that there's no generics covariance in the CLR, so your object must be Type {0} does not have matching protected member: {1} - Invalid callback. Setup on method with return type ({0}) cannot invoke callback with return type ({1}). + Invalid callback. Setup on method with return type '{0}' cannot invoke callback with return type '{1}'. Invalid callback. Setup on method with {0} parameter(s) cannot invoke callback with different number of parameters ({1}). From 6560d831791eb2c4037c099db70370c3037eac22 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Sun, 17 Jan 2021 19:45:31 +0100 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e0449e90..0e1f76c7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1 * `AmbiguousMatchException` raised when interface has property indexer besides property in VB. (@mujdatdinc, #1129) * Interface default methods are ignored (@hahn-kev, #972) +* Callback validation too strict when setting up a task's `.Result` property (@stakx, #1132) + ## 4.16.0 (2021-01-16)