Browse Source

Run tests on Avalonia.Headless

pull/10473/head
Max Katz 3 years ago
parent
commit
5e4509deb1
  1. 7
      Avalonia.sln
  2. 1
      nukebuild/Build.cs
  3. 3
      src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
  4. 13
      src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
  5. 2
      src/Headless/Avalonia.Headless/IHeadlessWindow.cs
  6. 19
      tests/Avalonia.Headless.UnitTests/Avalonia.Headless.UnitTests.csproj
  7. 37
      tests/Avalonia.Headless.UnitTests/InputTests.cs
  8. 39
      tests/Avalonia.Headless.UnitTests/RenderingTests.cs
  9. 24
      tests/Avalonia.Headless.UnitTests/TestApplication.cs
  10. 32
      tests/Avalonia.Headless.UnitTests/ThreadingTests.cs

7
Avalonia.sln

@ -250,6 +250,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit", "src\Headless\Avalonia.Headless.XUnit\Avalonia.Headless.XUnit.csproj", "{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.UnitTests", "tests\Avalonia.Headless.UnitTests\Avalonia.Headless.UnitTests.csproj", "{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -585,6 +587,10 @@ Global
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -655,6 +661,7 @@ Global
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

1
nukebuild/Build.cs

@ -212,6 +212,7 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
RunCoreTest("Avalonia.Skia.UnitTests");
RunCoreTest("Avalonia.ReactiveUI.UnitTests");
RunCoreTest("Avalonia.Headless.UnitTests");
});
Target RunRenderTests => _ => _

3
src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

@ -19,7 +19,8 @@ namespace Avalonia.Headless
public static void Initialize()
{
AvaloniaLocator.CurrentMutable
.Bind<IPlatformRenderInterface>().ToConstant(new HeadlessPlatformRenderInterface());
.Bind<IPlatformRenderInterface>().ToConstant(new HeadlessPlatformRenderInterface())
.Bind<IFontManagerImpl>().ToConstant(new HeadlessFontManagerStub());
}
public IEnumerable<string> InstalledFontNames { get; } = new[] { "Tahoma" };

13
src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs

@ -215,10 +215,19 @@ namespace Avalonia.Headless
});
}
public IRef<IWriteableBitmapImpl>? GetLastRenderedFrame()
public Bitmap? GetLastRenderedFrame()
{
lock (_sync)
return _lastRenderedFrame?.PlatformImpl?.CloneAs<IWriteableBitmapImpl>();
{
if (_lastRenderedFrame is null)
{
return null;
}
using var lockedFramebuffer = _lastRenderedFrame.Lock();
return new Bitmap(lockedFramebuffer.Format, AlphaFormat.Opaque, lockedFramebuffer.Address,
lockedFramebuffer.Size, lockedFramebuffer.Dpi, lockedFramebuffer.RowBytes);
}
}
private ulong Timestamp => (ulong)_st.ElapsedMilliseconds;

2
src/Headless/Avalonia.Headless/IHeadlessWindow.cs

@ -8,7 +8,7 @@ namespace Avalonia.Headless
{
public interface IHeadlessWindow
{
IRef<IWriteableBitmapImpl>? GetLastRenderedFrame();
Bitmap? GetLastRenderedFrame();
void KeyPress(Key key, RawInputModifiers modifiers);
void KeyRelease(Key key, RawInputModifiers modifiers);
void MouseDown(Point point, int button, RawInputModifiers modifiers = RawInputModifiers.None);

19
tests/Avalonia.Headless.UnitTests/Avalonia.Headless.UnitTests.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<Import Project="..\..\build\UnitTests.NetCore.targets" />
<Import Project="..\..\build\UnitTests.NetFX.props" />
<Import Project="..\..\build\Moq.props" />
<Import Project="..\..\build\XUnit.props" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\SharedVersion.props" />
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
<ProjectReference Include="..\..\src\Headless\Avalonia.Headless.XUnit\Avalonia.Headless.XUnit.csproj" />
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
</Project>

37
tests/Avalonia.Headless.UnitTests/InputTests.cs

@ -0,0 +1,37 @@
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Threading;
using Xunit;
namespace Avalonia.Headless.XUnit.Tests;
public class InputTests
{
[Fact]
public void Should_Click_Button_On_Window()
{
var buttonClicked = false;
var button = new Button
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
button.Click += (_, _) => buttonClicked = true;
var window = new Window
{
Width = 100,
Height = 100,
Content = button
};
window.Show();
Dispatcher.UIThread.RunJobs();
((IHeadlessWindow)window.PlatformImpl!).MouseDown(new Point(50, 50), 0);
((IHeadlessWindow)window.PlatformImpl!).MouseUp(new Point(50, 50), 0);
Assert.True(buttonClicked);
}
}

39
tests/Avalonia.Headless.UnitTests/RenderingTests.cs

@ -0,0 +1,39 @@
using System.IO;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
using Xunit;
namespace Avalonia.Headless.XUnit.Tests;
public class RenderingTests
{
[Fact]
public void Should_Render_Last_Frame_To_Bitmap()
{
var window = new Window
{
Content = new ContentControl
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
Padding = new Thickness(4),
Content = new PathIcon
{
Data = StreamGeometry.Parse("M0,9 L10,0 20,9 19,10 10,2 1,10 z")
}
},
SizeToContent = SizeToContent.WidthAndHeight
};
window.Show();
Dispatcher.UIThread.RunJobs();
AvaloniaHeadlessPlatform.ForceRenderTimerTick();
var frame = ((IHeadlessWindow)window.PlatformImpl!).GetLastRenderedFrame();
Assert.NotNull(frame);
}
}

24
tests/Avalonia.Headless.UnitTests/TestApplication.cs

@ -0,0 +1,24 @@
using Avalonia.Headless.XUnit;
using Avalonia.Headless.XUnit.Tests;
using Avalonia.Themes.Simple;
using Xunit;
[assembly: AvaloniaTestFramework(typeof(TestApplication))]
[assembly: CollectionBehavior(DisableTestParallelization = true)]
namespace Avalonia.Headless.XUnit.Tests;
public class TestApplication : Application
{
public TestApplication()
{
Styles.Add(new SimpleTheme());
}
public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure<TestApplication>()
.UseSkia()
.UseHeadless(new AvaloniaHeadlessPlatformOptions
{
UseHeadlessDrawing = false
});
}

32
tests/Avalonia.Headless.UnitTests/ThreadingTests.cs

@ -0,0 +1,32 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Threading;
using Xunit;
namespace Avalonia.Headless.XUnit.Tests;
public class ThreadingTests
{
[Fact]
public void Should_Be_On_Dispatcher_Thread()
{
Dispatcher.UIThread.VerifyAccess();
}
[Fact]
public async Task DispatcherTimer_Works_On_The_Same_Thread()
{
var currentThread = Thread.CurrentThread;
var tcs = new TaskCompletionSource();
DispatcherTimer.RunOnce(() =>
{
Assert.Equal(currentThread, Thread.CurrentThread);
tcs.SetResult();
}, TimeSpan.FromTicks(1));
await tcs.Task;
}
}
Loading…
Cancel
Save