Skip to content

Latest commit

 

History

History
342 lines (257 loc) · 12.3 KB

exception-message-format.md

File metadata and controls

342 lines (257 loc) · 12.3 KB

Exception Message Format

When a Verify test fails, the exception message is designed to be machine-parsable. This enables tooling (IDE extensions, CI integrations, diff tools) to programmatically extract file paths and take action on verification failures.

Message Structure

The message has two parts: a file listing followed by optional file content.

File Listing

The first line is always the directory:

Directory: /path/to/test/project

Then zero or more categorized sections, each listing file pairs:

  • New - a .received. file exists with no corresponding .verified. file (first test run or new test).
  • NotEqual - both files exist but content differs.
  • Delete - a .verified. file exists that is no longer produced by any test.
  • Equal - both files exist and match (included for completeness when other categories are present).
  • InlineNew - an inline snapshot with no expected value yet.
  • InlineNotEqual - an inline snapshot whose expected value differs from the result.

File paths in these sections are relative to the reported directory, and keep any subdirectory. UseUniqueDirectory and VerifyDirectory place snapshots in a subdirectory, so combining the reported directory with the listed path is what rebuilds the full path.

Inline entries use a different shape: a Source: line with the absolute source file path and 1 based line number (path:line), followed by optional absolute staged file paths:

InlineNotEqual:
  - Source: /path/to/MyTests.cs:12
    Received: /path/to/obj/VerifyInline/def.received.txt
    Expected: /path/to/obj/VerifyInline/def.expected.txt
    Patch: /path/to/obj/VerifyInline/def.inlinepatch

The staged path lines are omitted when staging was unavailable (build server, or the project does not consume Verify's build props). The Patch: file is readable via the DiffEngine InlinePatchFile API.

File Content

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'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 +.

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:

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:

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.

Example: All Categories

Directory: {ProjectDirectory}
New:
  - Received: MyTests.Test1.received.txt
    Verified: MyTests.Test1.verified.txt
NotEqual:
  - Received: MyTests.Test2.received.txt
    Verified: MyTests.Test2.verified.txt
Delete:
  - MyTests.OldTest.verified.txt
Equal:
  - Received: MyTests.Test3.received.txt
    Verified: MyTests.Test3.verified.txt

FileContent:

New:

Received: MyTests.Test1.received.txt
the new content

NotEqual:

Received: MyTests.Test2.received.txt
Verified: MyTests.Test2.verified.txt
Diff:
  [BOF]
- verified text
+ received text
  [EOF]

snippet source | anchor

Inline snapshot examples

Directory: {ProjectDirectory}
InlineNew:
  - Source: {ProjectDirectory}MyTests.cs:10
    Received: {ProjectDirectory}obj/VerifyInline/abc.received.txt
    Expected: {ProjectDirectory}obj/VerifyInline/abc.expected.txt
    Patch: {ProjectDirectory}obj/VerifyInline/abc.inlinepatch

FileContent:

InlineNew:

Source: {ProjectDirectory}MyTests.cs:10
Received:
the new content

snippet source | anchor

Directory: {ProjectDirectory}
InlineNotEqual:
  - Source: {ProjectDirectory}MyTests.cs:12
    Received: {ProjectDirectory}obj/VerifyInline/def.received.txt
    Expected: {ProjectDirectory}obj/VerifyInline/def.expected.txt
    Patch: {ProjectDirectory}obj/VerifyInline/def.inlinepatch
Delete:
  - MyTests.OldTest.verified.txt

FileContent:

InlineNotEqual:

Source: {ProjectDirectory}MyTests.cs:12
Received:
received text
Expected:
expected text

snippet source | anchor

Only the first target of a verification is inlined, so one message can carry an inline section and the file sections for the remaining targets together:

Directory: {ProjectDirectory}
InlineNotEqual:
  - Source: {ProjectDirectory}MyTests.cs:14
NotEqual:
  - Received: MyTests.Test1#01.received.txt
    Verified: MyTests.Test1#01.verified.txt
Delete:
  - MyTests.OldTest.verified.txt

FileContent:

InlineNotEqual:

Source: {ProjectDirectory}MyTests.cs:14
Received:
inline received
Expected:
inline expected

NotEqual:

Received: MyTests.Test1#01.received.txt
Verified: MyTests.Test1#01.verified.txt
Diff:
  [BOF]
- verified text
+ received text
  [EOF]

snippet source | anchor

NotEqual with Comparer Message

When a custom comparer provides a message, the content section uses Compare Result: instead of a diff or the file content:

Directory: {ProjectDirectory}
NotEqual:
  - Received: MyTests.Test1.received.txt
    Verified: MyTests.Test1.verified.txt

FileContent:

NotEqual:

Received: MyTests.Test1.received.txt
Verified: MyTests.Test1.verified.txt
Compare Result:
The comparer reported a difference

snippet source | anchor

Content Omission

The FileContent: section can be suppressed globally:

public static class ModuleInitializer
{
    [ModuleInitializer]
    public static void Init() =>
        VerifierSettings.OmitContentFromException();
}

snippet source | anchor

This is useful in CI environments where only the file paths are needed.

Parsing Exception Messages

The Verify.ExceptionParsing NuGet package provides a parser for this format.

Usage

static Result ParseExceptionMessage(string exceptionMessage)
{
    var result = Parser.Parse(exceptionMessage);

    // result.New: files with no corresponding .verified. file
    // result.NotEqual: files where .received. differs from .verified.
    // result.Delete: .verified. files no longer produced by any test
    // result.Equal: files where .received. matches .verified.

    foreach (var file in result.NotEqual)
    {
        Debug.WriteLine($"Received: {file.Received}");
        Debug.WriteLine($"Verified: {file.Verified}");
    }

    return result;
}

snippet source | anchor

The Result contains:

  • New - list of FilePair (received and verified paths).
  • NotEqual - list of FilePair.
  • Delete - list of file paths.
  • Equal - list of FilePair.
  • InlineNew - list of InlineEntry (source file, line, and optional staged paths).
  • InlineNotEqual - list of InlineEntry.

Test Framework Prefixes

Different test frameworks prepend different prefixes to the exception message. The parser handles these automatically:

  • NUnit: VerifyException : Directory: ...
  • MSTest: Test method ... threw exception:\nVerifyException: Directory: ...
  • Other frameworks: Directory: ...