From 5b216b38d27b768253109d5c14a59b9fadd24ab8 Mon Sep 17 00:00:00 2001
From: Erik White <26148654+Erik-White@users.noreply.github.com>
Date: Sun, 17 May 2026 13:30:03 +0200
Subject: [PATCH 1/8] Build fixes and tidy up
---
ImageSharp.Textures.sln | 18 +++++++++---------
src/Directory.Build.props | 3 +--
tests/Directory.Build.props | 2 +-
tests/Directory.Build.targets | 4 ++--
.../ImageSharp.Textures.Tests.csproj | 1 -
5 files changed, 13 insertions(+), 15 deletions(-)
diff --git a/ImageSharp.Textures.sln b/ImageSharp.Textures.sln
index 636514f8..7568b07c 100644
--- a/ImageSharp.Textures.sln
+++ b/ImageSharp.Textures.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29613.14
+# Visual Studio Version 18
+VisualStudioVersion = 18.5.11716.220
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Textures", "src\ImageSharp.Textures\ImageSharp.Textures.csproj", "{1588F6C4-2186-4A35-9693-E9F296791393}"
EndProject
@@ -50,13 +50,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
EndProjectSection
EndProject
Global
- GlobalSection(SharedMSBuildProjectFiles) = preSolution
- shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{1588f6c4-2186-4a35-9693-e9f296791393}*SharedItemsImports = 5
- tests\Images\Images.projitems*{17fcbd4d-d232-45e8-876f-dfbc2fad52cf}*SharedItemsImports = 5
- tests\Images\Images.projitems*{18be79b6-6b95-4ed7-a963-ad75f6cb9f3c}*SharedItemsImports = 5
- tests\Images\Images.projitems*{68a8cc40-6aed-4e96-b524-31b1158fdeea}*SharedItemsImports = 13
- tests\Images\Images.projitems*{b159ffd1-e646-42d0-892c-4abf69103712}*SharedItemsImports = 5
- EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
@@ -94,4 +87,11 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F1762A0D-74C4-454A-BCB7-C010BB067E58}
EndGlobalSection
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{1588f6c4-2186-4a35-9693-e9f296791393}*SharedItemsImports = 5
+ tests\Images\Images.projitems*{17fcbd4d-d232-45e8-876f-dfbc2fad52cf}*SharedItemsImports = 5
+ tests\Images\Images.projitems*{18be79b6-6b95-4ed7-a963-ad75f6cb9f3c}*SharedItemsImports = 5
+ tests\Images\Images.projitems*{68a8cc40-6aed-4e96-b524-31b1158fdeea}*SharedItemsImports = 13
+ tests\Images\Images.projitems*{b159ffd1-e646-42d0-892c-4abf69103712}*SharedItemsImports = 5
+ EndGlobalSection
EndGlobal
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 2813cc4b..aa98dc2e 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -11,7 +11,7 @@
-->
-
+
@@ -22,7 +22,6 @@
-
diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props
index 775062ad..527225fe 100644
--- a/tests/Directory.Build.props
+++ b/tests/Directory.Build.props
@@ -11,7 +11,7 @@
-->
-
+
diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets
index c88a39e7..8d0956c9 100644
--- a/tests/Directory.Build.targets
+++ b/tests/Directory.Build.targets
@@ -18,9 +18,9 @@
-
+
-
+
diff --git a/tests/ImageSharp.Textures.Tests/ImageSharp.Textures.Tests.csproj b/tests/ImageSharp.Textures.Tests/ImageSharp.Textures.Tests.csproj
index ac9c7c4c..a7e6504d 100644
--- a/tests/ImageSharp.Textures.Tests/ImageSharp.Textures.Tests.csproj
+++ b/tests/ImageSharp.Textures.Tests/ImageSharp.Textures.Tests.csproj
@@ -3,7 +3,6 @@
net8.0
True
- AnyCPU;x64;x86
SixLabors.ImageSharp.Textures.Tests
SixLabors.ImageSharp.Textures.Tests
true
From e095e127266e4738db950186a562e3873d1d4b68 Mon Sep 17 00:00:00 2001
From: Erik White <26148654+Erik-White@users.noreply.github.com>
Date: Sun, 17 May 2026 13:32:55 +0200
Subject: [PATCH 2/8] Fix race condition with file name collisions
---
.../TextureProviders/TestTextureProvider.cs | 197 ++++++++++--------
1 file changed, 105 insertions(+), 92 deletions(-)
diff --git a/tests/ImageSharp.Textures.Tests/TestUtilities/TextureProviders/TestTextureProvider.cs b/tests/ImageSharp.Textures.Tests/TestUtilities/TextureProviders/TestTextureProvider.cs
index 372164db..06faae91 100644
--- a/tests/ImageSharp.Textures.Tests/TestUtilities/TextureProviders/TestTextureProvider.cs
+++ b/tests/ImageSharp.Textures.Tests/TestUtilities/TextureProviders/TestTextureProvider.cs
@@ -1,129 +1,142 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-using System.IO;
-using System.Text;
using System.Globalization;
+using System.Text;
using SixLabors.ImageSharp.Textures.Formats;
using SixLabors.ImageSharp.Textures.Tests.Enums;
using SixLabors.ImageSharp.Textures.TextureFormats;
-using Xunit;
-namespace SixLabors.ImageSharp.Textures.Tests.TestUtilities.TextureProviders
+namespace SixLabors.ImageSharp.Textures.Tests.TestUtilities.TextureProviders;
+
+public class TestTextureProvider : ITestTextureProvider
{
- public class TestTextureProvider : ITestTextureProvider
- {
- public string MethodName { get; }
+ public string MethodName { get; }
- ///
- public ImagingTestCaseUtility Utility { get; private set; }
+ ///
+ public ImagingTestCaseUtility Utility { get; private set; }
- ///
- public TestTextureFormat TextureFormat { get; }
+ ///
+ public TestTextureFormat TextureFormat { get; }
- ///
- public TestTextureType TextureType { get; }
+ ///
+ public TestTextureType TextureType { get; }
- ///
- public TestTextureTool TextureTool { get; }
+ ///
+ public TestTextureTool TextureTool { get; }
- public string InputFile { get; }
+ public string InputFile { get; }
- public bool IsRegex { get; }
+ public bool IsRegex { get; }
- public virtual Texture GetTexture(ITextureDecoder decoder)
- {
- using FileStream fileStream = File.OpenRead(this.InputFile);
+ public virtual Texture GetTexture(ITextureDecoder decoder)
+ {
+ using FileStream fileStream = File.OpenRead(this.InputFile);
- Texture result = decoder.DecodeTexture(Configuration.Default, fileStream);
+ Texture result = decoder.DecodeTexture(Configuration.Default, fileStream);
- Assert.True(fileStream.Length == fileStream.Position, "The texture file stream was not read to the end");
+ Assert.True(fileStream.Length == fileStream.Position, "The texture file stream was not read to the end");
- return result;
- }
+ return result;
+ }
- public TestTextureProvider(
- string methodName,
- TestTextureFormat textureFormat,
- TestTextureType textureType,
- TestTextureTool textureTool,
- string inputFile,
- bool isRegex)
+ public TestTextureProvider(
+ string methodName,
+ TestTextureFormat textureFormat,
+ TestTextureType textureType,
+ TestTextureTool textureTool,
+ string inputFile,
+ bool isRegex,
+ string testGroupName = "",
+ string outputSubfolderName = "")
+ {
+ this.MethodName = methodName;
+ this.TextureFormat = textureFormat;
+ this.TextureType = textureType;
+ this.TextureTool = textureTool;
+ this.InputFile = inputFile;
+ this.IsRegex = isRegex;
+ this.Utility = new ImagingTestCaseUtility
{
- this.MethodName = methodName;
- this.TextureFormat = textureFormat;
- this.TextureType = textureType;
- this.TextureTool = textureTool;
- this.InputFile = inputFile;
- this.IsRegex = isRegex;
- this.Utility = new ImagingTestCaseUtility
- {
- SourceFileOrDescription = inputFile,
- TestName = methodName
- };
- }
+ SourceFileOrDescription = inputFile,
+ };
+ this.Utility.Init(testGroupName, methodName, outputSubfolderName);
+ }
- private void SaveMipMaps(MipMap[] mipMaps, string name)
+ private void SaveMipMaps(MipMap[] mipMaps, string name)
+ {
+ // Include the input file's relative path under the format root in the output dir, not just its bare filename.
+ // Some test cases would otherwise collide on the same output path and either silently overwrite each other or race when run in parallel.
+ string formatRoot = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TextureFormat.ToString());
+ string relativeFromFormatRoot = Path.GetRelativePath(formatRoot, this.InputFile);
+ string inputSubpath = Path.Combine(
+ Path.GetDirectoryName(relativeFromFormatRoot) ?? string.Empty,
+ Path.GetFileNameWithoutExtension(relativeFromFormatRoot));
+
+ string path = Path.Combine(
+ TestEnvironment.ActualOutputDirectoryFullPath,
+ this.TextureFormat.ToString(),
+ this.TextureType.ToString(),
+ this.TextureTool.ToString(),
+ this.MethodName,
+ inputSubpath);
+
+ Directory.CreateDirectory(path);
+
+ for (int i = 0; i < mipMaps.Length; i++)
{
- string path = Path.Combine(TestEnvironment.ActualOutputDirectoryFullPath, this.TextureFormat.ToString(), this.TextureType.ToString(), this.TextureTool.ToString(), this.MethodName, Path.GetFileNameWithoutExtension(this.InputFile));
-
- Directory.CreateDirectory(path);
-
- for (int i = 0; i < mipMaps.Length; i++)
+ string filename = string.Format(CultureInfo.InvariantCulture, "mipmap-{0}", i + 1);
+ if (!string.IsNullOrEmpty(name))
{
- string filename = string.Format(CultureInfo.InvariantCulture, "mipmap-{0}", i + 1);
- if (!string.IsNullOrEmpty(name))
- {
- filename = string.Format(CultureInfo.InvariantCulture, "{0}-{1}", filename, name);
- }
-
- using Image image = mipMaps[i].GetImage();
- image.Save(Path.Combine(path, string.Format(CultureInfo.InvariantCulture, "{0}.png", filename)));
+ filename = string.Format(CultureInfo.InvariantCulture, "{0}-{1}", filename, name);
}
+
+ using Image image = mipMaps[i].GetImage();
+ image.Save(Path.Combine(path, string.Format(CultureInfo.InvariantCulture, "{0}.png", filename)));
}
+ }
- public void SaveTextures(Texture texture)
+ public void SaveTextures(Texture texture)
+ {
+ if (TestEnvironment.RunsOnCI)
{
- if (TestEnvironment.RunsOnCI)
- {
- return;
- }
+ return;
+ }
- if (texture is CubemapTexture cubemapTexture)
- {
- this.SaveMipMaps(cubemapTexture.PositiveX.MipMaps.ToArray(), "positive-x");
- this.SaveMipMaps(cubemapTexture.NegativeX.MipMaps.ToArray(), "negative-x");
- this.SaveMipMaps(cubemapTexture.PositiveY.MipMaps.ToArray(), "positive-y");
- this.SaveMipMaps(cubemapTexture.NegativeY.MipMaps.ToArray(), "negative-y");
- this.SaveMipMaps(cubemapTexture.PositiveZ.MipMaps.ToArray(), "positive-z");
- this.SaveMipMaps(cubemapTexture.NegativeZ.MipMaps.ToArray(), "negative-z");
- }
+ if (texture is CubemapTexture cubemapTexture)
+ {
+ this.SaveMipMaps(cubemapTexture.PositiveX.MipMaps.ToArray(), "positive-x");
+ this.SaveMipMaps(cubemapTexture.NegativeX.MipMaps.ToArray(), "negative-x");
+ this.SaveMipMaps(cubemapTexture.PositiveY.MipMaps.ToArray(), "positive-y");
+ this.SaveMipMaps(cubemapTexture.NegativeY.MipMaps.ToArray(), "negative-y");
+ this.SaveMipMaps(cubemapTexture.PositiveZ.MipMaps.ToArray(), "positive-z");
+ this.SaveMipMaps(cubemapTexture.NegativeZ.MipMaps.ToArray(), "negative-z");
+ }
- if (texture is FlatTexture flatTexture)
- {
- this.SaveMipMaps(flatTexture.MipMaps.ToArray(), null);
- }
+ if (texture is FlatTexture flatTexture)
+ {
+ this.SaveMipMaps(flatTexture.MipMaps.ToArray(), null);
+ }
- if (texture is VolumeTexture volumeTexture)
+ if (texture is VolumeTexture volumeTexture)
+ {
+ for (int i = 0; i < volumeTexture.Slices.Count; i++)
{
- for (int i = 0; i < volumeTexture.Slices.Count; i++)
- {
- this.SaveMipMaps(volumeTexture.Slices[i].MipMaps.ToArray(), string.Format(CultureInfo.InvariantCulture, "slice{0}", i + 1));
- }
+ this.SaveMipMaps(volumeTexture.Slices[i].MipMaps.ToArray(), string.Format(CultureInfo.InvariantCulture, "slice{0}", i + 1));
}
}
+ }
- public override string ToString()
- {
- var stringBuilder = new StringBuilder();
- stringBuilder.AppendLine();
- stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Method Name: {0}", this.MethodName));
- stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Texture Format: {0}", this.TextureFormat));
- stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Texture Type: {0}", this.TextureType));
- stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Texture Tool: {0}", this.TextureTool));
- stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Input File: {0}", this.InputFile));
- stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Is Regex: {0}", this.IsRegex));
- return stringBuilder.ToString();
- }
+ public override string ToString()
+ {
+ var stringBuilder = new StringBuilder();
+ stringBuilder.AppendLine();
+ stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Method Name: {0}", this.MethodName));
+ stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Texture Format: {0}", this.TextureFormat));
+ stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Texture Type: {0}", this.TextureType));
+ stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Texture Tool: {0}", this.TextureTool));
+ stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Input File: {0}", this.InputFile));
+ stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Is Regex: {0}", this.IsRegex));
+ return stringBuilder.ToString();
}
}
From 7441ddf52e6a166d5fb3959ef5cc5ed97a0e0420 Mon Sep 17 00:00:00 2001
From: Erik White <26148654+Erik-White@users.noreply.github.com>
Date: Sun, 17 May 2026 13:35:32 +0200
Subject: [PATCH 3/8] Convenience method for comparing cubemap faces
---
.../TestUtilities/TestImageExtensions.cs | 451 ++++++++++--------
1 file changed, 246 insertions(+), 205 deletions(-)
diff --git a/tests/ImageSharp.Textures.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Textures.Tests/TestUtilities/TestImageExtensions.cs
index 5218853d..1b072ff5 100644
--- a/tests/ImageSharp.Textures.Tests/TestUtilities/TestImageExtensions.cs
+++ b/tests/ImageSharp.Textures.Tests/TestUtilities/TestImageExtensions.cs
@@ -1,229 +1,270 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-using System;
-using System.IO;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Textures.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Textures.Tests.TestUtilities.TextureProviders;
+using SixLabors.ImageSharp.Textures.TextureFormats;
-namespace SixLabors.ImageSharp.Textures.Tests.TestUtilities
+namespace SixLabors.ImageSharp.Textures.Tests.TestUtilities;
+
+public static class TestImageExtensions
{
- public static class TestImageExtensions
+ public static void DebugSave(
+ this Image image,
+ ITestTextureProvider provider,
+ FormattableString testOutputDetails,
+ string extension = "png",
+ bool appendPixelTypeToFileName = false,
+ bool appendSourceFileOrDescription = false,
+ IImageEncoder encoder = null) => image.DebugSave(
+ provider,
+ (object)testOutputDetails,
+ extension,
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription,
+ encoder);
+
+ ///
+ /// Saves the image only when not running in the CI server.
+ ///
+ /// The image.
+ /// The image provider.
+ /// Details to be concatenated to the test output file, describing the parameters of the test.
+ /// The extension.
+ /// A boolean indicating whether to append the pixel type to the output file name.
+ /// A boolean indicating whether to append SourceFileOrDescription to the test output file name.
+ /// Custom encoder to use.
+ /// The input image.
+ public static Image DebugSave(
+ this Image image,
+ ITestTextureProvider provider,
+ object testOutputDetails = null,
+ string extension = "png",
+ bool appendPixelTypeToFileName = false,
+ bool appendSourceFileOrDescription = false,
+ IImageEncoder encoder = null)
{
- public static void DebugSave(
- this Image image,
- ITestTextureProvider provider,
- FormattableString testOutputDetails,
- string extension = "png",
- bool appendPixelTypeToFileName = false,
- bool appendSourceFileOrDescription = false,
- IImageEncoder encoder = null) => image.DebugSave(
- provider,
- (object)testOutputDetails,
- extension,
- appendPixelTypeToFileName,
- appendSourceFileOrDescription,
- encoder);
-
- ///
- /// Saves the image only when not running in the CI server.
- ///
- /// The image.
- /// The image provider.
- /// Details to be concatenated to the test output file, describing the parameters of the test.
- /// The extension.
- /// A boolean indicating whether to append the pixel type to the output file name.
- /// A boolean indicating whether to append SourceFileOrDescription to the test output file name.
- /// Custom encoder to use.
- /// The input image.
- public static Image DebugSave(
- this Image image,
- ITestTextureProvider provider,
- object testOutputDetails = null,
- string extension = "png",
- bool appendPixelTypeToFileName = false,
- bool appendSourceFileOrDescription = false,
- IImageEncoder encoder = null)
+ if (TestEnvironment.RunsOnCI)
{
- if (TestEnvironment.RunsOnCI)
- {
- return image;
- }
-
- // We are running locally then we want to save it out
- provider.Utility.SaveTestOutputFile(
- image,
- extension,
- testOutputDetails: testOutputDetails,
- appendPixelTypeToFileName: appendPixelTypeToFileName,
- appendSourceFileOrDescription: appendSourceFileOrDescription,
- encoder: encoder);
return image;
}
- public static void DebugSave(
- this Image image,
- ITestTextureProvider provider,
- IImageEncoder encoder,
- FormattableString testOutputDetails,
- bool appendPixelTypeToFileName = false) => image.DebugSave(provider, encoder, (object)testOutputDetails, appendPixelTypeToFileName);
-
- ///
- /// Saves the image only when not running in the CI server.
- ///
- /// The image
- /// The image provider
- /// The image encoder
- /// Details to be concatenated to the test output file, describing the parameters of the test.
- /// A boolean indicating whether to append the pixel type to the output file name.
- public static void DebugSave(
- this Image image,
- ITestTextureProvider provider,
- IImageEncoder encoder,
- object testOutputDetails = null,
- bool appendPixelTypeToFileName = false)
+ // We are running locally then we want to save it out
+ provider.Utility.SaveTestOutputFile(
+ image,
+ extension,
+ testOutputDetails: testOutputDetails,
+ appendPixelTypeToFileName: appendPixelTypeToFileName,
+ appendSourceFileOrDescription: appendSourceFileOrDescription,
+ encoder: encoder);
+ return image;
+ }
+
+ public static void DebugSave(
+ this Image image,
+ ITestTextureProvider provider,
+ IImageEncoder encoder,
+ FormattableString testOutputDetails,
+ bool appendPixelTypeToFileName = false) => image.DebugSave(provider, encoder, (object)testOutputDetails, appendPixelTypeToFileName);
+
+ ///
+ /// Saves the image only when not running in the CI server.
+ ///
+ /// The image
+ /// The image provider
+ /// The image encoder
+ /// Details to be concatenated to the test output file, describing the parameters of the test.
+ /// A boolean indicating whether to append the pixel type to the output file name.
+ public static void DebugSave(
+ this Image image,
+ ITestTextureProvider provider,
+ IImageEncoder encoder,
+ object testOutputDetails = null,
+ bool appendPixelTypeToFileName = false)
+ {
+ if (TestEnvironment.RunsOnCI)
{
- if (TestEnvironment.RunsOnCI)
- {
- return;
- }
-
- // We are running locally then we want to save it out
- provider.Utility.SaveTestOutputFile(
- image,
- encoder: encoder,
- testOutputDetails: testOutputDetails,
- appendPixelTypeToFileName: appendPixelTypeToFileName);
+ return;
}
- public static Image CompareToReferenceOutput(
- this Image image,
- ITestTextureProvider provider,
- FormattableString testOutputDetails,
- string extension = "png",
- bool appendPixelTypeToFileName = false,
- bool appendSourceFileOrDescription = false)
- where TPixel : unmanaged, IPixel => image.CompareToReferenceOutput(
- provider,
- (object)testOutputDetails,
- extension,
- appendPixelTypeToFileName,
- appendSourceFileOrDescription);
-
- ///
- /// Compares the image against the expected Reference output, throws an exception if the images are not similar enough.
- /// The output file should be named identically to the output produced by .
- ///
- /// The pixel format.
- /// The image which should be compared to the reference image.
- /// The image provider.
- /// Details to be concatenated to the test output file, describing the parameters of the test.
- /// The extension
- /// A boolean indicating whether to append the pixel type to the output file name.
- /// A boolean indicating whether to append to the test output file name.
- /// The image.
- public static Image CompareToReferenceOutput(
- this Image image,
- ITestTextureProvider provider,
- object testOutputDetails = null,
- string extension = "png",
- bool appendPixelTypeToFileName = false,
- bool appendSourceFileOrDescription = false)
- where TPixel : unmanaged, IPixel => CompareToReferenceOutput(
- image,
- ImageComparer.Tolerant(),
- provider,
- testOutputDetails,
- extension,
- appendPixelTypeToFileName,
- appendSourceFileOrDescription);
-
- public static Image CompareToReferenceOutput(
- this Image image,
- ImageComparer comparer,
- ITestTextureProvider provider,
- FormattableString testOutputDetails,
- string extension = "png",
- bool appendPixelTypeToFileName = false)
- where TPixel : unmanaged, IPixel => image.CompareToReferenceOutput(
- comparer,
- provider,
- (object)testOutputDetails,
- extension,
- appendPixelTypeToFileName);
-
- ///
- /// Compares the image against the expected Reference output, throws an exception if the images are not similar enough.
- /// The output file should be named identically to the output produced by .
- ///
- /// The pixel format.
- /// The image which should be compared to the reference output.
- /// The to use.
- /// The image provider.
- /// Details to be concatenated to the test output file, describing the parameters of the test.
- /// The extension
- /// A boolean indicating whether to append the pixel type to the output file name.
- /// A boolean indicating whether to append SourceFileOrDescription to the test output file name.
- /// A custom decoder.
- /// The image.
- public static Image CompareToReferenceOutput(
- this Image image,
- ImageComparer comparer,
- ITestTextureProvider provider,
- object testOutputDetails = null,
- string extension = "png",
- bool appendPixelTypeToFileName = false,
- bool appendSourceFileOrDescription = false,
- IImageDecoder decoder = null)
- where TPixel : unmanaged, IPixel
- {
- using (Image referenceImage = GetReferenceOutputImage(
- provider,
- testOutputDetails,
- extension,
- appendPixelTypeToFileName,
- appendSourceFileOrDescription,
- decoder))
- {
- comparer.VerifySimilarity(referenceImage, image);
- }
+ // We are running locally then we want to save it out
+ provider.Utility.SaveTestOutputFile(
+ image,
+ encoder: encoder,
+ testOutputDetails: testOutputDetails,
+ appendPixelTypeToFileName: appendPixelTypeToFileName);
+ }
- return image;
+ public static Image CompareToReferenceOutput(
+ this Image image,
+ ITestTextureProvider provider,
+ FormattableString testOutputDetails,
+ string extension = "png",
+ bool appendPixelTypeToFileName = false,
+ bool appendSourceFileOrDescription = false)
+ where TPixel : unmanaged, IPixel => image.CompareToReferenceOutput(
+ provider,
+ (object)testOutputDetails,
+ extension,
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription);
+
+ ///
+ /// Compares the image against the expected Reference output, throws an exception if the images are not similar enough.
+ /// The output file should be named identically to the output produced by .
+ ///
+ /// The pixel format.
+ /// The image which should be compared to the reference image.
+ /// The image provider.
+ /// Details to be concatenated to the test output file, describing the parameters of the test.
+ /// The extension
+ /// A boolean indicating whether to append the pixel type to the output file name.
+ /// A boolean indicating whether to append to the test output file name.
+ /// The image.
+ public static Image CompareToReferenceOutput(
+ this Image image,
+ ITestTextureProvider provider,
+ object testOutputDetails = null,
+ string extension = "png",
+ bool appendPixelTypeToFileName = false,
+ bool appendSourceFileOrDescription = false)
+ where TPixel : unmanaged, IPixel => CompareToReferenceOutput(
+ image,
+ ImageComparer.Tolerant(),
+ provider,
+ testOutputDetails,
+ extension,
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription);
+
+ public static Image CompareToReferenceOutput(
+ this Image image,
+ ImageComparer comparer,
+ ITestTextureProvider provider,
+ FormattableString testOutputDetails,
+ string extension = "png",
+ bool appendPixelTypeToFileName = false)
+ where TPixel : unmanaged, IPixel => image.CompareToReferenceOutput(
+ comparer,
+ provider,
+ (object)testOutputDetails,
+ extension,
+ appendPixelTypeToFileName);
+
+ ///
+ /// Compares the image against the expected Reference output, throws an exception if the images are not similar enough.
+ /// The output file should be named identically to the output produced by .
+ ///
+ /// The pixel format.
+ /// The image which should be compared to the reference output.
+ /// The to use.
+ /// The image provider.
+ /// Details to be concatenated to the test output file, describing the parameters of the test.
+ /// The extension
+ /// A boolean indicating whether to append the pixel type to the output file name.
+ /// A boolean indicating whether to append SourceFileOrDescription to the test output file name.
+ /// A custom decoder.
+ /// The image.
+ public static Image CompareToReferenceOutput(
+ this Image image,
+ ImageComparer comparer,
+ ITestTextureProvider provider,
+ object testOutputDetails = null,
+ string extension = "png",
+ bool appendPixelTypeToFileName = false,
+ bool appendSourceFileOrDescription = false,
+ IImageDecoder decoder = null)
+ where TPixel : unmanaged, IPixel
+ {
+ using (Image referenceImage = GetReferenceOutputImage(
+ provider,
+ testOutputDetails,
+ extension,
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription,
+ decoder))
+ {
+ comparer.VerifySimilarity(referenceImage, image);
}
- public static Image GetReferenceOutputImage(
- this ITestTextureProvider provider,
- object testOutputDetails = null,
- string extension = "png",
- bool appendPixelTypeToFileName = false,
- bool appendSourceFileOrDescription = false,
- IImageDecoder decoder = null)
- where TPixel : unmanaged, IPixel
+ return image;
+ }
+
+ ///
+ /// Compares all six faces of the cubemap's first mipmap against their individual reference images.
+ /// Reference files must be named "{testName}_{facePrefix}posX{faceSuffix}.png" etc.,
+ /// matching the saved debug output.
+ ///
+ /// The pixel format.
+ /// The decoded cubemap.
+ /// The comparer to use for every face.
+ /// The test texture provider.
+ ///
+ /// Optional suffix appended after the face name in the reference filename. Useful for
+ /// parameterized cubemap tests that share a single test name across multiple inputs
+ /// (e.g. a block-size suffix).
+ ///
+ public static void CompareFacesToReferenceOutput(
+ this CubemapTexture cubemap,
+ ImageComparer comparer,
+ ITestTextureProvider provider,
+ string faceSuffix = null)
+ where TPixel : unmanaged, IPixel
+ {
+ CompareFace(cubemap.PositiveX, BuildDetails("posX", faceSuffix), comparer, provider);
+ CompareFace(cubemap.NegativeX, BuildDetails("negX", faceSuffix), comparer, provider);
+ CompareFace(cubemap.PositiveY, BuildDetails("posY", faceSuffix), comparer, provider);
+ CompareFace(cubemap.NegativeY, BuildDetails("negY", faceSuffix), comparer, provider);
+ CompareFace(cubemap.PositiveZ, BuildDetails("posZ", faceSuffix), comparer, provider);
+ CompareFace(cubemap.NegativeZ, BuildDetails("negZ", faceSuffix), comparer, provider);
+ }
+
+ private static string BuildDetails(string faceName, string suffix)
+ => string.IsNullOrEmpty(suffix) ? faceName : $"{faceName}_{suffix}";
+
+ private static void CompareFace(
+ FlatTexture face,
+ string details,
+ ImageComparer comparer,
+ ITestTextureProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image faceImage = face.MipMaps[0].GetImage();
+ (faceImage as Image).CompareToReferenceOutput(comparer, provider, testOutputDetails: details);
+ }
+
+ public static Image GetReferenceOutputImage(
+ this ITestTextureProvider provider,
+ object testOutputDetails = null,
+ string extension = "png",
+ bool appendPixelTypeToFileName = false,
+ bool appendSourceFileOrDescription = false,
+ IImageDecoder decoder = null)
+ where TPixel : unmanaged, IPixel
+ {
+ string referenceOutputFile = provider.Utility.GetReferenceOutputFileName(
+ extension,
+ testOutputDetails,
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription);
+
+ if (!File.Exists(referenceOutputFile))
{
- string referenceOutputFile = provider.Utility.GetReferenceOutputFileName(
- extension,
- testOutputDetails,
- appendPixelTypeToFileName,
- appendSourceFileOrDescription);
-
- if (!File.Exists(referenceOutputFile))
- {
- throw new FileNotFoundException($"Reference output file {referenceOutputFile} is missing", referenceOutputFile);
- }
-
- IImageFormat format = TestEnvironment.GetImageFormat(referenceOutputFile);
- decoder ??= TestEnvironment.GetReferenceDecoder(referenceOutputFile);
-
- ImageSharp.Configuration configuration = ImageSharp.Configuration.Default.Clone();
- configuration.ImageFormatsManager.SetDecoder(format, decoder);
- DecoderOptions options = new()
- {
- Configuration = configuration
- };
-
- return Image.Load(options, referenceOutputFile);
+ throw new FileNotFoundException($"Reference output file {referenceOutputFile} is missing", referenceOutputFile);
}
+
+ IImageFormat format = TestEnvironment.GetImageFormat(referenceOutputFile);
+ decoder ??= TestEnvironment.GetReferenceDecoder(referenceOutputFile);
+
+ ImageSharp.Configuration configuration = ImageSharp.Configuration.Default.Clone();
+ configuration.ImageFormatsManager.SetDecoder(format, decoder);
+ DecoderOptions options = new()
+ {
+ Configuration = configuration
+ };
+
+ return Image.Load(options, referenceOutputFile);
}
}
From 07793ba2b8d7dc66da3d470612d8c21f8cf0ca07 Mon Sep 17 00:00:00 2001
From: Erik White <26148654+Erik-White@users.noreply.github.com>
Date: Sun, 17 May 2026 13:35:56 +0200
Subject: [PATCH 4/8] Support test data subdirectories
---
.../Attributes/WithFileAttribute.cs | 88 +++++++++++--------
1 file changed, 50 insertions(+), 38 deletions(-)
diff --git a/tests/ImageSharp.Textures.Tests/TestUtilities/Attributes/WithFileAttribute.cs b/tests/ImageSharp.Textures.Tests/TestUtilities/Attributes/WithFileAttribute.cs
index b8eed784..8fd3c6cb 100644
--- a/tests/ImageSharp.Textures.Tests/TestUtilities/Attributes/WithFileAttribute.cs
+++ b/tests/ImageSharp.Textures.Tests/TestUtilities/Attributes/WithFileAttribute.cs
@@ -1,57 +1,69 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
using System.Reflection;
-using System.Text.RegularExpressions;
using SixLabors.ImageSharp.Textures.Tests.Enums;
using SixLabors.ImageSharp.Textures.Tests.TestUtilities.TextureProviders;
using Xunit.Sdk;
-namespace SixLabors.ImageSharp.Textures.Tests.TestUtilities.Attributes
+namespace SixLabors.ImageSharp.Textures.Tests.TestUtilities.Attributes;
+
+public class WithFileAttribute : DataAttribute
{
- public class WithFileAttribute : DataAttribute
+ private readonly TestTextureFormat textureFormat;
+ private readonly TestTextureType textureType;
+ private readonly TestTextureTool textureTool;
+ private readonly string inputFile;
+
+ public WithFileAttribute(TestTextureFormat textureFormat, TestTextureType textureType, TestTextureTool textureTool, string inputFile)
{
- private readonly TestTextureFormat textureFormat;
- private readonly TestTextureType textureType;
- private readonly TestTextureTool textureTool;
- private readonly string inputFile;
- private readonly bool isRegex;
+ this.textureFormat = textureFormat;
+ this.textureType = textureType;
+ this.textureTool = textureTool;
+ this.inputFile = inputFile;
+ }
- public WithFileAttribute(TestTextureFormat textureFormat, TestTextureType textureType, TestTextureTool textureTool, string inputFile, bool isRegex = false)
- {
- this.textureFormat = textureFormat;
- this.textureType = textureType;
- this.textureTool = textureTool;
- this.inputFile = inputFile;
- this.isRegex = isRegex;
- }
+ public override IEnumerable
From 15982db23b87a4e157fbd6bee4602c504cc3c8c3 Mon Sep 17 00:00:00 2001
From: Erik White <26148654+Erik-White@users.noreply.github.com>
Date: Sun, 17 May 2026 18:15:50 +0200
Subject: [PATCH 8/8] Update shared infra
---
shared-infrastructure | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/shared-infrastructure b/shared-infrastructure
index 57699ffb..4a5a9fe7 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 57699ffb797bc2389c5d6cbb3b1800f2eb5fb947
+Subproject commit 4a5a9fe756e75c92ef9042b0ea4d94bc35e6ace9