Skip to content

Commit dc2e307

Browse files
mattleibowCopilot
andcommitted
Split SKPixelComparerTest into per-category test files
Split the monolithic 775-line test class into focused files: - SKPixelComparerTestBase: shared constants and helpers - SKPixelComparerCompareTest: base comparison and metrics (15 tests) - SKPixelComparerToleranceTest: tolerance-based comparison (14 tests) - SKPixelComparerMaskTest: mask-based comparison (5 tests) - SKPixelComparerDifferenceMaskTest: GenerateDifferenceMask (1 test) - SKPixelComparerDifferenceImageTest: GenerateDifferenceImage (5 tests) - SKPixelComparerOptionsTest: SKPixelComparerOptions/alpha (7 tests) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1d31c7e commit dc2e307

8 files changed

+815
-775
lines changed
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
using System;
2+
using Xunit;
3+
4+
namespace SkiaSharp.Extended.Tests
5+
{
6+
public class SKPixelComparerCompareTest : SKPixelComparerTestBase
7+
{
8+
[Theory]
9+
[InlineData(0xFFFFFFFF, 0xFF000000, 19125, 25)]
10+
[InlineData(0xFF000000, 0xFFFFFFFF, 19125, 25)]
11+
[InlineData(0xFF000000, 0xFF000001, 25, 25)]
12+
[InlineData(0xFFFFFFFF, 0xFFFFFFFF, 0, 0)]
13+
[InlineData(0xFF000000, 0xFF000000, 0, 0)]
14+
[InlineData(0xFF000001, 0xFF000001, 0, 0)]
15+
[InlineData(0xFF00FF00, 0xFF00FF00, 0, 0)]
16+
public void DifferentImagesReportDifferenceCorrectly(uint firstColor, uint secondColor, int absolute, int count)
17+
{
18+
using var first = CreateTestImage(firstColor);
19+
using var second = CreateTestImage(secondColor);
20+
21+
var result = SKPixelComparer.Compare(first, second);
22+
23+
Assert.Equal(count, result.ErrorPixelCount);
24+
Assert.Equal(25, result.TotalPixels);
25+
Assert.Equal(absolute, result.AbsoluteError);
26+
}
27+
28+
[Theory]
29+
[InlineData(0xFFFFFFFF, 0xFF000000, 19125, 25)]
30+
[InlineData(0xFF000000, 0xFFFFFFFF, 19125, 25)]
31+
[InlineData(0xFF000000, 0xFF000001, 25, 25)]
32+
[InlineData(0xFFFFFFFF, 0xFFFFFFFF, 0, 0)]
33+
[InlineData(0xFF000000, 0xFF000000, 0, 0)]
34+
[InlineData(0xFF000001, 0xFF000001, 0, 0)]
35+
[InlineData(0xFF00FF00, 0xFF00FF00, 0, 0)]
36+
public void DifferentBitmapsReportDifferenceCorrectly(uint firstColor, uint secondColor, int absolute, int count)
37+
{
38+
using var first = CreateTestBitmap(firstColor);
39+
using var second = CreateTestBitmap(secondColor);
40+
41+
var result = SKPixelComparer.Compare(first, second);
42+
43+
Assert.Equal(count, result.ErrorPixelCount);
44+
Assert.Equal(25, result.TotalPixels);
45+
Assert.Equal(absolute, result.AbsoluteError);
46+
}
47+
48+
[Theory]
49+
[InlineData(0xFFFFFFFF, 0xFF000000, 19125, 25)]
50+
[InlineData(0xFF000000, 0xFFFFFFFF, 19125, 25)]
51+
[InlineData(0xFF000000, 0xFF000001, 25, 25)]
52+
[InlineData(0xFFFFFFFF, 0xFFFFFFFF, 0, 0)]
53+
[InlineData(0xFF000000, 0xFF000000, 0, 0)]
54+
[InlineData(0xFF000001, 0xFF000001, 0, 0)]
55+
[InlineData(0xFF00FF00, 0xFF00FF00, 0, 0)]
56+
public void DifferentPixmapsReportDifferenceCorrectly(uint firstColor, uint secondColor, int absolute, int count)
57+
{
58+
using var firstBitmap = CreateTestBitmap(firstColor);
59+
using var first = firstBitmap.PeekPixels();
60+
using var secondBitmap = CreateTestBitmap(secondColor);
61+
using var second = secondBitmap.PeekPixels();
62+
63+
var result = SKPixelComparer.Compare(first, second);
64+
65+
Assert.Equal(count, result.ErrorPixelCount);
66+
Assert.Equal(25, result.TotalPixels);
67+
Assert.Equal(absolute, result.AbsoluteError);
68+
}
69+
70+
[Theory]
71+
[InlineData(jpgFirst, jpgFirst)]
72+
[InlineData(pngFirst, pngFirst)]
73+
[InlineData(jpgSecond, jpgSecond)]
74+
[InlineData(pngSecond, pngSecond)]
75+
public void SameImagesReportNoDifference(string first, string second)
76+
{
77+
using var firstImage = SKImage.FromEncodedData(GetImagePath(first));
78+
using var secondImage = SKImage.FromEncodedData(GetImagePath(second));
79+
80+
var result = SKPixelComparer.Compare(firstImage, secondImage);
81+
82+
Assert.Equal(0, result.ErrorPixelCount);
83+
Assert.Equal(300104, result.TotalPixels);
84+
Assert.Equal(0, result.AbsoluteError);
85+
}
86+
87+
[Theory]
88+
[InlineData(jpgFirst, jpgSecond, 2259184, 15870, 0.05288166768853464)]
89+
[InlineData(pngFirst, pngSecond, 2249290, 12570, 0.041885479700370536)]
90+
public void SimilarFilesAreSimilar(string first, string second, int expAbsError, int expPixError, double expPixPercent)
91+
{
92+
var result = SKPixelComparer.Compare(GetImagePath(first), GetImagePath(second));
93+
94+
Assert.Equal(expAbsError, result.AbsoluteError);
95+
Assert.Equal(expPixError, result.ErrorPixelCount);
96+
Assert.Equal(expPixPercent, result.ErrorPixelPercentage);
97+
}
98+
99+
[Theory]
100+
[InlineData(jpgFirst, jpgSecond, 2259184, 15870, 0.05288166768853464)]
101+
[InlineData(pngFirst, pngSecond, 2249290, 12570, 0.041885479700370536)]
102+
public void SimilarImagesAreSimilar(string first, string second, int expAbsError, int expPixError, double expPixPercent)
103+
{
104+
using var firstImage = SKImage.FromEncodedData(GetImagePath(first));
105+
using var secondImage = SKImage.FromEncodedData(GetImagePath(second));
106+
107+
var result = SKPixelComparer.Compare(firstImage, secondImage);
108+
109+
Assert.Equal(expAbsError, result.AbsoluteError);
110+
Assert.Equal(expPixError, result.ErrorPixelCount);
111+
Assert.Equal(expPixPercent, result.ErrorPixelPercentage);
112+
}
113+
114+
[Theory]
115+
[InlineData(jpgFirst, pngFirst, 884487, 231040, 0.7698664462986164)]
116+
[InlineData(jpgSecond, pngSecond, 873399, 221697, 0.7387339055793991)]
117+
public void SimilarFilesAreCompressedDifferent(string first, string second, int expAbsError, int expPixError, double expPixPercent)
118+
{
119+
var result = SKPixelComparer.Compare(GetImagePath(first), GetImagePath(second));
120+
121+
Assert.Equal(expAbsError, result.AbsoluteError);
122+
Assert.Equal(expPixError, result.ErrorPixelCount);
123+
Assert.Equal(expPixPercent, result.ErrorPixelPercentage);
124+
}
125+
126+
[Theory]
127+
[InlineData(jpgFirst, pngFirst, 884487, 231040, 0.7698664462986164)]
128+
[InlineData(jpgSecond, pngSecond, 873399, 221697, 0.7387339055793991)]
129+
public void SimilarImagesAreCompressedDifferent(string first, string second, int expAbsError, int expPixError, double expPixPercent)
130+
{
131+
using var firstImage = SKImage.FromEncodedData(GetImagePath(first));
132+
using var secondImage = SKImage.FromEncodedData(GetImagePath(second));
133+
134+
var result = SKPixelComparer.Compare(firstImage, secondImage);
135+
136+
Assert.Equal(expAbsError, result.AbsoluteError);
137+
Assert.Equal(expPixError, result.ErrorPixelCount);
138+
Assert.Equal(expPixPercent, result.ErrorPixelPercentage);
139+
}
140+
141+
[Theory]
142+
[InlineData(10, 3, 10, 10)]
143+
[InlineData(10, 10, 10, 3)]
144+
[InlineData(3, 10, 10, 10)]
145+
[InlineData(10, 10, 3, 10)]
146+
public void DifferentSizeImagesFail(int w1, int h1, int w2, int h2)
147+
{
148+
using var first = CreateTestImage(SKColors.Black, w1, h1);
149+
using var second = CreateTestImage(SKColors.Black, w2, h2);
150+
151+
var ex = Assert.Throws<InvalidOperationException>(() => SKPixelComparer.Compare(first, second));
152+
Assert.Contains($"{w1}x{h1} vs {w2}x{h2}", ex.Message);
153+
}
154+
155+
[Theory]
156+
[InlineData(0xFFFFFFFF, 0xFF000000, 4876875)]
157+
[InlineData(0xFF000000, 0xFFFFFFFF, 4876875)]
158+
[InlineData(0xFF000000, 0xFF000001, 25)]
159+
[InlineData(0xFFFFFFFF, 0xFFFFFFFF, 0)]
160+
[InlineData(0xFF000000, 0xFF000000, 0)]
161+
public void CompareTracksSumSquaredError(uint firstColor, uint secondColor, long expectedSumSquaredError)
162+
{
163+
using var first = CreateTestImage(firstColor);
164+
using var second = CreateTestImage(secondColor);
165+
166+
var result = SKPixelComparer.Compare(first, second);
167+
168+
Assert.Equal(expectedSumSquaredError, result.SumSquaredError);
169+
}
170+
171+
[Fact]
172+
public void IdenticalImagesHaveZeroMetrics()
173+
{
174+
using var first = CreateTestImage(0xFF808080);
175+
using var second = CreateTestImage(0xFF808080);
176+
177+
var result = SKPixelComparer.Compare(first, second);
178+
179+
Assert.Equal(0, result.SumSquaredError);
180+
Assert.Equal(0.0, result.MeanAbsoluteError);
181+
Assert.Equal(0.0, result.MeanSquaredError);
182+
Assert.Equal(0.0, result.RootMeanSquaredError);
183+
Assert.Equal(0.0, result.NormalizedRootMeanSquaredError);
184+
Assert.Equal(double.PositiveInfinity, result.PeakSignalToNoiseRatio);
185+
}
186+
187+
[Fact]
188+
public void MaxDifferenceImagesHaveCorrectMetrics()
189+
{
190+
using var first = CreateTestImage(0xFF000000);
191+
using var second = CreateTestImage(0xFFFFFFFF);
192+
193+
var result = SKPixelComparer.Compare(first, second);
194+
195+
Assert.Equal(255.0, result.MeanAbsoluteError);
196+
Assert.Equal(65025.0, result.MeanSquaredError);
197+
Assert.Equal(255.0, result.RootMeanSquaredError);
198+
Assert.Equal(1.0, result.NormalizedRootMeanSquaredError);
199+
Assert.Equal(0.0, result.PeakSignalToNoiseRatio);
200+
}
201+
202+
[Fact]
203+
public void MetricsAreConsistentWithFormulas()
204+
{
205+
using var first = CreateTestImage(0xFF000000);
206+
using var second = CreateTestImage(0xFF010203);
207+
208+
var result = SKPixelComparer.Compare(first, second);
209+
210+
// Per pixel: ΔR=1, ΔG=2, ΔB=3
211+
// 25 pixels, 3 channels per pixel = 75 channel values
212+
var expectedAbsoluteError = (1 + 2 + 3) * 25;
213+
var expectedSumSquared = (long)(1 * 1 + 2 * 2 + 3 * 3) * 25;
214+
215+
Assert.Equal(expectedAbsoluteError, result.AbsoluteError);
216+
Assert.Equal(expectedSumSquared, result.SumSquaredError);
217+
Assert.Equal((double)expectedAbsoluteError / (25 * 3.0), result.MeanAbsoluteError);
218+
Assert.Equal((double)expectedSumSquared / (25 * 3.0), result.MeanSquaredError);
219+
Assert.Equal(Math.Sqrt((double)expectedSumSquared / (25 * 3.0)), result.RootMeanSquaredError);
220+
}
221+
222+
[Fact]
223+
public void ZeroTotalPixelsResultDoesNotThrow()
224+
{
225+
var result = new SKPixelComparisonResult(0, 0, 0, 0);
226+
227+
Assert.Equal(0.0, result.ErrorPixelPercentage);
228+
Assert.Equal(0.0, result.MeanAbsoluteError);
229+
Assert.Equal(0.0, result.MeanSquaredError);
230+
Assert.Equal(0.0, result.RootMeanSquaredError);
231+
Assert.Equal(0.0, result.NormalizedRootMeanSquaredError);
232+
Assert.Equal(double.PositiveInfinity, result.PeakSignalToNoiseRatio);
233+
}
234+
235+
[Fact]
236+
public void ChannelCountReflectsCompareAlpha()
237+
{
238+
var rgb = new SKPixelComparisonResult(100, 10, 50, 200);
239+
var rgba = new SKPixelComparisonResult(100, 10, 50, 200, 4);
240+
241+
Assert.Equal(3, rgb.ChannelCount);
242+
Assert.Equal(4, rgba.ChannelCount);
243+
244+
// MAE differs due to different divisors
245+
Assert.Equal(50.0 / (100 * 3.0), rgb.MeanAbsoluteError);
246+
Assert.Equal(50.0 / (100 * 4.0), rgba.MeanAbsoluteError);
247+
}
248+
}
249+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using Xunit;
2+
3+
namespace SkiaSharp.Extended.Tests
4+
{
5+
public class SKPixelComparerDifferenceImageTest : SKPixelComparerTestBase
6+
{
7+
[Fact]
8+
public void GenerateDifferenceImageShowsPerChannelDifferences()
9+
{
10+
using var first = CreateTestImage(0xFF102030);
11+
using var second = CreateTestImage(0xFF132639);
12+
13+
using var diff = SKPixelComparer.GenerateDifferenceImage(first, second);
14+
15+
Assert.Equal(5, diff.Width);
16+
Assert.Equal(5, diff.Height);
17+
18+
using var bitmap = GetNormalizedBitmap(diff);
19+
using var pixmap = bitmap.PeekPixels();
20+
var pixel = pixmap.GetPixelSpan<SKColor>()[0];
21+
22+
Assert.Equal(3, pixel.Red);
23+
Assert.Equal(6, pixel.Green);
24+
Assert.Equal(9, pixel.Blue);
25+
}
26+
27+
[Fact]
28+
public void GenerateDifferenceImageIdenticalIsBlack()
29+
{
30+
using var first = CreateTestImage(0xFFAABBCC);
31+
using var second = CreateTestImage(0xFFAABBCC);
32+
33+
using var diff = SKPixelComparer.GenerateDifferenceImage(first, second);
34+
35+
using var bitmap = GetNormalizedBitmap(diff);
36+
using var pixmap = bitmap.PeekPixels();
37+
var pixel = pixmap.GetPixelSpan<SKColor>()[0];
38+
39+
Assert.Equal(0, pixel.Red);
40+
Assert.Equal(0, pixel.Green);
41+
Assert.Equal(0, pixel.Blue);
42+
}
43+
44+
[Fact]
45+
public void GenerateDifferenceImageWithBitmapsWorks()
46+
{
47+
using var first = CreateTestBitmap(0xFF000000);
48+
using var second = CreateTestBitmap(0xFF050505);
49+
50+
using var diff = SKPixelComparer.GenerateDifferenceImage(first, second);
51+
52+
Assert.NotNull(diff);
53+
Assert.Equal(5, diff.Width);
54+
Assert.Equal(5, diff.Height);
55+
}
56+
57+
[Fact]
58+
public void GenerateDifferenceImageWithDifferentSizesFails()
59+
{
60+
using var first = CreateTestImage(SKColors.Black, 5, 5);
61+
using var second = CreateTestImage(SKColors.Black, 10, 10);
62+
63+
Assert.Throws<System.InvalidOperationException>(() => SKPixelComparer.GenerateDifferenceImage(first, second));
64+
}
65+
66+
[Fact]
67+
public void GenerateDifferenceImageProducesValidImage()
68+
{
69+
using var first = CreateTestImage(0xFF000000);
70+
using var second = CreateTestImage(0xFF050505);
71+
72+
using var diff = SKPixelComparer.GenerateDifferenceImage(first, second);
73+
74+
Assert.NotNull(diff);
75+
Assert.Equal(5, diff.Width);
76+
Assert.Equal(5, diff.Height);
77+
}
78+
}
79+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Xunit;
2+
3+
namespace SkiaSharp.Extended.Tests
4+
{
5+
public class SKPixelComparerDifferenceMaskTest : SKPixelComparerTestBase
6+
{
7+
[Fact]
8+
public void GenerateDifferenceMaskProducesValidImage()
9+
{
10+
using var first = CreateTestImage(0xFF000000);
11+
using var second = CreateTestImage(0xFF050505);
12+
13+
using var mask = SKPixelComparer.GenerateDifferenceMask(first, second);
14+
15+
Assert.NotNull(mask);
16+
Assert.Equal(5, mask.Width);
17+
Assert.Equal(5, mask.Height);
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)