diff --git a/.github/workflows/merge-dependabot.yml b/.github/workflows/merge-dependabot.yml
index ab77887df..0afbdeaa1 100644
--- a/.github/workflows/merge-dependabot.yml
+++ b/.github/workflows/merge-dependabot.yml
@@ -25,6 +25,9 @@ jobs:
# Dependabot records the update type in its commit message metadata, for example
# "update-type: version-update:semver-minor". A grouped bump lists one per dependency.
# --match-head-commit refuses the merge if the branch moved after this build ran.
+ # A bump that conflicts with main (an earlier bump merged an adjacent line) is skipped:
+ # Dependabot rebases it, the rebase reruns Build, and that run triggers this workflow again.
+ # GitHub computes mergeability lazily, so UNKNOWN is retried briefly.
- name: Merge when the bump is minor or patch
env:
GH_TOKEN: ${{ github.token }}
@@ -42,4 +45,13 @@ jobs:
echo "::warning::No open pull request for $BRANCH"
exit 0
fi
+ for attempt in 1 2 3 4 5 6; do
+ mergeable=$(gh pr view "$pr" --json mergeable --jq '.mergeable')
+ [ "$mergeable" != "UNKNOWN" ] && break
+ sleep 5
+ done
+ if [ "$mergeable" = "CONFLICTING" ]; then
+ echo "::warning::Pull request #$pr conflicts with the base branch, leaving for Dependabot to rebase"
+ exit 0
+ fi
gh pr merge "$pr" --squash --match-head-commit "$HEAD_SHA"
diff --git a/docs/comparer.md b/docs/comparer.md
index 63ca864ad..d64c6aaa7 100644
--- a/docs/comparer.md
+++ b/docs/comparer.md
@@ -415,7 +415,7 @@ Unsupported variants (16-bit, Adam7 interlacing) cause the decoder to throw. For
## 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.DiffPlex](https://github.com/VerifyTests/Verify.DiffPlex): Comparison of text via [DiffPlex](https://github.com/mmanela/diffplex). Not required: a text diff is now shown by default. See [Text Diff Format](/docs/exception-message-format.md#text-diff-format).
* [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).
diff --git a/docs/exception-message-format.md b/docs/exception-message-format.md
index 79564e3bb..99f4b8678 100644
--- a/docs/exception-message-format.md
+++ b/docs/exception-message-format.md
@@ -51,6 +51,76 @@ The staged path lines are omitted when staging was unavailable (build server, or
After the file listing, a `FileContent:` section includes the text content of new and not-equal files. This section is only present when there are text-based new or not-equal files. Binary files are listed in the file listing but their content is not included.
+A not-equal text file shows a `Diff:` of the verified text against the received text, rather than both texts in full. Lines compare exactly, whitespace and case included. When the texts differ only in something a line diff does not see, such as line endings, both texts are shown in full instead.
+
+
+### Text Diff Format
+
+The diff is produced by [DiffEngine](https://github.com/VerifyTests/DiffEngine)'s `TextDiff.Format`, in one of three formats:
+
+ * `Compact` (the default): the changed lines prefixed with `-` or `+`, each unchanged line next to a change prefixed with its received line number, and `[BOF]` or `[EOF]` where a change touches either end.
+ * `Full`: every line, prefixed with `-`, `+` or two spaces.
+ * `Minimal`: only the changed lines, prefixed with `-` or `+`.
+
+
+
+```txt
+Directory: {ProjectDirectory}
+NotEqual:
+ - Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+ Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+
+FileContent:
+
+NotEqual:
+
+Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+Diff:
+2 line 2
+- line 3
++ line three
+4 line 4
+
+7 line 7
++ line 8
+ [EOF]
+```
+snippet source | anchor
+
+
+The format is set globally:
+
+
+
+```cs
+public static class ModuleInitializer
+{
+ [ModuleInitializer]
+ public static void Init() =>
+ VerifierSettings.UseTextDiffFormat(DiffEngine.TextDiffFormat.Full);
+}
+```
+snippet source | anchor
+
+
+To show both texts in full, as before diffs were shown, disable the diff:
+
+
+
+```cs
+public static class ModuleInitializer
+{
+ [ModuleInitializer]
+ public static void Init() =>
+ VerifierSettings.DisableTextDiff();
+}
+```
+snippet source | anchor
+
+
+This only changes the exception message. Launching a diff tool is controlled separately, by [DisableDiff](/docs/verify-options.md#disablediff).
+
## Example: All Categories
@@ -80,11 +150,14 @@ the new content
NotEqual:
Received: MyTests.Test2.received.txt
-received text
Verified: MyTests.Test2.verified.txt
-verified text
+Diff:
+ [BOF]
+- verified text
++ received text
+ [EOF]
```
-snippet source | anchor
+snippet source | anchor
@@ -163,17 +236,20 @@ inline expected
NotEqual:
Received: MyTests.Test1#01.received.txt
-received text
Verified: MyTests.Test1#01.verified.txt
-verified text
+Diff:
+ [BOF]
+- verified text
++ received text
+ [EOF]
```
-snippet source | anchor
+snippet source | anchor
### NotEqual with Comparer Message
-When a custom comparer provides a message, the content section uses `Compare Result:` instead of inline file content:
+When a custom comparer provides a message, the content section uses `Compare Result:` instead of a diff or the file content:
diff --git a/docs/mdsource/comparer.source.md b/docs/mdsource/comparer.source.md
index 9d9bf461e..11e834f2f 100644
--- a/docs/mdsource/comparer.source.md
+++ b/docs/mdsource/comparer.source.md
@@ -136,7 +136,7 @@ Unsupported variants (16-bit, Adam7 interlacing) cause the decoder to throw. For
## 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.DiffPlex](https://github.com/VerifyTests/Verify.DiffPlex): Comparison of text via [DiffPlex](https://github.com/mmanela/diffplex). Not required: a text diff is now shown by default. See [Text Diff Format](/docs/exception-message-format.md#text-diff-format).
* [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).
diff --git a/docs/mdsource/exception-message-format.source.md b/docs/mdsource/exception-message-format.source.md
index 279b93078..d02b0384a 100644
--- a/docs/mdsource/exception-message-format.source.md
+++ b/docs/mdsource/exception-message-format.source.md
@@ -44,6 +44,29 @@ The staged path lines are omitted when staging was unavailable (build server, or
After the file listing, a `FileContent:` section includes the text content of new and not-equal files. This section is only present when there are text-based new or not-equal files. Binary files are listed in the file listing but their content is not included.
+A not-equal text file shows a `Diff:` of the verified text against the received text, rather than both texts in full. Lines compare exactly, whitespace and case included. When the texts differ only in something a line diff does not see, such as line endings, both texts are shown in full instead.
+
+
+### Text Diff Format
+
+The diff is produced by [DiffEngine](https://github.com/VerifyTests/DiffEngine)'s `TextDiff.Format`, in one of three formats:
+
+ * `Compact` (the default): the changed lines prefixed with `-` or `+`, each unchanged line next to a change prefixed with its received line number, and `[BOF]` or `[EOF]` where a change touches either end.
+ * `Full`: every line, prefixed with `-`, `+` or two spaces.
+ * `Minimal`: only the changed lines, prefixed with `-` or `+`.
+
+snippet: VerifyExceptionMessageBuilderTests.NotEqual_TextDiffCompact.verified.txt
+
+The format is set globally:
+
+snippet: UseTextDiffFormat
+
+To show both texts in full, as before diffs were shown, disable the diff:
+
+snippet: DisableTextDiff
+
+This only changes the exception message. Launching a diff tool is controlled separately, by [DisableDiff](/docs/verify-options.md#disablediff).
+
## Example: All Categories
@@ -63,7 +86,7 @@ snippet: ExceptionMessageFormatSamples.InlineAndFileTogether.verified.txt
### NotEqual with Comparer Message
-When a custom comparer provides a message, the content section uses `Compare Result:` instead of inline file content:
+When a custom comparer provides a message, the content section uses `Compare Result:` instead of a diff or the file content:
snippet: ExceptionMessageFormatSamples.NotEqualWithMessage.verified.txt
diff --git a/docs/mdsource/verify-options.source.md b/docs/mdsource/verify-options.source.md
index eb4b057b4..3074045af 100644
--- a/docs/mdsource/verify-options.source.md
+++ b/docs/mdsource/verify-options.source.md
@@ -30,7 +30,7 @@ snippet: OnFluentHandlers
## OmitContentFromException
-By default, when a verify mismatch occurs for text, the content of the received and verified files is included in the exception that is thrown. This results in that text being included in test runners and build output. To omit the content use `VerifierSettings.OmitContentFromException`.
+By default, when a verify mismatch occurs for text, a diff of the received and verified files is included in the exception that is thrown. This results in that text being included in test runners and build output. To omit the content use `VerifierSettings.OmitContentFromException`. To change the diff format, or show both files in full, see [Text Diff Format](/docs/exception-message-format.md#text-diff-format).
## DisableDiff
diff --git a/docs/verify-options.md b/docs/verify-options.md
index 4d15d422f..1b7bf34ec 100644
--- a/docs/verify-options.md
+++ b/docs/verify-options.md
@@ -123,7 +123,7 @@ public Task OnFluentCallbacks() =>
## OmitContentFromException
-By default, when a verify mismatch occurs for text, the content of the received and verified files is included in the exception that is thrown. This results in that text being included in test runners and build output. To omit the content use `VerifierSettings.OmitContentFromException`.
+By default, when a verify mismatch occurs for text, a diff of the received and verified files is included in the exception that is thrown. This results in that text being included in test runners and build output. To omit the content use `VerifierSettings.OmitContentFromException`. To change the diff format, or show both files in full, see [Text Diff Format](/docs/exception-message-format.md#text-diff-format).
## DisableDiff
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 55b3f9d3b..17732a2f6 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -7,7 +7,7 @@
-
+
diff --git a/src/ModuleInitDocs/DisableTextDiff.cs b/src/ModuleInitDocs/DisableTextDiff.cs
new file mode 100644
index 000000000..fa53e6732
--- /dev/null
+++ b/src/ModuleInitDocs/DisableTextDiff.cs
@@ -0,0 +1,13 @@
+public class DisableTextDiff
+{
+ #region DisableTextDiff
+
+ public static class ModuleInitializer
+ {
+ [ModuleInitializer]
+ public static void Init() =>
+ VerifierSettings.DisableTextDiff();
+ }
+
+ #endregion
+}
diff --git a/src/ModuleInitDocs/UseTextDiffFormat.cs b/src/ModuleInitDocs/UseTextDiffFormat.cs
new file mode 100644
index 000000000..280ad78e0
--- /dev/null
+++ b/src/ModuleInitDocs/UseTextDiffFormat.cs
@@ -0,0 +1,13 @@
+public class UseTextDiffFormat
+{
+ #region UseTextDiffFormat
+
+ public static class ModuleInitializer
+ {
+ [ModuleInitializer]
+ public static void Init() =>
+ VerifierSettings.UseTextDiffFormat(DiffEngine.TextDiffFormat.Full);
+ }
+
+ #endregion
+}
diff --git a/src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.AllCategories.verified.txt b/src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.AllCategories.verified.txt
index d19d2c1e9..c726fb5c6 100644
--- a/src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.AllCategories.verified.txt
+++ b/src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.AllCategories.verified.txt
@@ -21,7 +21,10 @@ the new content
NotEqual:
Received: MyTests.Test2.received.txt
-received text
Verified: MyTests.Test2.verified.txt
-verified text
+Diff:
+ [BOF]
+- verified text
++ received text
+ [EOF]
diff --git a/src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.InlineAndFileTogether.verified.txt b/src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.InlineAndFileTogether.verified.txt
index c21869426..d39a1c3fd 100644
--- a/src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.InlineAndFileTogether.verified.txt
+++ b/src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.InlineAndFileTogether.verified.txt
@@ -20,7 +20,10 @@ inline expected
NotEqual:
Received: MyTests.Test1#01.received.txt
-received text
Verified: MyTests.Test1#01.verified.txt
-verified text
+Diff:
+ [BOF]
+- verified text
++ received text
+ [EOF]
diff --git a/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.MultipleItem.verified.txt b/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.MultipleItem.verified.txt
index 610e969a5..55697bd04 100644
--- a/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.MultipleItem.verified.txt
+++ b/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.MultipleItem.verified.txt
@@ -30,9 +30,12 @@ the content
NotEqual:
Received: ExceptionParsingTests.Fake.received.txt
-receivedText
Verified: ExceptionParsingTests.Fake.verified.txt
-verifiedText
+Diff:
+ [BOF]
+- verifiedText
++ receivedText
+ [EOF]
,
result: {
diff --git a/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.SingleItem.verified.txt b/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.SingleItem.verified.txt
index 1ca0055f3..bfa097c8c 100644
--- a/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.SingleItem.verified.txt
+++ b/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.SingleItem.verified.txt
@@ -23,9 +23,12 @@ the content
NotEqual:
Received: ExceptionParsingTests.Fake.received.txt
-receivedText
Verified: ExceptionParsingTests.Fake.verified.txt
-verifiedText
+Diff:
+ [BOF]
+- verifiedText
++ receivedText
+ [EOF]
,
result: {
diff --git a/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.SingleNotEqual.verified.txt b/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.SingleNotEqual.verified.txt
index d2142783c..6139a809d 100644
--- a/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.SingleNotEqual.verified.txt
+++ b/src/Verify.ExceptionParsing.Tests/ExceptionParsingTests.SingleNotEqual.verified.txt
@@ -10,9 +10,12 @@ FileContent:
NotEqual:
Received: ExceptionParsingTests.Fake.received.txt
-receivedText
Verified: ExceptionParsingTests.Fake.verified.txt
-verifiedText
+Diff:
+ [BOF]
+- verifiedText
++ receivedText
+ [EOF]
,
result: {
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.AllCategories.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.AllCategories.verified.txt
index f239de1f6..a830f3dbb 100644
--- a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.AllCategories.verified.txt
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.AllCategories.verified.txt
@@ -21,7 +21,10 @@ new content
NotEqual:
Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
-received
Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
-verified
+Diff:
+ [BOF]
+- verified
++ received
+ [EOF]
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.MultipleNotEqual_MixedMessageAndNoMessage.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.MultipleNotEqual_MixedMessageAndNoMessage.verified.txt
index 6066ad879..ff02c667a 100644
--- a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.MultipleNotEqual_MixedMessageAndNoMessage.verified.txt
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.MultipleNotEqual_MixedMessageAndNoMessage.verified.txt
@@ -10,9 +10,12 @@ FileContent:
NotEqual:
Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
-received text
Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
-verified text
+Diff:
+ [BOF]
+- verified text
++ received text
+ [EOF]
Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffCompact.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffCompact.verified.txt
new file mode 100644
index 000000000..43a886caa
--- /dev/null
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffCompact.verified.txt
@@ -0,0 +1,21 @@
+Directory: {ProjectDirectory}
+NotEqual:
+ - Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+ Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+
+FileContent:
+
+NotEqual:
+
+Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+Diff:
+2 line 2
+- line 3
++ line three
+4 line 4
+
+7 line 7
++ line 8
+ [EOF]
+
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffDisabled.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffDisabled.verified.txt
new file mode 100644
index 000000000..931654a7e
--- /dev/null
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffDisabled.verified.txt
@@ -0,0 +1,27 @@
+Directory: {ProjectDirectory}
+NotEqual:
+ - Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+ Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+
+FileContent:
+
+NotEqual:
+
+Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+line 1
+line 2
+line three
+line 4
+line 5
+line 6
+line 7
+line 8
+Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+line 1
+line 2
+line 3
+line 4
+line 5
+line 6
+line 7
+
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffEmptyFallsBackToContent.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffEmptyFallsBackToContent.verified.txt
new file mode 100644
index 000000000..9f74a82f7
--- /dev/null
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffEmptyFallsBackToContent.verified.txt
@@ -0,0 +1,16 @@
+Directory: {ProjectDirectory}
+NotEqual:
+ - Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+ Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+
+FileContent:
+
+NotEqual:
+
+Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+a
+b
+Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+a
+b
+
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffFull.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffFull.verified.txt
new file mode 100644
index 000000000..2d53e1a73
--- /dev/null
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffFull.verified.txt
@@ -0,0 +1,22 @@
+Directory: {ProjectDirectory}
+NotEqual:
+ - Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+ Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+
+FileContent:
+
+NotEqual:
+
+Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+Diff:
+ line 1
+ line 2
+- line 3
++ line three
+ line 4
+ line 5
+ line 6
+ line 7
++ line 8
+
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffMinimal.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffMinimal.verified.txt
new file mode 100644
index 000000000..ee20cf848
--- /dev/null
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffMinimal.verified.txt
@@ -0,0 +1,16 @@
+Directory: {ProjectDirectory}
+NotEqual:
+ - Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+ Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+
+FileContent:
+
+NotEqual:
+
+Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+Diff:
+- line 3
++ line three
++ line 8
+
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffWhitespace.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffWhitespace.verified.txt
new file mode 100644
index 000000000..25ea07d1b
--- /dev/null
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.NotEqual_TextDiffWhitespace.verified.txt
@@ -0,0 +1,17 @@
+Directory: {ProjectDirectory}
+NotEqual:
+ - Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+ Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+
+FileContent:
+
+NotEqual:
+
+Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
+Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
+Diff:
+1 a
+- b
++ b
+3 c
+
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.SingleNotEqual_Text.verified.txt b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.SingleNotEqual_Text.verified.txt
index b2043d71a..d33c8acc7 100644
--- a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.SingleNotEqual_Text.verified.txt
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.SingleNotEqual_Text.verified.txt
@@ -8,7 +8,10 @@ FileContent:
NotEqual:
Received: VerifyExceptionMessageBuilderTests.Fake.received.txt
-received content
Verified: VerifyExceptionMessageBuilderTests.Fake.verified.txt
-verified content
+Diff:
+ [BOF]
+- verified content
++ received content
+ [EOF]
diff --git a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.cs b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.cs
index 4906e53d1..cac619835 100644
--- a/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.cs
+++ b/src/Verify.ExceptionParsing.Tests/VerifyExceptionMessageBuilderTests.cs
@@ -1,3 +1,4 @@
+using DiffEngine;
using FilePair = VerifyTests.FilePair;
public class VerifyExceptionMessageBuilderTests
@@ -156,6 +157,58 @@ public Task MultipleNotEqual_MixedMessageAndNoMessage()
return BuildVerify([], notEquals, [], []);
}
+ const string multiLineVerified = "line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7";
+ const string multiLineReceived = "line 1\nline 2\nline three\nline 4\nline 5\nline 6\nline 7\nline 8";
+
+ [Fact]
+ public Task NotEqual_TextDiffCompact() =>
+ BuildVerifyTextDiff(multiLineReceived, multiLineVerified, TextDiffFormat.Compact);
+
+ [Fact]
+ public Task NotEqual_TextDiffFull() =>
+ BuildVerifyTextDiff(multiLineReceived, multiLineVerified, TextDiffFormat.Full);
+
+ [Fact]
+ public Task NotEqual_TextDiffMinimal() =>
+ BuildVerifyTextDiff(multiLineReceived, multiLineVerified, TextDiffFormat.Minimal);
+
+ ///
+ /// With the diff disabled the full received and verified text is shown, as before diffs existed.
+ ///
+ [Fact]
+ public Task NotEqual_TextDiffDisabled() =>
+ BuildVerifyTextDiff(multiLineReceived, multiLineVerified, null);
+
+ ///
+ /// A whitespace only change is a difference, and has to show as one.
+ ///
+ [Fact]
+ public Task NotEqual_TextDiffWhitespace() =>
+ BuildVerifyTextDiff("a\n b\nc", "a\nb\nc", TextDiffFormat.Compact);
+
+ ///
+ /// Line endings split lines rather than belong to them, so texts that differ only in line
+ /// endings have an empty diff, and the full text is shown instead.
+ ///
+ [Fact]
+ public Task NotEqual_TextDiffEmptyFallsBackToContent() =>
+ BuildVerifyTextDiff("a\r\nb", "a\nb", TextDiffFormat.Compact);
+
+ static Task BuildVerifyTextDiff(string received, string verified, TextDiffFormat? format)
+ {
+ var message = VerifyExceptionMessageBuilder.Build(
+ projectDirectory,
+ [],
+ [new(new("txt", receivedTxt, verifiedTxt), null, new(received), verified)],
+ [],
+ [],
+ null,
+ null,
+ format);
+
+ return Verifier.Verify(message);
+ }
+
static Task BuildVerify(
IReadOnlyCollection @new,
IReadOnlyCollection notEquals,
diff --git a/src/Verify/Serialization/VerifierSettings.cs b/src/Verify/Serialization/VerifierSettings.cs
index dcfec655c..4dc85f98a 100644
--- a/src/Verify/Serialization/VerifierSettings.cs
+++ b/src/Verify/Serialization/VerifierSettings.cs
@@ -168,6 +168,7 @@ internal static void Reset()
UniquePrefixDisabled = false;
UseUniqueDirectorySplitMode = false;
omitContentFromException = false;
+ textDiffFormat = TextDiffFormat.Compact;
fixNewlinesOnRead = false;
ignoreTrailingNewline = false;
encoding = new UTF8Encoding(true, true);
diff --git a/src/Verify/Verifier/VerifyExceptionMessageBuilder.cs b/src/Verify/Verifier/VerifyExceptionMessageBuilder.cs
index fbaa979ce..ebce9c985 100644
--- a/src/Verify/Verifier/VerifyExceptionMessageBuilder.cs
+++ b/src/Verify/Verifier/VerifyExceptionMessageBuilder.cs
@@ -20,7 +20,23 @@ public static string Build(
IReadOnlyCollection delete,
IReadOnlyCollection equal,
InlineSection? inline = null,
- string? hint = null)
+ string? hint = null) =>
+ Build(directory, @new, notEquals, delete, equal, inline, hint, VerifierSettings.textDiffFormat);
+
+ ///
+ /// is null to show the full received and verified text of a
+ /// mismatched text file rather than a diff. Passed rather than read from the settings so tests
+ /// can vary it without changing global state.
+ ///
+ public static string Build(
+ string directory,
+ IReadOnlyCollection @new,
+ IReadOnlyCollection notEquals,
+ IReadOnlyCollection delete,
+ IReadOnlyCollection equal,
+ InlineSection? inline,
+ string? hint,
+ TextDiffFormat? textDiffFormat)
{
var builder = new StringBuilder($"Directory: {directory}\n");
@@ -75,7 +91,7 @@ public static string Build(
}
}
- AppendContent(directory, @new, notEquals, inline, hint, builder);
+ AppendContent(directory, @new, notEquals, inline, hint, textDiffFormat, builder);
return builder.ToString();
}
@@ -94,6 +110,7 @@ static void AppendContent(
IReadOnlyCollection notEquals,
InlineSection? inline,
string? hint,
+ TextDiffFormat? textDiffFormat,
StringBuilder builder)
{
var omit = VerifierSettings.omitContentFromException;
@@ -170,13 +187,13 @@ inlineContent is null &&
builder.AppendLineN();
foreach (var notEqual in notEqualContentFiles)
{
- AppendNotEqualContent(directory, builder, notEqual);
+ AppendNotEqualContent(directory, builder, notEqual, textDiffFormat);
builder.AppendLineN();
}
}
}
- static void AppendNotEqualContent(string directory, StringBuilder builder, NotEqualResult notEqual)
+ static void AppendNotEqualContent(string directory, StringBuilder builder, NotEqualResult notEqual, TextDiffFormat? textDiffFormat)
{
var item = notEqual.File;
var message = notEqual.Message;
@@ -184,6 +201,19 @@ static void AppendNotEqualContent(string directory, StringBuilder builder, NotEq
var verifiedPath = IoHelpers.GetRelativePath(directory, item.VerifiedPath);
if (message is null)
{
+ var diff = Diff(notEqual, textDiffFormat);
+ if (diff is not null)
+ {
+ builder.AppendLineN(
+ $"""
+ Received: {receivedPath}
+ Verified: {verifiedPath}
+ Diff:
+ {diff}
+ """);
+ return;
+ }
+
builder.AppendLineN(
$"""
Received: {receivedPath}
@@ -203,4 +233,28 @@ static void AppendNotEqualContent(string directory, StringBuilder builder, NotEq
""");
}
}
+
+ ///
+ /// A line diff of the verified text against the received text, or null to fall back to showing
+ /// both in full: when diffs are disabled, when either text is missing, and when the diff comes
+ /// back empty because the texts differ only in something a line diff does not see, such as line
+ /// endings.
+ ///
+ static string? Diff(NotEqualResult notEqual, TextDiffFormat? textDiffFormat)
+ {
+ if (textDiffFormat is not { } format ||
+ notEqual.ReceivedText is not { } received ||
+ notEqual.VerifiedText is not { } verified)
+ {
+ return null;
+ }
+
+ var diff = TextDiff.Format(verified, received.ToString(), format);
+ if (diff.Length == 0)
+ {
+ return null;
+ }
+
+ return diff;
+ }
}
diff --git a/src/Verify/VerifierSettings.cs b/src/Verify/VerifierSettings.cs
index 0466249ab..0f5b420d6 100644
--- a/src/Verify/VerifierSettings.cs
+++ b/src/Verify/VerifierSettings.cs
@@ -7,6 +7,28 @@ public static partial class VerifierSettings
public static void OmitContentFromException() =>
omitContentFromException = true;
+ internal static TextDiffFormat? textDiffFormat = TextDiffFormat.Compact;
+
+ ///
+ /// The format of the line diff shown in the exception message when a text file does not match
+ /// and no string comparer supplied a message. Defaults to .
+ ///
+ public static void UseTextDiffFormat(TextDiffFormat format)
+ {
+ InnerVerifier.ThrowIfVerifyHasBeenRun();
+ textDiffFormat = format;
+ }
+
+ ///
+ /// Show the full received and verified text in the exception message, instead of a line diff,
+ /// when a text file does not match. Does not affect launching a diff tool.
+ ///
+ public static void DisableTextDiff()
+ {
+ InnerVerifier.ThrowIfVerifyHasBeenRun();
+ textDiffFormat = null;
+ }
+
///
/// Automatically accept the results of all tests.
///