wabbajack/Wabbajack.VirtualFileSystem.Test/FileExtractorTests.cs

248 lines
8.2 KiB
C#
Raw Normal View History

2020-09-04 21:00:29 +00:00
using System;
2020-09-29 12:35:31 +00:00
using System.IO;
2020-09-04 21:00:29 +00:00
using System.IO.Compression;
2020-09-08 22:15:33 +00:00
using System.Linq;
2020-09-04 21:00:29 +00:00
using System.Threading.Tasks;
using Wabbajack.Common;
2020-09-08 22:15:33 +00:00
using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.NexusApi;
2020-09-04 21:00:29 +00:00
using Xunit;
2020-09-09 02:34:53 +00:00
using Xunit.Abstractions;
2020-09-04 21:00:29 +00:00
namespace Wabbajack.VirtualFileSystem.Test
{
2020-09-09 02:34:53 +00:00
public class FileExtractorTests : IAsyncLifetime
2020-09-04 21:00:29 +00:00
{
2020-09-09 02:34:53 +00:00
private ITestOutputHelper _helper;
private IDisposable _unsub;
public FileExtractorTests(ITestOutputHelper helper)
{
_helper = helper;
2020-09-09 04:06:15 +00:00
_unsub = Utils.LogMessages.Subscribe(f =>
{
try
{
_helper.WriteLine(f.ShortDescription);
}
2020-10-01 03:50:09 +00:00
catch (Exception)
2020-09-09 04:06:15 +00:00
{
// ignored
}
});
2020-09-09 02:34:53 +00:00
}
public async Task InitializeAsync()
{
}
public async Task DisposeAsync()
{
_unsub.Dispose();
}
2020-09-04 21:00:29 +00:00
[Fact]
public async Task CanGatherDataFromZipFiles()
{
await using var temp = await TempFolder.Create();
await using var archive = new TempFile();
for (int i = 0; i < 10; i ++)
{
await WriteRandomData(temp.Dir.Combine($"{i}.bin"), _rng.Next(10, 1024));
}
await ZipUpFolder(temp.Dir, archive.Path, false);
var results = await FileExtractor2.GatheringExtract(new NativeFileStreamFactory(archive.Path),
_ => true,
async (path, sfn) =>
2020-09-11 01:22:07 +00:00
{
await using var s = await sfn.GetStream();
return await s.xxHashAsync();
});
2020-09-04 21:00:29 +00:00
Assert.Equal(10, results.Count);
foreach (var (path, hash) in results)
{
Assert.Equal(await temp.Dir.Combine(path).FileHashAsync(), hash);
}
2020-09-08 22:15:33 +00:00
}
2020-09-29 12:35:31 +00:00
[Fact]
public async Task SmallFilesShouldntCrash()
{
await using var temp = await TempFolder.Create();
await using var archive = new TempFile();
for (int i = 0; i < 1; i ++)
{
await WriteRandomData(temp.Dir.Combine($"{i}.bin"), _rng.Next(10, 10));
}
await ZipUpFolder(temp.Dir, archive.Path, false);
var results = await FileExtractor2.GatheringExtract(new NativeFileStreamFactory(archive.Path),
_ => true,
async (path, sfn) =>
{
await using var s = await sfn.GetStream();
return await s.xxHashAsync();
});
Assert.Equal(1, results.Count);
foreach (var (path, hash) in results)
{
Assert.Equal(await temp.Dir.Combine(path).FileHashAsync(), hash);
}
}
2020-10-06 02:52:33 +00:00
/* Takes to long to run in CI, enable when needed for verification
2020-09-29 12:35:31 +00:00
2020-10-05 22:12:21 +00:00
[Fact]
public async Task MissingFileFromArchiveShouldBeFound()
{
FileExtractor2.FavorPerfOverRAM = true;
// From a bug in 2.3.0.1
var src = await DownloadMod(Game.SkyrimSpecialEdition, 21166, 136259);
var results = await FileExtractor2.GatheringExtract(new NativeFileStreamFactory(src),
f => true,
async (p, s) =>
{
await using var stream = await s.GetStream();
return stream.Length;
});
Assert.NotEmpty(results);
}
2020-10-06 02:52:33 +00:00
*/
2020-09-29 12:35:31 +00:00
2020-09-11 01:22:07 +00:00
[Fact]
public async Task CanExtractEmptyFiles()
{
await using var temp = await TempFolder.Create();
await using var archive = new TempFile();
for (int i = 0; i < 1; i ++)
{
await WriteRandomData(temp.Dir.Combine($"{i}.bin"), _rng.Next(10, 1024));
}
await (await temp.Dir.Combine("empty.txt").Create()).DisposeAsync();
await ZipUpFolder(temp.Dir, archive.Path, false);
var results = await FileExtractor2.GatheringExtract(new NativeFileStreamFactory(archive.Path),
_ => true,
async (path, sfn) =>
{
await using var s = await sfn.GetStream();
return await s.xxHashAsync();
});
Assert.Equal(2, results.Count);
foreach (var (path, hash) in results)
{
Assert.Equal(await temp.Dir.Combine(path).FileHashAsync(), hash);
}
}
2020-09-08 22:15:33 +00:00
private static Extension OMODExtension = new Extension(".omod");
private static Extension CRCExtension = new Extension(".crc");
2020-09-04 21:00:29 +00:00
2020-09-08 22:15:33 +00:00
[Fact]
public async Task CanGatherDataFromOMODFiles()
{
var src = await DownloadMod(Game.Oblivion, 18498);
2020-09-04 21:00:29 +00:00
2020-09-08 22:15:33 +00:00
await FileExtractor2.GatheringExtract(new NativeFileStreamFactory(src),
p => p.Extension == OMODExtension, async (path, sfn) =>
{
await FileExtractor2.GatheringExtract(sfn, _ => true, async (ipath, isfn) => {
2020-09-29 12:35:31 +00:00
// We shouldn't have any .crc files because this file should be recognized as a OMOD and extracted correctly
Assert.NotEqual(CRCExtension, ipath.Extension);
return 0;
2020-09-08 22:15:33 +00:00
});
return 0;
});
2020-09-04 21:00:29 +00:00
}
2020-09-29 12:35:31 +00:00
[Fact]
public async Task SmallZipNoLongerCrashes()
{
var src = await DownloadMod(Game.Fallout4, 29596, 120918);
await using var tmpFolder = await TempFolder.Create();
await FileExtractor2.ExtractAll(src, tmpFolder.Dir);
}
2020-09-04 21:00:29 +00:00
private static readonly Random _rng = new Random();
private static async Task WriteRandomData(AbsolutePath path, int size)
{
var buff = new byte[size];
_rng.NextBytes(buff);
await path.WriteAllBytesAsync(buff);
}
2020-09-29 12:35:31 +00:00
private async Task WriteRandomData(Stream path, long size)
{
var buff = new byte[size];
_rng.NextBytes(buff);
await path.WriteAsync(buff);
}
2020-09-04 21:00:29 +00:00
private static async Task AddFile(AbsolutePath filename, string text)
{
filename.Parent.CreateDirectory();
await filename.WriteAllTextAsync(text);
}
private static async Task ZipUpFolder(AbsolutePath folder, AbsolutePath output, bool deleteSource = true)
{
ZipFile.CreateFromDirectory((string)folder, (string)output);
if (deleteSource)
await folder.DeleteDirectory();
}
2020-09-08 22:15:33 +00:00
private static AbsolutePath _stagingFolder = ((RelativePath)"NexusDownloads").RelativeToEntryPoint();
2020-09-09 02:34:53 +00:00
2020-09-08 22:15:33 +00:00
private static async Task<AbsolutePath> DownloadMod(Game game, int mod)
{
using var client = await NexusApiClient.Get();
var results = await client.GetModFiles(game, mod);
var file = results.files.FirstOrDefault(f => f.is_primary) ??
results.files.OrderByDescending(f => f.uploaded_timestamp).First();
2020-09-29 12:35:31 +00:00
return await DownloadNexusFile(game, mod, file);
}
private static async Task<AbsolutePath> DownloadNexusFile(Game game, int mod, NexusFileInfo file)
{
2020-09-08 22:15:33 +00:00
var src = _stagingFolder.Combine(file.file_name);
if (src.Exists) return src;
var state = new NexusDownloader.State
{
ModID = mod,
Game = game,
FileID = file.file_id
};
await state.Download(src);
return src;
}
2020-09-29 12:35:31 +00:00
private async Task<AbsolutePath> DownloadMod(Game game, int mod, int fileId)
{
using var client = await NexusApiClient.Get();
var results = await client.GetModFiles(game, mod);
var file = results.files.FirstOrDefault(f => f.file_id == fileId);
return await DownloadNexusFile(game, mod, file);
}
2020-09-08 22:15:33 +00:00
2020-09-04 21:00:29 +00:00
}
}