2019-09-24 04:20:24 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.IO.Compression;
|
|
|
|
|
using System.Linq;
|
2020-03-26 04:25:48 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2019-10-29 21:30:27 +00:00
|
|
|
|
using Alphaleonis.Win32.Filesystem;
|
2019-09-24 04:20:24 +00:00
|
|
|
|
using Wabbajack.Common;
|
2020-03-26 21:15:44 +00:00
|
|
|
|
using Xunit;
|
2019-09-24 04:20:24 +00:00
|
|
|
|
using Directory = Alphaleonis.Win32.Filesystem.Directory;
|
|
|
|
|
using File = Alphaleonis.Win32.Filesystem.File;
|
2019-10-29 21:30:27 +00:00
|
|
|
|
using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo;
|
2019-09-24 04:20:24 +00:00
|
|
|
|
using Path = Alphaleonis.Win32.Filesystem.Path;
|
|
|
|
|
|
|
|
|
|
namespace Wabbajack.Test
|
|
|
|
|
{
|
2020-04-10 19:33:09 +00:00
|
|
|
|
public class TestUtils : IAsyncDisposable
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2020-02-24 23:18:29 +00:00
|
|
|
|
private static Random _rng = new Random();
|
2019-09-24 04:20:24 +00:00
|
|
|
|
public TestUtils()
|
|
|
|
|
{
|
|
|
|
|
ID = RandomName();
|
2020-03-26 21:15:44 +00:00
|
|
|
|
WorkingDirectory = ((RelativePath)"tmp_data").RelativeToEntryPoint();
|
2019-09-24 04:20:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-26 04:25:48 +00:00
|
|
|
|
public AbsolutePath WorkingDirectory { get;}
|
2019-09-24 04:20:24 +00:00
|
|
|
|
public string ID { get; }
|
2020-02-24 23:18:29 +00:00
|
|
|
|
public Random RNG => _rng;
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2019-11-16 22:02:36 +00:00
|
|
|
|
public Game Game { get; set; }
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-03-26 04:25:48 +00:00
|
|
|
|
public AbsolutePath TestFolder => WorkingDirectory.Combine(ID);
|
|
|
|
|
public AbsolutePath GameFolder => WorkingDirectory.Combine(ID, "game_folder");
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-03-26 04:25:48 +00:00
|
|
|
|
public AbsolutePath MO2Folder => WorkingDirectory.Combine(ID, "mo2_folder");
|
|
|
|
|
public AbsolutePath ModsFolder => MO2Folder.Combine(Consts.MO2ModFolderName);
|
|
|
|
|
public AbsolutePath DownloadsFolder => MO2Folder.Combine("downloads");
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-03-26 04:25:48 +00:00
|
|
|
|
public AbsolutePath InstallFolder => TestFolder.Combine("installed");
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2019-11-16 21:29:05 +00:00
|
|
|
|
public HashSet<string> Profiles = new HashSet<string>();
|
|
|
|
|
|
|
|
|
|
public List<string> Mods = new List<string>();
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-05-23 21:41:41 +00:00
|
|
|
|
public async Task Configure(IEnumerable<(string ModName, bool IsEnabled)> enabledMods = null)
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2020-03-28 02:54:14 +00:00
|
|
|
|
await MO2Folder.Combine("ModOrganizer.ini").WriteAllLinesAsync(
|
|
|
|
|
"[General]",
|
|
|
|
|
$"gameName={Game.MetaData().MO2Name}",
|
|
|
|
|
$"gamePath={((string)GameFolder).Replace("\\", "\\\\")}",
|
|
|
|
|
$"download_directory={DownloadsFolder}");
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-03-26 04:25:48 +00:00
|
|
|
|
DownloadsFolder.CreateDirectory();
|
|
|
|
|
GameFolder.Combine("Data").CreateDirectory();
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-05-23 21:41:41 +00:00
|
|
|
|
if (enabledMods == null)
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2020-05-23 21:41:41 +00:00
|
|
|
|
Profiles.Do(profile =>
|
|
|
|
|
{
|
2020-05-25 17:34:25 +00:00
|
|
|
|
MO2Folder.Combine("profiles", profile, "modlist.txt").WriteAllLinesAsync(
|
2020-05-23 21:41:41 +00:00
|
|
|
|
Mods.Select(s => $"+{s}").ToArray());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Profiles.Do(profile =>
|
|
|
|
|
{
|
2020-05-25 17:34:25 +00:00
|
|
|
|
MO2Folder.Combine("profiles", profile, "modlist.txt").WriteAllLinesAsync(
|
2020-05-23 21:41:41 +00:00
|
|
|
|
enabledMods.Select(s => $"{(s.IsEnabled ? "+" : "-")}{s.ModName}").ToArray());
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-09-24 04:20:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-28 03:15:48 +00:00
|
|
|
|
public string AddProfile(string name = null)
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2019-10-28 03:15:48 +00:00
|
|
|
|
string profile_name = name ?? RandomName();
|
2020-03-26 21:15:44 +00:00
|
|
|
|
MO2Folder.Combine("profiles", profile_name).CreateDirectory();
|
2019-09-24 04:20:24 +00:00
|
|
|
|
Profiles.Add(profile_name);
|
|
|
|
|
return profile_name;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
public async Task<string> AddMod(string name = null)
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2020-05-25 17:34:25 +00:00
|
|
|
|
string mod_name = name ?? RandomName();
|
|
|
|
|
var mod_folder = MO2Folder.Combine(Consts.MO2ModFolderName, (RelativePath)mod_name);
|
|
|
|
|
mod_folder.CreateDirectory();
|
|
|
|
|
await mod_folder.Combine("meta.ini").WriteAllTextAsync("[General]");
|
|
|
|
|
Mods.Add(mod_name);
|
|
|
|
|
return mod_name;
|
2019-09-24 04:20:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a file to the given mod with a given path in the mod. Fills it with random data unless
|
|
|
|
|
/// random_fill == 0;
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mod_name"></param>
|
|
|
|
|
/// <param name="path"></param>
|
|
|
|
|
/// <param name="random_fill"></param>
|
|
|
|
|
/// <returns></returns>
|
2020-05-25 17:34:25 +00:00
|
|
|
|
public async Task<AbsolutePath> AddModFile(string mod_name, string path, int random_fill=128)
|
2019-11-02 21:08:37 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var full_path = ModsFolder.Combine(mod_name, path);
|
|
|
|
|
full_path.Parent.CreateDirectory();
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await GenerateRandomFileData(full_path, random_fill);
|
2019-11-02 21:08:37 +00:00
|
|
|
|
return full_path;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
public async Task GenerateRandomFileData(AbsolutePath full_path, int random_fill)
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
|
|
|
|
byte[] bytes = new byte[0];
|
|
|
|
|
if (random_fill != 0)
|
|
|
|
|
{
|
|
|
|
|
bytes = new byte[random_fill];
|
|
|
|
|
RNG.NextBytes(bytes);
|
|
|
|
|
}
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await full_path.WriteAllBytesAsync(bytes);
|
2019-09-24 04:20:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-24 23:18:29 +00:00
|
|
|
|
public static byte[] RandomData(int? size = null, int maxSize = 1024)
|
|
|
|
|
{
|
|
|
|
|
if (size == null)
|
|
|
|
|
size = _rng.Next(1, maxSize);
|
|
|
|
|
var arr = new byte[(int) size];
|
|
|
|
|
_rng.NextBytes(arr);
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-10 19:33:09 +00:00
|
|
|
|
public async ValueTask DisposeAsync()
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2020-04-10 19:33:09 +00:00
|
|
|
|
var exts = new[] { ".md", ".exe" };
|
|
|
|
|
await WorkingDirectory.Combine(ID).DeleteDirectory();
|
2019-09-24 04:20:24 +00:00
|
|
|
|
Profiles.Do(p =>
|
|
|
|
|
{
|
2020-04-10 19:33:09 +00:00
|
|
|
|
foreach (var ext in exts)
|
|
|
|
|
{
|
2019-09-24 04:20:24 +00:00
|
|
|
|
var path = Path.Combine(Directory.GetCurrentDirectory(), p + ext);
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
File.Delete(path);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns a random string name (with spaces)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string RandomName()
|
|
|
|
|
{
|
|
|
|
|
return Guid.NewGuid().ToString();
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-22 20:58:50 +00:00
|
|
|
|
public byte[] RandomData(int size = 0)
|
|
|
|
|
{
|
|
|
|
|
if (size == 0)
|
|
|
|
|
size = _rng.Next(256);
|
|
|
|
|
var data = new byte[size];
|
|
|
|
|
_rng.NextBytes(data);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
public async ValueTask<string> AddManualDownload(Dictionary<string, byte[]> contents)
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
|
|
|
|
var name = RandomName() + ".zip";
|
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await using FileStream fs = await DownloadsFolder.Combine(name).Create();
|
2020-03-26 21:15:44 +00:00
|
|
|
|
using ZipArchive archive = new ZipArchive(fs, ZipArchiveMode.Create);
|
|
|
|
|
contents.Do(kv =>
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var entry = archive.CreateEntry(kv.Key);
|
2020-05-25 17:34:25 +00:00
|
|
|
|
using var os = entry.Open();
|
|
|
|
|
os.Write(kv.Value, 0, kv.Value.Length);
|
2020-03-26 21:15:44 +00:00
|
|
|
|
});
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await DownloadsFolder.Combine(name + Consts.MetaFileExtension).WriteAllLinesAsync(
|
2019-09-24 04:20:24 +00:00
|
|
|
|
"[General]",
|
|
|
|
|
"manualURL=<TESTING>"
|
2020-03-28 02:54:14 +00:00
|
|
|
|
);
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-25 16:24:16 +00:00
|
|
|
|
public async Task VerifyInstalledFile(string mod, string file)
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var src = MO2Folder.Combine((string)Consts.MO2ModFolderName, mod, file);
|
|
|
|
|
Assert.True(src.Exists);
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var dest = InstallFolder.Combine((string)Consts.MO2ModFolderName, mod, file);
|
2020-03-28 02:54:14 +00:00
|
|
|
|
Assert.True(dest.Exists, $"Destination {dest} doesn't exist");
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-05-25 16:24:16 +00:00
|
|
|
|
var srcData = await src.ReadAllBytesAsync();
|
|
|
|
|
var destData = await dest.ReadAllBytesAsync();
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
Assert.Equal(srcData.Length, destData.Length);
|
2019-09-24 04:20:24 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
for(int x = 0; x < srcData.Length; x++)
|
2019-09-24 04:20:24 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
if (srcData[x] != destData[x])
|
|
|
|
|
Assert.True(false, $"Index {x} of {mod}\\{file} are not the same");
|
2019-09-24 04:20:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-07 00:24:33 +00:00
|
|
|
|
|
2020-05-25 16:24:16 +00:00
|
|
|
|
public async Task VerifyInstalledGameFile(string file)
|
2020-01-07 00:24:33 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var src = GameFolder.Combine(file);
|
|
|
|
|
Assert.True(src.Exists);
|
2020-01-07 00:24:33 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var dest = InstallFolder.Combine((string)Consts.GameFolderFilesDir, file);
|
|
|
|
|
Assert.True(dest.Exists);
|
2020-01-07 00:24:33 +00:00
|
|
|
|
|
2020-05-25 16:24:16 +00:00
|
|
|
|
var srcData = await src.ReadAllBytesAsync();
|
|
|
|
|
var destData = await dest.ReadAllBytesAsync();
|
2020-01-07 00:24:33 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
Assert.Equal(srcData.Length, destData.Length);
|
2019-10-29 21:30:27 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
for(int x = 0; x < srcData.Length; x++)
|
2020-01-07 00:24:33 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
if (srcData[x] != destData[x])
|
|
|
|
|
Assert.True(false, $"Index {x} of {Consts.GameFolderFilesDir}\\{file} are not the same");
|
2020-01-07 00:24:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-26 21:15:44 +00:00
|
|
|
|
public AbsolutePath PathOfInstalledFile(string mod, string file)
|
2019-11-18 05:21:24 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
return InstallFolder.Combine((string)Consts.MO2ModFolderName, mod, file);
|
2019-11-18 05:21:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
public async ValueTask VerifyAllFiles(bool gameFileShouldNotExistInGameFolder = true)
|
2019-10-29 21:30:27 +00:00
|
|
|
|
{
|
2020-05-10 21:35:15 +00:00
|
|
|
|
if (gameFileShouldNotExistInGameFolder)
|
|
|
|
|
{
|
|
|
|
|
foreach (var file in Game.MetaData().RequiredFiles!)
|
|
|
|
|
{
|
|
|
|
|
Assert.False(InstallFolder.Combine(Consts.GameFolderFilesDir, (RelativePath)file).Exists);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var skipFiles = new []{"portable.txt"}.Select(e => (RelativePath)e).ToHashSet();
|
|
|
|
|
foreach (var destFile in InstallFolder.EnumerateFiles())
|
2019-10-29 21:30:27 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var relFile = destFile.RelativeTo(InstallFolder);
|
|
|
|
|
if (destFile.InFolder(Consts.LOOTFolderFilesDir.RelativeTo(MO2Folder)) || destFile.InFolder(Consts.GameFolderFilesDir.RelativeTo(MO2Folder)))
|
2019-10-29 21:30:27 +00:00
|
|
|
|
continue;
|
2020-01-06 23:08:19 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
if (!skipFiles.Contains(relFile))
|
|
|
|
|
Assert.True(MO2Folder.Combine(relFile).Exists, $"Only in Destination: {relFile}");
|
2019-10-29 21:30:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var skipExtensions = new []{".txt", ".ini"}.Select(e => new Extension(e)).ToHashSet();
|
2019-10-29 21:30:27 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
foreach (var srcFile in MO2Folder.EnumerateFiles())
|
2019-10-29 21:30:27 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var relFile = srcFile.RelativeTo(MO2Folder);
|
2019-10-29 21:30:27 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
if (relFile.StartsWith("downloads\\"))
|
2019-10-29 21:30:27 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var destFile = InstallFolder.Combine(relFile);
|
|
|
|
|
Assert.True(destFile.Exists, $"Only in Source: {relFile}");
|
2019-10-29 21:30:27 +00:00
|
|
|
|
|
2020-03-26 21:15:44 +00:00
|
|
|
|
if (!skipExtensions.Contains(srcFile.Extension))
|
2019-10-29 21:30:27 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
Assert.Equal(srcFile.Size, destFile.Size);
|
2020-05-25 17:34:25 +00:00
|
|
|
|
Assert.Equal(await srcFile.FileHashAsync(), await destFile.FileHashAsync());
|
2019-10-29 21:30:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-07 00:24:33 +00:00
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
public async ValueTask<AbsolutePath> AddGameFile(string path, int i)
|
2020-01-07 00:24:33 +00:00
|
|
|
|
{
|
2020-03-26 21:15:44 +00:00
|
|
|
|
var fullPath = GameFolder.Combine(path);
|
|
|
|
|
fullPath.Parent.CreateDirectory();
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await GenerateRandomFileData(fullPath, i);
|
2020-03-26 21:15:44 +00:00
|
|
|
|
return fullPath;
|
2020-01-07 00:24:33 +00:00
|
|
|
|
}
|
2019-09-24 04:20:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|