mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-11-15 17:02:03 +00:00
311 lines
10 KiB
C#
311 lines
10 KiB
C#
|
|
using System.IO;
|
||
|
|
using System.Linq;
|
||
|
|
using SharpCompress.Archives;
|
||
|
|
using SharpCompress.Archives.SevenZip;
|
||
|
|
using SharpCompress.Common;
|
||
|
|
using SharpCompress.Common.SevenZip;
|
||
|
|
using SharpCompress.Factories;
|
||
|
|
using SharpCompress.Readers;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
namespace SharpCompress.Test.SevenZip;
|
||
|
|
|
||
|
|
// Parallel counterpart of SevenZipArchiveTests: every test here opts in via
|
||
|
|
// ReaderOptions.EnableParallelism (default is sequential decode), covering the same archives to
|
||
|
|
// verify decoded content is identical regardless of which decode path 7-Zip's automatic parallel
|
||
|
|
// LZMA2 solid-folder decode takes.
|
||
|
|
public class SevenZipArchiveParallelTests : ArchiveTests
|
||
|
|
{
|
||
|
|
private static ReaderOptions Parallel(ReaderOptions options) =>
|
||
|
|
options.WithEnableParallelism(true);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_Solid_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead("7Zip.solid.7z", Parallel(ReaderOptions.ForExternalStream));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_NonSolid_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead("7Zip.nonsolid.7z", Parallel(ReaderOptions.ForExternalStream));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMA_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead("7Zip.LZMA.7z", Parallel(ReaderOptions.ForExternalStream));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMA_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.LZMA.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMAAES_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead(
|
||
|
|
"7Zip.LZMA.Aes.7z",
|
||
|
|
Parallel(ReaderOptions.ForExternalStream) with
|
||
|
|
{
|
||
|
|
Password = "testpassword",
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMAAES_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead(
|
||
|
|
"7Zip.LZMA.Aes.7z",
|
||
|
|
Parallel(ReaderOptions.ForFilePath) with
|
||
|
|
{
|
||
|
|
Password = "testpassword",
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_PPMd_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead("7Zip.PPMd.7z", Parallel(ReaderOptions.ForExternalStream));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_PPMd_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.PPMd.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMA2_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead("7Zip.LZMA2.7z", Parallel(ReaderOptions.ForExternalStream));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMA2_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.LZMA2.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMA2_EXE_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead(
|
||
|
|
new SevenZipFactory(),
|
||
|
|
"7Zip.LZMA2.exe",
|
||
|
|
Parallel(ReaderOptions.ForExternalStream).WithLookForHeader(true)
|
||
|
|
);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMA2_EXE_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead(
|
||
|
|
"7Zip.LZMA2.exe",
|
||
|
|
Parallel(ReaderOptions.ForFilePath).WithLookForHeader(true),
|
||
|
|
new SevenZipFactory()
|
||
|
|
);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMA2AES_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead(
|
||
|
|
"7Zip.LZMA2.Aes.7z",
|
||
|
|
Parallel(ReaderOptions.ForExternalStream) with
|
||
|
|
{
|
||
|
|
Password = "testpassword",
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_LZMA2AES_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead(
|
||
|
|
"7Zip.LZMA2.Aes.7z",
|
||
|
|
Parallel(ReaderOptions.ForFilePath) with
|
||
|
|
{
|
||
|
|
Password = "testpassword",
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_BZip2_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead("7Zip.BZip2.7z", Parallel(ReaderOptions.ForExternalStream));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_BZip2_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.BZip2.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_Copy_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead("7Zip.Copy.7z", Parallel(ReaderOptions.ForExternalStream));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_Copy_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.Copy.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_Copy_CompressionType_Parallel()
|
||
|
|
{
|
||
|
|
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "7Zip.Copy.7z")))
|
||
|
|
using (
|
||
|
|
var archive = SevenZipArchive.OpenArchive(
|
||
|
|
stream,
|
||
|
|
Parallel(ReaderOptions.ForExternalStream)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
{
|
||
|
|
foreach (var entry in archive.Entries.Where(e => !e.IsDirectory))
|
||
|
|
{
|
||
|
|
Assert.Equal(CompressionType.None, entry.CompressionType);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_ZSTD_StreamRead_Parallel() =>
|
||
|
|
ArchiveStreamRead("7Zip.ZSTD.7z", Parallel(ReaderOptions.ForExternalStream));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_ZSTD_PathRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.ZSTD.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_ZSTD_Split_Parallel() =>
|
||
|
|
ArchiveStreamMultiRead(
|
||
|
|
Parallel(ReaderOptions.ForFilePath),
|
||
|
|
"7Zip.ZSTD.Split.7z.001",
|
||
|
|
"7Zip.ZSTD.Split.7z.002",
|
||
|
|
"7Zip.ZSTD.Split.7z.003",
|
||
|
|
"7Zip.ZSTD.Split.7z.004",
|
||
|
|
"7Zip.ZSTD.Split.7z.005",
|
||
|
|
"7Zip.ZSTD.Split.7z.006"
|
||
|
|
);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_EOS_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.eos.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_Delta_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.delta.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_ARM_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.ARM.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_ARMT_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.ARMT.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_BCJ_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.BCJ.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_BCJ2_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.BCJ2.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_IA64_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.IA64.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_PPC_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.PPC.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_SPARC_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.SPARC.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_ARM64_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.ARM64.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_RISCV_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.RISCV.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_Filters_FileRead_Parallel() =>
|
||
|
|
ArchiveFileRead("7Zip.Filters.7z", Parallel(ReaderOptions.ForFilePath));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_Tar_PathRead_Parallel()
|
||
|
|
{
|
||
|
|
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "7Zip.Tar.tar.7z")))
|
||
|
|
using (
|
||
|
|
var archive = SevenZipArchive.OpenArchive(
|
||
|
|
stream,
|
||
|
|
Parallel(ReaderOptions.ForExternalStream)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
{
|
||
|
|
var entry = archive.Entries.First();
|
||
|
|
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key.NotNull()));
|
||
|
|
|
||
|
|
var size = entry.Size;
|
||
|
|
var scratch = new FileInfo(Path.Combine(SCRATCH_FILES_PATH, "7Zip.Tar.tar"));
|
||
|
|
var test = new FileInfo(Path.Combine(TEST_ARCHIVES_PATH, "7Zip.Tar.tar"));
|
||
|
|
|
||
|
|
Assert.Equal(size, scratch.Length);
|
||
|
|
Assert.Equal(size, test.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
CompareArchivesByPath(
|
||
|
|
Path.Combine(SCRATCH_FILES_PATH, "7Zip.Tar.tar"),
|
||
|
|
Path.Combine(TEST_ARCHIVES_PATH, "7Zip.Tar.tar")
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_Solid_ExtractAllEntries_Contiguous_Parallel()
|
||
|
|
{
|
||
|
|
// This test verifies that solid archives iterate entries as contiguous streams
|
||
|
|
// rather than recreating the decompression stream for each entry, with the parallel
|
||
|
|
// decode path opted in.
|
||
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.solid.7z");
|
||
|
|
using var archive = SevenZipArchive.OpenArchive(
|
||
|
|
testArchive,
|
||
|
|
Parallel(ReaderOptions.ForFilePath)
|
||
|
|
);
|
||
|
|
Assert.True(archive.IsSolid);
|
||
|
|
|
||
|
|
using var reader = archive.ExtractAllEntries();
|
||
|
|
while (reader.MoveToNextEntry())
|
||
|
|
{
|
||
|
|
if (!reader.Entry.IsDirectory)
|
||
|
|
{
|
||
|
|
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
VerifyFiles();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void SevenZipArchive_EmptyStream_WriteToDirectory_Parallel()
|
||
|
|
{
|
||
|
|
// This test specifically verifies that archives with empty-stream entries
|
||
|
|
// (files with size 0 and no compressed data) can be extracted without throwing
|
||
|
|
// NullReferenceException, with the parallel decode path opted in.
|
||
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.EmptyStream.7z");
|
||
|
|
using var archive = SevenZipArchive.OpenArchive(
|
||
|
|
testArchive,
|
||
|
|
Parallel(ReaderOptions.ForFilePath)
|
||
|
|
);
|
||
|
|
|
||
|
|
var emptyStreamFileCount = 0;
|
||
|
|
foreach (var entry in archive.Entries)
|
||
|
|
{
|
||
|
|
if (!entry.IsDirectory)
|
||
|
|
{
|
||
|
|
var sevenZipEntry = entry as SevenZipEntry;
|
||
|
|
if (sevenZipEntry?.FilePart.Header.HasStream == false)
|
||
|
|
{
|
||
|
|
emptyStreamFileCount++;
|
||
|
|
}
|
||
|
|
|
||
|
|
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Assert.True(
|
||
|
|
emptyStreamFileCount > 0,
|
||
|
|
"Test archive should contain at least one empty-stream entry"
|
||
|
|
);
|
||
|
|
|
||
|
|
var extractedFiles = Directory.GetFiles(
|
||
|
|
SCRATCH_FILES_PATH,
|
||
|
|
"*",
|
||
|
|
SearchOption.AllDirectories
|
||
|
|
);
|
||
|
|
Assert.NotEmpty(extractedFiles);
|
||
|
|
|
||
|
|
foreach (var file in extractedFiles)
|
||
|
|
{
|
||
|
|
var fileInfo = new FileInfo(file);
|
||
|
|
Assert.Equal(0, fileInfo.Length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|