diff --git a/claude.md b/claude.md index cdd57ea14..6c2f12e98 100644 --- a/claude.md +++ b/claude.md @@ -211,9 +211,13 @@ Reference existing adapters like `Verify.Xunit/Verifier.cs` or `Verify.NUnit/Ver ### Accepting New Snapshots -When tests fail, `.received.*` files are created showing actual output. To accept a new snapshot, copy the `.received.*` file to the corresponding `.verified.*` filename. +When tests fail, `.received.*` files are created showing actual output. To accept a new snapshot, copy the `.received.*` file to the path on the `Verified:` line of the exception message. Do not derive the verified name from the received name — the two are not always the same. -**Multi-target naming**: When a test project targets multiple frameworks, `.received.` files include a runtime suffix (e.g., `.DotNet11_0.received.txt`) but `.verified.` files do **not** (e.g., `.verified.txt`). When accepting snapshots, strip the runtime suffix from the filename. +**Multi-target naming**: When a test project targets multiple frameworks (e.g., `Verify.Tests`), the `.received.` file always carries a runtime and version suffix (e.g., `.DotNet11_0.received.txt`). The `.verified.` file carries whatever `UniqueFor*` the test asked for, which may be nothing (`.verified.txt`), the runtime (`.DotNet.verified.txt`), or the same runtime and version (`.DotNet11_0.verified.txt`). + +**Single-target naming**: When a test project targets a single framework (e.g., `StaticSettingsTests`), the `.received.` file uses the same uniqueness as its `.verified.` file, including any `UniqueForRuntime`/`UniqueForRuntimeAndVersion` suffix. + +**Parameters**: Ignored parameters (`IgnoreParameters`, `IgnoreParametersForVerified`, `IgnoreConstructorParameters`) are kept in the `.received.` name and dropped from the `.verified.` name, regardless of how many frameworks are targeted. ### Debugging Tests diff --git a/docs/ai-usage.md b/docs/ai-usage.md index 103a63be0..5d76d824e 100644 --- a/docs/ai-usage.md +++ b/docs/ai-usage.md @@ -75,13 +75,14 @@ Verified: TestClass.Method.verified.txt ### Step 3: Determine the action -- **If the change is expected** (due to an intentional code change): copy the `.received.*` file over the `.verified.*` file to accept the new snapshot. -- **If it is a new test** (no `.verified.*` file): accept the `.received.*` file as the new snapshot by renaming it to `.verified.*`. +- **If the change is expected** (due to an intentional code change): copy the `.received.*` file to the `Verified:` path to accept the new snapshot. +- **If it is a new test** (no `.verified.*` file): accept the `.received.*` file as the new snapshot by copying it to the `Verified:` path. - **If the change is a bug**: fix the code, not the snapshot. Re-run the test to confirm the fix. ## Rules - **Never hand-edit `.verified.*` files** to make tests pass. Always let Verify generate the correct output by running the test. +- **Never derive the verified name from the received name.** The two are not always identical. Multi-targeted projects add a runtime and version suffix to the received file, and ignored parameters are kept in the received name but dropped from the verified name. Always take the destination from the `Verified:` line of the exception message. - Snapshot files live next to the test source file. For a test in `Tests/MyTests.cs`, look for `Tests/MyTests.MethodName.verified.txt`. ## Scrubbed values @@ -132,9 +133,10 @@ When a snapshot test fails: 1. Run the failing test and read the `.received.*` file that was generated. 2. Compare it to the corresponding `.verified.*` file. 3. Determine if the difference is expected (due to an intentional code change) or a bug. - - **If expected**: copy the `.received.*` file over the `.verified.*` file to accept the new snapshot, or delete the `.verified.*` file and rename the `.received.*` file. + - **If expected**: copy the `.received.*` file to the `Verified:` path listed in the exception message to accept the new snapshot. - **If a bug**: fix the code, not the snapshot. 4. Never hand-edit `.verified.*` files to make tests pass. Always let Verify generate the correct output by running the test. +5. Never derive the verified name from the received name. The two are not always identical. Multi-targeted projects add a runtime and version suffix to the received file, and ignored parameters are kept in the received name but dropped from the verified name. Always take the destination from the `Verified:` line of the exception message. ### Scrubbed values diff --git a/docs/mdsource/ai-usage.source.md b/docs/mdsource/ai-usage.source.md index 3d64caf07..b1f7413d3 100644 --- a/docs/mdsource/ai-usage.source.md +++ b/docs/mdsource/ai-usage.source.md @@ -68,13 +68,14 @@ Verified: TestClass.Method.verified.txt ### Step 3: Determine the action -- **If the change is expected** (due to an intentional code change): copy the `.received.*` file over the `.verified.*` file to accept the new snapshot. -- **If it is a new test** (no `.verified.*` file): accept the `.received.*` file as the new snapshot by renaming it to `.verified.*`. +- **If the change is expected** (due to an intentional code change): copy the `.received.*` file to the `Verified:` path to accept the new snapshot. +- **If it is a new test** (no `.verified.*` file): accept the `.received.*` file as the new snapshot by copying it to the `Verified:` path. - **If the change is a bug**: fix the code, not the snapshot. Re-run the test to confirm the fix. ## Rules - **Never hand-edit `.verified.*` files** to make tests pass. Always let Verify generate the correct output by running the test. +- **Never derive the verified name from the received name.** The two are not always identical. Multi-targeted projects add a runtime and version suffix to the received file, and ignored parameters are kept in the received name but dropped from the verified name. Always take the destination from the `Verified:` line of the exception message. - Snapshot files live next to the test source file. For a test in `Tests/MyTests.cs`, look for `Tests/MyTests.MethodName.verified.txt`. ## Scrubbed values @@ -125,9 +126,10 @@ When a snapshot test fails: 1. Run the failing test and read the `.received.*` file that was generated. 2. Compare it to the corresponding `.verified.*` file. 3. Determine if the difference is expected (due to an intentional code change) or a bug. - - **If expected**: copy the `.received.*` file over the `.verified.*` file to accept the new snapshot, or delete the `.verified.*` file and rename the `.received.*` file. + - **If expected**: copy the `.received.*` file to the `Verified:` path listed in the exception message to accept the new snapshot. - **If a bug**: fix the code, not the snapshot. 4. Never hand-edit `.verified.*` files to make tests pass. Always let Verify generate the correct output by running the test. +5. Never derive the verified name from the received name. The two are not always identical. Multi-targeted projects add a runtime and version suffix to the received file, and ignored parameters are kept in the received name but dropped from the verified name. Always take the destination from the `Verified:` line of the exception message. ### Scrubbed values diff --git a/docs/mdsource/naming.source.md b/docs/mdsource/naming.source.md index 43cd3fc85..f1b57df8a 100644 --- a/docs/mdsource/naming.source.md +++ b/docs/mdsource/naming.source.md @@ -322,7 +322,19 @@ eg. add the following to `.gitignore` ## Received and multi-targeting -When a test project uses more than one `TargetFrameworks` (eg `net48;net7.0`) the runtime and version will be always be added as a uniqueness to the received file. This prevents file locking contention when the tests from both target framework run in parallel. +When a test project uses more than one `TargetFrameworks` (eg `net48;net7.0`) the runtime and version will always be added as a uniqueness to the received file name. This prevents file locking contention when the tests from both target framework run in parallel. + +This applies to the default file naming. Under [UseUniqueDirectory](#useuniquedirectory) the received files use the same uniqueness as the verified files. + + +## Received and single-targeting + +When a test project uses a single `TargetFramework`, there is no such contention, so the received file uses the same uniqueness as the verified file. With `UniqueForRuntime` both files include the runtime: + +``` +TheTest.TheMethod.DotNet.received.txt +TheTest.TheMethod.DotNet.verified.txt +``` ## Orphaned verified files diff --git a/docs/naming.md b/docs/naming.md index 92313bfc1..d865aef3d 100644 --- a/docs/naming.md +++ b/docs/naming.md @@ -897,7 +897,19 @@ eg. add the following to `.gitignore` ## Received and multi-targeting -When a test project uses more than one `TargetFrameworks` (eg `net48;net7.0`) the runtime and version will be always be added as a uniqueness to the received file. This prevents file locking contention when the tests from both target framework run in parallel. +When a test project uses more than one `TargetFrameworks` (eg `net48;net7.0`) the runtime and version will always be added as a uniqueness to the received file name. This prevents file locking contention when the tests from both target framework run in parallel. + +This applies to the default file naming. Under [UseUniqueDirectory](#useuniquedirectory) the received files use the same uniqueness as the verified files. + + +## Received and single-targeting + +When a test project uses a single `TargetFramework`, there is no such contention, so the received file uses the same uniqueness as the verified file. With `UniqueForRuntime` both files include the runtime: + +``` +TheTest.TheMethod.DotNet.received.txt +TheTest.TheMethod.DotNet.verified.txt +``` ## Orphaned verified files diff --git a/src/StaticSettingsTests/SingleTfmTests.cs b/src/StaticSettingsTests/SingleTfmTests.cs index 93960aec7..cab7d1285 100644 --- a/src/StaticSettingsTests/SingleTfmTests.cs +++ b/src/StaticSettingsTests/SingleTfmTests.cs @@ -20,4 +20,58 @@ public async Task Simple() File.Delete(received); } } + + // With a single target framework the received file carries the same uniqueness as the verified + // file, so the two names match and tooling can pair a received file with its verified file. When + // multiple frameworks are targeted the received file uses the runtime and version instead, which + // Verify.Tests covers via DanglingFiles. + [Fact] + public Task ReceivedUsesRuntime() => + AssertReceivedIsSuffixed( + "SingleTfmTests.ReceivedUsesRuntime", + Namer.Runtime, + _ => _.UniqueForRuntime()); + + [Fact] + public Task ReceivedUsesRuntimeAndVersion() => + AssertReceivedIsSuffixed( + "SingleTfmTests.ReceivedUsesRuntimeAndVersion", + Namer.RuntimeAndVersion, + _ => _.UniqueForRuntimeAndVersion()); + + [Fact] + public Task ReceivedUsesRuntimeForFileName() => + AssertReceivedIsSuffixed( + "CustomFileName", + Namer.Runtime, + _ => + { + _.UseFileName("CustomFileName"); + _.UniqueForRuntime(); + }); + + static async Task AssertReceivedIsSuffixed(string prefix, string suffix, Action configure) + { + var verified = CurrentFile.Relative($"{prefix}.{suffix}.verified.txt"); + var received = CurrentFile.Relative($"{prefix}.{suffix}.received.txt"); + var unsuffixed = CurrentFile.Relative($"{prefix}.received.txt"); + File.Delete(verified); + File.Delete(received); + File.Delete(unsuffixed); + var settings = new VerifySettings(); + settings.DisableDiff(); + configure(settings); + try + { + await Assert.ThrowsAsync(() => Verify("value", settings)); + Assert.True(File.Exists(received)); + Assert.False(File.Exists(unsuffixed)); + } + finally + { + File.Delete(verified); + File.Delete(received); + File.Delete(unsuffixed); + } + } } \ No newline at end of file diff --git a/src/Verify/Verifier/InnerVerifier.cs b/src/Verify/Verifier/InnerVerifier.cs index 6d089e20c..0ff3d3850 100644 --- a/src/Verify/Verifier/InnerVerifier.cs +++ b/src/Verify/Verifier/InnerVerifier.cs @@ -306,22 +306,18 @@ void InitForFileConvention(Namer namer, string typeAndMethod, Action