mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-04-22 22:19:37 +00:00
207 lines
7.4 KiB
C#
207 lines
7.4 KiB
C#
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using SharpCompress.Archives;
|
|
using SharpCompress.Archives.SevenZip;
|
|
using SharpCompress.Readers;
|
|
using Xunit;
|
|
using PublicISevenZipAsyncReader = SharpCompress.Readers.SevenZip.ISevenZipAsyncReader;
|
|
using PublicSevenZipReader = SharpCompress.Readers.SevenZip.SevenZipReader;
|
|
|
|
namespace SharpCompress.Test.SevenZip;
|
|
|
|
public class SevenZipArchiveAsyncTests : ArchiveTests
|
|
{
|
|
[Fact]
|
|
public async Task SevenZipArchive_LZMA_AsyncStreamExtraction()
|
|
{
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.LZMA.7z");
|
|
await ExtractAllEntriesSequentiallyAsync(testArchive);
|
|
}
|
|
|
|
//[Fact]
|
|
public async Task SevenZipArchive_LZMA2_AsyncStreamExtraction()
|
|
{
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.LZMA2.7z");
|
|
await ExtractAllEntriesSequentiallyAsync(testArchive);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SevenZipArchive_Solid_AsyncStreamExtraction()
|
|
{
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.solid.7z");
|
|
await ExtractAllEntriesSequentiallyAsync(testArchive);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SevenZipArchive_BZip2_AsyncStreamExtraction()
|
|
{
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.BZip2.7z");
|
|
await ExtractAllEntriesSequentiallyAsync(testArchive);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SevenZipReader_OpenAsyncReader_ReturnsSevenZipReader()
|
|
{
|
|
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "7Zip.LZMA.7z"));
|
|
await using var reader = await PublicSevenZipReader.OpenAsyncReader(stream);
|
|
|
|
Assert.IsAssignableFrom<PublicISevenZipAsyncReader>(reader);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReaderFactory_OpenAsyncReader_SevenZip_ReturnsSevenZipReader()
|
|
{
|
|
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "7Zip.LZMA.7z"));
|
|
await using var reader = await ReaderFactory.OpenAsyncReader(stream);
|
|
|
|
Assert.IsAssignableFrom<PublicISevenZipAsyncReader>(reader);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SevenZipArchive_PPMd_AsyncStreamExtraction()
|
|
{
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.PPMd.7z");
|
|
await ExtractAllEntriesSequentiallyAsync(testArchive);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SevenZipArchive_Solid_ExtractAllEntries_Contiguous_Async()
|
|
{
|
|
// This test verifies that solid archives iterate entries as contiguous streams
|
|
// rather than recreating the decompression stream for each entry
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.solid.7z");
|
|
await using var archive = await SevenZipArchive.OpenAsyncArchive(testArchive);
|
|
Assert.True(((SevenZipArchive)archive).IsSolid);
|
|
|
|
await using var reader = await archive.ExtractAllEntriesAsync();
|
|
while (await reader.MoveToNextEntryAsync())
|
|
{
|
|
if (!reader.Entry.IsDirectory)
|
|
{
|
|
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
|
}
|
|
}
|
|
|
|
VerifyFiles();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SevenZipArchive_Solid_VerifyStreamReuse()
|
|
{
|
|
// This test verifies that the folder stream is reused within each folder
|
|
// and not recreated for each entry in solid archives
|
|
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.solid.7z");
|
|
await using var archive = await SevenZipArchive.OpenAsyncArchive(testArchive);
|
|
Assert.True(((SevenZipArchive)archive).IsSolid);
|
|
|
|
await using var reader = await archive.ExtractAllEntriesAsync();
|
|
|
|
var sevenZipReader = Assert.IsType<PublicSevenZipReader>(reader);
|
|
sevenZipReader.DiagnosticsEnabled = true;
|
|
|
|
Stream? currentFolderStreamInstance = null;
|
|
object? currentFolder = null;
|
|
var entryCount = 0;
|
|
var entriesInCurrentFolder = 0;
|
|
var streamRecreationsWithinFolder = 0;
|
|
|
|
while (await reader.MoveToNextEntryAsync())
|
|
{
|
|
if (!reader.Entry.IsDirectory)
|
|
{
|
|
// Extract the entry to trigger GetEntryStream
|
|
using var entryStream = await reader.OpenEntryStreamAsync();
|
|
var buffer = new byte[4096];
|
|
while (entryStream.Read(buffer, 0, buffer.Length) > 0)
|
|
{
|
|
// Read the stream to completion
|
|
}
|
|
|
|
entryCount++;
|
|
|
|
var folderStream = sevenZipReader.DiagnosticsCurrentFolderStream;
|
|
var folder = sevenZipReader.DiagnosticsCurrentFolder;
|
|
|
|
Assert.NotNull(folderStream); // Folder stream should exist
|
|
|
|
// Check if we're in a new folder
|
|
if (currentFolder == null || !ReferenceEquals(currentFolder, folder))
|
|
{
|
|
// Starting a new folder
|
|
currentFolder = folder;
|
|
currentFolderStreamInstance = folderStream;
|
|
entriesInCurrentFolder = 1;
|
|
}
|
|
else
|
|
{
|
|
// Same folder - verify stream wasn't recreated
|
|
entriesInCurrentFolder++;
|
|
|
|
if (!ReferenceEquals(currentFolderStreamInstance, folderStream))
|
|
{
|
|
// Stream was recreated within the same folder - this is the bug we're testing for!
|
|
streamRecreationsWithinFolder++;
|
|
}
|
|
|
|
currentFolderStreamInstance = folderStream;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Verify we actually tested multiple entries
|
|
Assert.True(entryCount > 1, "Test should have multiple entries to verify stream reuse");
|
|
|
|
// The critical check: within a single folder, the stream should NEVER be recreated
|
|
Assert.Equal(0, streamRecreationsWithinFolder); // Folder stream should remain the same for all entries in the same folder
|
|
}
|
|
|
|
private async Task ExtractAllEntriesSequentiallyAsync(string testArchive)
|
|
{
|
|
#if NETFRAMEWORK
|
|
using var stream = File.OpenRead(testArchive);
|
|
#else
|
|
await using var stream = File.OpenRead(testArchive);
|
|
#endif
|
|
await using var archive = await ArchiveFactory.OpenAsyncArchive(stream);
|
|
|
|
await using var reader = await archive.ExtractAllEntriesAsync();
|
|
while (await reader.MoveToNextEntryAsync())
|
|
{
|
|
if (reader.Entry.IsDirectory)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var targetPath = Path.Combine(SCRATCH_FILES_PATH, reader.Entry.Key!);
|
|
var targetDir = Path.GetDirectoryName(targetPath);
|
|
|
|
if (!string.IsNullOrEmpty(targetDir) && !Directory.Exists(targetDir))
|
|
{
|
|
Directory.CreateDirectory(targetDir);
|
|
}
|
|
|
|
#if NETFRAMEWORK
|
|
using var sourceStream = await reader.OpenEntryStreamAsync(CancellationToken.None);
|
|
#else
|
|
await using var sourceStream = await reader.OpenEntryStreamAsync(
|
|
CancellationToken.None
|
|
);
|
|
#endif
|
|
#if NETFRAMEWORK
|
|
using var targetStream = File.Create(targetPath);
|
|
#else
|
|
await using var targetStream = File.Create(targetPath);
|
|
#endif
|
|
#if NETFRAMEWORK
|
|
await sourceStream.CopyToAsync(targetStream, 81920, CancellationToken.None);
|
|
#else
|
|
await sourceStream.CopyToAsync(targetStream, CancellationToken.None);
|
|
#endif
|
|
}
|
|
|
|
VerifyFiles();
|
|
}
|
|
}
|