Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit e7b239c

Browse files
committed
Improvements to the AsyncTaskMethodBuilder tests
* Be sure to safely restore the synchronization context in a finally block when it is modified * Fix hanging test * Add additional coverage for completion cache, with Stephen's suggested test cases
1 parent a941521 commit e7b239c

File tree

1 file changed

+156
-84
lines changed

1 file changed

+156
-84
lines changed

src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs

Lines changed: 156 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,37 @@ public class AsyncTaskMethodBuilderTests
1818
public static void VoidMethodBuilder_TrackedContext()
1919
{
2020
SynchronizationContext previousContext = SynchronizationContext.Current;
21-
var trackedContext = new TrackOperationsSynchronizationContext();
22-
SynchronizationContext.SetSynchronizationContext(trackedContext);
23-
24-
// TrackedCount should increase as Create() is called, and decrease as SetResult() is called.
25-
26-
// Completing in opposite order as created.
27-
var avmb1 = AsyncVoidMethodBuilder.Create();
28-
Assert.Equal(1, trackedContext.TrackedCount);
29-
var avmb2 = AsyncVoidMethodBuilder.Create();
30-
Assert.Equal(2, trackedContext.TrackedCount);
31-
avmb2.SetResult();
32-
Assert.Equal(1, trackedContext.TrackedCount);
33-
avmb1.SetResult();
34-
Assert.Equal(0, trackedContext.TrackedCount);
35-
36-
// Completing in same order as created
37-
avmb1 = AsyncVoidMethodBuilder.Create();
38-
Assert.Equal(1, trackedContext.TrackedCount);
39-
avmb2 = AsyncVoidMethodBuilder.Create();
40-
Assert.Equal(2, trackedContext.TrackedCount);
41-
avmb1.SetResult();
42-
Assert.Equal(1, trackedContext.TrackedCount);
43-
avmb2.SetResult();
44-
Assert.Equal(0, trackedContext.TrackedCount);
45-
46-
SynchronizationContext.SetSynchronizationContext(previousContext);
21+
try
22+
{
23+
var trackedContext = new TrackOperationsSynchronizationContext();
24+
SynchronizationContext.SetSynchronizationContext(trackedContext);
25+
26+
// TrackedCount should increase as Create() is called, and decrease as SetResult() is called.
27+
28+
// Completing in opposite order as created.
29+
var avmb1 = AsyncVoidMethodBuilder.Create();
30+
Assert.Equal(1, trackedContext.TrackedCount);
31+
var avmb2 = AsyncVoidMethodBuilder.Create();
32+
Assert.Equal(2, trackedContext.TrackedCount);
33+
avmb2.SetResult();
34+
Assert.Equal(1, trackedContext.TrackedCount);
35+
avmb1.SetResult();
36+
Assert.Equal(0, trackedContext.TrackedCount);
37+
38+
// Completing in same order as created
39+
avmb1 = AsyncVoidMethodBuilder.Create();
40+
Assert.Equal(1, trackedContext.TrackedCount);
41+
avmb2 = AsyncVoidMethodBuilder.Create();
42+
Assert.Equal(2, trackedContext.TrackedCount);
43+
avmb1.SetResult();
44+
Assert.Equal(1, trackedContext.TrackedCount);
45+
avmb2.SetResult();
46+
Assert.Equal(0, trackedContext.TrackedCount);
47+
}
48+
finally
49+
{
50+
SynchronizationContext.SetSynchronizationContext(previousContext);
51+
}
4752
}
4853

4954
// Test not having a sync context with successful completion (SetResult)
@@ -83,14 +88,20 @@ public static void TaskMethodBuilder_DoesNotTouchSyncContext()
8388
{
8489
// Verify that AsyncTaskMethodBuilder is not touching sync context
8590
SynchronizationContext previousContext = SynchronizationContext.Current;
86-
var trackedContext = new TrackOperationsSynchronizationContext();
87-
SynchronizationContext.SetSynchronizationContext(trackedContext);
91+
try
92+
{
93+
var trackedContext = new TrackOperationsSynchronizationContext();
94+
SynchronizationContext.SetSynchronizationContext(trackedContext);
8895

89-
var atmb = AsyncTaskMethodBuilder.Create();
90-
Assert.Equal(0, trackedContext.TrackedCount);
91-
atmb.SetResult();
92-
Assert.Equal(0, trackedContext.TrackedCount);
93-
SynchronizationContext.SetSynchronizationContext(previousContext);
96+
var atmb = AsyncTaskMethodBuilder.Create();
97+
Assert.Equal(0, trackedContext.TrackedCount);
98+
atmb.SetResult();
99+
Assert.Equal(0, trackedContext.TrackedCount);
100+
}
101+
finally
102+
{
103+
SynchronizationContext.SetSynchronizationContext(previousContext);
104+
}
94105
}
95106

