using System.IO;
using System.Runtime.CompilerServices;
using Avalonia.Controls;
using Avalonia.Media.Imaging;
using Avalonia.Rendering;
using SixLabors.ImageSharp;
using Xunit;
using Avalonia.Platform;
using System.Threading.Tasks;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Threading;
using Avalonia.Media;
using Avalonia.Rendering.Composition;
using Avalonia.Skia;
using Avalonia.Threading;
using Avalonia.UnitTests;
using Avalonia.Utilities;
using SixLabors.ImageSharp.PixelFormats;
using Image = SixLabors.ImageSharp.Image;
namespace Avalonia.Skia.RenderTests
{
public class TestBase : IDisposable
{
private static string s_fontUri = "resm:Avalonia.Skia.RenderTests.Assets?assembly=Avalonia.Skia.RenderTests#Noto Mono";
public static FontFamily TestFontFamily = new FontFamily(s_fontUri);
private const double AllowedError = 0.022;
public TestBase(string outputPath)
{
outputPath = outputPath.Replace('\\', Path.DirectorySeparatorChar);
var testPath = GetTestsDirectory();
var testFiles = Path.Combine(testPath, "TestFiles");
OutputPath = Path.Combine(testFiles, "Skia", outputPath);
TestRenderHelper.BeginTest();
}
public string OutputPath
{
get;
}
protected async Task RenderToFile(Control target, [CallerMemberName] string testName = "", double dpi = 96)
{
if (!Directory.Exists(OutputPath))
{
Directory.CreateDirectory(OutputPath);
}
var immediatePath = Path.Combine(OutputPath, testName + ".immediate.out.png");
var compositedPath = Path.Combine(OutputPath, testName + ".composited.out.png");
var glesPath = Path.Combine(OutputPath, testName + ".composited.gles.out.png");
var vulkanPath = Path.Combine(OutputPath, testName + ".composited.vulkan.out.png");
await TestRenderHelper.RenderToFile(target, immediatePath, true, dpi);
await TestRenderHelper.RenderToFile(target, compositedPath, false, dpi);
if (MesaSoftwareRenderer.GlEnabled)
await TestRenderHelper.RenderCompositedToFile(target, glesPath, MesaSoftwareRenderer.Gl, dpi);
if (MesaSoftwareRenderer.VulkanEnabled)
await TestRenderHelper.RenderCompositedToFile(target, vulkanPath, MesaSoftwareRenderer.Vulkan, dpi);
}
/// The base name of the compared images.
/// Skips the immediate renderer output comparison.
/// Skips all composited output comparisons.
///
/// Skips Mesa GPU output comparisons. For tests that render via a custom flow that only
/// produces the regular composited output.
///
///
/// Error tolerance override for Mesa GPU outputs, for tests with known minor
/// rasterization differences between GPU and CPU rendering.
///
protected void CompareImages([CallerMemberName] string testName = "",
bool skipImmediate = false, bool skipCompositor = false, bool skipGpu = false,
double? gpuAllowedError = null)
{
var expectedPath = Path.Combine(OutputPath, testName + ".expected.png");
using (var expected = Image.Load(expectedPath))
{
void Compare(string outputType, double allowedError)
{
var actualPath = Path.Combine(OutputPath, testName + "." + outputType + ".out.png");
using var actual = Image.Load(actualPath);
var error = TestRenderHelper.CompareImages(actual, expected);
if (error > allowedError)
{
Assert.Fail(actualPath + ": Error = " + error);
}
}
if (!skipImmediate)
Compare("immediate", AllowedError);
if (!skipCompositor)
{
Compare("composited", AllowedError);
if (!skipGpu)
{
if (MesaSoftwareRenderer.GlEnabled)
Compare("composited.gles", gpuAllowedError ?? AllowedError);
if (MesaSoftwareRenderer.VulkanEnabled)
Compare("composited.vulkan", gpuAllowedError ?? AllowedError);
}
}
}
}
protected void CompareImagesNoRenderer([CallerMemberName] string testName = "", string? expectedName = null)
{
var expectedPath = Path.Combine(OutputPath, (expectedName ?? testName) + ".expected.png");
var actualPath = Path.Combine(OutputPath, testName + ".out.png");
TestRenderHelper.AssertCompareImages(actualPath, expectedPath);
}
private static string GetTestsDirectory() => TestRenderHelper.GetTestsDirectory();
public void Dispose() => TestRenderHelper.EndTest();
}
}