diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index 35a2535f..9ebb1677 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -335,9 +335,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.18, )", - "resolved": "8.0.18", - "contentHash": "OiXqr2YIBEV9dsAWEtasK470ALyJ0VxJ9k4MotOxlWV6HeEgrJKYMW4HHj1OCCXvqE0/A25wEKPkpfiBARgDZA==" + "requested": "[8.0.17, )", + "resolved": "8.0.17", + "contentHash": "x5/y4l8AtshpBOrCZdlE4txw8K3e3s9meBFeZeR3l8hbbku2V7kK6ojhXvrbjg1rk3G+JqL1BI26gtgc1ZrdUw==" }, "Microsoft.SourceLink.GitHub": { "type": "Direct", diff --git a/tests/SharpCompress.Test/ReaderTests.cs b/tests/SharpCompress.Test/ReaderTests.cs index b51fd804..b919331d 100644 --- a/tests/SharpCompress.Test/ReaderTests.cs +++ b/tests/SharpCompress.Test/ReaderTests.cs @@ -126,7 +126,7 @@ public abstract class ReaderTests : TestBase CancellationToken cancellationToken = default ) { - while (reader.MoveToNextEntry()) + while (await reader.MoveToNextEntryAsync(cancellationToken)) { if (!reader.Entry.IsDirectory) { diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs new file mode 100644 index 00000000..798c15b1 --- /dev/null +++ b/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs @@ -0,0 +1,196 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Archives; +using SharpCompress.Archives.Zip; +using SharpCompress.Common; +using SharpCompress.Writers; +using SharpCompress.Writers.Zip; +using Xunit; + +namespace SharpCompress.Test.Zip; + +public class ZipArchiveAsyncTests : ArchiveTests +{ + public ZipArchiveAsyncTests() => UseExtensionInsteadOfNameToVerify = true; + + [Fact] + public async Task Zip_ZipX_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.zipx"); + + [Fact] + public async Task Zip_BZip2_Streamed_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.bzip2.dd.zip"); + + [Fact] + public async Task Zip_BZip2_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.bzip2.zip"); + + [Fact] + public async Task Zip_Deflate_Streamed2_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.deflate.dd-.zip"); + + [Fact] + public async Task Zip_Deflate_Streamed_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.deflate.dd.zip"); + + [Fact] + public async Task Zip_Deflate_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.deflate.zip"); + + [Fact] + public async Task Zip_Deflate64_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.deflate64.zip"); + + [Fact] + public async Task Zip_LZMA_Streamed_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.lzma.dd.zip"); + + [Fact] + public async Task Zip_LZMA_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.lzma.zip"); + + [Fact] + public async Task Zip_PPMd_Streamed_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.ppmd.dd.zip"); + + [Fact] + public async Task Zip_PPMd_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.ppmd.zip"); + + [Fact] + public async Task Zip_None_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.none.zip"); + + [Fact] + public async Task Zip_Zip64_ArchiveStreamRead_Async() => + await ArchiveStreamReadAsync("Zip.zip64.zip"); + + [Fact] + public async Task Zip_Shrink_ArchiveStreamRead_Async() + { + UseExtensionInsteadOfNameToVerify = true; + UseCaseInsensitiveToVerify = true; + await ArchiveStreamReadAsync("Zip.shrink.zip"); + } + + [Fact] + public async Task Zip_Implode_ArchiveStreamRead_Async() + { + UseExtensionInsteadOfNameToVerify = true; + UseCaseInsensitiveToVerify = true; + await ArchiveStreamReadAsync("Zip.implode.zip"); + } + + [Fact] + public async Task Zip_Reduce1_ArchiveStreamRead_Async() + { + UseExtensionInsteadOfNameToVerify = true; + UseCaseInsensitiveToVerify = true; + await ArchiveStreamReadAsync("Zip.reduce1.zip"); + } + + [Fact] + public async Task Zip_Reduce2_ArchiveStreamRead_Async() + { + UseExtensionInsteadOfNameToVerify = true; + UseCaseInsensitiveToVerify = true; + await ArchiveStreamReadAsync("Zip.reduce2.zip"); + } + + [Fact] + public async Task Zip_Reduce3_ArchiveStreamRead_Async() + { + UseExtensionInsteadOfNameToVerify = true; + UseCaseInsensitiveToVerify = true; + await ArchiveStreamReadAsync("Zip.reduce3.zip"); + } + + [Fact] + public async Task Zip_Reduce4_ArchiveStreamRead_Async() + { + UseExtensionInsteadOfNameToVerify = true; + UseCaseInsensitiveToVerify = true; + await ArchiveStreamReadAsync("Zip.reduce4.zip"); + } + + [Fact] + public async Task Zip_Random_Write_Remove_Async() + { + var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); + var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + var modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); + + using (var archive = ZipArchive.Open(unmodified)) + { + var entry = archive.Entries.Single(x => + x.Key.NotNull().EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ); + archive.RemoveEntry(entry); + + WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); + writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866); + + await archive.SaveToAsync(scratchPath, writerOptions); + } + CompareArchivesByPath(modified, scratchPath, Encoding.GetEncoding(866)); + } + + [Fact] + public async Task Zip_Random_Write_Add_Async() + { + var jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"); + var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); + var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); + var modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + using (var archive = ZipArchive.Open(unmodified)) + { + archive.AddEntry("jpg\\test.jpg", jpg); + + WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); + writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866); + + await archive.SaveToAsync(scratchPath, writerOptions); + } + CompareArchivesByPath(modified, scratchPath, Encoding.GetEncoding(866)); + } + + [Fact] + public async Task Zip_Create_New_Async() + { + var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); + var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + using (var archive = ZipArchive.Create()) + { + archive.DeflateCompressionLevel = Compressors.Deflate.CompressionLevel.BestSpeed; + archive.AddAllFromDirectory(ORIGINAL_FILES_PATH); + + WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); + writerOptions.ArchiveEncoding.Default = Encoding.UTF8; + + await archive.SaveToAsync(scratchPath, writerOptions); + } + CompareArchivesByPath(unmodified, scratchPath); + } + + [Fact] + public async Task Zip_Deflate_Entry_Stream_Async() + { + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip"))) + using (var archive = ZipArchive.Open(stream)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + await entry.WriteToDirectoryAsync( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + } + } + VerifyFiles(); + } +} diff --git a/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs new file mode 100644 index 00000000..2892be57 --- /dev/null +++ b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs @@ -0,0 +1,254 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using SharpCompress.Common; +using SharpCompress.Readers; +using SharpCompress.Readers.Zip; +using SharpCompress.Test.Mocks; +using Xunit; + +namespace SharpCompress.Test.Zip; + +public class ZipReaderAsyncTests : ReaderTests +{ + public ZipReaderAsyncTests() => UseExtensionInsteadOfNameToVerify = true; + + [Fact] + public async Task Issue_269_Double_Skip_Async() + { + var path = Path.Combine(TEST_ARCHIVES_PATH, "PrePostHeaders.zip"); + using Stream stream = new ForwardOnlyStream(File.OpenRead(path)); + using var reader = ReaderFactory.Open(stream); + var count = 0; + while (await reader.MoveToNextEntryAsync()) + { + count++; + if (!reader.Entry.IsDirectory) + { + if (count % 2 != 0) + { + await reader.WriteEntryToAsync(Stream.Null); + } + } + } + } + + [Fact] + public async Task Zip_Zip64_Streamed_Read_Async() => + await ReadAsync("Zip.zip64.zip", CompressionType.Deflate); + + [Fact] + public async Task Zip_ZipX_Streamed_Read_Async() => + await ReadAsync("Zip.zipx", CompressionType.LZMA); + + [Fact] + public async Task Zip_BZip2_Streamed_Read_Async() => + await ReadAsync("Zip.bzip2.dd.zip", CompressionType.BZip2); + + [Fact] + public async Task Zip_BZip2_Read_Async() => + await ReadAsync("Zip.bzip2.zip", CompressionType.BZip2); + + [Fact] + public async Task Zip_Deflate_Streamed2_Read_Async() => + await ReadAsync("Zip.deflate.dd-.zip", CompressionType.Deflate); + + [Fact] + public async Task Zip_Deflate_Streamed_Read_Async() => + await ReadAsync("Zip.deflate.dd.zip", CompressionType.Deflate); + + [Fact] + public async Task Zip_Deflate_Streamed_Skip_Async() + { + using Stream stream = new ForwardOnlyStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); + using var reader = ReaderFactory.Open(stream); + var x = 0; + while (await reader.MoveToNextEntryAsync()) + { + if (!reader.Entry.IsDirectory) + { + x++; + if (x % 2 == 0) + { + await reader.WriteEntryToDirectoryAsync( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + } + } + } + } + + [Fact] + public async Task Zip_Deflate_Read_Async() => + await ReadAsync("Zip.deflate.zip", CompressionType.Deflate); + + [Fact] + public async Task Zip_Deflate64_Read_Async() => + await ReadAsync("Zip.deflate64.zip", CompressionType.Deflate64); + + [Fact] + public async Task Zip_LZMA_Streamed_Read_Async() => + await ReadAsync("Zip.lzma.dd.zip", CompressionType.LZMA); + + [Fact] + public async Task Zip_LZMA_Read_Async() => + await ReadAsync("Zip.lzma.zip", CompressionType.LZMA); + + [Fact] + public async Task Zip_PPMd_Streamed_Read_Async() => + await ReadAsync("Zip.ppmd.dd.zip", CompressionType.PPMd); + + [Fact] + public async Task Zip_PPMd_Read_Async() => + await ReadAsync("Zip.ppmd.zip", CompressionType.PPMd); + + [Fact] + public async Task Zip_None_Read_Async() => + await ReadAsync("Zip.none.zip", CompressionType.None); + + [Fact] + public async Task Zip_Deflate_NoEmptyDirs_Read_Async() => + await ReadAsync("Zip.deflate.noEmptyDirs.zip", CompressionType.Deflate); + + [Fact] + public async Task Zip_BZip2_PkwareEncryption_Read_Async() + { + using ( + Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip")) + ) + using (var reader = ZipReader.Open(stream, new ReaderOptions { Password = "test" })) + { + while (await reader.MoveToNextEntryAsync()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); + await reader.WriteEntryToDirectoryAsync( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + } + } + } + VerifyFiles(); + } + + [Fact] + public async Task Zip_Reader_Disposal_Test_Async() + { + using var stream = new TestStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); + using (var reader = ReaderFactory.Open(stream)) + { + while (await reader.MoveToNextEntryAsync()) + { + if (!reader.Entry.IsDirectory) + { + await reader.WriteEntryToDirectoryAsync( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + } + } + } + Assert.True(stream.IsDisposed); + } + + [Fact] + public async Task Zip_Reader_Disposal_Test2_Async() + { + using var stream = new TestStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); + var reader = ReaderFactory.Open(stream); + while (await reader.MoveToNextEntryAsync()) + { + if (!reader.Entry.IsDirectory) + { + await reader.WriteEntryToDirectoryAsync( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + } + } + Assert.False(stream.IsDisposed); + } + + [Fact] + public async Task Zip_LZMA_WinzipAES_Read_Async() => + await Assert.ThrowsAsync(async () => + { + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.WinzipAES.zip") + ) + ) + using (var reader = ZipReader.Open(stream, new ReaderOptions { Password = "test" })) + { + while (await reader.MoveToNextEntryAsync()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(CompressionType.Unknown, reader.Entry.CompressionType); + await reader.WriteEntryToDirectoryAsync( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + } + } + } + VerifyFiles(); + }); + + [Fact] + public async Task Zip_Deflate_WinzipAES_Read_Async() + { + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip") + ) + ) + using (var reader = ZipReader.Open(stream, new ReaderOptions { Password = "test" })) + { + while (await reader.MoveToNextEntryAsync()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(CompressionType.Unknown, reader.Entry.CompressionType); + await reader.WriteEntryToDirectoryAsync( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + } + } + } + VerifyFiles(); + } + + [Fact] + public async Task Zip_Deflate_ZipCrypto_Read_Async() + { + var count = 0; + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "zipcrypto.zip"))) + using (var reader = ZipReader.Open(stream, new ReaderOptions { Password = "test" })) + { + while (await reader.MoveToNextEntryAsync()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(CompressionType.None, reader.Entry.CompressionType); + await reader.WriteEntryToDirectoryAsync( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + count++; + } + } + } + Assert.Equal(8, count); + } +} diff --git a/tests/SharpCompress.Test/Zip/ZipWriterAsyncTests.cs b/tests/SharpCompress.Test/Zip/ZipWriterAsyncTests.cs new file mode 100644 index 00000000..bd37e914 --- /dev/null +++ b/tests/SharpCompress.Test/Zip/ZipWriterAsyncTests.cs @@ -0,0 +1,67 @@ +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Common; +using Xunit; + +namespace SharpCompress.Test.Zip; + +public class ZipWriterAsyncTests : WriterTests +{ + public ZipWriterAsyncTests() + : base(ArchiveType.Zip) { } + + [Fact] + public async Task Zip_Deflate_Write_Async() => + await WriteAsync( + CompressionType.Deflate, + "Zip.deflate.noEmptyDirs.zip", + "Zip.deflate.noEmptyDirs.zip", + Encoding.UTF8 + ); + + [Fact] + public async Task Zip_BZip2_Write_Async() => + await WriteAsync( + CompressionType.BZip2, + "Zip.bzip2.noEmptyDirs.zip", + "Zip.bzip2.noEmptyDirs.zip", + Encoding.UTF8 + ); + + [Fact] + public async Task Zip_None_Write_Async() => + await WriteAsync( + CompressionType.None, + "Zip.none.noEmptyDirs.zip", + "Zip.none.noEmptyDirs.zip", + Encoding.UTF8 + ); + + [Fact] + public async Task Zip_LZMA_Write_Async() => + await WriteAsync( + CompressionType.LZMA, + "Zip.lzma.noEmptyDirs.zip", + "Zip.lzma.noEmptyDirs.zip", + Encoding.UTF8 + ); + + [Fact] + public async Task Zip_PPMd_Write_Async() => + await WriteAsync( + CompressionType.PPMd, + "Zip.ppmd.noEmptyDirs.zip", + "Zip.ppmd.noEmptyDirs.zip", + Encoding.UTF8 + ); + + [Fact] + public async Task Zip_Rar_Write_Async() => + await Assert.ThrowsAsync(async () => + await WriteAsync( + CompressionType.Rar, + "Zip.ppmd.noEmptyDirs.zip", + "Zip.ppmd.noEmptyDirs.zip" + ) + ); +}