123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- using System;
- using System.Threading;
- using System.Threading.Tasks;
- using Avalonia.Controls.Platform;
- using Avalonia.Threading;
- using Xunit;
- namespace Avalonia.Base.UnitTests;
- // Some of these exceptions are based from https://github.com/dotnet/wpf-test/blob/05797008bb4975ceeb71be36c47f01688f535d53/src/Test/ElementServices/FeatureTests/Untrusted/Dispatcher/UnhandledExceptionTest.cs#L30
- public partial class DispatcherTests
- {
- private const string ExpectedExceptionText = "Exception thrown inside Dispatcher.Invoke / Dispatcher.BeginInvoke.";
- private int _numberOfHandlerOnUnhandledEventInvoked;
- private int _numberOfHandlerOnUnhandledEventFilterInvoked;
- public DispatcherTests()
- {
- _numberOfHandlerOnUnhandledEventInvoked = 0;
- _numberOfHandlerOnUnhandledEventFilterInvoked = 0;
- }
- [Fact]
- public void DispatcherHandlesExceptionWithPost()
- {
- var impl = new ManagedDispatcherImpl(null);
- var disp = new Dispatcher(impl);
- var handled = false;
- var executed = false;
- disp.UnhandledException += (sender, args) =>
- {
- handled = true;
- args.Handled = true;
- };
- disp.Post(() => ThrowAnException());
- disp.Post(() => executed = true);
- disp.RunJobs();
-
- Assert.True(handled);
- Assert.True(executed);
- }
- [Fact]
- public void SyncContextExceptionCanBeHandledWithPost()
- {
- var impl = new ManagedDispatcherImpl(null);
- var disp = new Dispatcher(impl);
- var syncContext = disp.GetContextWithPriority(DispatcherPriority.Background);
- var handled = false;
- var executed = false;
- disp.UnhandledException += (sender, args) =>
- {
- handled = true;
- args.Handled = true;
- };
- syncContext.Post(_ => ThrowAnException(), null);
- syncContext.Post(_ => executed = true, null);
- disp.RunJobs();
- Assert.True(handled);
- Assert.True(executed);
- }
- [Fact]
- public void CanRemoveDispatcherExceptionHandler()
- {
- var impl = new ManagedDispatcherImpl(null);
- var dispatcher = new Dispatcher(impl);
- var caughtCorrectException = false;
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterRequestCatch;
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionNotHandled;
- dispatcher.UnhandledExceptionFilter -=
- HandlerOnUnhandledExceptionFilterRequestCatch;
- dispatcher.UnhandledException -=
- HandlerOnUnhandledExceptionNotHandled;
- try
- {
- dispatcher.Post(ThrowAnException, DispatcherPriority.Normal);
- dispatcher.RunJobs();
- }
- catch (Exception e)
- {
- caughtCorrectException = e.Message == ExpectedExceptionText;
- }
- finally
- {
- Verification(caughtCorrectException, 0, 0);
- }
- }
- [Fact]
- public void CanHandleExceptionWithUnhandledException()
- {
- var impl = new ManagedDispatcherImpl(null);
- var dispatcher = new Dispatcher(impl);
-
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterRequestCatch;
-
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionHandled;
- var caughtCorrectException = true;
- try
- {
- dispatcher.Post(ThrowAnException, DispatcherPriority.Normal);
- dispatcher.RunJobs();
- }
- catch (Exception)
- {
- // should be no exception here.
- caughtCorrectException = false;
- }
- finally
- {
- Verification(caughtCorrectException, 1, 1);
- }
- }
- [Fact]
- public void InvokeMethodDoesntTriggerUnhandledException()
- {
- var impl = new ManagedDispatcherImpl(null);
- var dispatcher = new Dispatcher(impl);
-
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterRequestCatch;
-
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionHandled;
- var caughtCorrectException = false;
- try
- {
- // Since both Invoke and InvokeAsync can throw exception, there is no need to pass them to the UnhandledException.
- dispatcher.Invoke(ThrowAnException, DispatcherPriority.Normal);
- dispatcher.RunJobs();
- }
- catch (Exception e)
- {
- // should be no exception here.
- caughtCorrectException = e.Message == ExpectedExceptionText;
- }
- finally
- {
- Verification(caughtCorrectException, 0, 0);
- }
- }
- [Fact]
- public void InvokeAsyncMethodDoesntTriggerUnhandledException()
- {
- var impl = new ManagedDispatcherImpl(null);
- var dispatcher = new Dispatcher(impl);
-
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterRequestCatch;
-
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionHandled;
- var caughtCorrectException = false;
- try
- {
- // Since both Invoke and InvokeAsync can throw exception, there is no need to pass them to the UnhandledException.
- var op = dispatcher.InvokeAsync(ThrowAnException, DispatcherPriority.Normal);
- op.Wait();
- dispatcher.RunJobs();
- }
- catch (Exception e)
- {
- // should be no exception here.
- caughtCorrectException = e.Message == ExpectedExceptionText;
- }
- finally
- {
- Verification(caughtCorrectException, 0, 0);
- }
- }
- [Fact]
- public void CanRethrowExceptionWithUnhandledException()
- {
- var impl = new ManagedDispatcherImpl(null);
- var dispatcher = new Dispatcher(impl);
-
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterRequestCatch;
-
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionNotHandled;
- var caughtCorrectException = false;
- try
- {
- dispatcher.Post(ThrowAnException, DispatcherPriority.Normal);
- dispatcher.RunJobs();
- }
- catch (Exception e)
- {
- caughtCorrectException = e.Message == ExpectedExceptionText;
- }
- finally
- {
- Verification(caughtCorrectException, 1, 1);
- }
- }
- [Fact]
- public void MultipleUnhandledExceptionFilterCannotResetRequestCatchFlag()
- {
- var impl = new ManagedDispatcherImpl(null);
- var dispatcher = new Dispatcher(impl);
-
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterNotRequestCatch;
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterRequestCatch;
-
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionNotHandled;
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionHandled;
- var caughtCorrectException = false;
- try
- {
- dispatcher.Post(ThrowAnException, DispatcherPriority.Normal);
- dispatcher.RunJobs();
- }
- catch (Exception e)
- {
- caughtCorrectException = e.Message == ExpectedExceptionText;
- }
- finally
- {
- Verification(caughtCorrectException, 0, 2);
- }
- }
- [Fact]
- public void MultipleUnhandledExceptionCannotResetHandleFlag()
- {
- var impl = new ManagedDispatcherImpl(null);
- var dispatcher = new Dispatcher(impl);
-
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterRequestCatch;
-
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionHandled;
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionNotHandled;
- var caughtCorrectException = true;
-
- try
- {
- dispatcher.Post(ThrowAnException, DispatcherPriority.Normal);
- dispatcher.RunJobs();
- }
- catch (Exception)
- {
- // should be no exception here.
- caughtCorrectException = false;
- }
- finally
- {
- Verification(caughtCorrectException, 1, 1);
- }
- }
- [Fact]
- public void CanPushFrameAndShutdownDispatcherFromUnhandledException()
- {
- var impl = new ManagedDispatcherImpl(null);
- var dispatcher = new Dispatcher(impl);
-
- dispatcher.UnhandledExceptionFilter +=
- HandlerOnUnhandledExceptionFilterNotRequestCatchPushFrame;
-
- dispatcher.UnhandledException +=
- HandlerOnUnhandledExceptionHandledPushFrame;
- var caughtCorrectException = false;
- try
- {
- dispatcher.Post(ThrowAnException, DispatcherPriority.Normal);
- dispatcher.RunJobs();
- }
- catch (Exception e)
- {
- caughtCorrectException = e.Message == ExpectedExceptionText;
- }
- finally
- {
- Verification(caughtCorrectException, 0, 1);
- }
- }
-
- private void Verification(bool caughtCorrectException, int numberOfHandlerOnUnhandledEventShouldInvoke,
- int numberOfHandlerOnUnhandledEventFilterShouldInvoke)
- {
- Assert.True(
- _numberOfHandlerOnUnhandledEventInvoked >= numberOfHandlerOnUnhandledEventShouldInvoke,
- "Number of handler invoked on UnhandledException is invalid");
- Assert.True(
- _numberOfHandlerOnUnhandledEventFilterInvoked >= numberOfHandlerOnUnhandledEventFilterShouldInvoke,
- "Number of handler invoked on UnhandledExceptionFilter is invalid");
- Assert.True(caughtCorrectException, "Wrong exception caught.");
- }
- private void HandlerOnUnhandledExceptionFilterRequestCatch(object sender,
- DispatcherUnhandledExceptionFilterEventArgs args)
- {
- args.RequestCatch = true;
- _numberOfHandlerOnUnhandledEventFilterInvoked += 1;
- Assert.Equal(ExpectedExceptionText, args.Exception.Message);
- }
- private void HandlerOnUnhandledExceptionFilterNotRequestCatchPushFrame(object sender,
- DispatcherUnhandledExceptionFilterEventArgs args)
- {
- HandlerOnUnhandledExceptionFilterNotRequestCatch(sender, args);
- var frame = new DispatcherFrame();
- args.Dispatcher.InvokeAsync(() => frame.Continue = false, DispatcherPriority.Background);
- args.Dispatcher.PushFrame(frame);
- }
- private void HandlerOnUnhandledExceptionFilterNotRequestCatch(object sender,
- DispatcherUnhandledExceptionFilterEventArgs args)
- {
- args.RequestCatch = false;
- _numberOfHandlerOnUnhandledEventFilterInvoked += 1;
- Assert.Equal(ExpectedExceptionText, args.Exception.Message);
- }
- private void HandlerOnUnhandledExceptionHandledPushFrame(object sender, DispatcherUnhandledExceptionEventArgs args)
- {
- Assert.Equal(ExpectedExceptionText, args.Exception.Message);
- Assert.False(_numberOfHandlerOnUnhandledEventFilterInvoked == 0,
- "UnhandledExceptionFilter should be invoked before UnhandledException.");
- args.Handled = true;
- _numberOfHandlerOnUnhandledEventInvoked += 1;
- var dispatcher = args.Dispatcher;
- var frame = new DispatcherFrame();
- dispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
- dispatcher.PushFrame(frame);
- }
- private void HandlerOnUnhandledExceptionHandled(object sender, DispatcherUnhandledExceptionEventArgs args)
- {
- Assert.Equal(ExpectedExceptionText, args.Exception.Message);
- Assert.False(_numberOfHandlerOnUnhandledEventFilterInvoked == 0,
- "UnhandledExceptionFilter should be invoked before UnhandledException.");
- args.Handled = true;
- _numberOfHandlerOnUnhandledEventInvoked += 1;
- }
- private void HandlerOnUnhandledExceptionNotHandled(object sender, DispatcherUnhandledExceptionEventArgs args)
- {
- Assert.Equal(ExpectedExceptionText, args.Exception.Message);
- Assert.False(_numberOfHandlerOnUnhandledEventFilterInvoked == 0,
- "UnhandledExceptionFilter should be invoked before UnhandledException.");
- args.Handled = false;
- _numberOfHandlerOnUnhandledEventInvoked += 1;
- }
- private void ThrowAnException()
- {
- throw new Exception(ExpectedExceptionText);
- }
- }
|