Skip to content

Commit fdda4c6

Browse files
committed
Add more unit tests for synchronous exceptions
1 parent 923d479 commit fdda4c6

File tree

2 files changed

+133
-4
lines changed

2 files changed

+133
-4
lines changed

tests/CommunityToolkit.Mvvm.UnitTests/Test_AsyncRelayCommand.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,35 @@ private static async Task Test_AsyncRelayCommand_AllowConcurrentExecutions_TestL
321321
Assert.AreSame(args.Item2, EventArgs.Empty);
322322
}
323323

324+
[TestMethod]
325+
public void Test_AsyncRelayCommand_EnsureExceptionThrown_Synchronously()
326+
{
327+
Exception? executeException = null;
328+
329+
AsyncRelayCommand command = new(async () =>
330+
{
331+
await Task.CompletedTask;
332+
333+
throw new Exception(nameof(Test_AsyncRelayCommand_EnsureExceptionThrown_Synchronously));
334+
});
335+
336+
try
337+
{
338+
AsyncContext.Run(async () =>
339+
{
340+
command.Execute(null);
341+
342+
await Task.Delay(500);
343+
});
344+
}
345+
catch (Exception e)
346+
{
347+
executeException = e;
348+
}
349+
350+
Assert.AreEqual(nameof(Test_AsyncRelayCommand_EnsureExceptionThrown_Synchronously), executeException?.Message);
351+
}
352+
324353
// See https://github.com/CommunityToolkit/dotnet/pull/251
325354
[TestMethod]
326355
public async Task Test_AsyncRelayCommand_EnsureExceptionThrown()
@@ -384,6 +413,32 @@ async void TestCallback(Action throwAction, Action completeAction)
384413
Assert.IsTrue(success);
385414
}
386415

416+
[TestMethod]
417+
public async Task Test_AsyncRelayCommand_ThrowingTaskBubblesToUnobservedTaskException_Synchronously()
418+
{
419+
static async Task TestMethodAsync(Action action)
420+
{
421+
await Task.CompletedTask;
422+
423+
action();
424+
}
425+
426+
async void TestCallback(Action throwAction, Action completeAction)
427+
{
428+
AsyncRelayCommand command = new(() => TestMethodAsync(throwAction), AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
429+
430+
command.Execute(null);
431+
432+
await Task.Delay(200);
433+
434+
completeAction();
435+
}
436+
437+
bool success = await TaskSchedulerTestHelper.IsExceptionBubbledUpToUnobservedTaskExceptionAsync(TestCallback);
438+
439+
Assert.IsTrue(success);
440+
}
441+
387442
// See https://github.com/CommunityToolkit/dotnet/issues/108
388443
[TestMethod]
389444
public void Test_AsyncRelayCommand_ExecuteDoesNotRaiseCanExecuteChanged()

tests/CommunityToolkit.Mvvm.UnitTests/Test_AsyncRelayCommand{T}.cs

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,42 @@ private static async Task Test_AsyncRelayCommandOfT_AllowConcurrentExecutions_Te
242242
_ = Assert.ThrowsException<InvalidCastException>(() => command.Execute(new object()));
243243
}
244244

245+
[TestMethod]
246+
public void Test_AsyncRelayCommandOfT_EnsureExceptionThrown_Synchronously()
247+
{
248+
Exception? executeException = null;
249+
250+
AsyncRelayCommand<int> command = new(async delay =>
251+
{
252+
await Task.CompletedTask;
253+
254+
throw new Exception(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown_Synchronously));
255+
});
256+
257+
try
258+
{
259+
AsyncContext.Run(async () =>
260+
{
261+
command.Execute((object)42);
262+
263+
await Task.Delay(500);
264+
});
265+
}
266+
catch (Exception e)
267+
{
268+
executeException = e;
269+
}
270+
271+
Assert.AreEqual(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown_Synchronously), executeException?.Message);
272+
}
273+
245274
// See https://github.com/CommunityToolkit/dotnet/pull/251
246275
[TestMethod]
247276
public async Task Test_AsyncRelayCommandOfT_EnsureExceptionThrown()
248277
{
249278
const int delay = 500;
250279

251280
Exception? executeException = null;
252-
Exception? executeTException = null;
253281
Exception? executeAsyncException = null;
254282

255283
AsyncRelayCommand<int> command = new(async delay =>
@@ -273,6 +301,27 @@ public async Task Test_AsyncRelayCommandOfT_EnsureExceptionThrown()
273301
executeException = e;
274302
}
275303

304+
executeAsyncException = await Assert.ThrowsExceptionAsync<Exception>(() => command.ExecuteAsync((object)delay));
305+
306+
Assert.AreEqual(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown), executeException?.Message);
307+
Assert.AreEqual(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown), executeAsyncException?.Message);
308+
}
309+
310+
[TestMethod]
311+
public async Task Test_AsyncRelayCommandOfT_EnsureExceptionThrown_GenericExecute()
312+
{
313+
const int delay = 500;
314+
315+
Exception? executeTException = null;
316+
Exception? executeAsyncException = null;
317+
318+
AsyncRelayCommand<int> command = new(async delay =>
319+
{
320+
await Task.Delay(delay);
321+
322+
throw new Exception(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown_GenericExecute));
323+
});
324+
276325
try
277326
{
278327
AsyncContext.Run(async () =>
@@ -289,9 +338,8 @@ public async Task Test_AsyncRelayCommandOfT_EnsureExceptionThrown()
289338

290339
executeAsyncException = await Assert.ThrowsExceptionAsync<Exception>(() => command.ExecuteAsync(delay));
291340

292-
Assert.AreEqual(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown), executeException?.Message);
293-
Assert.AreEqual(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown), executeTException?.Message);
294-
Assert.AreEqual(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown), executeAsyncException?.Message);
341+
Assert.AreEqual(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown_GenericExecute), executeTException?.Message);
342+
Assert.AreEqual(nameof(Test_AsyncRelayCommandOfT_EnsureExceptionThrown_GenericExecute), executeAsyncException?.Message);
295343
}
296344

297345
[TestMethod]
@@ -320,6 +368,32 @@ async void TestCallback(Action throwAction, Action completeAction)
320368
Assert.IsTrue(success);
321369
}
322370

371+
[TestMethod]
372+
public async Task Test_AsyncRelayCommandOfT_ThrowingTaskBubblesToUnobservedTaskException_Synchronously()
373+
{
374+
static async Task TestMethodAsync(Action action)
375+
{
376+
await Task.CompletedTask;
377+
378+
action();
379+
}
380+
381+
async void TestCallback(Action throwAction, Action completeAction)
382+
{
383+
AsyncRelayCommand<string> command = new(s => TestMethodAsync(throwAction), AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
384+
385+
command.Execute(null);
386+
387+
await Task.Delay(200);
388+
389+
completeAction();
390+
}
391+
392+
bool success = await TaskSchedulerTestHelper.IsExceptionBubbledUpToUnobservedTaskExceptionAsync(TestCallback);
393+
394+
Assert.IsTrue(success);
395+
}
396+
323397
public async Task Test_AsyncRelayCommand_ExecuteDoesNotRaiseCanExecuteChanged()
324398
{
325399
TaskCompletionSource<object?> tcs = new();

0 commit comments

Comments
 (0)