Skip to content

Commit

Permalink
Fix random test failures and add empty dispatcher verification to tes…
Browse files Browse the repository at this point in the history
…ts (#17628)

* Add VerifyEmptyDispatcherAfterTestAttribute

* Use VerifyEmptyDispatcherAfterTest and fix failing tests

* Remove unsupported timeout from sync xUnit tests
  • Loading branch information
MrJul authored Nov 30, 2024
1 parent e8ce578 commit 1583de3
Show file tree
Hide file tree
Showing 24 changed files with 141 additions and 44 deletions.
1 change: 1 addition & 0 deletions Avalonia.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=TYPEDEF/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION_005FMEMBER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</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">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Interfaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="I" Suffix="" Style="AaBb" /&gt;</s:String>
Expand Down
16 changes: 8 additions & 8 deletions build/XUnit.props
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.assert" Version="2.4.2" />
<PackageReference Include="xunit.core" Version="2.4.2" />
<PackageReference Include="xunit.extensibility.core" Version="2.4.2" />
<PackageReference Include="xunit.extensibility.execution" Version="2.4.2" />
<PackageReference Include="xunit.runner.console" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.assert" Version="2.9.2" />
<PackageReference Include="xunit.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.execution" Version="2.9.2" />
<PackageReference Include="xunit.runner.console" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
<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>
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
Expand Down
22 changes: 22 additions & 0 deletions src/Avalonia.Base/Threading/Dispatcher.Queue.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

Expand Down Expand Up @@ -270,4 +271,25 @@ public bool HasJobsWithPriority(DispatcherPriority priority)
lock (InstanceLock)
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();
}
}
15 changes: 13 additions & 2 deletions src/Avalonia.Base/Threading/DispatcherOperation.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;

namespace Avalonia.Threading;

[DebuggerDisplay("{DebugDisplay}")]
public class DispatcherOperation
{
protected readonly bool ThrowOnUiThread;
Expand All @@ -25,7 +26,7 @@ public DispatcherPriority Priority
}
}

protected object? Callback;
protected internal object? Callback;
protected object? TaskSource;

internal DispatcherOperation? SequentialPrev { get; set; }
Expand Down Expand Up @@ -53,6 +54,16 @@ private protected DispatcherOperation(Dispatcher dispatcher, DispatcherPriority
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>
/// An event that is raised when the operation is aborted or canceled.
/// </summary>
Expand Down
19 changes: 18 additions & 1 deletion src/Avalonia.Base/Threading/DispatcherPriorityQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,23 @@ private void RemoveItemFromSequentialChain(DispatcherOperation item)
// Step 3: cleanup
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;
}
}


Expand All @@ -415,4 +432,4 @@ public PriorityChain(DispatcherPriority priority) // NOTE: should be Priority
public DispatcherOperation? Head { get; set; }

