I have code that calculates the SHA256 integrity hash of a file from the web. For example, the integrity hash of jquery-3.7.1.min.js
is /JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=
(source). I have some units tests to test the code, and that always worked fine. Now, I thinks since .NET 9, the tests fail on my Windows machine. In Github actions (Linux) these test still work fine. This is a simplified version of the code:
[Fact]
public void Test()
{
// Arrange
const string Expected = "/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=";
var fileContents = TestResources.GetFileContents("MyTests.Resources.jquery-3.7.1.min.js"); // read from embedded resource
var sha256Hasher = SHA256.Create();
// Act
var byteResult = sha256Hasher.ComputeHash(Encoding.UTF8.GetBytes(fileContents));
// Assert
var result = Convert.ToBase64String(byteResult);
result.Should().Be(Expected);
/*
Expected result to be the same string, but they differ at index 0:
↓ (actual)
"eqaw4I9IoPldjffqieTL…"
"/JqT3SQfawRcv/BIHPTh…"
↑ (expected).
*/
}
public static string GetFileContents(string filename)
{
var assembly = typeof(TestResources).GetTypeInfo().Assembly;
using var resource = assembly.GetManifestResourceStream(filename);
using var reader = new StreamReader(resource!);
var result = reader.ReadToEnd();
return result;
}
When I rewrite the test to fetch the actual CDN url, it works fine:
[Fact]
public async Task TestWithStream()
{
// Arrange
const string Expected = "/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=";
var httpClient = new HttpClient();
using var stream = await httpClient.GetStreamAsync(new Uri(".7.1.min.js"));
var sha256Hasher = SHA256.Create();
// Act
var byteResult = sha256Hasher.ComputeHash(stream);
// Assert
var result = Convert.ToBase64String(byteResult);
result.Should().Be(Expected); // test passed!
}
This is not the situation I want in a unit test because it now depends on an external resource and internet access. So I think it might has something to do with encoding, how the resource is stored on disk, etc. But everything I try doesn't give the right result. Any ideas?
I have code that calculates the SHA256 integrity hash of a file from the web. For example, the integrity hash of jquery-3.7.1.min.js
is /JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=
(source). I have some units tests to test the code, and that always worked fine. Now, I thinks since .NET 9, the tests fail on my Windows machine. In Github actions (Linux) these test still work fine. This is a simplified version of the code:
[Fact]
public void Test()
{
// Arrange
const string Expected = "/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=";
var fileContents = TestResources.GetFileContents("MyTests.Resources.jquery-3.7.1.min.js"); // read from embedded resource
var sha256Hasher = SHA256.Create();
// Act
var byteResult = sha256Hasher.ComputeHash(Encoding.UTF8.GetBytes(fileContents));
// Assert
var result = Convert.ToBase64String(byteResult);
result.Should().Be(Expected);
/*
Expected result to be the same string, but they differ at index 0:
↓ (actual)
"eqaw4I9IoPldjffqieTL…"
"/JqT3SQfawRcv/BIHPTh…"
↑ (expected).
*/
}
public static string GetFileContents(string filename)
{
var assembly = typeof(TestResources).GetTypeInfo().Assembly;
using var resource = assembly.GetManifestResourceStream(filename);
using var reader = new StreamReader(resource!);
var result = reader.ReadToEnd();
return result;
}
When I rewrite the test to fetch the actual CDN url, it works fine:
[Fact]
public async Task TestWithStream()
{
// Arrange
const string Expected = "/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=";
var httpClient = new HttpClient();
using var stream = await httpClient.GetStreamAsync(new Uri("https://code.jquery/jquery-3.7.1.min.js"));
var sha256Hasher = SHA256.Create();
// Act
var byteResult = sha256Hasher.ComputeHash(stream);
// Assert
var result = Convert.ToBase64String(byteResult);
result.Should().Be(Expected); // test passed!
}
This is not the situation I want in a unit test because it now depends on an external resource and internet access. So I think it might has something to do with encoding, how the resource is stored on disk, etc. But everything I try doesn't give the right result. Any ideas?
Share Improve this question asked Mar 21 at 9:53 MarthijnMarthijn 3,4342 gold badges33 silver badges49 bronze badges 4- 8 Check the line endings of MyTests.Resources.jquery-3.7.1.min.js on your Windows machine. (My guess is that it's got CR-LF line endings, potentially due to autocrlf=true in your git repo, whereas on Linux it'll have LF endings. That's just a guess.) – Jon Skeet Commented Mar 21 at 10:13
- 1 Have you checked the content of the embedded file? – shingo Commented Mar 21 at 10:15
- 4 Very simple first test - print the file length in each case. I suspect you'll see a difference, which would mean that it's got nothing to do with sha256, and everything to do with the actual content being different. – Jon Skeet Commented Mar 21 at 10:15
- Thanks @jon-skeet, it was the line endings indeed. Today I learned about the autocrlf setting :) – Marthijn Commented Mar 22 at 8:52
1 Answer
Reset to default 4The issue here is with the line endings. I ran the same code but when I used CRLF line endings, I got the Hash eqaw4I9IoPldjffqieTL/h7z0ejA9zc/fyXt+05KMl4=
.
As Jon Skeet mentioned, this is likely because you have autocrlf=true on your Git Repo.
You can either disable this (you may need to re-commit a new version of the jQuery.-3.7.1.min.js file, I am not too sure).
An alternate solution is to force fileContents to use LF line endings. The below code will achieve that :
var fileContents = TestResources.GetFileContents("MyTests.Resources.jquery-3.7.1.min.js").Replace("\r\n", "\n").Replace("\r", "\n");
This will ensure that fileContents is normalized to use LF Line endings.
I hope this helps, I am new to posting on StackOverflow so just trying to get the hang of it at the moment!