mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-11-15 17:02:03 +00:00
213 lines
7.1 KiB
C#
213 lines
7.1 KiB
C#
using System;
|
|
using System.Buffers.Binary;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using SharpCompress.Archives.SevenZip;
|
|
using SharpCompress.Common;
|
|
using SharpCompress.Crypto;
|
|
using SharpCompress.Test.Mocks;
|
|
using SharpCompress.Writers;
|
|
using SharpCompress.Writers.SevenZip;
|
|
using Xunit;
|
|
|
|
namespace SharpCompress.Test.SevenZip;
|
|
|
|
public class SevenZipWriterAsyncTests : TestBase
|
|
{
|
|
[Theory]
|
|
[InlineData(false, 1)]
|
|
[InlineData(true, 1)]
|
|
[InlineData(false, 256)]
|
|
[InlineData(true, 256)]
|
|
public async ValueTask SevenZipWriter_Async_HeaderCrc_MatchesWrittenBytes(
|
|
bool compressHeader,
|
|
int directoryCount
|
|
)
|
|
{
|
|
using var output = new MemoryStream();
|
|
await using (
|
|
var writer = new SevenZipWriter(
|
|
new AsyncOnlyStream(output),
|
|
new SevenZipWriterOptions { CompressHeader = compressHeader }
|
|
)
|
|
)
|
|
{
|
|
// Large names make the raw header span multiple pooled blocks.
|
|
for (var i = 0; i < directoryCount; i++)
|
|
{
|
|
await writer.WriteDirectoryAsync(
|
|
$"dir{i}-{new string('x', 512)}",
|
|
null,
|
|
CancellationToken.None
|
|
);
|
|
}
|
|
}
|
|
|
|
Assert.True(output.CanWrite);
|
|
var bytes = output.ToArray();
|
|
var headerOffset = BinaryPrimitives.ReadUInt64LittleEndian(bytes.AsSpan(12));
|
|
var headerSize = BinaryPrimitives.ReadUInt64LittleEndian(bytes.AsSpan(20));
|
|
var headerCrc = BinaryPrimitives.ReadUInt32LittleEndian(bytes.AsSpan(28));
|
|
Assert.Equal((ulong)bytes.Length, 32 + headerOffset + headerSize);
|
|
Assert.Equal(
|
|
Crc32Stream.Compute(
|
|
Crc32Stream.DEFAULT_POLYNOMIAL,
|
|
Crc32Stream.DEFAULT_SEED,
|
|
bytes.AsSpan(checked(32 + (int)headerOffset), checked((int)headerSize))
|
|
),
|
|
headerCrc
|
|
);
|
|
|
|
output.Position = 0;
|
|
await using var archive = await SevenZipArchive.OpenAsyncArchive(output);
|
|
var entries = await archive.EntriesAsync.ToListAsync();
|
|
Assert.Equal(directoryCount, entries.Count);
|
|
Assert.All(entries, entry => Assert.True(entry.IsDirectory));
|
|
}
|
|
|
|
[Fact]
|
|
public async ValueTask SevenZipWriter_Async_SingleFile_RoundTrip()
|
|
{
|
|
var content = "Hello, async 7z world!"u8.ToArray();
|
|
|
|
using var archiveStream = new MemoryStream();
|
|
|
|
await using (
|
|
var writer = new SevenZipWriter(
|
|
new AsyncOnlyStream(archiveStream),
|
|
new SevenZipWriterOptions()
|
|
)
|
|
)
|
|
{
|
|
await writer.WriteAsync("test.txt", new MemoryStream(content), DateTime.UtcNow);
|
|
}
|
|
|
|
archiveStream.Position = 0;
|
|
using var archive = (SevenZipArchive)SevenZipArchive.OpenArchive(archiveStream);
|
|
var entries = archive.Entries.Where(e => !e.IsDirectory).ToList();
|
|
Assert.Single(entries);
|
|
Assert.Equal("test.txt", entries[0].Key);
|
|
Assert.Equal(content.Length, (int)entries[0].Size);
|
|
|
|
using var output = new MemoryStream();
|
|
using (var entryStream = entries[0].OpenEntryStream())
|
|
{
|
|
entryStream.CopyTo(output);
|
|
}
|
|
|
|
Assert.Equal(content, output.ToArray());
|
|
}
|
|
|
|
[Fact]
|
|
public async ValueTask SevenZipWriter_Async_WithDirectory_RoundTrip()
|
|
{
|
|
using var archiveStream = new MemoryStream();
|
|
|
|
await using (
|
|
var writer = new SevenZipWriter(
|
|
new AsyncOnlyStream(archiveStream),
|
|
new SevenZipWriterOptions(CompressionType.LZMA2)
|
|
)
|
|
)
|
|
{
|
|
await writer.WriteDirectoryAsync("mydir", DateTime.UtcNow);
|
|
await writer.WriteAsync(
|
|
"mydir/file1.txt",
|
|
new MemoryStream(Encoding.UTF8.GetBytes("file one")),
|
|
DateTime.UtcNow
|
|
);
|
|
await writer.WriteAsync(
|
|
"mydir/file2.txt",
|
|
new MemoryStream(Encoding.UTF8.GetBytes("file two")),
|
|
DateTime.UtcNow
|
|
);
|
|
}
|
|
|
|
archiveStream.Position = 0;
|
|
using var archive = (SevenZipArchive)SevenZipArchive.OpenArchive(archiveStream);
|
|
var entries = archive.Entries.ToList();
|
|
|
|
Assert.Equal(3, entries.Count);
|
|
Assert.Contains(entries, e => e.IsDirectory && e.Key == "mydir");
|
|
Assert.Contains(entries, e => !e.IsDirectory && e.Key == "mydir/file1.txt");
|
|
Assert.Contains(entries, e => !e.IsDirectory && e.Key == "mydir/file2.txt");
|
|
}
|
|
|
|
[Fact]
|
|
public async ValueTask SevenZipWriter_Async_ViaWriterFactory()
|
|
{
|
|
var content = "Factory-created async archive"u8.ToArray();
|
|
|
|
using var archiveStream = new MemoryStream();
|
|
|
|
await using (
|
|
var writer = await WriterFactory.OpenAsyncWriter(
|
|
new AsyncOnlyStream(archiveStream),
|
|
ArchiveType.SevenZip,
|
|
new SevenZipWriterOptions()
|
|
)
|
|
)
|
|
{
|
|
await writer.WriteAsync("factory.txt", new MemoryStream(content), DateTime.UtcNow);
|
|
}
|
|
|
|
archiveStream.Position = 0;
|
|
using var archive = (SevenZipArchive)SevenZipArchive.OpenArchive(archiveStream);
|
|
var entry = archive.Entries.Single(e => !e.IsDirectory);
|
|
|
|
using var output = new MemoryStream();
|
|
using (var entryStream = entry.OpenEntryStream())
|
|
{
|
|
entryStream.CopyTo(output);
|
|
}
|
|
|
|
Assert.Equal("factory.txt", entry.Key);
|
|
Assert.Equal(content, output.ToArray());
|
|
}
|
|
|
|
[Fact]
|
|
public async ValueTask SevenZipWriter_Async_UsesAsyncSourceReads()
|
|
{
|
|
var content = "source stream supports async reads only"u8.ToArray();
|
|
|
|
using var archiveStream = new MemoryStream();
|
|
|
|
await using (var writer = new SevenZipWriter(archiveStream, new SevenZipWriterOptions()))
|
|
{
|
|
using var source = new AsyncOnlyStream(new MemoryStream(content));
|
|
await writer.WriteAsync("async-source.txt", source, DateTime.UtcNow);
|
|
}
|
|
|
|
archiveStream.Position = 0;
|
|
using var archive = (SevenZipArchive)SevenZipArchive.OpenArchive(archiveStream);
|
|
var entry = archive.Entries.Single(e => !e.IsDirectory);
|
|
|
|
using var output = new MemoryStream();
|
|
using (var entryStream = entry.OpenEntryStream())
|
|
{
|
|
entryStream.CopyTo(output);
|
|
}
|
|
|
|
Assert.Equal("async-source.txt", entry.Key);
|
|
Assert.Equal(content, output.ToArray());
|
|
}
|
|
|
|
[Fact]
|
|
public async ValueTask SevenZipWriter_Async_Cancelled_Throws()
|
|
{
|
|
using var archiveStream = new MemoryStream();
|
|
await using var writer = new SevenZipWriter(archiveStream, new SevenZipWriterOptions());
|
|
|
|
using var source = new MemoryStream("cancel me"u8.ToArray());
|
|
using var cts = new CancellationTokenSource();
|
|
cts.Cancel();
|
|
|
|
await Assert.ThrowsAnyAsync<OperationCanceledException>(() =>
|
|
writer.WriteAsync("cancel.txt", source, DateTime.UtcNow, cts.Token).AsTask()
|
|
);
|
|
}
|
|
}
|