-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose Comment in ZipArchive and ZipArchiveEntry #59442
Conversation
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Tagging subscribers to this area: @dotnet/area-system-io-compression Issue DetailsFixes #1547
|
src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
Show resolved
Hide resolved
218c347
to
be8acc7
Compare
8a36a78
to
eff8e13
Compare
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@carlossanlop thank you for your contribution! PTAL at my comments
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/tests/ZipArchive/zip_CreateTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/tests/ZipArchive/zip_CreateTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.cs
Outdated
Show resolved
Hide resolved
57cfa5a
to
cdb57d5
Compare
@adamsitnik I addressed your last comments. |
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
Outdated
Show resolved
Hide resolved
cdb57d5
to
d429b27
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you @carlossanlop !
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
Outdated
Show resolved
Hide resolved
…ing action when disposing.
Co-authored-by: Adam Sitnik <[email protected]>
3b0f43c
to
1596bb3
Compare
…long characters like emojis. Simplify tests.
Is this one ready to merge? |
I'd like @jozkee to take a last look, since it was his comments which I addressed in my last commit. |
protected const string LowerCaseOUmlautChar = "\u00F6"; | ||
protected const string CopyrightChar = "\u00A9"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's special about these versus '1' or 'a'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed chars that cannot be represented in ASCII.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you express that in the name of the const or in a comment?
foreach (object[] e in SharedComment_Data()) | ||
{ | ||
yield return e; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this to the end of the method to avoid mixing what is being reused from what is unique to this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to yield the shared cases first.
string asciiExpectedExactMaxLength = new('a', ushort.MaxValue); | ||
string asciiOriginalOverMaxLength = asciiExpectedExactMaxLength + "aaa"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these prefixed as Ascii considering that the method name is Utf8Comment_Data?
string asciiExpectedExactMaxLength = new('a', ushort.MaxValue); | |
string asciiOriginalOverMaxLength = asciiExpectedExactMaxLength + "aaa"; | |
string utf8ExpectedExactMaxLength = new('a', ushort.MaxValue); | |
string utf8OriginalOverMaxLength = asciiExpectedExactMaxLength + "aaa"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's test data. This method return test cases for both ASCII and UTF8. Renaming these variables would be incorrect.
string asciiOriginalOverMaxLength = asciiExpectedExactMaxLength + "aaa"; | ||
|
||
// A smiley emoji code point consists of two characters, | ||
// meaning the whole emoji should be fully truncated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add a case where the emoji does not get truncated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only case where the string is truncated is when it's length is greater than expected. The contents don't matter. So if a string is smaller than the max length, it should remain untouched, regardless of its contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
bytes = encoding.GetBytes(text); | ||
return maxBytes < bytes.Length ? bytes[0..maxBytes] : bytes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bytes[0..maxBytes]
is an allocation of it's own, isn't it? If so, consider implementing ArrayPool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was discussed before. We don't expect either the Comment
setter or the EntryName
setter to be called in a loop. That would be weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is being called in a foreach loop in your own tests.
runtime/src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.Comments.cs
Line 67 in 3444631
Assert.Equal(expectedCreateComment, entry.Comment); |
I don't know if enumeration of entries should care or not about one allocation, but it can definitely be improved to my suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened issue #64767 to follow up on this.
src/libraries/System.IO.Compression/tests/ZipArchive/zip_CreateTests.Comments.cs
Outdated
Show resolved
Hide resolved
[Theory] | ||
[MemberData(nameof(Utf8Comment_Data))] | ||
public static void Create_Comment_Utf8EntryName_NullEncoding(string originalComment, string expectedComment) => | ||
Create_Comment_EntryName_Encoding_Internal($"{SmileyEmoji}.txt", originalComment, expectedComment, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the entry name really need to be tested? It is not something that is being added in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The entry name is specifically being affected by this PR, because both the comment and the entry name share the same encoding the user specifies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was expecting that there were already tests that covered EntryName
with multiple encodings, if that's not the case then it is fine.
[Theory] | ||
[MemberData(nameof(Latin1Comment_Data))] | ||
public static void Create_Comment_Utf8EntryName_Latin1Encoding(string originalComment, string expectedComment) => | ||
// Emoji not supported by latin1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if you pass an emoji with latin1 encoding? I assume it just encodes it as something meaningless. We should assert that the latin1-encoded-emoji still gets truncated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how I would assert that in the tests. I just wanted to make sure the string got truncated, even if the final outputted string, when viewed by the user, will be garbage where the emoji was saved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how I would assert that in the tests.
On Latin1Comment_Data
add something like this:
string latin1ExpectedALettersAndTruncatedEmoji = new string('a', ushort.MaxValue - 1) + SmileyEmoji[0];
string latin1OriginalALettersAndEmoji = new string('a', ushort.MaxValue - 1) + SmileyEmoji;
My point being that the truncation logic only runs when it makes sense (UTF8).
public static void Update_Comment_AsciiEntryName_NullEncoding(string originalComment, string expectedComment) => | ||
Update_Comment_EntryName_Encoding_Internal("file.txt", | ||
originalComment, expectedComment, null, | ||
new string('a', ushort.MaxValue - 1) + $"{CopyrightChar}", new string('a', ushort.MaxValue - 1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is testing Utf8Comment_Data.Count()
times the string new string('a', ushort.MaxValue - 1) + $"{CopyrightChar}"
, you should create another Utf8Comment_Data that includes this as a parameter and remove the redundancy.
using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true, encoding)) | ||
{ | ||
ZipArchiveEntry entry = zip.CreateEntry(entryName, CompressionLevel.NoCompression); | ||
entry.Comment = comment; | ||
|
||
Assert.Equal(entryName, entry.FullName); | ||
Assert.Equal(comment, entry.Comment); | ||
entry.Comment = originalCreateComment; | ||
Assert.Equal(expectedCreateComment, entry.Comment); | ||
} | ||
|
||
// Open with no encoding to verify | ||
using (var zip = new ZipArchive(testStream, ZipArchiveMode.Read, leaveOpen: true)) | ||
using (var zip = new ZipArchive(ms, ZipArchiveMode.Read, leaveOpen: true, encoding)) | ||
{ | ||
ZipArchiveEntry entry = zip.Entries.FirstOrDefault(); | ||
|
||
Assert.Equal(entryName, entry.FullName); | ||
Assert.Equal(comment, entry.Comment); | ||
foreach (ZipArchiveEntry entry in zip.Entries) | ||
{ | ||
Assert.Equal(expectedCreateComment, entry.Comment); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call Create_Comment_EntryName_Encoding_Internal
instead to avoid code duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or even better, you could test ZipArchiveMode.Update inside Create_Comment_EntryName_Encoding_Internal
and remove zip_UpdateTests.Comments.cs entirely.
@@ -383,5 +383,57 @@ internal static void AddEntry(ZipArchive archive, string name, string contents, | |||
w.WriteLine(contents); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file should be in tests
folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I don't know why it was created there. Maybe we used to share something with another assembly, but it got removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah search didn't return the other file that consumes ZipTestHelper. It's the ZipFile.csproj. I'll revert the move of this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than the test nits; LGTM.
…sion.ZipFile depends on it too.
FYI I ran the MacOS CI leg twice but it failed with errors unrelated to this change: runtime 20220203.90 / Libraries Test Run release coreclr OSX x64 Debug |
Fixes #1547
Spec: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT