Browse Source
* Add VerifyEmptyDispatcherAfterTestAttribute * Use VerifyEmptyDispatcherAfterTest and fix failing tests * Remove unsupported timeout from sync xUnit testspull/17657/head
committed by
GitHub
24 changed files with 141 additions and 44 deletions
@ -1,7 +1,9 @@ |
|||||
using System.Reflection; |
using System.Reflection; |
||||
|
using Avalonia.UnitTests; |
||||
using Xunit; |
using Xunit; |
||||
|
|
||||
[assembly: AssemblyTitle("Avalonia.UnitTests")] |
[assembly: AssemblyTitle("Avalonia.Base.UnitTests")] |
||||
|
|
||||
// Don't run tests in parallel.
|
// Don't run tests in parallel.
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)] |
[assembly: CollectionBehavior(DisableTestParallelization = true)] |
||||
|
[assembly: VerifyEmptyDispatcherAfterTest] |
||||
|
|||||
@ -1,7 +1,9 @@ |
|||||
using System.Reflection; |
using System.Reflection; |
||||
|
using Avalonia.UnitTests; |
||||
using Xunit; |
using Xunit; |
||||
|
|
||||
[assembly: AssemblyTitle("Avalonia.Controls.UnitTests")] |
[assembly: AssemblyTitle("Avalonia.Controls.UnitTests")] |
||||
|
|
||||
// Don't run tests in parallel.
|
// Don't run tests in parallel.
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)] |
[assembly: CollectionBehavior(DisableTestParallelization = true)] |
||||
|
[assembly: VerifyEmptyDispatcherAfterTest] |
||||
|
|||||
@ -1,6 +1,8 @@ |
|||||
|
using Avalonia.UnitTests; |
||||
using Xunit; |
using Xunit; |
||||
|
|
||||
// Required to avoid InvalidOperationException sometimes thrown
|
// Required to avoid InvalidOperationException sometimes thrown
|
||||
// from Splat.MemoizingMRUCache.cs which is not thread-safe.
|
// from Splat.MemoizingMRUCache.cs which is not thread-safe.
|
||||
// Thrown when trying to access WhenActivated concurrently.
|
// Thrown when trying to access WhenActivated concurrently.
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)] |
[assembly: CollectionBehavior(DisableTestParallelization = true)] |
||||
|
[assembly: VerifyEmptyDispatcherAfterTest] |
||||
|
|||||
@ -0,0 +1,38 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Threading; |
||||
|
using Xunit; |
||||
|
using Xunit.Sdk; |
||||
|
|
||||
|
namespace Avalonia.UnitTests; |
||||
|
|
||||
|
public sealed class VerifyEmptyDispatcherAfterTestAttribute : BeforeAfterTestAttribute |
||||
|
{ |
||||
|
public override void After(MethodInfo methodUnderTest) |
||||
|
{ |
||||
|
if (typeof(ScopedTestBase).IsAssignableFrom(methodUnderTest.DeclaringType)) |
||||
|
return; |
||||
|
|
||||
|
var dispatcher = Dispatcher.UIThread; |
||||
|
var jobs = dispatcher.GetJobs(); |
||||
|
if (jobs.Count == 0) |
||||
|
return; |
||||
|
|
||||
|
dispatcher.ClearJobs(); |
||||
|
|
||||
|
// Ignore the Control.Loaded callback. It might happen synchronously or might be posted.
|
||||
|
if (jobs.Count == 1 && IsLoadedCallback(jobs[0])) |
||||
|
return; |
||||
|
|
||||
|
Assert.Fail( |
||||
|
$"The test left {jobs.Count} unprocessed dispatcher {(jobs.Count == 1 ? "job" : "jobs")}:\n" + |
||||
|
$"{string.Join(Environment.NewLine, jobs.Select(job => $" - {job.DebugDisplay}"))}\n" + |
||||
|
$"Consider using ScopedTestBase or UnitTestApplication.Start()."); |
||||
|
|
||||
|
static bool IsLoadedCallback(DispatcherOperation job) |
||||
|
=> job.Priority == DispatcherPriority.Loaded && |
||||
|
(job.Callback as Delegate)?.Method.DeclaringType?.DeclaringType == typeof(Control); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue