Browse Source

Fix hang if exception is thrown during headless session app construction (#21688)

pull/21693/head
Thad House 3 months ago
committed by GitHub
parent
commit
9448ef8a91
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 25
      src/Headless/Avalonia.Headless/HeadlessUnitTestSession.cs

25
src/Headless/Avalonia.Headless/HeadlessUnitTestSession.cs

@ -16,7 +16,7 @@ namespace Avalonia.Headless;
/// <summary> /// <summary>
/// Headless unit test session that needs to be used by the actual testing framework. /// Headless unit test session that needs to be used by the actual testing framework.
/// All UI tests are supposed to be executed from one of the <see cref="Dispatch"/> methods to keep execution flow on the UI thread. /// All UI tests are supposed to be executed from one of the <see cref="Dispatch"/> methods to keep execution flow on the UI thread.
/// Disposing unit test session stops internal dispatcher loop. /// Disposing unit test session stops internal dispatcher loop.
/// </summary> /// </summary>
public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable
{ {
@ -96,9 +96,18 @@ public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable
using var globalCts = token.Register(s => ((CancellationTokenSource)s!).Cancel(), cts, true); using var globalCts = token.Register(s => ((CancellationTokenSource)s!).Cancel(), cts, true);
using var localCts = cancellationToken.Register(s => ((CancellationTokenSource)s!).Cancel(), cts, true); using var localCts = cancellationToken.Register(s => ((CancellationTokenSource)s!).Cancel(), cts, true);
var application = _isolated IDisposable application = null!;
? EnsureIsolatedApplication() try
: EnsureSharedApplication(); {
application = _isolated
? EnsureIsolatedApplication()
: EnsureSharedApplication();
}
catch (Exception ex)
{
tcs.TrySetException(ex);
return; // Exit the dispatcher action if application initialization fails
}
bool shouldCancel = false; bool shouldCancel = false;
Exception? caught = null; Exception? caught = null;
@ -212,7 +221,7 @@ public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable
} }
/// <summary> /// <summary>
/// Creates instance of <see cref="HeadlessUnitTestSession"/>. /// Creates instance of <see cref="HeadlessUnitTestSession"/>.
/// </summary> /// </summary>
/// <param name="entryPointType"> /// <param name="entryPointType">
/// Parameter from which <see cref="AppBuilder"/> should be created. /// Parameter from which <see cref="AppBuilder"/> should be created.
@ -228,7 +237,7 @@ public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable
} }
/// <summary> /// <summary>
/// Creates instance of <see cref="HeadlessUnitTestSession"/>. /// Creates instance of <see cref="HeadlessUnitTestSession"/>.
/// </summary> /// </summary>
/// <param name="entryPointType"> /// <param name="entryPointType">
/// Parameter from which <see cref="AppBuilder"/> should be created. /// Parameter from which <see cref="AppBuilder"/> should be created.
@ -283,7 +292,7 @@ public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable
} }
else else
{ {
action(); action();
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@ -297,7 +306,7 @@ public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable
/// <summary> /// <summary>
/// Creates a session from AvaloniaTestApplicationAttribute attribute or reuses any existing. /// Creates a session from AvaloniaTestApplicationAttribute attribute or reuses any existing.
/// If AvaloniaTestApplicationAttribute doesn't exist, empty application is used. /// If AvaloniaTestApplicationAttribute doesn't exist, empty application is used.
/// </summary> /// </summary>
[UnconditionalSuppressMessage("Trimming", "IL2072", [UnconditionalSuppressMessage("Trimming", "IL2072",
Justification = "AvaloniaTestApplicationAttribute attribute should preserve type information.")] Justification = "AvaloniaTestApplicationAttribute attribute should preserve type information.")]

Loading…
Cancel
Save