96107
// AsyncTaskMethodBuilder<T>
@@ -112,20 +123,24 @@ public static void TaskMethodBuilderT_DoesNotTouchSyncContext()
112123
{
113124
// Verify that AsyncTaskMethodBuilder<T> is not touching sync context
114125
SynchronizationContext previousContext = SynchronizationContext.Current;
115-
var trackedContext = new TrackOperationsSynchronizationContext();
116-
SynchronizationContext.SetSynchronizationContext(trackedContext);
117-
118-
var atmb = AsyncTaskMethodBuilder<string>.Create();
119-
Assert.Equal(0, trackedContext.TrackedCount);
120-
atmb.SetResult("async");
121-
Assert.Equal(0, trackedContext.TrackedCount);
126+
try
127+
{
128+
var trackedContext = new TrackOperationsSynchronizationContext();
129+
SynchronizationContext.SetSynchronizationContext(trackedContext);
122130

123-
SynchronizationContext.SetSynchronizationContext(previousContext);
131+
var atmb = AsyncTaskMethodBuilder<string>.Create();
132+
Assert.Equal(0, trackedContext.TrackedCount);
133+
atmb.SetResult("async");
134+
Assert.Equal(0, trackedContext.TrackedCount);
135+
}
136+
finally
137+
{
138+
SynchronizationContext.SetSynchronizationContext(previousContext);
139+
}
124140
}
125141

126142
// Incorrect usage for AsyncTaskMethodBuilder
127143
[Fact]
128-
[ActiveIssue("Hangs")]
129144
public static void TaskMethodBuilder_IncorrectUsage()
130145
{
131146
var atmb = new AsyncTaskMethodBuilder();
@@ -134,11 +149,11 @@ public static void TaskMethodBuilder_IncorrectUsage()
134149

135150
// Incorrect usage for AsyncVoidMethodBuilder
136151
[Fact]
137-
[ActiveIssue("Hangs")]
138152
public static void VoidMethodBuilder_IncorrectUsage()
139153
{
140154
var avmb = AsyncVoidMethodBuilder.Create();
141155
Assert.Throws<ArgumentNullException>(() => { avmb.SetException(null); });
156+
avmb.SetResult();
142157
}
143158

144159
// Creating a task builder, building it, completing it successfully, and making sure it can't be reset
@@ -221,39 +236,43 @@ public static void AsyncMethodBuilderCreate_SetExceptionTest2()
221236
// Test captured sync context with exceptional completion
222237

223238
SynchronizationContext previousContext = SynchronizationContext.Current;
224-
225-
var trackedContext = new TrackOperationsSynchronizationContext();
226-
SynchronizationContext.SetSynchronizationContext(trackedContext);
227-
228-
// Completing in opposite order as created
229-
var avmb1 = AsyncVoidMethodBuilder.Create();
230-
Assert.Equal(1, trackedContext.TrackedCount);
231-
var avmb2 = AsyncVoidMethodBuilder.Create();
232-
Assert.Equal(2, trackedContext.TrackedCount);
233-
avmb2.SetException(new InvalidOperationException("uh oh 1"));
234-
Assert.Equal(1, trackedContext.TrackedCount);
235-
avmb1.SetException(new InvalidCastException("uh oh 2"));
236-
Assert.Equal(0, trackedContext.TrackedCount);
237-
238-
Assert.Equal(2, trackedContext.PostExceptions.Count);
239-
Assert.IsType<InvalidOperationException>(trackedContext.PostExceptions[0]);
240-
Assert.IsType<InvalidCastException>(trackedContext.PostExceptions[1]);
241-
242-
// Completing in same order as created
243-
var avmb3 = AsyncVoidMethodBuilder.Create();
244-
Assert.Equal(1, trackedContext.TrackedCount);
245-
var avmb4 = AsyncVoidMethodBuilder.Create();
246-
Assert.Equal(2, trackedContext.TrackedCount);
247-
avmb3.SetException(new InvalidOperationException("uh oh 3"));
248-
Assert.Equal(1, trackedContext.TrackedCount);
249-
avmb4.SetException(new InvalidCastException("uh oh 4"));
250-
Assert.Equal(0, trackedContext.TrackedCount);
251-
252-
Assert.Equal(4, trackedContext.PostExceptions.Count);
253-
Assert.IsType<InvalidOperationException>(trackedContext.PostExceptions[2]);
254-
Assert.IsType<InvalidCastException>(trackedContext.PostExceptions[3]);
255-
256-
SynchronizationContext.SetSynchronizationContext(previousContext);
239+
try
240+
{
241+
var trackedContext = new TrackOperationsSynchronizationContext();
242+
SynchronizationContext.SetSynchronizationContext(trackedContext);
243+
244+
// Completing in opposite order as created
245+
var avmb1 = AsyncVoidMethodBuilder.Create();
246+
Assert.Equal(1, trackedContext.TrackedCount);
247+
var avmb2 = AsyncVoidMethodBuilder.Create();
248+
Assert.Equal(2, trackedContext.TrackedCount);
249+
avmb2.SetException(new InvalidOperationException("uh oh 1"));
250+
Assert.Equal(1, trackedContext.TrackedCount);
251+
avmb1.SetException(new InvalidCastException("uh oh 2"));
252+
Assert.Equal(0, trackedContext.TrackedCount);
253+
254+
Assert.Equal(2, trackedContext.PostExceptions.Count);
255+
Assert.IsType<InvalidOperationException>(trackedContext.PostExceptions[0]);
256+
Assert.IsType<InvalidCastException>(trackedContext.PostExceptions[1]);
257+
258+
// Completing in same order as created
259+
var avmb3 = AsyncVoidMethodBuilder.Create();
260+
Assert.Equal(1, trackedContext.TrackedCount);
261+
var avmb4 = AsyncVoidMethodBuilder.Create();
262+
Assert.Equal(2, trackedContext.TrackedCount);
263+
avmb3.SetException(new InvalidOperationException("uh oh 3"));
264+
Assert.Equal(1, trackedContext.TrackedCount);
265+
avmb4.SetException(new InvalidCastException("uh oh 4"));
266+
Assert.Equal(0, trackedContext.TrackedCount);
267+
268+
Assert.Equal(4, trackedContext.PostExceptions.Count);
269+
Assert.IsType<InvalidOperationException>(trackedContext.PostExceptions[2]);
270+
Assert.IsType<InvalidCastException>(trackedContext.PostExceptions[3]);
271+
}
272+
finally
273+
{
274+
SynchronizationContext.SetSynchronizationContext(previousContext);
275+
}
257276
}
258277

