2019-11-11 06:15:52 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
2019-12-04 01:26:26 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2019-11-11 06:15:52 +00:00
|
|
|
|
using Alphaleonis.Win32.Filesystem;
|
|
|
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using Wabbajack.Common;
|
|
|
|
|
using Wabbajack.Lib.Downloaders;
|
|
|
|
|
using Wabbajack.Lib.NexusApi;
|
|
|
|
|
using Directory = Alphaleonis.Win32.Filesystem.Directory;
|
|
|
|
|
using File = Alphaleonis.Win32.Filesystem.File;
|
|
|
|
|
using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo;
|
|
|
|
|
using Path = Alphaleonis.Win32.Filesystem.Path;
|
|
|
|
|
|
|
|
|
|
namespace Compression.BSA.Test
|
|
|
|
|
{
|
|
|
|
|
[TestClass]
|
|
|
|
|
public class BSATests
|
|
|
|
|
{
|
2019-11-21 15:41:46 +00:00
|
|
|
|
private static string _stagingFolder = "NexusDownloads";
|
|
|
|
|
private static string _bsaFolder = "BSAs";
|
|
|
|
|
private static string _testDir = "BSA Test Dir";
|
|
|
|
|
private static string _tempDir = "BSA Temp Dir";
|
2019-11-11 06:15:52 +00:00
|
|
|
|
|
|
|
|
|
public TestContext TestContext { get; set; }
|
|
|
|
|
|
2019-11-17 04:16:42 +00:00
|
|
|
|
private static WorkQueue Queue { get; set; }
|
|
|
|
|
|
2019-11-11 06:15:52 +00:00
|
|
|
|
[ClassInitialize]
|
2019-12-04 01:26:26 +00:00
|
|
|
|
public static async Task Setup(TestContext testContext)
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-11-17 04:16:42 +00:00
|
|
|
|
Queue = new WorkQueue();
|
2019-12-04 04:12:08 +00:00
|
|
|
|
Utils.LogMessages.Subscribe(f => testContext.WriteLine(f.ShortDescription));
|
2019-11-21 15:41:46 +00:00
|
|
|
|
if (!Directory.Exists(_stagingFolder))
|
|
|
|
|
Directory.CreateDirectory(_stagingFolder);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
|
2019-11-21 15:41:46 +00:00
|
|
|
|
if (!Directory.Exists(_bsaFolder))
|
|
|
|
|
Directory.CreateDirectory(_bsaFolder);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
|
2019-11-21 15:41:46 +00:00
|
|
|
|
var modIDs = new[]
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
|
|
|
|
(Game.SkyrimSpecialEdition, 12604), // SkyUI
|
|
|
|
|
(Game.Skyrim, 3863), // SkyUI
|
|
|
|
|
(Game.Skyrim, 51473), // iNeed
|
2019-12-23 23:05:00 +00:00
|
|
|
|
//(Game.Fallout4, 22223) // 10mm SMG
|
|
|
|
|
(Game.Fallout4, 4472) // True Storms
|
2019-11-11 06:15:52 +00:00
|
|
|
|
};
|
|
|
|
|
|
2019-12-07 02:45:13 +00:00
|
|
|
|
await Task.WhenAll(modIDs.Select(async (info) =>
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-12-06 05:29:17 +00:00
|
|
|
|
var filename = await DownloadMod(info);
|
2019-11-21 15:41:46 +00:00
|
|
|
|
var folder = Path.Combine(_bsaFolder, info.Item1.ToString(), info.Item2.ToString());
|
2019-11-11 06:15:52 +00:00
|
|
|
|
if (!Directory.Exists(folder))
|
|
|
|
|
Directory.CreateDirectory(folder);
|
2019-12-04 01:26:26 +00:00
|
|
|
|
await FileExtractor.ExtractAll(Queue, filename, folder);
|
2019-12-07 02:45:13 +00:00
|
|
|
|
}));
|
2019-11-11 06:15:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-06 05:29:17 +00:00
|
|
|
|
private static async Task<string> DownloadMod((Game, int) info)
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-12-07 03:50:50 +00:00
|
|
|
|
using (var client = await NexusApiClient.Get())
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-12-07 02:45:13 +00:00
|
|
|
|
var results = await client.GetModFiles(info.Item1, info.Item2);
|
2019-11-22 05:19:42 +00:00
|
|
|
|
var file = results.files.FirstOrDefault(f => f.is_primary) ??
|
|
|
|
|
results.files.OrderByDescending(f => f.uploaded_timestamp).First();
|
2019-11-21 15:41:46 +00:00
|
|
|
|
var src = Path.Combine(_stagingFolder, file.file_name);
|
2019-11-12 04:35:07 +00:00
|
|
|
|
|
|
|
|
|
if (File.Exists(src)) return src;
|
|
|
|
|
|
|
|
|
|
var state = new NexusDownloader.State
|
|
|
|
|
{
|
|
|
|
|
ModID = info.Item2.ToString(),
|
2019-12-09 22:46:03 +00:00
|
|
|
|
GameName = info.Item1.MetaData().NexusName,
|
2019-11-12 04:35:07 +00:00
|
|
|
|
FileID = file.file_id.ToString()
|
|
|
|
|
};
|
2019-12-06 05:29:17 +00:00
|
|
|
|
await state.Download(src);
|
2019-11-12 04:35:07 +00:00
|
|
|
|
return src;
|
|
|
|
|
}
|
2019-11-11 06:15:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IEnumerable<object[]> BSAs()
|
|
|
|
|
{
|
2019-11-21 15:41:46 +00:00
|
|
|
|
return Directory.EnumerateFiles(_bsaFolder, "*", DirectoryEnumerationOptions.Recursive)
|
2019-11-11 06:15:52 +00:00
|
|
|
|
.Where(f => Consts.SupportedBSAs.Contains(Path.GetExtension(f)))
|
|
|
|
|
.Select(nm => new object[] {nm});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[TestMethod]
|
|
|
|
|
[DataTestMethod]
|
|
|
|
|
[DynamicData(nameof(BSAs), DynamicDataSourceType.Method)]
|
2019-12-04 01:26:26 +00:00
|
|
|
|
public async Task BSACompressionRecompression(string bsa)
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
|
|
|
|
TestContext.WriteLine($"From {bsa}");
|
|
|
|
|
TestContext.WriteLine("Cleaning Output Dir");
|
2019-11-23 17:37:24 +00:00
|
|
|
|
if (Directory.Exists(_tempDir)) Utils.DeleteDirectory(_tempDir);
|
2019-11-21 15:41:46 +00:00
|
|
|
|
Directory.CreateDirectory(_tempDir);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
|
|
|
|
|
TestContext.WriteLine($"Reading {bsa}");
|
2019-11-21 15:41:46 +00:00
|
|
|
|
string tempFile = Path.Combine("tmp.bsa");
|
2019-11-16 00:01:37 +00:00
|
|
|
|
using (var a = BSADispatch.OpenRead(bsa))
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-12-04 01:26:26 +00:00
|
|
|
|
await a.Files.PMap(Queue, file =>
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-11-21 15:41:46 +00:00
|
|
|
|
var absName = Path.Combine(_tempDir, file.Path);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
ViaJson(file.State);
|
|
|
|
|
|
2019-11-21 15:41:46 +00:00
|
|
|
|
if (!Directory.Exists(Path.GetDirectoryName(absName)))
|
|
|
|
|
Directory.CreateDirectory(Path.GetDirectoryName(absName));
|
2019-11-11 06:15:52 +00:00
|
|
|
|
|
|
|
|
|
|
2019-11-21 15:41:46 +00:00
|
|
|
|
using (var fs = File.OpenWrite(absName))
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-11-16 00:01:37 +00:00
|
|
|
|
file.CopyDataTo(fs);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 15:41:46 +00:00
|
|
|
|
Assert.AreEqual(file.Size, new FileInfo(absName).Length);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"Building {bsa}");
|
|
|
|
|
|
|
|
|
|
using (var w = ViaJson(a.State).MakeBuilder())
|
|
|
|
|
{
|
2019-12-04 01:26:26 +00:00
|
|
|
|
await a.Files.PMap(Queue, file =>
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-11-21 15:41:46 +00:00
|
|
|
|
var absPath = Path.Combine(_tempDir, file.Path);
|
|
|
|
|
using (var str = File.OpenRead(absPath))
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
2019-11-16 00:01:37 +00:00
|
|
|
|
w.AddFile(ViaJson(file.State), str);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
2019-11-21 15:41:46 +00:00
|
|
|
|
w.Build(tempFile);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"Verifying {bsa}");
|
2019-11-21 15:41:46 +00:00
|
|
|
|
using (var b = BSADispatch.OpenRead(tempFile))
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"Performing A/B tests on {bsa}");
|
|
|
|
|
Assert.AreEqual(JsonConvert.SerializeObject(a.State), JsonConvert.SerializeObject(b.State));
|
|
|
|
|
|
|
|
|
|
// Check same number of files
|
|
|
|
|
Assert.AreEqual(a.Files.Count(), b.Files.Count());
|
|
|
|
|
var idx = 0;
|
2019-11-12 04:35:07 +00:00
|
|
|
|
|
2019-12-04 01:26:26 +00:00
|
|
|
|
await a.Files.Zip(b.Files, (ai, bi) => (ai, bi))
|
2019-11-17 04:16:42 +00:00
|
|
|
|
.PMap(Queue, pair =>
|
2019-11-12 04:35:07 +00:00
|
|
|
|
{
|
|
|
|
|
idx++;
|
|
|
|
|
Assert.AreEqual(JsonConvert.SerializeObject(pair.ai.State),
|
|
|
|
|
JsonConvert.SerializeObject(pair.bi.State));
|
|
|
|
|
//Console.WriteLine($" - {pair.ai.Path}");
|
|
|
|
|
Assert.AreEqual(pair.ai.Path, pair.bi.Path);
|
|
|
|
|
//Equal(pair.ai.Compressed, pair.bi.Compressed);
|
|
|
|
|
Assert.AreEqual(pair.ai.Size, pair.bi.Size);
|
2019-11-16 00:01:37 +00:00
|
|
|
|
CollectionAssert.AreEqual(GetData(pair.ai), GetData(pair.bi));
|
2019-11-12 04:35:07 +00:00
|
|
|
|
});
|
2019-11-11 06:15:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 00:01:37 +00:00
|
|
|
|
private static byte[] GetData(IFile pairAi)
|
2019-11-11 06:15:52 +00:00
|
|
|
|
{
|
|
|
|
|
using (var ms = new MemoryStream())
|
|
|
|
|
{
|
2019-11-16 00:01:37 +00:00
|
|
|
|
pairAi.CopyDataTo(ms);
|
2019-11-11 06:15:52 +00:00
|
|
|
|
return ms.ToArray();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static T ViaJson<T>(T i)
|
|
|
|
|
{
|
|
|
|
|
var settings = new JsonSerializerSettings
|
|
|
|
|
{
|
|
|
|
|
TypeNameHandling = TypeNameHandling.All
|
|
|
|
|
};
|
|
|
|
|
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(i, settings), settings);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|