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)
diff --git a/src/Moq/MethodCall.cs b/src/Moq/MethodCall.cs
index 02209c4e4..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
@@ -310,7 +312,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))
{
@@ -321,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}).
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()
{