# Comparer
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:
```cs
static Task CompareImages(
Stream received,
Stream verified,
IReadOnlyDictionary context)
{
// Fake comparison
if (received.Length == verified.Length)
{
return Task.FromResult(CompareResult.Equal);
}
var result = CompareResult.NotEqual();
return Task.FromResult(result);
}
```
snippet source | anchor
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
```cs
[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);
```
snippet source | anchor
### Static comparer
```cs
VerifierSettings.RegisterStreamComparer(
extension: "png",
compare: CompareImages);
await VerifyFile("TheImage.png");
```
snippet source | anchor
## Default Comparison
```cs
const int bufferSize = 1024 * sizeof(long);
public static async Task 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 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;
}
```
snippet source | anchor
## Pre-packaged comparers
* [Verify.AngleSharp.Diffing](https://github.com/VerifyTests/Verify.AngleSharp.Diffing): Comparison of html files via [AngleSharp.Diffing](https://github.com/AngleSharp/AngleSharp.Diffing).
* [Verify.DiffPlex](https://github.com/VerifyTests/Verify.DiffPlex): Comparison of text via [DiffPlex](https://github.com/mmanela/diffplex).
* [Verify.ICSharpCode.Decompiler](https://github.com/VerifyTests/Verify.ICSharpCode.Decompiler): Comparison of assemblies and types via [ICSharpCode.Decompiler](https://github.com/icsharpcode/ILSpy/wiki/Getting-Started-With-ICSharpCode.Decompiler).
* [Verify.ImageHash](https://github.com/VerifyTests/Verify.ImageHash): Comparison of images via [ImageHash](https://github.com/coenm/ImageHash).
* [Verify.ImageMagick](https://github.com/VerifyTests/Verify.ImageMagick): Verification and comparison of images via [Magick.NET](https://github.com/dlemstra/Magick.NET).
* [Verify.Phash](https://github.com/VerifyTests/Verify.Phash): Comparison of images via [Phash](https://github.com/pgrho/phash).
* [Verify.Quibble](https://github.com/VerifyTests/Verify.Quibble): Comparison of objects via [Quibble](https://github.com/nrkno/Quibble).