Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Await anything & custom awaitable types #1123

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1ca6039
Define `Await` operator & show its usage in test
stakx Dec 29, 2020
0792369
`IAwaitableHandler`s wrap & unwrap awaitables
stakx Dec 29, 2020
b3b0109
Awaited setups lift invocation results to awaitables
stakx Dec 30, 2020
a8082a4
Test `.Callback`, `.Throws`, and recursive setups
stakx Dec 29, 2020
40d0130
Only lift result when necessary
stakx Dec 30, 2020
2825207
Duplicate tests for `ValueTask<>`
stakx Dec 29, 2020
b960239
Add `IAwaitableHandler` for `ValueTask<>`
stakx Dec 29, 2020
cfb3f8f
Add tests for non-generic `Task` and `ValueTask`
stakx Dec 29, 2020
84acfdf
Add `IAwaitableHandler` for `Task` and `ValueTask`
stakx Dec 30, 2020
88c4438
Add tests for `SetupSequence`'s `Pass`, `Returns`, and `Throws`
stakx Dec 30, 2020
ef77bbd
Add test for `Await` in `Mock.Of`
stakx Dec 30, 2020
a0ffad9
`Await` should support 'await anything'
stakx Dec 30, 2020
2d9a7bb
Enable custom `IAwaitHandler`s & `Await` methods
stakx Dec 30, 2020
f2146b2
Create abstract base class `AwaitableHandler`
stakx Dec 30, 2020
058eb0a
Delegate to `AwaitableHandler`s where appropriate
stakx Dec 30, 2020
48270bc
Implement support for 'await anything'
stakx Dec 30, 2020
8a90122
Add tests for `SetupSet`
stakx Dec 30, 2020
35832e6
Infer awaits during delegate-to-expression reconstruction
stakx Dec 30, 2020
2b7cb48
Add one more test & clean up another
stakx Dec 30, 2020
7bd534e
Resolve a (very serious!) CodeFactor issue
stakx Dec 30, 2020
8528b9a
Ensure any await is visible in setup expressions
stakx Dec 30, 2020
c996878
Update the changelog
stakx Dec 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/Moq/ExpressionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,13 @@ void Split(Expression e, out Expression r /* remainder */, out InvocationShape p
else if (methodCallExpression.IsAwait(out var awaitableHandler))
{
Split(methodCallExpression.Arguments.Single(), out r, out p);
p = new InvocationShape(
expression:
Expression.Lambda(
new AwaitExpression(methodCallExpression.Arguments.Single(), awaitableHandler),
p.Expression.Parameters),
method: p.Method,
arguments: p.Arguments);
p.AwaitableHandler = awaitableHandler;
}
else
Expand Down
24 changes: 24 additions & 0 deletions tests/Moq.Tests/AwaitOperatorFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

Expand Down Expand Up @@ -589,6 +590,29 @@ public async Task Mock_Of()
Assert.Equal(expectedSameName, actualName);
}

[Fact]
public void Await__is_represented__in_setup_Expression()
{
var mock = new Mock<IPerson>();
mock.Setup(m => Await(m.DoSomethingTaskAsync()));
var setup = mock.Setups.Last();
Assert.Contains("aWAiT", setup.Expression.ToStringFixed(), StringComparison.OrdinalIgnoreCase);
// ^^^^^
// NOTE: Depending on the exact scenario, the `Await` method name may get converted to
// a faux `await` keyword (e.g. with `SetupSet`). Right now, we don't care too much about
// that slight loss of accuracy, as long as a clue for the occurred await remains.
Comment on lines +601 to +603
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps, for overall consistency, all setup expressions should be post-processed to rewrite Await calls as (await …). That might not be worth the trouble if we later decide to go in the oppsosite direction (i.e. if we want to try and preserve the original Await method identity in expression trees reconstructed from delegates).

}

[Fact]
public void Await__is_represented__in_setup_OriginalExpression()
{
// NOTE: The note in the test above applies here, too.
var mock = new Mock<IPerson>();
mock.Setup(m => Await(m.DoSomethingTaskAsync()));
var setup = mock.Setups.Last();
Assert.Contains("await", setup.OriginalExpression.ToStringFixed(), StringComparison.OrdinalIgnoreCase);
}

public interface IPerson
{
IPerson Friend { get; }
Expand Down