using System; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.IO.Compression; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Microsoft.VisualStudio.TestTools.UnitTesting; using Wabbajack.Common; 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 Wabbajack.Test { public class TestUtils : IDisposable { public TestUtils() { RNG = new Random(); ID = RandomName(); WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "tmp_data"); } public string WorkingDirectory { get;} public string ID { get; } public Random RNG { get; } public string GameName { get; set; } public string TestFolder => Path.Combine(WorkingDirectory, ID); public string GameFolder => Path.Combine(WorkingDirectory, ID, "game_folder"); public string MO2Folder => Path.Combine(WorkingDirectory, ID, "mo2_folder"); public string ModsFolder => Path.Combine(MO2Folder, "mods"); public string DownloadsFolder => Path.Combine(MO2Folder, "downloads"); public string InstallFolder => Path.Combine(TestFolder, "installed"); public void Configure() { File.WriteAllLines(Path.Combine(MO2Folder, "ModOrganizer.ini"), new [] { "[General]", $"gameName={GameName}", $"gamePath={GameFolder.Replace("\\", "\\\\")}", $"download_directory={DownloadsFolder}" }); Directory.CreateDirectory(DownloadsFolder); Directory.CreateDirectory(Path.Combine(GameFolder, "Data")); Profiles.Do(profile => { File.WriteAllLines(Path.Combine(MO2Folder, "profiles", profile, "modlist.txt"), Mods.Select(s => $"+{s}").ToArray()); }); } public string AddProfile(string name = null) { string profile_name = name ?? RandomName(); Directory.CreateDirectory(Path.Combine(MO2Folder, "profiles", profile_name)); Profiles.Add(profile_name); return profile_name; } public HashSet Profiles = new HashSet(); public string AddMod(string name = null) { string mod_name = name ?? RandomName(); var mod_folder = Path.Combine(MO2Folder, "mods", mod_name); Directory.CreateDirectory(mod_folder); File.WriteAllText(Path.Combine(mod_folder, "meta.ini"), "[General]"); Mods.Add(mod_name); return mod_name; } public List Mods = new List(); /// /// Adds a file to the given mod with a given path in the mod. Fills it with random data unless /// random_fill == 0; /// /// /// /// /// public string AddModFile(string mod_name, string path, int random_fill=128) { var full_path = Path.Combine(ModsFolder, mod_name, path); Directory.CreateDirectory(Path.GetDirectoryName(full_path)); GenerateRandomFileData(full_path, random_fill); return full_path; } public void GenerateRandomFileData(string full_path, int random_fill) { byte[] bytes = new byte[0]; if (random_fill != 0) { bytes = new byte[random_fill]; RNG.NextBytes(bytes); } File.WriteAllBytes(full_path, bytes); } public void Dispose() { var exts = new [] {".md", ".exe"}; Directory.Delete(Path.Combine(WorkingDirectory, ID), true); Profiles.Do(p => { foreach (var ext in exts) { var path = Path.Combine(Directory.GetCurrentDirectory(), p + ext); if (File.Exists(path)) File.Delete(path); } }); } /// /// Returns a random string name (with spaces) /// private char[] _nameChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+=-_ ".ToCharArray(); public string RandomName() { return Guid.NewGuid().ToString(); } public string AddManualDownload(Dictionary contents) { var name = RandomName() + ".zip"; using(FileStream fs = new FileStream(Path.Combine(DownloadsFolder, name), FileMode.Create)) using (ZipArchive archive = new ZipArchive(fs, ZipArchiveMode.Create)) { contents.Do(kv => { var entry = archive.CreateEntry(kv.Key); using (var os = entry.Open()) os.Write(kv.Value, 0, kv.Value.Length); }); } File.WriteAllLines(Path.Combine(DownloadsFolder, name+".meta"), new string[] { "[General]", "manualURL=" }); return name; } public void VerifyInstalledFile(string mod, string file) { var src = Path.Combine(MO2Folder, "mods", mod, file); Assert.IsTrue(File.Exists(src), src); var dest = Path.Combine(InstallFolder, "mods", mod, file); Assert.IsTrue(File.Exists(dest), dest); var src_data = File.ReadAllBytes(src); var dest_data = File.ReadAllBytes(dest); Assert.AreEqual(src_data.Length, dest_data.Length); for(int x = 0; x < src_data.Length; x++) { if (src_data[x] != dest_data[x]) Assert.Fail($"Index {x} of {mod}\\{file} are not the same"); } } public void VerifyAllFiles() { foreach (var dest_file in Directory.EnumerateFiles(InstallFolder, "*", DirectoryEnumerationOptions.Recursive)) { var rel_file = dest_file.RelativeTo(InstallFolder); if (rel_file.StartsWith(Consts.LOOTFolderFilesDir) || rel_file.StartsWith(Consts.GameFolderFilesDir)) continue; Assert.IsTrue(File.Exists(Path.Combine(MO2Folder, rel_file)), $"Only in Destination: {rel_file}"); } var skip_extensions = new HashSet {".txt", ".ini"}; foreach (var src_file in Directory.EnumerateFiles(MO2Folder, "*", DirectoryEnumerationOptions.Recursive)) { var rel_file = src_file.RelativeTo(MO2Folder); if (rel_file.StartsWith("downloads\\")) continue; var dest_file = Path.Combine(InstallFolder, rel_file); Assert.IsTrue(File.Exists(dest_file), $"Only in Source: {rel_file}"); var fi_src = new FileInfo(src_file); var fi_dest = new FileInfo(dest_file); if (!skip_extensions.Contains(Path.GetExtension(src_file))) { Assert.AreEqual(fi_src.Length, fi_dest.Length, $"Differing sizes {rel_file}"); Assert.AreEqual(src_file.FileHash(), dest_file.FileHash(), $"Differing content hash {rel_file}"); } } } } }