This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
using System.IO.Compression;
|
||||
using Ludarium.Application;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace Ludarium.UnitTests;
|
||||
|
||||
public sealed class ArchiveAnalysisTests
|
||||
{
|
||||
[Fact]
|
||||
public void EnumeratesCentralDirectoryWithoutExtractingMembers()
|
||||
{
|
||||
using var stream = CreateZip(("games/demo.nes", new byte[] { 1, 2, 3 }), ("manual.txt", "offline"u8.ToArray()));
|
||||
|
||||
var result = ArchiveAnalysis.InspectZip(Guid.NewGuid(), stream);
|
||||
|
||||
Assert.True(result.Complete);
|
||||
Assert.Equal(2, result.Members.Count);
|
||||
Assert.Contains(result.Members, x => x.Path == "games/demo.nes" && x.UncompressedSize == 3 && x.ContentBlobId is null);
|
||||
Assert.Equal([0, 1], result.Members.Select(x => x.Sequence));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordsTraversalAsUnsafeAndNeverExtractsIt()
|
||||
{
|
||||
using var stream = CreateZip(("../escape.exe", new byte[] { 1 }));
|
||||
|
||||
var result = ArchiveAnalysis.InspectZip(Guid.NewGuid(), stream);
|
||||
|
||||
Assert.False(result.Complete);
|
||||
Assert.True(Assert.Single(result.Members).UnsafePath);
|
||||
Assert.Contains(result.Findings, x => x.Contains("never extracted", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StopsAtConfiguredMemberLimit()
|
||||
{
|
||||
using var stream = CreateZip(("one.bin", new byte[] { 1 }), ("two.bin", new byte[] { 2 }));
|
||||
|
||||
var result = ArchiveAnalysis.InspectZip(Guid.NewGuid(), stream, new ArchiveLimits(MaxMembers: 1));
|
||||
|
||||
Assert.Single(result.Members);
|
||||
Assert.Contains(result.Findings, x => x.Contains("member limit", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HonorsCancellationBeforeEnumeratingMembers()
|
||||
{
|
||||
using var stream = CreateZip(("one.bin", new byte[] { 1 }));
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
cancellation.Cancel();
|
||||
|
||||
Assert.Throws<OperationCanceledException>(() =>
|
||||
ArchiveAnalysis.InspectZip(Guid.NewGuid(), stream, cancellationToken: cancellation.Token));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnumeratesSevenZipHeadersWithoutExtractingMembers()
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"ludarium-{Guid.NewGuid():N}.7z");
|
||||
try
|
||||
{
|
||||
using (var writer = WriterFactory.OpenWriter(path, ArchiveType.SevenZip, new WriterOptions(CompressionType.LZMA)))
|
||||
{
|
||||
using var first = new MemoryStream(new byte[] { 1, 2, 3 });
|
||||
writer.Write("games/demo.nes", first, null);
|
||||
using var second = new MemoryStream("offline"u8.ToArray());
|
||||
writer.Write("manual.txt", second, null);
|
||||
}
|
||||
using var stream = File.OpenRead(path);
|
||||
|
||||
var result = ArchiveAnalysis.InspectSevenZip(Guid.NewGuid(), stream);
|
||||
|
||||
Assert.True(result.Complete);
|
||||
Assert.Equal(2, result.Members.Count);
|
||||
Assert.Contains(result.Members, x => x.Path == "games/demo.nes" && x.UncompressedSize == 3);
|
||||
}
|
||||
finally { File.Delete(path); }
|
||||
}
|
||||
|
||||
private static MemoryStream CreateZip(params (string Name, byte[] Data)[] entries)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true))
|
||||
{
|
||||
foreach (var (name, data) in entries)
|
||||
{
|
||||
var entry = archive.CreateEntry(name, CompressionLevel.SmallestSize);
|
||||
using var output = entry.Open();
|
||||
output.Write(data);
|
||||
}
|
||||
}
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user