public DispatcherOperation? Tail { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

namespace Avalonia.Base.UnitTests.Composition;

public class CompositionAnimationTests
public class CompositionAnimationTests : ScopedTestBase
{

class AnimationDataProvider : DataAttribute
Expand Down Expand Up @@ -114,4 +114,4 @@ public override string ToString()
return Name;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace Avalonia.Base.UnitTests.Input
{
public class AccessKeyHandlerTests
public class AccessKeyHandlerTests : ScopedTestBase
{
[Fact]
public void Should_Raise_Key_Events_For_Unregistered_Access_Key()
Expand Down
2 changes: 1 addition & 1 deletion tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

namespace Avalonia.Base.UnitTests.Input;

public abstract class PointerTestsBase
public abstract class PointerTestsBase : ScopedTestBase
{
private protected static void SetHit(Mock<IHitTester> renderer, Control? hit)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Avalonia.Base.UnitTests.Layout
{
public class LayoutableTests_EffectiveViewportChanged
public class LayoutableTests_EffectiveViewportChanged : ScopedTestBase
{
[Fact]
public async Task EffectiveViewportChanged_Not_Raised_When_Control_Added_To_Tree_And_Layout_Pass_Has_Not_Run()
Expand All @@ -38,9 +38,7 @@ await RunOnUIThread.Execute(async () =>
[Fact]
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 () =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
var root = CreateRoot();
var target = new Canvas();
Expand All @@ -64,9 +62,7 @@ await RunOnUIThread.Execute(async () =>
[Fact]
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 () =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
var root = CreateRoot();
var target = new Canvas();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Avalonia.Base.UnitTests.Layout
{
public class LayoutableTests_LayoutRounding
public class LayoutableTests_LayoutRounding : ScopedTestBase
{
[Theory]
[InlineData(100, 100)]
Expand Down Expand Up @@ -112,15 +112,15 @@ private static void AssertEqual(Point expected, Point actual)
{
if (!expected.NearlyEquals(actual))
{
throw new EqualException(expected, actual);
throw EqualException.ForMismatchedValues(expected, actual);
}
}

private static void AssertEqual(Size expected, Size actual)
{
if (!expected.NearlyEquals(actual))
{
throw new EqualException(expected, actual);
throw EqualException.ForMismatchedValues(expected, actual);
}
}

Expand Down
4 changes: 3 additions & 1 deletion tests/Avalonia.Base.UnitTests/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Reflection;
using Avalonia.UnitTests;
using Xunit;

[assembly: AssemblyTitle("Avalonia.UnitTests")]
[assembly: AssemblyTitle("Avalonia.Base.UnitTests")]

// Don't run tests in parallel.
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: VerifyEmptyDispatcherAfterTest]
6 changes: 5 additions & 1 deletion tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,10 @@ public void Close_Window_On_Alt_F4_When_ComboBox_Is_Focus()
}

[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
{
FlowDirection = FlowDirection.RightToLeft,
Expand All @@ -385,6 +387,8 @@ public void FlowDirection_Of_RectangleContent_Shuold_Be_LeftToRight()
[Fact]
public void FlowDirection_Of_RectangleContent_Updated_After_InvalidateMirrorTransform()
{
using var app = UnitTestApplication.Start(TestServices.StyledWindow);

var parentContent = new Decorator()
{
Child = new Control()
Expand Down
4 changes: 3 additions & 1 deletion tests/Avalonia.Controls.UnitTests/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Reflection;
using Avalonia.UnitTests;
using Xunit;

[assembly: AssemblyTitle("Avalonia.Controls.UnitTests")]

// Don't run tests in parallel.
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: VerifyEmptyDispatcherAfterTest]
2 changes: 2 additions & 0 deletions tests/Avalonia.Controls.UnitTests/TabControlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@ public void SelectedContentTemplate_Updates_After_New_ContentTemplate()
[Fact]
public void Previous_ContentTemplate_Is_Not_Reused_When_TabItem_Changes()
{
using var app = UnitTestApplication.Start(TestServices.StyledWindow);

int templatesBuilt = 0;

var target = new TabControl
Expand Down
6 changes: 3 additions & 3 deletions tests/Avalonia.Headless.UnitTests/InputTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Layout;
Expand Down Expand Up @@ -35,12 +36,11 @@ public InputTests()
#if NUNIT
[AvaloniaTest, Timeout(10000)]
#elif XUNIT
[AvaloniaFact(Timeout = 10000)]
[AvaloniaFact]
#endif
public void Should_Click_Button_On_Window()
{
Assert.True(_setupApp == Application.Current);

var buttonClicked = false;
var button = new Button
{
Expand All @@ -62,7 +62,7 @@ public void Should_Click_Button_On_Window()
#if NUNIT
[AvaloniaTest, Timeout(10000)]
#elif XUNIT
[AvaloniaFact(Timeout = 10000)]
[AvaloniaFact]
#endif
public void Change_Window_Position()
{
Expand Down
8 changes: 4 additions & 4 deletions tests/Avalonia.Headless.UnitTests/RenderingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class RenderingTests
#if NUNIT
[AvaloniaTest, Timeout(10000)]
#elif XUNIT
[AvaloniaFact(Timeout = 10000)]
[AvaloniaFact]
#endif
public void Should_Render_Last_Frame_To_Bitmap()
{
Expand Down Expand Up @@ -43,7 +43,7 @@ public void Should_Render_Last_Frame_To_Bitmap()
#if NUNIT
[AvaloniaTest, Timeout(10000)]
#elif XUNIT
[AvaloniaFact(Timeout = 10000)]
[AvaloniaFact]
#endif
public void Should_Not_Crash_On_GeometryGroup()
{
Expand Down Expand Up @@ -79,7 +79,7 @@ public void Should_Not_Crash_On_GeometryGroup()
#if NUNIT
[AvaloniaTest, Timeout(10000)]
#elif XUNIT
[AvaloniaFact(Timeout = 10000)]
[AvaloniaFact]
#endif
public void Should_Not_Crash_On_CombinedGeometry()
{
Expand Down Expand Up @@ -110,7 +110,7 @@ public void Should_Not_Crash_On_CombinedGeometry()
#if NUNIT
[AvaloniaTest, Timeout(10000)]
#elif XUNIT
[AvaloniaFact(Timeout = 10000)]
[AvaloniaFact]
#endif
public void Should_Not_Hang_With_Non_Trivial_Layout()
{
Expand Down
2 changes: 1 addition & 1 deletion tests/Avalonia.Headless.UnitTests/ServicesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class ServicesTests
#if NUNIT
[AvaloniaTest, Timeout(10000)]
#elif XUNIT
[AvaloniaFact(Timeout = 10000)]
[AvaloniaFact]
#endif
public void Can_Access_Screens()
{
Expand Down
2 changes: 1 addition & 1 deletion tests/Avalonia.Headless.UnitTests/ThreadingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class ThreadingTests
#if NUNIT
[AvaloniaTest, Timeout(10000)]
#elif XUNIT
[AvaloniaFact(Timeout = 10000)]
[AvaloniaFact]
#endif
public void Should_Be_On_Dispatcher_Thread()
{
Expand Down
8 changes: 4 additions & 4 deletions tests/Avalonia.IntegrationTests.Appium/WindowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -411,16 +411,16 @@ private static void AssertCloseEnough(PixelPoint expected, PixelPoint actual)
// 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.
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)
throw new EqualException(expected, actual);
throw EqualException.ForMismatchedValues(expected, actual);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
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)
throw new EqualException(expected, actual);
throw EqualException.ForMismatchedValues(expected, actual);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Update="xunit.runner.console" Version="2.7.0">
<PackageReference Update="xunit.runner.console" Version="2.9.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Update="xunit.runner.visualstudio" Version="2.5.7">
<PackageReference Update="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Loading

0 comments on commit 1583de3

Please sign in to comment.