From fd2e8a90adebd0408440a0d522d252da36700a1a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 10 Dec 2024 14:57:27 +1000 Subject: [PATCH] Migrate tests --- .editorconfig | 12 ++-- .gitattributes | 7 ++ shared-infrastructure | 2 +- .../Icc/ColorProfileConverterTests.Icc.cs | 63 ++++++++++++++++++ .../ColorProfiles/Icc/TestIccProfiles.cs | 35 ++++++++++ .../ImageSharp.Tests/ImageSharp.Tests.csproj | 7 +- .../Metadata/Profiles/ICC/IccProfileTests.cs | 66 ------------------- 7 files changed, 114 insertions(+), 78 deletions(-) create mode 100644 tests/ImageSharp.Tests/ColorProfiles/Icc/ColorProfileConverterTests.Icc.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/Icc/TestIccProfiles.cs diff --git a/.editorconfig b/.editorconfig index c28089d72..af1e5b44c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -104,8 +104,8 @@ dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:war dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion # Expression-level preferences -dotnet_style_object_initializer = true:warning -dotnet_style_collection_initializer = true:warning +dotnet_style_object_initializer = true:error +dotnet_style_collection_initializer = true:error dotnet_style_explicit_tuple_names = true:warning dotnet_style_prefer_inferred_tuple_names = true:warning dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning @@ -135,9 +135,9 @@ csharp_style_prefer_null_check_over_type_check = true:warning # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#c-style-rules [*.{cs,csx,cake}] # 'var' preferences -csharp_style_var_for_built_in_types = false:warning -csharp_style_var_when_type_is_apparent = false:warning -csharp_style_var_elsewhere = false:warning +csharp_style_var_for_built_in_types = false:error +csharp_style_var_when_type_is_apparent = false:error +csharp_style_var_elsewhere = false:error # Expression-bodied members csharp_style_expression_bodied_methods = true:warning csharp_style_expression_bodied_constructors = true:warning @@ -160,7 +160,7 @@ csharp_style_pattern_local_over_anonymous_function = true:warning csharp_style_deconstructed_variable_declaration = true:warning csharp_style_prefer_index_operator = true:warning csharp_style_prefer_range_operator = true:warning -csharp_style_implicit_object_creation_when_type_is_apparent = true:warning +csharp_style_implicit_object_creation_when_type_is_apparent = true:error # "Null" checking preferences csharp_style_throw_expression = true:warning csharp_style_conditional_delegate_call = true:warning diff --git a/.gitattributes b/.gitattributes index b5f742ab4..f7bd4d061 100644 --- a/.gitattributes +++ b/.gitattributes @@ -136,3 +136,10 @@ *.ico filter=lfs diff=lfs merge=lfs -text *.cur filter=lfs diff=lfs merge=lfs -text *.ani filter=lfs diff=lfs merge=lfs -text +*.heic filter=lfs diff=lfs merge=lfs -text +*.hif filter=lfs diff=lfs merge=lfs -text +*.avif filter=lfs diff=lfs merge=lfs -text +############################################################################### +# Handle ICC files by git lfs +############################################################################### +*.icc filter=lfs diff=lfs merge=lfs -text diff --git a/shared-infrastructure b/shared-infrastructure index 1dbfb576c..5e13cde85 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f +Subproject commit 5e13cde851a3d6e95d0dfdde2a57071f1efda9c3 diff --git a/tests/ImageSharp.Tests/ColorProfiles/Icc/ColorProfileConverterTests.Icc.cs b/tests/ImageSharp.Tests/ColorProfiles/Icc/ColorProfileConverterTests.Icc.cs new file mode 100644 index 000000000..b3aa29f18 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/Icc/ColorProfileConverterTests.Icc.cs @@ -0,0 +1,63 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; +using Wacton.Unicolour; +using Wacton.Unicolour.Icc; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles.Icc; + +public class ColorProfileConverterTests +{ + [Theory] + [InlineData(TestIccProfiles.Fogra39, TestIccProfiles.Fogra39)] + [InlineData(TestIccProfiles.Fogra39, TestIccProfiles.Swop2006)] + [InlineData(TestIccProfiles.Swop2006, TestIccProfiles.Fogra39)] + [InlineData(TestIccProfiles.Swop2006, TestIccProfiles.Swop2006)] + public void CanConvertCmykIccProfiles(string sourceProfileName, string targetProfileName) + { + Cmyk input = new(GetNormalizedRandomValue(), GetNormalizedRandomValue(), GetNormalizedRandomValue(), GetNormalizedRandomValue()); + + ColorProfileConverter converter = new(new ColorConversionOptions + { + SourceIccProfile = TestIccProfiles.GetProfile(sourceProfileName), + TargetIccProfile = TestIccProfiles.GetProfile(targetProfileName), + }); + + Cmyk expectedTargetValues = GetExpectedTargetCmyk(sourceProfileName, targetProfileName, input); + Cmyk actualTargetValues = converter.Convert(input); + + const double tolerance = 0.0000005; + Assert.Equal(expectedTargetValues.C, actualTargetValues.C, tolerance); + Assert.Equal(expectedTargetValues.M, actualTargetValues.M, tolerance); + Assert.Equal(expectedTargetValues.Y, actualTargetValues.Y, tolerance); + Assert.Equal(expectedTargetValues.K, actualTargetValues.K, tolerance); + } + + private static Cmyk GetExpectedTargetCmyk(string sourceProfileName, string targetProfileName, Cmyk sourceCmyk) + { + Wacton.Unicolour.Configuration sourceConfig = TestIccProfiles.GetUnicolourConfiguration(sourceProfileName); + Wacton.Unicolour.Configuration targetConfig = TestIccProfiles.GetUnicolourConfiguration(targetProfileName); + + Channels channels = new(sourceCmyk.C, sourceCmyk.M, sourceCmyk.Y, sourceCmyk.K); + + Unicolour source = new(sourceConfig, channels); + ColourSpace pcs = sourceConfig.Icc.Profile!.Header.Pcs == "Lab " ? ColourSpace.Lab : ColourSpace.Xyz; + ColourTriplet pcsTriplet = pcs == ColourSpace.Lab ? source.Lab.Triplet : source.Xyz.Triplet; + Unicolour target = new(targetConfig, pcs, pcsTriplet.Tuple); + double[] targetCmyk = target.Icc.Values; + return new Cmyk((float)targetCmyk[0], (float)targetCmyk[1], (float)targetCmyk[2], (float)targetCmyk[3]); + } + + private static float GetNormalizedRandomValue() + { + // Generate a random value between 0 (inclusive) and 1 (exclusive). + double value = Random.Shared.NextDouble(); + + // If the random value is exactly 0, return 0F to ensure inclusivity at the lower bound. + // For non-zero values, add a small increment (0.0000001F) to ensure the range + // is inclusive at the upper bound while retaining precision. + // Clamp the result between 0 and 1 to ensure it does not exceed the bounds. + return value == 0 ? 0F : Math.Clamp((float)value + 0.0000001F, 0, 1); + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/Icc/TestIccProfiles.cs b/tests/ImageSharp.Tests/ColorProfiles/Icc/TestIccProfiles.cs new file mode 100644 index 000000000..49b1e6672 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/Icc/TestIccProfiles.cs @@ -0,0 +1,35 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Collections.Concurrent; +using SixLabors.ImageSharp.Metadata.Profiles.Icc; +using Wacton.Unicolour.Icc; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles.Icc; + +internal static class TestIccProfiles +{ + private static readonly ConcurrentDictionary ProfileCache = new(); + private static readonly ConcurrentDictionary UnicolourConfigurationCache = new(); + + public const string Fogra39 = "Coated_Fogra39L_VIGC_300.icc"; + + public const string Swop2006 = "SWOP2006_Coated5v2.icc"; + + public static IccProfile GetProfile(string file) + => ProfileCache.GetOrAdd(file, f => new IccProfile(File.ReadAllBytes(GetFullPath(f)))); + + public static Wacton.Unicolour.Configuration GetUnicolourConfiguration(string file) + => UnicolourConfigurationCache.GetOrAdd( + file, + f => + { + string p = GetFullPath(f); + bool b = File.Exists(p); + var profile = new Profile(p); + return new Wacton.Unicolour.Configuration(iccConfiguration: new(GetFullPath(f), Intent.Unspecified)); + }); + + private static string GetFullPath(string file) + => Path.GetFullPath(Path.Combine(".", "TestDataIcc", "Profiles", file)); +} diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 6fd3eb30c..a84da86cf 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -32,11 +32,8 @@ True PixelOperationsTests.Specialized.Generated.tt - - Always - - - Always + + PreserveNewest diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs index 6b7050161..9c4abfe3e 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs @@ -1,11 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Tests.TestDataIcc; -using Wacton.Unicolour; -using Wacton.Unicolour.Icc; namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Icc; @@ -43,67 +40,4 @@ public class IccProfileTests Assert.Equal(expected, result); } - - private const string Fogra39 = "Coated_Fogra39L_VIGC_300.icc"; - private const string Swop2006 = "SWOP2006_Coated5v2.icc"; - - [Theory] - [InlineData(Fogra39, Fogra39)] - [InlineData(Fogra39, Swop2006)] - [InlineData(Swop2006, Fogra39)] - [InlineData(Swop2006, Swop2006)] - public void UnicolourComparison(string sourceProfileName, string targetProfileName) - { - string sourceIccFilepath = Path.Combine(".", "TestDataIcc", "Profiles", sourceProfileName); - string targetIccFilepath = Path.Combine(".", "TestDataIcc", "Profiles", targetProfileName); - - // TODO: pass in specific values to test? use random values? - Cmyk input = new(0.8f, 0.6f, 0.4f, 0.2f); - Cmyk expectedTargetValues = GetExpectedTargetCmyk(sourceIccFilepath, targetIccFilepath, input); - - ColorProfileConverter converter = new(new ColorConversionOptions - { - SourceIccProfile = new IccProfile(File.ReadAllBytes(sourceIccFilepath)), - TargetIccProfile = new IccProfile(File.ReadAllBytes(targetIccFilepath)) - }); - - Cmyk actualTargetValues = converter.Convert(input); - - const double tolerance = 0.0000005; - Assert.Equal(expectedTargetValues.C, actualTargetValues.C, tolerance); - Assert.Equal(expectedTargetValues.M, actualTargetValues.M, tolerance); - Assert.Equal(expectedTargetValues.Y, actualTargetValues.Y, tolerance); - Assert.Equal(expectedTargetValues.K, actualTargetValues.K, tolerance); - } - - private static Cmyk GetExpectedTargetCmyk(string sourceIccFilepath, string targetIccFilepath, Cmyk sourceCmyk) - { - Wacton.Unicolour.Configuration sourceConfig = GetUnicolourConfig(sourceIccFilepath); - Wacton.Unicolour.Configuration targetConfig = GetUnicolourConfig(targetIccFilepath); - - Channels channels = new(sourceCmyk.C, sourceCmyk.M, sourceCmyk.Y, sourceCmyk.K); - - Unicolour source = new(sourceConfig, channels); - ColourSpace pcs = sourceConfig.Icc.Profile!.Header.Pcs == "Lab " ? ColourSpace.Lab : ColourSpace.Xyz; - ColourTriplet pcsTriplet = pcs == ColourSpace.Lab ? source.Lab.Triplet : source.Xyz.Triplet; - Unicolour target = new(targetConfig, pcs, pcsTriplet.Tuple); - double[] targetCmyk = target.Icc.Values; - return new Cmyk((float)targetCmyk[0], (float)targetCmyk[1], (float)targetCmyk[2], (float)targetCmyk[3]); - } - - // Unicolour configurations are relatively expensive to instantiate - private static readonly Dictionary UnicolourConfigCache = new(); - - private static Wacton.Unicolour.Configuration GetUnicolourConfig(string iccFilepath) - { - Wacton.Unicolour.Configuration config; - if (UnicolourConfigCache.TryGetValue(iccFilepath, out config)) - { - return config; - } - - config = new Wacton.Unicolour.Configuration(iccConfiguration: new(iccFilepath, Intent.Unspecified)); - UnicolourConfigCache.Add(iccFilepath, config); - return config; - } }