Files
sharpcompress/tests/SharpCompress.Test/LargeArchiveTests.cs

209 lines
7.2 KiB
C#
Raw Permalink Normal View History

using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using SharpCompress.Archives;
using SharpCompress.Crypto;
using SharpCompress.Readers;
using SharpCompress.Test.Mocks;
using Xunit;
namespace SharpCompress.Test;
[Collection(LargeArchiveCollection.Name)]
public class LargeArchiveTests : TestBase
{
private const long LargeFileSize = 64L * 1024 * 1024;
private const uint LargeFileCrc = 0xF9081EB0;
private const int BufferSize = 64 * 1024;
[Theory]
[InlineData("Large/Large.zip")]
[InlineData("Large/Large.tar")]
[InlineData("Large/Large.gz")]
[InlineData("Large/Large.rar")]
[InlineData("Large/Large.7z")]
public void OpenArchive_ShouldStreamLargeEntry(string fixtureName)
{
2026-08-01 13:26:48 +01:00
using var stream = File.OpenRead(GetMaterializedFixturePath(fixtureName));
using var archive = ArchiveFactory.OpenArchive(stream);
VerifyArchive(archive);
}
[Theory]
[InlineData("Large/Large.zip")]
[InlineData("Large/Large.tar")]
[InlineData("Large/Large.gz")]
[InlineData("Large/Large.rar")]
[InlineData("Large/Large.7z")]
public async Task OpenAsyncArchive_ShouldStreamLargeEntry(string fixtureName)
{
await using var stream = new AsyncOnlyStream(
2026-08-01 13:26:48 +01:00
File.OpenRead(await GetMaterializedFixturePathAsync(fixtureName))
);
await using var archive = await ArchiveFactory.OpenAsyncArchive(stream);
var entry = await GetSingleEntryAsync(archive);
2026-08-03 16:01:58 +01:00
var entryStream = await entry.OpenEntryStreamAsync();
await using var entryStreamScope = entryStream.DisposeAsyncScope();
await VerifyContentAsync(entry.Key, entryStream);
}
[Theory]
[InlineData("Large/Large.zip")]
[InlineData("Large/Large.tar")]
[InlineData("Large/Large.gz")]
[InlineData("Large/Large.rar")]
[InlineData("Large/Large.tar.gz")]
public void OpenReader_ShouldStreamLargeEntry(string fixtureName)
{
2026-08-01 13:26:48 +01:00
using var stream = File.OpenRead(GetMaterializedFixturePath(fixtureName));
using var reader = ReaderFactory.OpenReader(stream);
VerifyReader(reader);
}
[Theory]
[InlineData("Large/Large.zip")]
[InlineData("Large/Large.tar")]
[InlineData("Large/Large.gz")]
[InlineData("Large/Large.rar")]
[InlineData("Large/Large.tar.gz")]
public async Task OpenAsyncReader_ShouldStreamLargeEntry(string fixtureName)
{
2026-08-01 13:26:48 +01:00
await using var stream = new AsyncOnlyStream(
File.OpenRead(await GetMaterializedFixturePathAsync(fixtureName))
);
await using var reader = await ReaderFactory.OpenAsyncReader(stream);
Assert.True(await reader.MoveToNextEntryAsync());
Assert.False(reader.Entry.IsDirectory);
2026-08-03 16:01:58 +01:00
await using var entryStream = await reader.OpenEntryStreamAsync();
await VerifyContentAsync(reader.Entry.Key, entryStream);
Assert.False(await reader.MoveToNextEntryAsync());
}
2026-08-03 16:38:27 +01:00
[Fact]
public async Task OpenAsyncReader_WithGZipExtensionHint_ShouldStreamLargeTarEntry()
{
using var file = File.OpenRead(GetFixturePath("Large/Large.tar.gz"));
await using var stream = new AsyncOnlyStream(new ForwardOnlyStream(file));
var options = new ReaderOptions { ExtensionHint = "gz" };
await using var reader = await ReaderFactory.OpenAsyncReader(stream, options);
Assert.True(await reader.MoveToNextEntryAsync());
Assert.False(reader.Entry.IsDirectory);
await using var entryStream = await reader.OpenEntryStreamAsync();
await VerifyContentAsync(reader.Entry.Key, entryStream);
Assert.False(await reader.MoveToNextEntryAsync());
}
private static string GetFixturePath(string fixtureName) =>
Path.Combine(TEST_ARCHIVES_PATH, fixtureName);
2026-08-01 13:26:48 +01:00
private string GetMaterializedFixturePath(string fixtureName) =>
fixtureName == "Large/Large.tar" ? MaterializeTarFixture() : GetFixturePath(fixtureName);
2026-08-01 13:26:48 +01:00
private async Task<string> GetMaterializedFixturePathAsync(string fixtureName) =>
fixtureName == "Large/Large.tar"
? await MaterializeTarFixtureAsync()
: GetFixturePath(fixtureName);
private string MaterializeTarFixture()
{
var tarPath = Path.Combine(SCRATCH_FILES_PATH, "Large.tar");
using var compressedStream = File.OpenRead(GetFixturePath("Large/Large.tar.gz"));
using var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress);
using var tarStream = File.Create(tarPath);
gzipStream.CopyTo(tarStream);
return tarPath;
}
private async Task<string> MaterializeTarFixtureAsync()
{
var tarPath = Path.Combine(SCRATCH_FILES_PATH, "Large.tar");
using var compressedStream = File.OpenRead(GetFixturePath("Large/Large.tar.gz"));
using var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress);
using var tarStream = File.Create(tarPath);
await gzipStream.CopyToAsync(tarStream);
return tarPath;
}
private static void VerifyArchive(IArchive archive)
{
var entry = Assert.Single(archive.Entries);
Assert.False(entry.IsDirectory);
using var entryStream = entry.OpenEntryStream();
VerifyContent(entry.Key, entryStream);
}
private static async Task<IArchiveEntry> GetSingleEntryAsync(IAsyncArchive archive)
{
IArchiveEntry? entry = null;
await foreach (var candidate in archive.EntriesAsync)
{
Assert.Null(entry);
entry = candidate;
}
return entry ?? throw new InvalidOperationException("The archive contains no entries.");
}
private static void VerifyReader(IReader reader)
{
Assert.True(reader.MoveToNextEntry());
Assert.False(reader.Entry.IsDirectory);
using var entryStream = reader.OpenEntryStream();
VerifyContent(reader.Entry.Key, entryStream);
Assert.False(reader.MoveToNextEntry());
}
private static void VerifyContent(string? key, Stream entryStream)
{
Assert.Equal("large.bin", key);
using var crcStream = new Crc32Stream(Stream.Null);
var buffer = new byte[BufferSize];
long length = 0;
int bytesRead;
while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)
{
crcStream.Write(buffer, 0, bytesRead);
length += bytesRead;
}
Assert.Equal(LargeFileSize, length);
Assert.Equal(LargeFileCrc, crcStream.Crc);
}
private static async Task VerifyContentAsync(string? key, Stream entryStream)
{
Assert.Equal("large.bin", key);
using var crcStream = new Crc32Stream(Stream.Null);
var buffer = new byte[BufferSize];
long length = 0;
int bytesRead;
while ((bytesRead = await entryStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await crcStream.WriteAsync(buffer, 0, bytesRead);
length += bytesRead;
}
Assert.Equal(LargeFileSize, length);
Assert.Equal(LargeFileCrc, crcStream.Crc);
}
}
[CollectionDefinition(LargeArchiveCollection.Name, DisableParallelization = true)]
public sealed class LargeArchiveCollection
{
public const string Name = "Large archive fixtures";
}