sharpemu/tests/SharpEmu.Libs.Tests/FileSystem/ZArchiveWriterTests.cs

109 lines
3.9 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.HLE.FileSystem;
using Xunit;
namespace SharpEmu.Libs.Tests.FileSystem;
public sealed class ZArchiveWriterTests : IDisposable
{
private readonly string _directory = Directory.CreateTempSubdirectory("sharpemu-zarpack-").FullName;
private readonly string _game;
public ZArchiveWriterTests()
{
_game = Path.Combine(_directory, "game");
Put("eboot.bin", Bytes(150_000, 1));
Put(Path.Combine("sce_sys", "param.json"), Bytes(700, 2));
Put(Path.Combine("data", "Level", "a.bin"), Bytes(0, 3));
Put(Path.Combine("data", "Level", "b.bin"), Bytes(200_000, 4));
Put(Path.Combine("data", new string('n', 200) + ".bin"), Bytes(10, 5));
}
public void Dispose() => Directory.Delete(_directory, recursive: true);
private void Put(string relative, byte[] data)
{
var path = Path.Combine(_game, relative);
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
File.WriteAllBytes(path, data);
}
private static byte[] Bytes(int length, int seed)
{
var bytes = new byte[length];
new System.Random(seed).NextBytes(bytes.AsSpan(0, length / 2));
for (var index = length / 2; index < length; index++)
{
bytes[index] = (byte)(index % 7);
}
return bytes;
}
[Fact]
public void AFolderReadsBackFromItsArchive()
{
var archivePath = Path.Combine(_directory, "game.zar");
var reports = new List<ZArchiveWriter.Progress>();
ZArchiveWriter.Pack(_game, archivePath, new SynchronousProgress(reports.Add));
using var archive = ZArchive.Open(archivePath)!;
Assert.NotNull(archive);
foreach (var path in Directory.EnumerateFiles(_game, "*", SearchOption.AllDirectories))
{
var expected = File.ReadAllBytes(path);
var node = archive.LookUp(Path.GetRelativePath(_game, path));
Assert.True(archive.IsFile(node));
var actual = new byte[expected.Length];
Assert.Equal(expected.Length, archive.Read(node, 0, actual));
Assert.Equal(expected, actual);
}
Assert.Equal(["data", "eboot.bin", "sce_sys"], archive.GetEntries(archive.LookUp(string.Empty)).Select(e => e.Name).Order());
Assert.Equal(reports[^1].BytesTotal, reports[^1].BytesDone);
Assert.Equal(5, reports[^1].FilesTotal);
}
[Fact]
public void ACancelledPackLeavesNoArchive()
{
var archivePath = Path.Combine(_directory, "game.zar");
using var cancelled = new CancellationTokenSource();
cancelled.Cancel();
Assert.Throws<OperationCanceledException>(() => ZArchiveWriter.Pack(_game, archivePath, cancellationToken: cancelled.Token));
Assert.Empty(Directory.EnumerateFiles(_directory));
}
[Fact]
public void AnArchiveMatchesItsFolderUntilTheFolderChanges()
{
var archivePath = Path.Combine(_directory, "game.zar");
ZArchiveWriter.Pack(_game, archivePath);
Assert.True(ZArchiveWriter.MatchesFolder(archivePath, _game));
Put("added.bin", Bytes(5, 6));
Assert.False(ZArchiveWriter.MatchesFolder(archivePath, _game));
File.Delete(Path.Combine(_game, "added.bin"));
Put("eboot.bin", Bytes(150_001, 1));
Assert.False(ZArchiveWriter.MatchesFolder(archivePath, _game));
File.WriteAllBytes(archivePath, Bytes(4096, 7));
Assert.False(ZArchiveWriter.MatchesFolder(archivePath, _game));
}
[Fact]
public void AnArchiveCannotBeWrittenIntoTheFolderItPacks()
{
Assert.Throws<IOException>(() => ZArchiveWriter.Pack(_game, Path.Combine(_game, "game.zar")));
}
private sealed class SynchronousProgress(Action<ZArchiveWriter.Progress> report) : IProgress<ZArchiveWriter.Progress>
{
public void Report(ZArchiveWriter.Progress value) => report(value);
}
}