Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

84 changes: 58 additions & 26 deletions src/Verify.Tests/NewLineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,38 @@ public async Task StringWithDifferingNewline()
var cr = await Assert.ThrowsAnyAsync<Exception>(() => Verify("a\nb", settings));
Assert.Contains("carriage return", cr.ToString());

// The rejection writes received, so the run is not silent, and is not wrapped in a
// generic "Failed to compare files" that hides the cause.
// Globbed because received carries the namer uniqueness suffix, while the verified
// file above is the unsuffixed fallback.
var directory = Path.GetDirectoryName(fullPath)!;
const string receivedPattern = "NewLineTests.StringWithDifferingNewline*.received.txt";
foreach (var stale in Directory.EnumerateFiles(directory, receivedPattern))
{
File.Delete(stale);
}

await File.WriteAllTextAsync(fullPath, "a\r\nb");
var rejection = await Assert.ThrowsAnyAsync<Exception>(() => Verify("a\nb", settings));
Assert.DoesNotContain("Failed to compare files", rejection.Message);
Assert.Contains("*.verified.txt text eol=lf", rejection.Message);
var received = Directory.EnumerateFiles(directory, receivedPattern).Single();
Assert.Equal("a\nb", await File.ReadAllTextAsync(received));
File.Delete(received);

// The suggested .gitattributes line uses the extension of the failing file,
// which is not always txt
var jsonPath = CurrentFile.Relative("NewLineTests.StringWithDifferingNewline.verified.json");
await File.WriteAllTextAsync(jsonPath, "{\r\n}");
var json = await Assert.ThrowsAnyAsync<Exception>(
() => Verify("{\n}", extension: "json", settings: settings));
Assert.Contains("*.verified.json text eol=lf", json.Message);
File.Delete(jsonPath);
foreach (var stale in Directory.EnumerateFiles(directory, "NewLineTests.StringWithDifferingNewline*.received.json"))
{
File.Delete(stale);
}

// A verified file using \n still matches received content normalized to \n
await File.WriteAllTextAsync(fullPath, "a\nb");
await Verify("a\r\nb", settings);
Expand All @@ -65,32 +97,6 @@ public async Task StringWithDifferingNewline()
File.Delete(fullPath);
}

#if NET10
[Fact]
public async Task TrailingNewlinesRaw()
{
var file = CurrentFile.Relative("NewLineTests.TrailingNewlinesRaw.verified.txt");
File.Delete(file);
var settings = new VerifySettings();
settings.DisableRequireUniquePrefix();

// A verified file containing \r is rejected
await File.WriteAllTextAsync(file, "a\r\n");
var exception = await Assert.ThrowsAnyAsync<Exception>(() => Verify("a\n", settings));
Assert.Contains("carriage return", exception.ToString());

// Trailing newlines are now compared exactly, with no tolerance
await File.WriteAllTextAsync(file, "a\n");
await Verify("a\n", settings);
await Assert.ThrowsAsync<VerifyException>(() => Verify("a", settings));

await File.WriteAllTextAsync(file, "a\n\n");
await Verify("a\n\n", settings);
await Assert.ThrowsAsync<VerifyException>(() => Verify("a\n", settings));
File.Delete(file);
}
#endif

//TODO: add test for trailing newlines
// [Fact]
// public async Task TrailingNewlinesObject()
Expand All @@ -116,4 +122,30 @@ public async Task TrailingNewlinesRaw()
// }

#endif

#if NET10_0
[Fact]
public async Task TrailingNewlinesRaw()
{
var file = CurrentFile.Relative("NewLineTests.TrailingNewlinesRaw.verified.txt");
File.Delete(file);
var settings = new VerifySettings();
settings.DisableRequireUniquePrefix();

// A verified file containing \r is rejected
await File.WriteAllTextAsync(file, "a\r\n");
var exception = await Assert.ThrowsAnyAsync<Exception>(() => Verify("a\n", settings));
Assert.Contains("carriage return", exception.ToString());

// Trailing newlines are now compared exactly, with no tolerance
await File.WriteAllTextAsync(file, "a\n");
await Verify("a\n", settings);
await Assert.ThrowsAsync<VerifyException>(() => Verify("a", settings));

await File.WriteAllTextAsync(file, "a\n\n");
await Verify("a\n\n", settings);
await Assert.ThrowsAsync<VerifyException>(() => Verify("a\n", settings));
File.Delete(file);
}
#endif
}
3 changes: 2 additions & 1 deletion src/Verify.Tests/Serialization/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4545,7 +4545,8 @@ public Task Dictionary_ScrubDictionaryKeys() =>
},
})
.AddScrubber(_ => _.Replace("key", "scrubbed"));
#if NET10

#if NET10_0
[Fact]
Task SecondsFractionUpperLong() =>
Verify("""
Expand Down
6 changes: 5 additions & 1 deletion src/Verify/Compare/Comparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ public static async Task<EqualityResult> Text(FilePair filePair, StringBuilder r
var verified = await File.ReadAllTextAsync(filePair.VerifiedPath, VerifierSettings.Encoding);
if (verified.Contains('\r'))
{
throw new($@"Verified file must use \n line endings, but it contains a \r (carriage return). Path: {filePair.VerifiedPath}. See https://github.com/verifytests/verify#text-file-settings");
// Write received before throwing. Otherwise the run produces no output at all,
// which reads as "verify silently did nothing" rather than a line ending problem.
// Accepting the received file also rewrites verified with \n endings.
IoHelpers.WriteText(filePair.ReceivedPath, received);
throw new VerifiedLineEndingException(filePair.VerifiedPath, filePair.Extension);
}

var result = await CompareStrings(filePair.Extension, received, verified, settings, bypassComparer);
Expand Down
12 changes: 12 additions & 0 deletions src/Verify/Compare/VerifiedLineEndingException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class VerifiedLineEndingException(string path, string extension) :
Exception(
$"""
Verified file must use \n line endings, but it contains a \r (carriage return).
Path: {path}
The usual cause is git checking the file out with \r\n. Add to .gitattributes:
*.verified.{extension} text eol=lf working-tree-encoding=UTF-8
then re-checkout the files:
git rm --cached -r .
git reset --hard
See https://github.com/verifytests/verify#text-file-settings
""");
6 changes: 6 additions & 0 deletions src/Verify/Verifier/VerifyEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ static async Task<EqualityResult> GetResult(VerifySettings settings, FilePair fi
stream.MoveToStart();
return await FileComparer.DoCompare(settings, file, textHasFailed || bypassComparers, stream);
}
catch (VerifiedLineEndingException)
{
// Already names the file and the fix. Wrapping it hides that behind a generic
// "failed to compare" message.
throw;
}
catch (Exception exception)
{
throw new(
Expand Down
Loading