<!--
GENERATED FILE - DO NOT EDIT
This file was generated by [MarkdownSnippets](https://github.com/SimonCropp/MarkdownSnippets).
Source File: /docs/mdsource/comparer.source.md
To change this file edit the source file and then run MarkdownSnippets.
-->

# 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:

<!-- snippet: ImageComparer -->
<a id='snippet-ImageComparer'></a>
```cs
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);
}
```
<sup><a href='/src/Verify.Tests/Snippets/ComparerSnippets.cs#L34-L51' title='Snippet source file'>snippet source</a> | <a href='#snippet-ImageComparer' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

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

<!-- snippet: InstanceComparer -->
<a id='snippet-InstanceComparer'></a>
```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);
```
<sup><a href='/src/Verify.Tests/Snippets/ComparerSnippets.cs#L5-L20' title='Snippet source file'>snippet source</a> | <a href='#snippet-InstanceComparer' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


### Static comparer

<!-- snippet: StaticComparer -->
<a id='snippet-StaticComparer'></a>
```cs
VerifierSettings.RegisterStreamComparer(
    extension: "png",
    compare: CompareImages);
await VerifyFile("TheImage.png");
```
<sup><a href='/src/Verify.Tests/Snippets/ComparerSnippets.cs#L24-L31' title='Snippet source file'>snippet source</a> | <a href='#snippet-StaticComparer' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


## Default Comparison

<!-- snippet: DefualtCompare -->
<a id='snippet-DefualtCompare'></a>
```cs
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;
}
```
<sup><a href='/src/Verify/Compare/StreamComparer.cs#L3-L65' title='Snippet source file'>snippet source</a> | <a href='#snippet-DefualtCompare' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


## 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).