From 7b13bdc57e8ef767e6787732e075ff4b26c0e79f Mon Sep 17 00:00:00 2001 From: Johann Dirry Date: Wed, 25 Mar 2026 14:11:41 +0100 Subject: [PATCH 1/2] adding unit tests for custom swatch colors --- .../CustomSemanticSwatchTests.cs | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs diff --git a/tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs b/tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs new file mode 100644 index 0000000000..2032d022c3 --- /dev/null +++ b/tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs @@ -0,0 +1,168 @@ +using System.Windows.Media; + +namespace MaterialColorUtilities.Tests; + +public sealed class CustomSemanticSwatchTests +{ + [Test] + public async Task CustomSemanticSwatches_ExtractExpectedThemeColors() + { + var materialDynamicColors = new MaterialDynamicColors(); + + foreach (var semanticColor in GetSemanticColorExpectations()) + { + foreach (var isDark in new[] { false, true }) + { + var expected = isDark ? semanticColor.Dark : semanticColor.Light; + var scheme = CreateSchemeWithCustomErrorSwatch(semanticColor.Swatch, isDark); + + await Assert.That(materialDynamicColors.ErrorPaletteKeyColor.GetColor(scheme)) + .IsEqualTo(expected.PaletteKey) + .Because($"{semanticColor.Name} palette key did not match for {(isDark ? "dark" : "light")} mode."); + + await Assert.That(materialDynamicColors.Error.GetColor(scheme)) + .IsEqualTo(expected.Role) + .Because($"{semanticColor.Name} role color did not match for {(isDark ? "dark" : "light")} mode."); + + await Assert.That(materialDynamicColors.OnError.GetColor(scheme)) + .IsEqualTo(expected.OnRole) + .Because($"{semanticColor.Name} on-role color did not match for {(isDark ? "dark" : "light")} mode."); + + await Assert.That(materialDynamicColors.ErrorContainer.GetColor(scheme)) + .IsEqualTo(expected.Container) + .Because($"{semanticColor.Name} container color did not match for {(isDark ? "dark" : "light")} mode."); + + await Assert.That(materialDynamicColors.OnErrorContainer.GetColor(scheme)) + .IsEqualTo(expected.OnContainer) + .Because($"{semanticColor.Name} on-container color did not match for {(isDark ? "dark" : "light")} mode."); + } + } + } + + private static DynamicScheme CreateSchemeWithCustomErrorSwatch(Color semanticSwatch, bool isDark) + { + var sourceColor = Color.FromArgb(255, 106, 156, 89); + var baseScheme = DynamicSchemeFactory.Create( + sourceColor, + Variant.TonalSpot, + isDark, + 0.5, + Platform.Phone, + SpecVersion.Spec2025, + primary: null, + secondary: null, + tertiary: null, + neutral: null, + neutralVariant: null, + error: null); + + return new DynamicScheme( + baseScheme.SourceColorHct, + baseScheme.Variant, + baseScheme.IsDark, + baseScheme.ContrastLevel, + baseScheme.PlatformType, + baseScheme.SpecVersion, + baseScheme.PrimaryPalette, + baseScheme.SecondaryPalette, + baseScheme.TertiaryPalette, + baseScheme.NeutralPalette, + baseScheme.NeutralVariantPalette, + TonalPalette.FromInt(ColorUtils.ArgbFromColor(semanticSwatch))); + } + + private static SemanticColorExpectation[] GetSemanticColorExpectations() + { + return + [ + new SemanticColorExpectation( + "WarningHigh", + Color.FromArgb(255, 212, 69, 41), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 212, 69, 41), + Role: Color.FromArgb(255, 111, 15, 0), + OnRole: Colors.White, + Container: Color.FromArgb(255, 198, 59, 32), + OnContainer: Colors.White), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 212, 69, 41), + Role: Color.FromArgb(255, 255, 210, 201), + OnRole: Color.FromArgb(255, 80, 8, 0), + Container: Color.FromArgb(255, 247, 94, 63), + OnContainer: Colors.Black)), + new SemanticColorExpectation( + "WarningLow", + Color.FromArgb(255, 252, 163, 41), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 252, 163, 41), + Role: Color.FromArgb(255, 80, 47, 0), + OnRole: Colors.White, + Container: Color.FromArgb(255, 156, 95, 0), + OnContainer: Colors.White), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 252, 163, 41), + Role: Color.FromArgb(255, 255, 213, 169), + OnRole: Color.FromArgb(255, 57, 32, 0), + Container: Color.FromArgb(255, 205, 127, 0), + OnContainer: Colors.Black)), + new SemanticColorExpectation( + "Information", + Color.FromArgb(255, 0, 46, 122), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 0, 46, 122), + Role: Color.FromArgb(255, 5, 49, 125), + OnRole: Colors.White, + Container: Color.FromArgb(255, 76, 106, 184), + OnContainer: Colors.White), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 0, 46, 122), + Role: Color.FromArgb(255, 210, 219, 255), + OnRole: Color.FromArgb(255, 0, 33, 93), + Container: Color.FromArgb(255, 112, 142, 222), + OnContainer: Colors.Black)), + new SemanticColorExpectation( + "Safe", + Color.FromArgb(255, 41, 138, 64), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 41, 138, 64), + Role: Color.FromArgb(255, 0, 64, 21), + OnRole: Colors.White, + Container: Color.FromArgb(255, 24, 126, 53), + OnContainer: Colors.White), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 41, 138, 64), + Role: Color.FromArgb(255, 145, 242, 155), + OnRole: Color.FromArgb(255, 0, 45, 12), + Container: Color.FromArgb(255, 69, 163, 86), + OnContainer: Colors.Black)), + new SemanticColorExpectation( + "Error", + Color.FromArgb(255, 163, 23, 26), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 163, 23, 26), + Role: Color.FromArgb(255, 115, 0, 9), + OnRole: Colors.White, + Container: Color.FromArgb(255, 201, 53, 49), + OnContainer: Colors.White), + new ExtractedSemanticColors( + PaletteKey: Color.FromArgb(255, 163, 23, 26), + Role: Color.FromArgb(255, 255, 210, 205), + OnRole: Color.FromArgb(255, 84, 0, 4), + Container: Color.FromArgb(255, 251, 89, 80), + OnContainer: Colors.Black)) + ]; + } + + private sealed record SemanticColorExpectation( + string Name, + Color Swatch, + ExtractedSemanticColors Light, + ExtractedSemanticColors Dark); + + private sealed record ExtractedSemanticColors( + Color PaletteKey, + Color Role, + Color OnRole, + Color Container, + Color OnContainer); +} From 17c8b2459eabf5f13335640768550a4c6f8d9cc7 Mon Sep 17 00:00:00 2001 From: Johann Dirry Date: Mon, 30 Mar 2026 11:45:54 +0200 Subject: [PATCH 2/2] Update tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs Co-authored-by: Kevin B --- .../MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs b/tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs index 2032d022c3..8d2dfbbe0d 100644 --- a/tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs +++ b/tests/MaterialColorUtilities.Tests/CustomSemanticSwatchTests.cs @@ -5,7 +5,9 @@ namespace MaterialColorUtilities.Tests; public sealed class CustomSemanticSwatchTests { [Test] - public async Task CustomSemanticSwatches_ExtractExpectedThemeColors() + [Arguments(true)] + [Arguments(false)] + public async Task CustomSemanticSwatches_ExtractExpectedThemeColors(bool isDark) { var materialDynamicColors = new MaterialDynamicColors();