Fix random test failures and add empty dispatcher verification to tests (#17628)
* Add VerifyEmptyDispatcherAfterTestAttribute * Use VerifyEmptyDispatcherAfterTest and fix failing tests * Remove unsupported timeout from sync xUnit tests
This commit is contained in:
committed by
GitHub
parent
e8ce57871e
commit
1583de3e33
@@ -22,6 +22,7 @@
|
|||||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=TYPEDEF/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=TYPEDEF/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION_005FMEMBER/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION_005FMEMBER/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue"><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue"><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue"><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue"><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Interfaces/@EntryIndexedValue"><Policy Inspect="False" Prefix="I" Suffix="" Style="AaBb" /></s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Interfaces/@EntryIndexedValue"><Policy Inspect="False" Prefix="I" Suffix="" Style="AaBb" /></s:String>
|
||||||
|
|||||||
+8
-8
@@ -1,14 +1,14 @@
|
|||||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="xunit" Version="2.4.2" />
|
<PackageReference Include="xunit" Version="2.9.2" />
|
||||||
<PackageReference Include="xunit.assert" Version="2.4.2" />
|
<PackageReference Include="xunit.assert" Version="2.9.2" />
|
||||||
<PackageReference Include="xunit.core" Version="2.4.2" />
|
<PackageReference Include="xunit.core" Version="2.9.2" />
|
||||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.2" />
|
<PackageReference Include="xunit.extensibility.core" Version="2.9.2" />
|
||||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.2" />
|
<PackageReference Include="xunit.extensibility.execution" Version="2.9.2" />
|
||||||
<PackageReference Include="xunit.runner.console" Version="2.4.2" />
|
<PackageReference Include="xunit.runner.console" Version="2.9.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
|
||||||
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
|
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@@ -270,4 +271,25 @@ public partial class Dispatcher
|
|||||||
lock (InstanceLock)
|
lock (InstanceLock)
|
||||||
return _queue.MaxPriority >= priority;
|
return _queue.MaxPriority >= priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all pending jobs, unordered, without removing them.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Only use between unit tests!</remarks>
|
||||||
|
/// <returns>A list of jobs.</returns>
|
||||||
|
internal List<DispatcherOperation> GetJobs()
|
||||||
|
{
|
||||||
|
lock (InstanceLock)
|
||||||
|
return _queue.PeekAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears all pending jobs.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Only use between unit tests!</remarks>
|
||||||
|
internal void ClearJobs()
|
||||||
|
{
|
||||||
|
lock (InstanceLock)
|
||||||
|
_queue.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.ExceptionServices;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Avalonia.Threading;
|
namespace Avalonia.Threading;
|
||||||
|
|
||||||
|
[DebuggerDisplay("{DebugDisplay}")]
|
||||||
public class DispatcherOperation
|
public class DispatcherOperation
|
||||||
{
|
{
|
||||||
protected readonly bool ThrowOnUiThread;
|
protected readonly bool ThrowOnUiThread;
|
||||||
@@ -25,7 +26,7 @@ public class DispatcherOperation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected object? Callback;
|
protected internal object? Callback;
|
||||||
protected object? TaskSource;
|
protected object? TaskSource;
|
||||||
|
|
||||||
internal DispatcherOperation? SequentialPrev { get; set; }
|
internal DispatcherOperation? SequentialPrev { get; set; }
|
||||||
@@ -53,6 +54,16 @@ public class DispatcherOperation
|
|||||||
Dispatcher = dispatcher;
|
Dispatcher = dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal string DebugDisplay
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var method = (Callback as Delegate)?.Method;
|
||||||
|
var methodDisplay = method is null ? "???" : method.DeclaringType + "." + method.Name;
|
||||||
|
return $"{methodDisplay} [{Priority}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An event that is raised when the operation is aborted or canceled.
|
/// An event that is raised when the operation is aborted or canceled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -398,6 +398,23 @@ internal class DispatcherPriorityQueue
|
|||||||
// Step 3: cleanup
|
// Step 3: cleanup
|
||||||
item.SequentialPrev = item.SequentialNext = null;
|
item.SequentialPrev = item.SequentialNext = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<DispatcherOperation> PeekAll()
|
||||||
|
{
|
||||||
|
var operations = new List<DispatcherOperation>();
|
||||||
|
|
||||||
|
for (var item = _head; item is not null; item = item.SequentialNext)
|
||||||
|
operations.Add(item);
|
||||||
|
|
||||||
|
return operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_priorityChains.Clear();
|
||||||
|
_cacheReusableChains.Clear();
|
||||||
|
_head = _tail = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using Xunit.Sdk;
|
|||||||
|
|
||||||
namespace Avalonia.Base.UnitTests.Composition;
|
namespace Avalonia.Base.UnitTests.Composition;
|
||||||
|
|
||||||
public class CompositionAnimationTests
|
public class CompositionAnimationTests : ScopedTestBase
|
||||||
{
|
{
|
||||||
|
|
||||||
class AnimationDataProvider : DataAttribute
|
class AnimationDataProvider : DataAttribute
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Avalonia.Base.UnitTests.Input
|
namespace Avalonia.Base.UnitTests.Input
|
||||||
{
|
{
|
||||||
public class AccessKeyHandlerTests
|
public class AccessKeyHandlerTests : ScopedTestBase
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Raise_Key_Events_For_Unregistered_Access_Key()
|
public void Should_Raise_Key_Events_For_Unregistered_Access_Key()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using Moq;
|
|||||||
|
|
||||||
namespace Avalonia.Base.UnitTests.Input;
|
namespace Avalonia.Base.UnitTests.Input;
|
||||||
|
|
||||||
public abstract class PointerTestsBase
|
public abstract class PointerTestsBase : ScopedTestBase
|
||||||
{
|
{
|
||||||
private protected static void SetHit(Mock<IHitTester> renderer, Control? hit)
|
private protected static void SetHit(Mock<IHitTester> renderer, Control? hit)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Avalonia.Base.UnitTests.Layout
|
namespace Avalonia.Base.UnitTests.Layout
|
||||||
{
|
{
|
||||||
public class LayoutableTests_EffectiveViewportChanged
|
public class LayoutableTests_EffectiveViewportChanged : ScopedTestBase
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EffectiveViewportChanged_Not_Raised_When_Control_Added_To_Tree_And_Layout_Pass_Has_Not_Run()
|
public async Task EffectiveViewportChanged_Not_Raised_When_Control_Added_To_Tree_And_Layout_Pass_Has_Not_Run()
|
||||||
@@ -38,9 +38,7 @@ namespace Avalonia.Base.UnitTests.Layout
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task EffectiveViewportChanged_Raised_When_Control_Added_To_Tree_And_Layout_Pass_Has_Run()
|
public async Task EffectiveViewportChanged_Raised_When_Control_Added_To_Tree_And_Layout_Pass_Has_Run()
|
||||||
{
|
{
|
||||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
|
||||||
await RunOnUIThread.Execute(async () =>
|
await RunOnUIThread.Execute(async () =>
|
||||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
|
||||||
{
|
{
|
||||||
var root = CreateRoot();
|
var root = CreateRoot();
|
||||||
var target = new Canvas();
|
var target = new Canvas();
|
||||||
@@ -64,9 +62,7 @@ namespace Avalonia.Base.UnitTests.Layout
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task EffectiveViewportChanged_Raised_When_Root_LayedOut_And_Then_Control_Added_To_Tree_And_Layout_Pass_Runs()
|
public async Task EffectiveViewportChanged_Raised_When_Root_LayedOut_And_Then_Control_Added_To_Tree_And_Layout_Pass_Runs()
|
||||||
{
|
{
|
||||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
|
||||||
await RunOnUIThread.Execute(async () =>
|
await RunOnUIThread.Execute(async () =>
|
||||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
|
||||||
{
|
{
|
||||||
var root = CreateRoot();
|
var root = CreateRoot();
|
||||||
var target = new Canvas();
|
var target = new Canvas();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using Xunit.Sdk;
|
|||||||
|
|
||||||
namespace Avalonia.Base.UnitTests.Layout
|
namespace Avalonia.Base.UnitTests.Layout
|
||||||
{
|
{
|
||||||
public class LayoutableTests_LayoutRounding
|
public class LayoutableTests_LayoutRounding : ScopedTestBase
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(100, 100)]
|
[InlineData(100, 100)]
|
||||||
@@ -112,7 +112,7 @@ namespace Avalonia.Base.UnitTests.Layout
|
|||||||
{
|
{
|
||||||
if (!expected.NearlyEquals(actual))
|
if (!expected.NearlyEquals(actual))
|
||||||
{
|
{
|
||||||
throw new EqualException(expected, actual);
|
throw EqualException.ForMismatchedValues(expected, actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ namespace Avalonia.Base.UnitTests.Layout
|
|||||||
{
|
{
|
||||||
if (!expected.NearlyEquals(actual))
|
if (!expected.NearlyEquals(actual))
|
||||||
{
|
{
|
||||||
throw new EqualException(expected, actual);
|
throw EqualException.ForMismatchedValues(expected, actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -358,8 +358,10 @@ namespace Avalonia.Controls.UnitTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void FlowDirection_Of_RectangleContent_Shuold_Be_LeftToRight()
|
public void FlowDirection_Of_RectangleContent_Should_Be_LeftToRight()
|
||||||
{
|
{
|
||||||
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
||||||
|
|
||||||
var target = new ComboBox
|
var target = new ComboBox
|
||||||
{
|
{
|
||||||
FlowDirection = FlowDirection.RightToLeft,
|
FlowDirection = FlowDirection.RightToLeft,
|
||||||
@@ -385,6 +387,8 @@ namespace Avalonia.Controls.UnitTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void FlowDirection_Of_RectangleContent_Updated_After_InvalidateMirrorTransform()
|
public void FlowDirection_Of_RectangleContent_Updated_After_InvalidateMirrorTransform()
|
||||||
{
|
{
|
||||||
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
||||||
|
|
||||||
var parentContent = new Decorator()
|
var parentContent = new Decorator()
|
||||||
{
|
{
|
||||||
Child = new Control()
|
Child = new Control()
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -408,6 +408,8 @@ namespace Avalonia.Controls.UnitTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void Previous_ContentTemplate_Is_Not_Reused_When_TabItem_Changes()
|
public void Previous_ContentTemplate_Is_Not_Reused_When_TabItem_Changes()
|
||||||
{
|
{
|
||||||
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
||||||
|
|
||||||
int templatesBuilt = 0;
|
int templatesBuilt = 0;
|
||||||
|
|
||||||
var target = new TabControl
|
var target = new TabControl
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Layout;
|
using Avalonia.Layout;
|
||||||
@@ -35,12 +36,11 @@ public class InputTests
|
|||||||
#if NUNIT
|
#if NUNIT
|
||||||
[AvaloniaTest, Timeout(10000)]
|
[AvaloniaTest, Timeout(10000)]
|
||||||
#elif XUNIT
|
#elif XUNIT
|
||||||
[AvaloniaFact(Timeout = 10000)]
|
[AvaloniaFact]
|
||||||
#endif
|
#endif
|
||||||
public void Should_Click_Button_On_Window()
|
public void Should_Click_Button_On_Window()
|
||||||
{
|
{
|
||||||
Assert.True(_setupApp == Application.Current);
|
Assert.True(_setupApp == Application.Current);
|
||||||
|
|
||||||
var buttonClicked = false;
|
var buttonClicked = false;
|
||||||
var button = new Button
|
var button = new Button
|
||||||
{
|
{
|
||||||
@@ -62,7 +62,7 @@ public class InputTests
|
|||||||
#if NUNIT
|
#if NUNIT
|
||||||
[AvaloniaTest, Timeout(10000)]
|
[AvaloniaTest, Timeout(10000)]
|
||||||
#elif XUNIT
|
#elif XUNIT
|
||||||
[AvaloniaFact(Timeout = 10000)]
|
[AvaloniaFact]
|
||||||
#endif
|
#endif
|
||||||
public void Change_Window_Position()
|
public void Change_Window_Position()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class RenderingTests
|
|||||||
#if NUNIT
|
#if NUNIT
|
||||||
[AvaloniaTest, Timeout(10000)]
|
[AvaloniaTest, Timeout(10000)]
|
||||||
#elif XUNIT
|
#elif XUNIT
|
||||||
[AvaloniaFact(Timeout = 10000)]
|
[AvaloniaFact]
|
||||||
#endif
|
#endif
|
||||||
public void Should_Render_Last_Frame_To_Bitmap()
|
public void Should_Render_Last_Frame_To_Bitmap()
|
||||||
{
|
{
|
||||||
@@ -43,7 +43,7 @@ public class RenderingTests
|
|||||||
#if NUNIT
|
#if NUNIT
|
||||||
[AvaloniaTest, Timeout(10000)]
|
[AvaloniaTest, Timeout(10000)]
|
||||||
#elif XUNIT
|
#elif XUNIT
|
||||||
[AvaloniaFact(Timeout = 10000)]
|
[AvaloniaFact]
|
||||||
#endif
|
#endif
|
||||||
public void Should_Not_Crash_On_GeometryGroup()
|
public void Should_Not_Crash_On_GeometryGroup()
|
||||||
{
|
{
|
||||||
@@ -79,7 +79,7 @@ public class RenderingTests
|
|||||||
#if NUNIT
|
#if NUNIT
|
||||||
[AvaloniaTest, Timeout(10000)]
|
[AvaloniaTest, Timeout(10000)]
|
||||||
#elif XUNIT
|
#elif XUNIT
|
||||||
[AvaloniaFact(Timeout = 10000)]
|
[AvaloniaFact]
|
||||||
#endif
|
#endif
|
||||||
public void Should_Not_Crash_On_CombinedGeometry()
|
public void Should_Not_Crash_On_CombinedGeometry()
|
||||||
{
|
{
|
||||||
@@ -110,7 +110,7 @@ public class RenderingTests
|
|||||||
#if NUNIT
|
#if NUNIT
|
||||||
[AvaloniaTest, Timeout(10000)]
|
[AvaloniaTest, Timeout(10000)]
|
||||||
#elif XUNIT
|
#elif XUNIT
|
||||||
[AvaloniaFact(Timeout = 10000)]
|
[AvaloniaFact]
|
||||||
#endif
|
#endif
|
||||||
public void Should_Not_Hang_With_Non_Trivial_Layout()
|
public void Should_Not_Hang_With_Non_Trivial_Layout()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class ServicesTests
|
|||||||
#if NUNIT
|
#if NUNIT
|
||||||
[AvaloniaTest, Timeout(10000)]
|
[AvaloniaTest, Timeout(10000)]
|
||||||
#elif XUNIT
|
#elif XUNIT
|
||||||
[AvaloniaFact(Timeout = 10000)]
|
[AvaloniaFact]
|
||||||
#endif
|
#endif
|
||||||
public void Can_Access_Screens()
|
public void Can_Access_Screens()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class ThreadingTests
|
|||||||
#if NUNIT
|
#if NUNIT
|
||||||
[AvaloniaTest, Timeout(10000)]
|
[AvaloniaTest, Timeout(10000)]
|
||||||
#elif XUNIT
|
#elif XUNIT
|
||||||
[AvaloniaFact(Timeout = 10000)]
|
[AvaloniaFact]
|
||||||
#endif
|
#endif
|
||||||
public void Should_Be_On_Dispatcher_Thread()
|
public void Should_Be_On_Dispatcher_Thread()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -411,16 +411,16 @@ namespace Avalonia.IntegrationTests.Appium
|
|||||||
// the position of a centered window can be off by a bit. From initial testing, looks
|
// the position of a centered window can be off by a bit. From initial testing, looks
|
||||||
// like this shouldn't be more than 10 pixels.
|
// like this shouldn't be more than 10 pixels.
|
||||||
if (Math.Abs(expected.X - actual.X) > 10)
|
if (Math.Abs(expected.X - actual.X) > 10)
|
||||||
throw new EqualException(expected, actual);
|
throw EqualException.ForMismatchedValues(expected, actual);
|
||||||
if (Math.Abs(expected.Y - actual.Y) > 10)
|
if (Math.Abs(expected.Y - actual.Y) > 10)
|
||||||
throw new EqualException(expected, actual);
|
throw EqualException.ForMismatchedValues(expected, actual);
|
||||||
}
|
}
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
{
|
{
|
||||||
if (Math.Abs(expected.X - actual.X) > 15)
|
if (Math.Abs(expected.X - actual.X) > 15)
|
||||||
throw new EqualException(expected, actual);
|
throw EqualException.ForMismatchedValues(expected, actual);
|
||||||
if (Math.Abs(expected.Y - actual.Y) > 15)
|
if (Math.Abs(expected.Y - actual.Y) > 15)
|
||||||
throw new EqualException(expected, actual);
|
throw EqualException.ForMismatchedValues(expected, actual);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,11 +37,11 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Update="xunit.runner.console" Version="2.7.0">
|
<PackageReference Update="xunit.runner.console" Version="2.9.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Update="xunit.runner.visualstudio" Version="2.5.7">
|
<PackageReference Update="xunit.runner.visualstudio" Version="2.8.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Avalonia.ReactiveUI.UnitTests
|
namespace Avalonia.ReactiveUI.UnitTests
|
||||||
{
|
{
|
||||||
public class ReactiveUserControlTest
|
public class ReactiveUserControlTest : ScopedTestBase
|
||||||
{
|
{
|
||||||
public class ExampleViewModel : ReactiveObject, IActivatableViewModel
|
public class ExampleViewModel : ReactiveObject, IActivatableViewModel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Avalonia.UnitTests;
|
|||||||
/// Some tests are formatting numbers, expecting a dot as a decimal point.
|
/// Some tests are formatting numbers, expecting a dot as a decimal point.
|
||||||
/// Use this fixture to set the current culture to the invariant culture.
|
/// Use this fixture to set the current culture to the invariant culture.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
|
||||||
public sealed class InvariantCultureAttribute : BeforeAfterTestAttribute
|
public sealed class InvariantCultureAttribute : BeforeAfterTestAttribute
|
||||||
{
|
{
|
||||||
private CultureInfo? _previousCulture;
|
private CultureInfo? _previousCulture;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user