Skip to content

Commit 94867a0

Browse files
authored
Merge pull request #606 from leeoades/bugfix/really-guarantee-sync-context-lost
Created a custom awaiter that guarantees that we complete on a different threadpool thread.
2 parents 7223486 + 4941336 commit 94867a0

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

test/Stateless.Tests/Stateless.Tests.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
</PropertyGroup>
2121

2222
<ItemGroup>
23-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
23+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
2424
<PackageReference Include="xunit" Version="2.4.0" />
2525
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
2626
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />

test/Stateless.Tests/SynchronizationContextFixture.cs

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using System;
12
using System.Collections.Generic;
3+
using System.Runtime.CompilerServices;
24
using System.Threading;
35
using System.Threading.Tasks;
46
using Xunit;
@@ -41,15 +43,16 @@ private void CaptureSyncContext()
4143

4244
private async Task LoseSyncContext()
4345
{
44-
await Task.Run(() => { }).ConfigureAwait(false); // Switch synchronization context and continue
46+
await new CompletesOnDifferentThreadAwaitable(); // Switch synchronization context and continue
4547
Assert.NotEqual(_customSynchronizationContext, SynchronizationContext.Current);
4648
}
4749

4850
/// <summary>
49-
/// Tests capture the SynchronizationContext at various points through out their execution.
50-
/// This asserts that every capture is the expected SynchronizationContext instance and that is hasn't been lost.
51+
/// Tests capture the SynchronizationContext at various points throughout their execution.
52+
/// This asserts that every capture is the expected SynchronizationContext instance and that it hasn't been lost.
5153
/// </summary>
5254
/// <param name="numberOfExpectedCalls">Ensure that we have the expected number of captures</param>
55+
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
5356
private void AssertSyncContextAlwaysRetained(int numberOfExpectedCalls)
5457
{
5558
Assert.Equal(numberOfExpectedCalls, _capturedSyncContext.Count);
@@ -154,7 +157,7 @@ public async Task Multiple_Deactivations_should_retain_SyncContext()
154157

155158
// ASSERT
156159
AssertSyncContextAlwaysRetained(3);
157-
}
160+
}
158161

159162
[Fact]
160163
public async Task Multiple_OnEntry_should_retain_SyncContext()
@@ -338,4 +341,21 @@ public async Task InternalTransition_firing_a_sync_action_should_retain_SyncCont
338341
// ASSERT
339342
AssertSyncContextAlwaysRetained(1);
340343
}
344+
345+
private class CompletesOnDifferentThreadAwaitable
346+
{
347+
public CompletesOnDifferentThreadAwaiter GetAwaiter() => new();
348+
349+
internal class CompletesOnDifferentThreadAwaiter : INotifyCompletion
350+
{
351+
public void GetResult() { }
352+
353+
public bool IsCompleted => false;
354+
355+
public void OnCompleted(Action continuation)
356+
{
357+
ThreadPool.QueueUserWorkItem(_ => continuation());
358+
}
359+
}
360+
}
341361
}

0 commit comments

Comments
 (0)