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