protected override Task <decimal> InvokeTestMethodAsync(ExceptionAggregator aggregator) { SharedData.ExecutingTest(TestMethod); var sta = StaTaskScheduler.DefaultSta; var task = Task.Factory.StartNew(async() => { Debug.Assert(sta.StaThread == Thread.CurrentThread); using (await SharedData.TestSerializationGate.DisposableWaitAsync(CancellationToken.None)) { try { Debug.Assert(SynchronizationContext.Current is DispatcherSynchronizationContext); // Reset our flag ensuring that part of this test actually needs WpfFact s_wpfFactRequirementReason = null; // Just call back into the normal xUnit dispatch process now that we are on an STA Thread with no synchronization context. var invoker = new XunitTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource); return(invoker.RunAsync().JoinUsingDispatcher(CancellationTokenSource.Token)); } finally { // Cleanup the synchronization context even if the test is failing exceptionally SynchronizationContext.SetSynchronizationContext(null); } } }, CancellationTokenSource.Token, TaskCreationOptions.None, new SynchronizationContextTaskScheduler(sta.DispatcherSynchronizationContext)); return(task.Unwrap()); }
protected override Task <decimal> InvokeTestMethodAsync(ExceptionAggregator aggregator) { SharedData.ExecutingTest(TestMethod); Debug.Assert(StaTestFramework.IsCreated); var taskScheduler = new SynchronizationContextTaskScheduler(StaContext.Default.DispatcherSynchronizationContext); return(Task.Factory.StartNew(async() => { Debug.Assert(SynchronizationContext.Current is DispatcherSynchronizationContext); using (await SharedData.TestSerializationGate.DisposableWaitAsync(CancellationToken.None)) { // Just call back into the normal xUnit dispatch process now that we are on an STA Thread with no synchronization context. var invoker = new XunitTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource); return await invoker.RunAsync(); } }, CancellationTokenSource.Token, TaskCreationOptions.None, taskScheduler).Unwrap()); }
protected override Task <decimal> InvokeTestMethodAsync(ExceptionAggregator aggregator) { SharedData.ExecutingTest(TestMethod); DispatcherSynchronizationContext synchronizationContext = null; Dispatcher dispatcher = null; Thread staThread; using (var staThreadStartedEvent = new ManualResetEventSlim(initialState: false)) { staThread = new Thread((ThreadStart)(() => { // All WPF Tests need a DispatcherSynchronizationContext and we dont want to block pending keyboard // or mouse input from the user. So use background priority which is a single level below user input. synchronizationContext = new DispatcherSynchronizationContext(); dispatcher = Dispatcher.CurrentDispatcher; // xUnit creates its own synchronization context and wraps any existing context so that messages are // still pumped as necessary. So we are safe setting it here, where we are not safe setting it in test. SynchronizationContext.SetSynchronizationContext(synchronizationContext); staThreadStartedEvent.Set(); Dispatcher.Run(); })); staThread.Name = $"{nameof(WpfTestRunner)} {TestMethod.Name}"; staThread.SetApartmentState(ApartmentState.STA); staThread.Start(); staThreadStartedEvent.Wait(); Debug.Assert(synchronizationContext != null); } var taskScheduler = new SynchronizationContextTaskScheduler(synchronizationContext); var task = Task.Factory.StartNew(async() => { Debug.Assert(SynchronizationContext.Current is DispatcherSynchronizationContext); using (await SharedData.TestSerializationGate.DisposableWaitAsync(CancellationToken.None)) { // Sync up FTAO to the context that we are creating here. ForegroundThreadAffinitizedObject.CurrentForegroundThreadData = new ForegroundThreadData( Thread.CurrentThread, new SynchronizationContextTaskScheduler(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher, DispatcherPriority.Background)), ForegroundThreadDataKind.StaUnitTest); // Reset our flag ensuring that part of this test actually needs WpfFact s_wpfFactRequirementReason = null; // Just call back into the normal xUnit dispatch process now that we are on an STA Thread with no synchronization context. var invoker = new XunitTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource); return(await invoker.RunAsync()); } }, CancellationTokenSource.Token, TaskCreationOptions.None, taskScheduler).Unwrap(); return(Task.Run( async() => { try { return await task.ConfigureAwait(false); } finally { // Make sure to shut down the dispatcher. Certain framework types listed for the dispatcher // shutdown to perform cleanup actions. In the absence of an explicit shutdown, these actions // are delayed and run during AppDomain or process shutdown, where they can lead to crashes of // the test process. dispatcher.InvokeShutdown(); // Join the STA thread, which ensures shutdown is complete. staThread.Join(HangMitigatingTimeout); } })); }