-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement stream-based ZipFile ExtractToDirectory and CreateFromDirec…
…tory method overloads (#85491) * ref: Add stream-based ZipFile.CreateFromDirectory and ZipFile.ExtractToDirectory methods. * src: Add stream-based ZipFile.CreateFromDirectory ZipFile.ExtractToDirectory methods. * tests: Move wrongly placed tests to the correct class. * tests: Add stream-based tests for ZipFile.CreateFromDirectory and ZipFile.ExtractToDirectory. * src: Documentation and resource strings. * tests: More tests for unseekable/unreadable/unwritable streams. * Address suggestions and include more exception validation tests. * Fix braces after resolving conflict. * Use AssertExtensions.SequenceEqual for clearer error message. * Reset the resx file again. * Order results of dir enumeration tests
- Loading branch information
1 parent
7d50edd
commit cfa28e3
Showing
12 changed files
with
1,051 additions
and
361 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
188 changes: 147 additions & 41 deletions
188
src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Create.cs
Large diffs are not rendered by default.
Oops, something went wrong.
144 changes: 141 additions & 3 deletions
144
src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
172 changes: 172 additions & 0 deletions
172
src/libraries/System.IO.Compression.ZipFile/tests/ZipFile.Create.Stream.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Xunit; | ||
|
||
namespace System.IO.Compression.Tests; | ||
|
||
public class ZipFile_Create_Stream : ZipFileTestBase | ||
{ | ||
[Fact] | ||
public void CreateFromDirectory_NullSourceDirectory_Throws() | ||
{ | ||
using MemoryStream ms = new MemoryStream(); | ||
Assert.Throws<ArgumentNullException>(() => ZipFile.CreateFromDirectory(sourceDirectoryName: null, ms)); | ||
Assert.Throws<ArgumentNullException>(() => ZipFile.CreateFromDirectory(sourceDirectoryName: null, ms, CompressionLevel.NoCompression, includeBaseDirectory: false)); | ||
Assert.Throws<ArgumentNullException>(() => ZipFile.CreateFromDirectory(sourceDirectoryName: null, ms, CompressionLevel.NoCompression, includeBaseDirectory: false, Encoding.UTF8)); | ||
} | ||
|
||
[Theory] | ||
[InlineData((CompressionLevel)int.MinValue)] | ||
[InlineData((CompressionLevel)(-1))] | ||
[InlineData((CompressionLevel)4)] | ||
[InlineData((CompressionLevel)int.MaxValue)] | ||
public void CreateFromDirectory_CompressionLevel_OutOfRange_Throws(CompressionLevel invalidCompressionLevel) | ||
{ | ||
using MemoryStream ms = new MemoryStream(); | ||
Assert.Throws<ArgumentOutOfRangeException>(() => ZipFile.CreateFromDirectory("sourceDirectory", ms, invalidCompressionLevel, includeBaseDirectory: false)); | ||
Assert.Throws<ArgumentOutOfRangeException>(() => ZipFile.CreateFromDirectory("sourceDirectory", ms, invalidCompressionLevel, includeBaseDirectory: false, Encoding.UTF8)); | ||
} | ||
|
||
[Fact] | ||
public void CreateFromDirectory_UnwritableStream_Throws() | ||
{ | ||
using MemoryStream ms = new(); | ||
using WrappedStream destination = new(ms, canRead: true, canWrite: false, canSeek: true); | ||
Assert.Throws<ArgumentException>("destination", () => ZipFile.CreateFromDirectory(GetTestFilePath(), destination)); | ||
} | ||
|
||
[Fact] | ||
public void CreateFromDirectoryNormal() | ||
{ | ||
string folderName = zfolder("normal"); | ||
using MemoryStream destination = new(); | ||
ZipFile.CreateFromDirectory(folderName, destination); | ||
destination.Position = 0; | ||
IsZipSameAsDir(destination, folderName, ZipArchiveMode.Read, requireExplicit: false, checkTimes: false); | ||
} | ||
|
||
[Fact] | ||
public void CreateFromDirectoryNormal_Unreadable_Unseekable() | ||
{ | ||
string folderName = zfolder("normal"); | ||
using MemoryStream ms = new(); | ||
using WrappedStream destination = new(ms, canRead: false, canWrite: true, canSeek: false); | ||
ZipFile.CreateFromDirectory(folderName, destination); | ||
ms.Position = 0; | ||
IsZipSameAsDir(ms, folderName, ZipArchiveMode.Read, requireExplicit: false, checkTimes: false); | ||
} | ||
|
||
[Fact] | ||
public void CreateFromDirectory_IncludeBaseDirectory() | ||
{ | ||
string folderName = zfolder("normal"); | ||
using MemoryStream destination = new(); | ||
ZipFile.CreateFromDirectory(folderName, destination, CompressionLevel.Optimal, true); | ||
|
||
IEnumerable<string> expected = Directory.EnumerateFiles(zfolder("normal"), "*", SearchOption.AllDirectories); | ||
destination.Position = 0; | ||
using ZipArchive archive = new(destination); | ||
foreach (ZipArchiveEntry actualEntry in archive.Entries) | ||
{ | ||
string expectedFile = expected.Single(i => Path.GetFileName(i).Equals(actualEntry.Name)); | ||
Assert.StartsWith("normal", actualEntry.FullName); | ||
Assert.Equal(new FileInfo(expectedFile).Length, actualEntry.Length); | ||
using Stream expectedStream = File.OpenRead(expectedFile); | ||
using Stream actualStream = actualEntry.Open(); | ||
StreamsEqual(expectedStream, actualStream); | ||
} | ||
} | ||
|
||
[Fact] | ||
public void CreateFromDirectoryUnicode() | ||
{ | ||
string folderName = zfolder("unicode"); | ||
using MemoryStream destination = new(); | ||
ZipFile.CreateFromDirectory(folderName, destination); | ||
|
||
using ZipArchive archive = new(destination); | ||
IEnumerable<string> actual = archive.Entries.Select(entry => entry.Name); | ||
IEnumerable<string> expected = Directory.EnumerateFileSystemEntries(zfolder("unicode"), "*", SearchOption.AllDirectories).ToList(); | ||
Assert.True(Enumerable.SequenceEqual(expected.Select(i => Path.GetFileName(i)), actual.Select(i => i))); | ||
} | ||
|
||
[Fact] | ||
public void CreatedEmptyDirectoriesRoundtrip() | ||
{ | ||
using TempDirectory tempFolder = new(GetTestFilePath()); | ||
|
||
DirectoryInfo rootDir = new(tempFolder.Path); | ||
rootDir.CreateSubdirectory("empty1"); | ||
|
||
using MemoryStream destination = new(); | ||
ZipFile.CreateFromDirectory( | ||
rootDir.FullName, destination, | ||
CompressionLevel.Optimal, false, Encoding.UTF8); | ||
|
||
using ZipArchive archive = new(destination); | ||
|
||
Assert.Equal(1, archive.Entries.Count); | ||
Assert.StartsWith("empty1", archive.Entries[0].FullName); | ||
} | ||
|
||
[Fact] | ||
public void CreatedEmptyUtf32DirectoriesRoundtrip() | ||
{ | ||
using TempDirectory tempFolder = new(GetTestFilePath()); | ||
|
||
Encoding entryEncoding = Encoding.UTF32; | ||
DirectoryInfo rootDir = new(tempFolder.Path); | ||
rootDir.CreateSubdirectory("empty1"); | ||
|
||
using MemoryStream destination = new(); | ||
ZipFile.CreateFromDirectory( | ||
rootDir.FullName, destination, | ||
CompressionLevel.Optimal, false, entryEncoding); | ||
|
||
using ZipArchive archive = new(destination, ZipArchiveMode.Read, leaveOpen: false, entryEncoding); | ||
Assert.Equal(1, archive.Entries.Count); | ||
Assert.StartsWith("empty1", archive.Entries[0].FullName); | ||
} | ||
|
||
[Fact] | ||
public void CreatedEmptyRootDirectoryRoundtrips() | ||
{ | ||
using TempDirectory tempFolder = new(GetTestFilePath()); | ||
|
||
DirectoryInfo emptyRoot = new(tempFolder.Path); | ||
using MemoryStream destination = new(); | ||
ZipFile.CreateFromDirectory( | ||
emptyRoot.FullName, destination, | ||
CompressionLevel.Optimal, true); | ||
|
||
using ZipArchive archive = new(destination); | ||
Assert.Equal(1, archive.Entries.Count); | ||
} | ||
|
||
[Fact] | ||
public void CreateSetsExternalAttributesCorrectly() | ||
{ | ||
string folderName = zfolder("normal"); | ||
using MemoryStream destination = new(); | ||
ZipFile.CreateFromDirectory(folderName, destination); | ||
destination.Position = 0; | ||
using ZipArchive archive = new(destination); | ||
|
||
foreach (ZipArchiveEntry entry in archive.Entries) | ||
{ | ||
if (OperatingSystem.IsWindows()) | ||
{ | ||
Assert.Equal(0, entry.ExternalAttributes); | ||
} | ||
else | ||
{ | ||
Assert.NotEqual(0, entry.ExternalAttributes); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.