Comparer
April 16, 2026 ยท View on GitHub
Comparers are used to compare non-text files.
Custom Comparer
Using a custom comparer can be helpful when a result has changed, but not enough to fail verification. For example when rendering images/forms on different operating systems.
For samples purposes only the image sizes will be compared:
static Task<CompareResult> CompareImages(
Stream received,
Stream verified,
IReadOnlyDictionary<string, object> context)
{
// Fake comparison
if (received.Length == verified.Length)
{
return Task.FromResult(CompareResult.Equal);
}
var result = CompareResult.NotEqual();
return Task.FromResult(result);
}
The returned CompareResult.NotEqual takes an optional message that will be rendered in the resulting text displayed to the user on test failure.
If an input is split into multiple files, and a text file fails, then all subsequent binary comparisons will revert to the default comparison.
Instance comparer
[Fact]
public Task InstanceComparer()
{
var settings = new VerifySettings();
settings.UseStreamComparer(CompareImages);
return VerifyFile("sample.png", settings);
}
[Fact]
public Task InstanceComparerFluent() =>
VerifyFile("sample.png")
.UseStreamComparer(CompareImages);
Static comparer
VerifierSettings.RegisterStreamComparer(
extension: "png",
compare: CompareImages);
await VerifyFile("TheImage.png");
Default Comparison
const int bufferSize = 1024 * sizeof(long);
public static async Task<CompareResult> AreEqual(Stream stream1, Stream stream2)
{
EnsureAtStart(stream1);
EnsureAtStart(stream2);
var buffer1 = new byte[bufferSize];
var buffer2 = new byte[bufferSize];
while (true)
{
var count = await ReadBufferAsync(stream1, buffer1);
//no need to compare size here since only enter on files being same size
if (count == 0)
{
return CompareResult.Equal;
}
await ReadBufferAsync(stream2, buffer2);
for (var i = 0; i < count; i += sizeof(long))
{
if (BitConverter.ToInt64(buffer1, i) != BitConverter.ToInt64(buffer2, i))
{
return CompareResult.NotEqual();
}
}
}
}
static void EnsureAtStart(Stream stream)
{
if (stream.CanSeek &&
stream.Position != 0)
{
throw new("Expected stream to be at position 0.");
}
}
static async Task<int> ReadBufferAsync(Stream stream, byte[] buffer)
{
var bytesRead = 0;
while (bytesRead < buffer.Length)
{
var read = await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead);
if (read == 0)
{
// Reached end of stream.
return bytesRead;
}
bytesRead += read;
}
return bytesRead;
}
PNG SSIM comparer
Verify includes a built-in Structural Similarity Index (SSIM) comparer for PNG files. It is opt-in and, when enabled, replaces the default byte-for-byte comparison for the .png extension.
This is useful when rendered images differ slightly between runs (e.g. anti-aliasing, font hinting, platform-specific rasterization) but are perceptually identical.
public static class ModuleInitializer
{
[ModuleInitializer]
public static void Init() =>
VerifierSettings.UseSsimForPng();
}
The default threshold is 0.98. SSIM scores range from 0 (completely different) to 1 (identical). A custom threshold can be supplied:
public static class ModuleInitializer
{
[ModuleInitializer]
public static void Init() =>
VerifierSettings.UseSsimForPng(threshold: 0.995);
}
Dimension mismatches between the received and verified images are always reported as not equal, regardless of threshold.
Supported PNG variants
The bundled decoder targets the common subset of PNGs produced by test scenarios:
- 8-bit bit depth
- Color types: grayscale, RGB, RGBA, grayscale+alpha, and paletted (with optional
tRNStransparency) - Non-interlaced images
Unsupported variants (16-bit, Adam7 interlacing) cause the decoder to throw. For scenarios that require full PNG support, use one of the below comparers.
Pre-packaged comparers
- Verify.AngleSharp.Diffing: Comparison of html files via AngleSharp.Diffing.
- Verify.DiffPlex: Comparison of text via DiffPlex.
- Verify.ICSharpCode.Decompiler: Comparison of assemblies and types via ICSharpCode.Decompiler.
- Verify.ImageHash: Comparison of images via ImageHash.
- Verify.ImageMagick: Verification and comparison of images via Magick.NET.
- Verify.ImageSharp.Compare: Verification and comparison of images via Codeuctivity.ImageSharp.Compare.
- Verify.Phash: Comparison of images via Phash.
- Verify.Quibble: Comparison of objects via Quibble.
- YellowDogMan.Verify.ssimulacra2: Verification and comparison of images via ssimulacra2.