259278
// Creating a task builder, building it, completing it faulted, and making sure it can't be reset
@@ -324,6 +343,53 @@ public static void TaskMethodBuilderT_TaskIsCached()
324343
Assert.Same(t1, t2);
325344
}
326345

346+
[Fact]
347+
public static void TaskMethodBuilder_UsesCompletedCache()
348+
{
349+
var atmb1 = new AsyncTaskMethodBuilder();
350+
var atmb2 = new AsyncTaskMethodBuilder();
351+
atmb1.SetResult();
352+
atmb2.SetResult();
353+
Assert.Same(atmb1.Task, atmb2.Task);
354+
}
355+
356+
[Theory]
357+
[InlineData(true)]
358+
[InlineData(false)]
359+
public static void TaskMethodBuilderBoolean_UsesCompletedCache(bool result)
360+
{
361+
TaskMethodBuilderT_UsesCompletedCache(result, true);
362+
}
363+
364+
[Theory]
365+
[InlineData(0, true)]
366+
[InlineData(5, true)]
367+
[InlineData(-5, false)]
368+
[InlineData(42, false)]
369+
public static void TaskMethodBuilderInt32_UsesCompletedCache(int result, bool shouldBeCached)
370+
{
371+
TaskMethodBuilderT_UsesCompletedCache(result, shouldBeCached);
372+
}
373+
374+
[Theory]
375+
[InlineData((string)null, true)]
376+
[InlineData("test", false)]
377+
public static void TaskMethodBuilderRef_UsesCompletedCache(string result, bool shouldBeCached)
378+
{
379+
TaskMethodBuilderT_UsesCompletedCache(result, shouldBeCached);
380+
}
381+
382+
private static void TaskMethodBuilderT_UsesCompletedCache<T>(T result, bool shouldBeCached)
383+
{
384+
var atmb1 = new AsyncTaskMethodBuilder<T>();
385+
var atmb2 = new AsyncTaskMethodBuilder<T>();
386+
387+
atmb1.SetResult(result);
388+
atmb2.SetResult(result);
389+
390+
Assert.Equal(shouldBeCached, object.ReferenceEquals(atmb1.Task, atmb2.Task));
391+
}
392+
327393
[Fact]
328394
public static void Tcs_ValidateFaultedTask()
329395
{
@@ -355,14 +421,20 @@ public static void TaskMethodBuilderT_ValidateFaultedTask()
355421
public static void TrackedSyncContext_ValidateException()
356422
{
357423
SynchronizationContext previousContext = SynchronizationContext.Current;
358-
var tosc = new TrackOperationsSynchronizationContext();
359-
SynchronizationContext.SetSynchronizationContext(tosc);
360-
var avmb = AsyncVoidMethodBuilder.Create();
361-
try { throw new InvalidOperationException(); }
362-
catch (Exception exc) { avmb.SetException(exc); }
363-
Assert.NotEmpty(tosc.PostExceptions);
364-
ValidateException(tosc.PostExceptions[0]);
365-
SynchronizationContext.SetSynchronizationContext(previousContext);
424+
try
425+
{
426+
var tosc = new TrackOperationsSynchronizationContext();
427+
SynchronizationContext.SetSynchronizationContext(tosc);
428+
var avmb = AsyncVoidMethodBuilder.Create();
429+
try { throw new InvalidOperationException(); }
430+
catch (Exception exc) { avmb.SetException(exc); }
431+
Assert.NotEmpty(tosc.PostExceptions);
432+
ValidateException(tosc.PostExceptions[0]);
433+
}
434+
finally
435+
{
436+
SynchronizationContext.SetSynchronizationContext(previousContext);
437+
}
366438
}
367439

368440
// Running tasks with exceptions.

0 commit comments

Comments
 (0)