Fix Color equality regression for derived types by sealing the record - #36443
Fix Color equality regression for derived types by sealing the record#36443Shalini-Ashokan wants to merge 2 commits into
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36443Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36443" |
|
Hey there @@Shalini-Ashokan! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@Shalini-Ashokan — new AI review results are available based on this last commit:
b4295f0. To request a fresh review after new comments or commits, comment/review rerun.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ✅ PASSED
Platform: ANDROID · Base: net11.0 · Merge base: 7f139ed4
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🧪 ColorUnitTests ColorUnitTests |
✅ FAIL — 26s | ✅ PASS — 18s |
🔴 Without fix — 🧪 ColorUnitTests: FAIL ✅ · 26s
Determining projects to restore...
Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 1.65 sec).
Restored /home/vsts/work/1/s/src/Graphics/src/Text.Markdig/Graphics.Text.Markdig.csproj (in 1.14 sec).
Restored /home/vsts/work/1/s/src/Graphics/tests/Graphics.Tests/Graphics.Tests.csproj (in 2.92 sec).
Restored /home/vsts/work/1/s/src/Graphics/samples/GraphicsTester.Portable/GraphicsTester.Portable.csproj (in 14 ms).
Restored /home/vsts/work/1/s/src/Graphics/src/Graphics.Skia/Graphics.Skia.csproj (in 717 ms).
##vso[build.updatebuildnumber]11.0.0-ci+azdo.14657449
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net11.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]11.0.0-ci+azdo.14657449
Graphics.Skia -> /home/vsts/work/1/s/artifacts/bin/Graphics.Skia/Debug/net11.0/Microsoft.Maui.Graphics.Skia.dll
##vso[build.updatebuildnumber]11.0.0-ci+azdo.14657449
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/netstandard2.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]11.0.0-ci+azdo.14657449
Graphics.Text.Markdig -> /home/vsts/work/1/s/artifacts/bin/Graphics.Text.Markdig/Debug/netstandard2.0/Microsoft.Maui.Graphics.Text.Markdig.dll
GraphicsTester.Portable -> /home/vsts/work/1/s/artifacts/bin/GraphicsTester.Portable/Debug/net11.0/GraphicsTester.Portable.dll
Graphics.Tests -> /home/vsts/work/1/s/artifacts/bin/Graphics.Tests/Debug/net11.0/Graphics.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Graphics.Tests/Debug/net11.0/Graphics.Tests.dll (.NETCoreApp,Version=v11.0)
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.01] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 11.0.0-preview.6.26325.125)
[xUnit.net 00:00:00.20] Discovering: Graphics.Tests
[xUnit.net 00:00:00.50] Discovered: Graphics.Tests
[xUnit.net 00:00:00.52] Starting: Graphics.Tests
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "") [47 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "hsv(120, 100#, 50#)") [3 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "#12g") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: null) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "#ZZZ") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "hsv(120%, 100%, 50%)") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "hsva(120, 120%, 50%, a)") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "#1g3") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "#zyxv") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "222") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "notAColor") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "default") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "rgb255,0,0") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "rgb)255,0,0(") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "rgba(255, 0, 0, 0.8") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHsvaDouble [5 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestSetHue [5 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHashCode [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestColorFromValue [12 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.GetComplementary(original: "#00FF00", expected: "#FF00FF") [6 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.GetComplementary(original: "#0000FF", expected: "#FFFF00") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.GetComplementary(original: "#0AF56C", expected: "#F50A93") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.GetComplementary(original: "#FF0000", expected: "#00FFFF") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLModifiers [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestToString [4 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHex [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLToRGB [2 ms]
[xUnit.net 00:00:00.90] Assert.True() Failure
[xUnit.net 00:00:00.90] Expected: True
[xUnit.net 00:00:00.90] Actual: False
[xUnit.net 00:00:00.90] Stack Trace:
[xUnit.net 00:00:00.90] /_/src/Graphics/tests/Graphics.Tests/ColorUnitTests.cs(477,0): at Microsoft.Maui.Graphics.Tests.ColorUnitTests.ColorTypeIsSealed()
[xUnit.net 00:00:00.90] at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
[xUnit.net 00:00:00.90] at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestAddLuminosity [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHashCodeNamedColors [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.ToUInt [8 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.DefaultColorsMatch [< 1 ms]
Failed Microsoft.Maui.Graphics.Tests.ColorUnitTests.ColorTypeIsSealed [2 ms]
Error Message:
Assert.True() Failure
Expected: True
Actual: False
Stack Trace:
at Microsoft.Maui.Graphics.Tests.ColorUnitTests.ColorTypeIsSealed() in /_/src/Graphics/tests/Graphics.Tests/ColorUnitTests.cs:line 477
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromUint [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestRGBToHSL [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseAllBuiltInColors [3 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestToHex [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLPostSetEquality [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#a222", expected: [Color: Red=0.13333334, Green=0.13333334, Blue=0.13333334, Alpha=0.6666667]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#C2F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=0.7607843]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#000000", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#000", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#00FFff 40%", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "a222", expected: [Color: Red=0.13333334, Green=0.13333334, Blue=0.13333334, Alpha=0.6666667]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "C2F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=0.7607843]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "#111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [3 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "#a222", expected: [Color: Red=0.6666667, Green=0.13333334, Blue=0.13333334, Alpha=0.13333334]) [1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "#F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "#C2F2E2D2", expected: [Color: Red=0.7607843, Green=0.9490196, Blue=0.8862745, Alpha=0.8235294]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "a222", expected: [Color: Red=0.6666667, Green=0.13333334, Blue=0.13333334, Alpha=0.13333334]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "C2F2E2D2", expected: [Color: Red=0.7607843, Green=0.9490196, Blue=0.8862745, Alpha=0.8235294]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#a222", expected: [Color: Red=0.13333334, Green=0.13333334, Blue=0.13333334, Alpha=0.6666667]) [2 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#C2F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=0.7607843]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#000000", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#000", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#00FFff 40%", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "rgb(255,0,0)", expected: [Color: Red=1, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "rgb(100%, 0%, 0%)", expected: [Color: Red=1, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "rgba(0, 255, 0, 0.7)", expected: [Color: Red=0, Green=1, Blue=0, Alpha=0.7]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "rgba(0%, 100%, 0%, 0.7)", expected: [Color: Red=0, Green=1, Blue=0, Alpha=0.7]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsl(120, 100%, 50%)", expected: [Color: Red=0, Green=1, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsl(120, 75, 20%)", expected: [Color: Red=0.050000012, Green=0.35, Blue=0.050000012, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsla(160, 100%, 50%, .4)", expected: [Color: Red=0, Green=1, Blue=0.6666666, Alpha=0.4]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsla(160,100%,50%,.6)", expected: [Color: Red=0, Green=1, Blue=0.6666666, Alpha=0.6]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsv(120, 85%, 35%)", expected: [Color: Red=0.05249999, Green=0.35, Blue=0.05249999, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsv(120, 85, 35)", expected: [Color: Red=0.05249999, Green=0.35, Blue=0.05249999, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsva(120, 100%, 50%, .8)", expected: [Color: Red=0, Green=0.5, Blue=0, Alpha=0.8]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsva(120, 100, 50, .8)", expected: [Color: Red=0, Green=0.5, Blue=0, Alpha=0.8]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestZeroLuminosity [9 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.EqualsIsValueBasedForSameArgbValue [13 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHsv [6 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestClamping [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.EqualsIsFalseForDifferentArgbValue [8 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHashCodeAll [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.ZeroLuminToRGB [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHsva [7 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHsvDouble [< 1 ms]
[xUnit.net 00:00:00.90] Microsoft.Maui.Graphics.Tests.ColorUnitTests.ColorTypeIsSealed [FAIL]
[xUnit.net 00:00:00.97] Finished: Graphics.Tests
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.FromRGBADouble [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestMultiplyAlpha [12 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.FromRGBDouble [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLPostSetInequality [2 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLSetToDefaultValue [< 1 ms]
Test Run Failed.
Total tests: 89
Passed: 88
Failed: 1
Total time: 2.7170 Seconds
🟢 With fix — 🧪 ColorUnitTests: PASS ✅ · 18s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]11.0.0-ci+azdo.14657449
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net11.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]11.0.0-ci+azdo.14657449
##vso[build.updatebuildnumber]11.0.0-ci+azdo.14657449
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/netstandard2.0/Microsoft.Maui.Graphics.dll
Graphics.Skia -> /home/vsts/work/1/s/artifacts/bin/Graphics.Skia/Debug/net11.0/Microsoft.Maui.Graphics.Skia.dll
##vso[build.updatebuildnumber]11.0.0-ci+azdo.14657449
Graphics.Text.Markdig -> /home/vsts/work/1/s/artifacts/bin/Graphics.Text.Markdig/Debug/netstandard2.0/Microsoft.Maui.Graphics.Text.Markdig.dll
GraphicsTester.Portable -> /home/vsts/work/1/s/artifacts/bin/GraphicsTester.Portable/Debug/net11.0/GraphicsTester.Portable.dll
Graphics.Tests -> /home/vsts/work/1/s/artifacts/bin/Graphics.Tests/Debug/net11.0/Graphics.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Graphics.Tests/Debug/net11.0/Graphics.Tests.dll (.NETCoreApp,Version=v11.0)
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.01] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 11.0.0-preview.6.26325.125)
[xUnit.net 00:00:00.33] Discovering: Graphics.Tests
[xUnit.net 00:00:00.67] Discovered: Graphics.Tests
[xUnit.net 00:00:00.71] Starting: Graphics.Tests
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "") [39 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "hsv(120, 100#, 50#)") [5 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "#12g") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: null) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "#ZZZ") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "hsv(120%, 100%, 50%)") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "hsva(120, 120%, 50%, a)") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "#1g3") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "#zyxv") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "222") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "notAColor") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "default") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "rgb255,0,0") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "rgb)255,0,0(") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseBad(badValue: "rgba(255, 0, 0, 0.8") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHsvaDouble [1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestSetHue [5 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHashCode [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestColorFromValue [16 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.GetComplementary(original: "#00FF00", expected: "#FF00FF") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.GetComplementary(original: "#0000FF", expected: "#FFFF00") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.GetComplementary(original: "#0AF56C", expected: "#F50A93") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.GetComplementary(original: "#FF0000", expected: "#00FFFF") [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLModifiers [3 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestToString [2 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHex [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLToRGB [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestAddLuminosity [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHashCodeNamedColors [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.ToUInt [10 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.DefaultColorsMatch [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.ColorTypeIsSealed [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromUint [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestRGBToHSL [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseAllBuiltInColors [5 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestToHex [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLPostSetEquality [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#a222", expected: [Color: Red=0.13333334, Green=0.13333334, Blue=0.13333334, Alpha=0.6666667]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#C2F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=0.7607843]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#000000", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#000", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "#00FFff 40%", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "a222", expected: [Color: Red=0.13333334, Green=0.13333334, Blue=0.13333334, Alpha=0.6666667]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromArgb(value: "C2F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=0.7607843]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "#111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [2 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "#a222", expected: [Color: Red=0.6666667, Green=0.13333334, Blue=0.13333334, Alpha=0.13333334]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "#F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "#C2F2E2D2", expected: [Color: Red=0.7607843, Green=0.9490196, Blue=0.8862745, Alpha=0.8235294]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "a222", expected: [Color: Red=0.6666667, Green=0.13333334, Blue=0.13333334, Alpha=0.13333334]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromRgba(value: "C2F2E2D2", expected: [Color: Red=0.7607843, Green=0.9490196, Blue=0.8862745, Alpha=0.8235294]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#111", expected: [Color: Red=0.06666667, Green=0.06666667, Blue=0.06666667, Alpha=1]) [4 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#a222", expected: [Color: Red=0.13333334, Green=0.13333334, Blue=0.13333334, Alpha=0.6666667]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#C2F2E2D2", expected: [Color: Red=0.9490196, Green=0.8862745, Blue=0.8235294, Alpha=0.7607843]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#000000", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#000", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "#00FFff 40%", expected: [Color: Red=0, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "rgb(255,0,0)", expected: [Color: Red=1, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "rgb(100%, 0%, 0%)", expected: [Color: Red=1, Green=0, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "rgba(0, 255, 0, 0.7)", expected: [Color: Red=0, Green=1, Blue=0, Alpha=0.7]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "rgba(0%, 100%, 0%, 0.7)", expected: [Color: Red=0, Green=1, Blue=0, Alpha=0.7]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsl(120, 100%, 50%)", expected: [Color: Red=0, Green=1, Blue=0, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsl(120, 75, 20%)", expected: [Color: Red=0.050000012, Green=0.35, Blue=0.050000012, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsla(160, 100%, 50%, .4)", expected: [Color: Red=0, Green=1, Blue=0.6666666, Alpha=0.4]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsla(160,100%,50%,.6)", expected: [Color: Red=0, Green=1, Blue=0.6666666, Alpha=0.6]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsv(120, 85%, 35%)", expected: [Color: Red=0.05249999, Green=0.35, Blue=0.05249999, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsv(120, 85, 35)", expected: [Color: Red=0.05249999, Green=0.35, Blue=0.05249999, Alpha=1]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsva(120, 100%, 50%, .8)", expected: [Color: Red=0, Green=0.5, Blue=0, Alpha=0.8]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestParseValid(value: "hsva(120, 100, 50, .8)", expected: [Color: Red=0, Green=0.5, Blue=0, Alpha=0.8]) [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestZeroLuminosity [9 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.EqualsIsValueBasedForSameArgbValue [10 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHsv [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestClamping [4 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.EqualsIsFalseForDifferentArgbValue [6 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHashCodeAll [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.ZeroLuminToRGB [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHsva [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestFromHsvDouble [< 1 ms]
[xUnit.net 00:00:01.15] Finished: Graphics.Tests
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.FromRGBADouble [3 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestMultiplyAlpha [8 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.FromRGBDouble [2 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLPostSetInequality [< 1 ms]
Passed Microsoft.Maui.Graphics.Tests.ColorUnitTests.TestHSLSetToDefaultValue [< 1 ms]
Test Run Successful.
Total tests: 89
Passed: 89
Total time: 2.6078 Seconds
📁 Fix files reverted (9 files)
src/Graphics/src/Graphics/Color.cssrc/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txtsrc/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txtsrc/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txtsrc/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txtsrc/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txtsrc/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txtsrc/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txtsrc/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt
📋 Pre-Flight — Context & Validation
Issue: #36034 - Color record conversion changes equality for derived Color types
PR: #36443 - [WIP] Fix Color equality regression for derived types by sealing the record
Platforms Affected: Android, iOS, Windows, macOS, Tizen/Linux/other via shared Microsoft.Maui.Graphics
Files Changed: 9 implementation/API, 1 test
Key Findings
- #36034 is a regression from .NET MAUI 11 preview 3:
Colorbecame a record class, so record equality requires matchingEqualityContractand returns false for base-vs-derived colors with identical ARGB values. - PR #36443 fixes the symptom by sealing
Color, but that removes subclassing and was already flagged by MauiBot as a public source/binary breaking change. - The gate result provided by the caller passed: tests fail without the PR fix and pass with it. Gate verification was not rerun.
- Relevant test type is unit test:
src/Graphics/tests/Graphics.Tests/Graphics.Tests.csproj --filter ColorUnitTests.
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: high
Errors: 1 | Warnings: 1 | Suggestions: 0
Key code review findings:
- ✗
src/Graphics/src/Graphics/Color.cs:22seals publicColor, breaking existing source/binary consumers that derive from it. - ⚠
src/Graphics/tests/Graphics.Tests/ColorUnitTests.cs:472tests sealing rather than the original base-vs-derived equality regression.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #36443 | Seal Color so record equality cannot compare different runtime types. |
✅ PASSED (Gate) | Color.cs, PublicAPI files, ColorUnitTests.cs |
Original PR; fixes symptom with breaking inheritance change. |
🔬 Code Review — Deep Analysis
Code Review — PR #36443
Independent Assessment
What this changes: The PR changes Microsoft.Maui.Graphics.Color from public record class to public sealed record class, removes virtual from Equals(Color?), updates record-generated PublicAPI entries, and adds tests proving Color is sealed plus same-type value equality.
Inferred motivation: The change attempts to avoid record EqualityContract mismatches by making all Color instances share the same runtime type.
Reconciliation with PR Narrative
Author claims: PR #36443 fixes #36034, where Color record conversion caused base Color and derived Color instances with the same ARGB value to compare unequal.
Agreement/disagreement: The root cause is correct: record equality introduced runtime-type checks. The implementation avoids the scenario by prohibiting subclassing rather than restoring compatible subclass equality.
Prior Review Reconciliation
| Prior ❌ Error Finding | Source | Status | Evidence |
|---|---|---|---|
Sealing shipped public Color is a source/binary breaking change for apps/libraries deriving from Color. |
MauiBot inline review | ❌ Unresolved | src/Graphics/src/Graphics/Color.cs:22 changes public record class Color to public sealed record class Color. |
Blast Radius Assessment
- Runs for all instances: Yes. The type declaration changes globally for
Microsoft.Maui.Graphics.Color. - Startup impact: No direct startup work is introduced.
- Static/shared state: None.
- Public API impact: High. The change removes the ability to derive from
Colorand changes record-generated API shape.
CI Status
- Required-check result: undetermined;
ghwas unavailable because authentication was not configured in this environment. - Classification: undetermined.
- Action taken: confidence capped for CI status. The supplied gate result for the relevant regression tests was already passed and was not rerun.
Findings
❌ Error — Sealing Color is a public API breaking change
src/Graphics/src/Graphics/Color.cs:22 changes Color to sealed. Existing source with class BrandColor : Color no longer compiles, and existing binaries with derived Color types can fail to load. This fixes the equality symptom by removing the original supported scenario.
⚠️ Warning — Regression test locks in the breaking behavior
src/Graphics/tests/Graphics.Tests/ColorUnitTests.cs:472 asserts typeof(Color).IsSealed, but #36034 is specifically about base-vs-derived Color equality. The test no longer exercises the reported compatibility regression.
Failure-Mode Probing
- Existing source subclass: fails to compile because
Coloris sealed. - Existing binary subclass: can fail to load against the new assembly.
- Original reproduction: can no longer be represented because deriving from
Coloris prohibited. - Same-type equality: still passes, but that is not the problematic scenario.
Verdict: NEEDS_CHANGES
Confidence: high for the API compatibility issue; low for CI status because required checks could not be queried.
Summary: The PR identifies the right root cause but fixes it with a breaking public API change. Alternative candidates should preserve Color subclassing or explicitly justify a breaking change.
🛠️ Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix-1 | Keep Color as an unsealed record and remove the EqualityContract check from Equals(Color?). |
❌ FAIL | 2 files | Runtime equality still used record-generated Equals(object?); overriding it caused CS0111. |
| 2 | try-fix-2 | Convert Color to an explicit class : IEquatable<Color> with ARGB equality/operators and remove record-only unshipped API. |
✅ PASS | 10 files | Preserves subclassing and passes ColorUnitTests; expert review found no blockers. |
| PR | PR #36443 | Seal Color so record equality cannot compare different runtime types. |
✅ PASSED (Gate) | 10 files | Fixes symptom but breaks public inheritance compatibility. |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| maui-expert-reviewer | 1 | Yes | Suggested avoiding sealing by either removing record equality semantics or reverting away from record class. |
| maui-expert-reviewer | 2 | No | Reviewed candidate 2 and found no blocking issues; caveat is only preview/unshipped record API compatibility. |
Exhausted: No
Selected Fix: Candidate #2 — It passes the regression tests and is demonstrably better than PR #36443 because it fixes the equality regression without sealing the public Color type.
📝 Recommended PR Title & Description
Assessment: ✏️ Recommend updating — the winning fix is try-fix-2, not the current sealing approach, so the current title and description are now stale and describe the rejected implementation.
Recommended title
Graphics: Restore Color value equality without sealing the type
Recommended description
### Issue Details
`Color.Equals()` returns `false` when comparing a base `Color` and a subclassed `Color` with identical RGBA values, even though `ToInt()` matches. This is a regression starting in .NET MAUI 11 preview 3.
### Root Cause
`Color` was converted from a `class` to a `record class`. Records auto-generate equality paths that include an `EqualityContract` runtime-type check, so a base `Color` and a derived `Color` do not compare equal even when their byte-precision ARGB values match.
### Description of Change
Converted `Color` back to an explicit `class : IEquatable<Color>` and implemented value equality directly:
- `Equals(Color?)` compares the byte-precision ARGB value via `ToInt()`.
- `Equals(object?)`, `==`, and `!=` route through the same `Color` value equality.
- Record-generated members such as `EqualityContract`, `<Clone>$`, and `PrintMembers` are removed from `PublicAPI.Unshipped.txt`.
- Regression coverage now compares a base `Color` with a derived `Color` that has the same ARGB value.
This preserves the shipped ability to subclass `Color` while restoring value-based equality.
### What NOT to Do
- Do not seal `Color` just to avoid record equality's `EqualityContract` check; that fixes the symptom but breaks public subclassing compatibility.
- Do not try to customize only `Equals(Color?)` while keeping `Color` as a record; record-generated equality paths still control other comparisons and `Equals(object?)` cannot be redefined cleanly.
### Issues Fixed
Fixes #36034
### Reference
https://github.com/dotnet/maui/pull/36076
https://github.com/dotnet/maui/pull/36076#issuecomment-4782959118
🏁 Report — Final Recommendation
Comparative Fix Report — PR #36443
Candidate ranking
| Rank | Candidate | Regression tests | Assessment |
|---|---|---|---|
| 1 | try-fix-2 |
✅ PASS | Best concrete fix. Restores value equality for base/derived Color instances without sealing the public Color type, updates PublicAPI to remove record-only unshipped members, and adds regression coverage for the original derived-color scenario. |
| 2 | pr-plus-reviewer |
✅ PASS (same approach as try-fix-2) |
Applies expert reviewer feedback to the PR by replacing the sealing workaround with explicit class equality. Equivalent to try-fix-2, but try-fix-2 is the preserved concrete candidate diff from STEP 5a. |
| 3 | pr |
✅ PASS | Fixes the symptom by preventing subclasses, but introduces a public source/binary compatibility break by sealing Microsoft.Maui.Graphics.Color and tests the workaround rather than the original regression. |
| 4 | try-fix-1 |
❌ FAIL | Attempted to keep Color as an unsealed record and remove EqualityContract from Equals(Color?), but record-generated equality paths still failed and adding Equals(object?) caused CS0111. Failed regression/build validation, so it ranks below all passing candidates. |
CI and prior-review context
- Required/public checks for the PR head showed
maui-prfailed. Public AzDO log inspection found failures outside the Graphics/Color change area:Microsoft.Maui.UnitTests.dllHelix work item failed inDispatcherTests.CreateTimerNonRepeatingDoesNotRepeatwithNullReferenceException.Build Windows (Debug)failed while importing/copying build-task files because files under.buildtaskswere locked by.NET Hostprocesses.
- These failures do not directly implicate
src/Graphics/src/Graphics/Color.csorColorUnitTests. - Prior MauiBot/expert review already flagged the same unresolved major issue: sealing shipped
Coloris a breaking public API change.
Winning candidate
Winner: try-fix-2
try-fix-2 is the single best candidate because it passes the regression tests and addresses the actual root cause without removing the shipped ability to derive from Color. It also improves test coverage by checking base-vs-derived equality directly, whereas the raw PR locks in sealing as the behavior.
Recommendation
Do not merge the raw PR fix as submitted. Replace the PR implementation with try-fix-2/pr-plus-reviewer: make Color an explicit class : IEquatable<Color>, implement value equality/operators directly, remove record-generated API surface from PublicAPI.Unshipped, and keep the derived-color regression test.
🧭 Next Steps — alternative fix proposed (try-fix-2)
Automated review — alternative fix proposed
The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-2 as the strongest fix.
Why: try-fix-2 passes the regression tests and fixes Color value equality for derived types without sealing the public Color type. It avoids the PR fix public API break and includes direct derived-color regression coverage.
Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.
Candidate diff (try-fix-2)
diff --git a/src/Graphics/src/Graphics/Color.cs b/src/Graphics/src/Graphics/Color.cs
index 866d740377..a32125e976 100644
--- a/src/Graphics/src/Graphics/Color.cs
+++ b/src/Graphics/src/Graphics/Color.cs
@@ -14,7 +14,7 @@ namespace Microsoft.Maui.Graphics
[DebuggerDisplay("Red={Red}, Green={Green}, Blue={Blue}, Alpha={Alpha}")]
[TypeConverter(typeof(Converters.ColorTypeConverter))]
[ImmutableObject(true)]
- public record class Color
+ public class Color : IEquatable<Color>
{
/// <summary>
/// The red component of the color, ranging from 0.0 to 1.0.
@@ -116,6 +116,21 @@ namespace Microsoft.Maui.Graphics
public override int GetHashCode() => ToInt();
+ public override bool Equals(object? obj) => obj is Color other && Equals(other);
+
+ public static bool operator ==(Color? left, Color? right)
+ {
+ if (ReferenceEquals(left, right))
+ return true;
+
+ if (left is null || right is null)
+ return false;
+
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Color? left, Color? right) => !(left == right);
+
/// <summary>
/// Determines whether the specified <see cref="Color"/> is equal to the current color using byte-precision comparison.
/// </summary>
@@ -124,9 +139,6 @@ namespace Microsoft.Maui.Graphics
if (other is null)
return false;
- if (EqualityContract != other.EqualityContract)
- return false;
-
return ToInt() == other.ToInt();
}
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txt
index 52af5b2eb3..9ff6b16efc 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -1,11 +1,7 @@
#nullable enable
-Microsoft.Maui.Graphics.Color.Color(Microsoft.Maui.Graphics.Color! original) -> void
override Microsoft.Maui.Graphics.Color.Equals(object? obj) -> bool
static Microsoft.Maui.Graphics.Color.operator !=(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
static Microsoft.Maui.Graphics.Color.operator ==(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
-virtual Microsoft.Maui.Graphics.Color.<Clone>$() -> Microsoft.Maui.Graphics.Color!
-virtual Microsoft.Maui.Graphics.Color.EqualityContract.get -> System.Type!
-virtual Microsoft.Maui.Graphics.Color.PrintMembers(System.Text.StringBuilder! builder) -> bool
virtual Microsoft.Maui.Graphics.Color.Equals(Microsoft.Maui.Graphics.Color? other) -> bool
Microsoft.Maui.Graphics.Color.AddLuminosity(float delta) -> Microsoft.Maui.Graphics.Color!
Microsoft.Maui.Graphics.Color.ToArgbHex(bool includeAlpha = false) -> string!
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index b405760036..bafe3bc313 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -1,12 +1,8 @@
#nullable enable
-Microsoft.Maui.Graphics.Color.Color(Microsoft.Maui.Graphics.Color! original) -> void
override Microsoft.Maui.Graphics.Color.Equals(object? obj) -> bool
static Microsoft.Maui.Graphics.Color.operator !=(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
static Microsoft.Maui.Graphics.Color.operator ==(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
-virtual Microsoft.Maui.Graphics.Color.<Clone>$() -> Microsoft.Maui.Graphics.Color!
-virtual Microsoft.Maui.Graphics.Color.EqualityContract.get -> System.Type!
virtual Microsoft.Maui.Graphics.Color.Equals(Microsoft.Maui.Graphics.Color? other) -> bool
-virtual Microsoft.Maui.Graphics.Color.PrintMembers(System.Text.StringBuilder! builder) -> bool
Microsoft.Maui.Graphics.Color.AsPaint() -> Microsoft.Maui.Graphics.Paint!
Microsoft.Maui.Graphics.Color.MultiplyAlpha(float multiplyBy) -> Microsoft.Maui.Graphics.Color!
Microsoft.Maui.Graphics.Color.WithAlpha(float alpha) -> Microsoft.Maui.Graphics.Color!
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index b405760036..bafe3bc313 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -1,12 +1,8 @@
#nullable enable
-Microsoft.Maui.Graphics.Color.Color(Microsoft.Maui.Graphics.Color! original) -> void
override Microsoft.Maui.Graphics.Color.Equals(object? obj) -> bool
static Microsoft.Maui.Graphics.Color.operator !=(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
static Microsoft.Maui.Graphics.Color.operator ==(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
-virtual Microsoft.Maui.Graphics.Color.<Clone>$() -> Microsoft.Maui.Graphics.Color!
-virtual Microsoft.Maui.Graphics.Color.EqualityContract.get -> System.Type!
virtual Microsoft.Maui.Graphics.Color.Equals(Microsoft.Maui.Graphics.Color? other) -> bool
-virtual Microsoft.Maui.Graphics.Color.PrintMembers(System.Text.StringBuilder! builder) -> bool
Microsoft.Maui.Graphics.Color.AsPaint() -> Microsoft.Maui.Graphics.Paint!
Microsoft.Maui.Graphics.Color.MultiplyAlpha(float multiplyBy) -> Microsoft.Maui.Graphics.Color!
Microsoft.Maui.Graphics.Color.WithAlpha(float alpha) -> Microsoft.Maui.Graphics.Color!
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txt
index 55c756b6c1..d9765177a1 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txt
@@ -1,11 +1,7 @@
#nullable enable
-Microsoft.Maui.Graphics.Color.Color(Microsoft.Maui.Graphics.Color! original) -> void
override Microsoft.Maui.Graphics.Color.Equals(object? obj) -> bool
static Microsoft.Maui.Graphics.Color.operator !=(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
static Microsoft.Maui.Graphics.Color.operator ==(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
-virtual Microsoft.Maui.Graphics.Color.<Clone>$() -> Microsoft.Maui.Graphics.Color!
-virtual Microsoft.Maui.Graphics.Color.EqualityContract.get -> System.Type!
-virtual Microsoft.Maui.Graphics.Color.PrintMembers(System.Text.StringBuilder! builder) -> bool
virtual Microsoft.Maui.Graphics.Color.Equals(Microsoft.Maui.Graphics.Color? other) -> bool
Microsoft.Maui.Graphics.Color.AddLuminosity(float delta) -> Microsoft.Maui.Graphics.Color!
Microsoft.Maui.Graphics.Color.GetComplementary() -> Microsoft.Maui.Graphics.Color!
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index 55c756b6c1..d9765177a1 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -1,11 +1,7 @@
#nullable enable
-Microsoft.Maui.Graphics.Color.Color(Microsoft.Maui.Graphics.Color! original) -> void
override Microsoft.Maui.Graphics.Color.Equals(object? obj) -> bool
static Microsoft.Maui.Graphics.Color.operator !=(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
static Microsoft.Maui.Graphics.Color.operator ==(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
-virtual Microsoft.Maui.Graphics.Color.<Clone>$() -> Microsoft.Maui.Graphics.Color!
-virtual Microsoft.Maui.Graphics.Color.EqualityContract.get -> System.Type!
-virtual Microsoft.Maui.Graphics.Color.PrintMembers(System.Text.StringBuilder! builder) -> bool
virtual Microsoft.Maui.Graphics.Color.Equals(Microsoft.Maui.Graphics.Color? other) -> bool
Microsoft.Maui.Graphics.Color.AddLuminosity(float delta) -> Microsoft.Maui.Graphics.Color!
Microsoft.Maui.Graphics.Color.GetComplementary() -> Microsoft.Maui.Graphics.Color!
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index 55c756b6c1..d9765177a1 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -1,11 +1,7 @@
#nullable enable
-Microsoft.Maui.Graphics.Color.Color(Microsoft.Maui.Graphics.Color! original) -> void
override Microsoft.Maui.Graphics.Color.Equals(object? obj) -> bool
static Microsoft.Maui.Graphics.Color.operator !=(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
static Microsoft.Maui.Graphics.Color.operator ==(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
-virtual Microsoft.Maui.Graphics.Color.<Clone>$() -> Microsoft.Maui.Graphics.Color!
-virtual Microsoft.Maui.Graphics.Color.EqualityContract.get -> System.Type!
-virtual Microsoft.Maui.Graphics.Color.PrintMembers(System.Text.StringBuilder! builder) -> bool
virtual Microsoft.Maui.Graphics.Color.Equals(Microsoft.Maui.Graphics.Color? other) -> bool
Microsoft.Maui.Graphics.Color.AddLuminosity(float delta) -> Microsoft.Maui.Graphics.Color!
Microsoft.Maui.Graphics.Color.GetComplementary() -> Microsoft.Maui.Graphics.Color!
diff --git a/src/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txt
index b405760036..bafe3bc313 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -1,12 +1,8 @@
#nullable enable
-Microsoft.Maui.Graphics.Color.Color(Microsoft.Maui.Graphics.Color! original) -> void
override Microsoft.Maui.Graphics.Color.Equals(object? obj) -> bool
static Microsoft.Maui.Graphics.Color.operator !=(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
static Microsoft.Maui.Graphics.Color.operator ==(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
-virtual Microsoft.Maui.Graphics.Color.<Clone>$() -> Microsoft.Maui.Graphics.Color!
-virtual Microsoft.Maui.Graphics.Color.EqualityContract.get -> System.Type!
virtual Microsoft.Maui.Graphics.Color.Equals(Microsoft.Maui.Graphics.Color? other) -> bool
-virtual Microsoft.Maui.Graphics.Color.PrintMembers(System.Text.StringBuilder! builder) -> bool
Microsoft.Maui.Graphics.Color.AsPaint() -> Microsoft.Maui.Graphics.Paint!
Microsoft.Maui.Graphics.Color.MultiplyAlpha(float multiplyBy) -> Microsoft.Maui.Graphics.Color!
Microsoft.Maui.Graphics.Color.WithAlpha(float alpha) -> Microsoft.Maui.Graphics.Color!
diff --git a/src/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index b405760036..bafe3bc313 100644
--- a/src/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -1,12 +1,8 @@
#nullable enable
-Microsoft.Maui.Graphics.Color.Color(Microsoft.Maui.Graphics.Color! original) -> void
override Microsoft.Maui.Graphics.Color.Equals(object? obj) -> bool
static Microsoft.Maui.Graphics.Color.operator !=(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
static Microsoft.Maui.Graphics.Color.operator ==(Microsoft.Maui.Graphics.Color? left, Microsoft.Maui.Graphics.Color? right) -> bool
-virtual Microsoft.Maui.Graphics.Color.<Clone>$() -> Microsoft.Maui.Graphics.Color!
-virtual Microsoft.Maui.Graphics.Color.EqualityContract.get -> System.Type!
virtual Microsoft.Maui.Graphics.Color.Equals(Microsoft.Maui.Graphics.Color? other) -> bool
-virtual Microsoft.Maui.Graphics.Color.PrintMembers(System.Text.StringBuilder! builder) -> bool
Microsoft.Maui.Graphics.Color.AsPaint() -> Microsoft.Maui.Graphics.Paint!
Microsoft.Maui.Graphics.Color.MultiplyAlpha(float multiplyBy) -> Microsoft.Maui.Graphics.Color!
Microsoft.Maui.Graphics.Color.WithAlpha(float alpha) -> Microsoft.Maui.Graphics.Color!
diff --git a/src/Graphics/tests/Graphics.Tests/ColorUnitTests.cs b/src/Graphics/tests/Graphics.Tests/ColorUnitTests.cs
index 8dfd26efaa..cc9225c80b 100644
--- a/src/Graphics/tests/Graphics.Tests/ColorUnitTests.cs
+++ b/src/Graphics/tests/Graphics.Tests/ColorUnitTests.cs
@@ -470,11 +470,20 @@ namespace Microsoft.Maui.Graphics.Tests
}
[Fact]
- public void ColorTypeIsSealed()
+ public void EqualsIsValueBasedForDerivedColorWithSameArgbValue()
{
- // Sealing Color guarantees every instance shares the same runtime type, so its
- // record-generated equality (based on the ARGB value) can never be broken by a subclass.
- Assert.True(typeof(Color).IsSealed);
+ var baseColor = new Color(1f, 0f, 0f, 1f);
+ Color derivedColor = new DerivedColor(1f, 0f, 0f, 1f);
+
+ Assert.Equal(baseColor.ToInt(), derivedColor.ToInt());
+ Assert.Equal(baseColor, derivedColor);
+ Assert.Equal(derivedColor, baseColor);
+ Assert.True(baseColor == derivedColor);
+ Assert.True(derivedColor == baseColor);
+ Assert.True(baseColor.Equals(derivedColor));
+ Assert.True(derivedColor.Equals(baseColor));
+ Assert.True(EqualityComparer<Color>.Default.Equals(baseColor, derivedColor));
+ Assert.Equal(baseColor.GetHashCode(), derivedColor.GetHashCode());
}
[Fact]
@@ -500,5 +509,13 @@ namespace Microsoft.Maui.Graphics.Tests
Assert.True(color1 != color2);
Assert.False(color1.Equals(color2));
}
+
+ sealed class DerivedColor : Color
+ {
+ public DerivedColor(float red, float green, float blue, float alpha)
+ : base(red, green, blue, alpha)
+ {
+ }
+ }
}
}
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
This is intentional — we sealed Color on purpose, based on @AdamEssenmacher's suggestion in the issue. It fixes the equality bug, but means anyone who created a custom subclass of Color before will no longer be able to do so. We'll note this as a breaking change. |
kubaflo
left a comment
There was a problem hiding this comment.
IS this one ready for review?
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines: Successfully started running 2 pipeline(s). |
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
Color.Equals() returns false when comparing a base Color and a subclassed Color with identical RGBA values, even though ToInt() matches. Regression starting .NET MAUI 11 preview 3.
Root Cause
Color was converted from a class to a record class . Records auto-generate an EqualityContract check in Equals that requires both objects to have the exact same runtime type — so a base Color and a derived DerivedColor never match, even with identical byte values.
Description of Change
Made Color a sealed record class , so it can never be subclassed — every instance now shares the same EqualityContract , restoring pure value-based (ARGB) equality. Also removed the now-illegal virtual modifier on Equals(Color? other) since sealed types can't declare virtual members.
Issues Fixed
Fixes #36034
Reference :
#36076
#36076 (comment)