diff --git a/Wabbajack.Common/MessagePack.cs b/Wabbajack.Common/MessagePack.cs index fa7dfc7e..32ad9723 100644 --- a/Wabbajack.Common/MessagePack.cs +++ b/Wabbajack.Common/MessagePack.cs @@ -100,6 +100,12 @@ namespace Wabbajack.Common { public void Serialize(ref MessagePackWriter writer, RelativePath value, MessagePackSerializerOptions options) { + if (value == default) + { + writer.WriteString(new byte[0]); + return; + } + var encoded = Encoding.UTF8.GetBytes((string)value); writer.WriteString(encoded); } diff --git a/Wabbajack.Common/Paths.cs b/Wabbajack.Common/Paths.cs index ee53bfeb..21a46f2d 100644 --- a/Wabbajack.Common/Paths.cs +++ b/Wabbajack.Common/Paths.cs @@ -291,7 +291,7 @@ namespace Wabbajack.Common { if (useMove) { - File.Move(_path, dest._path); + File.Move(_path, dest._path, MoveOptions.ReplaceExisting); } else { @@ -329,10 +329,10 @@ namespace Wabbajack.Common public async Task WriteAllLinesAsync(params string[] strings) { - await WriteAllTextAsync(string.Join("\n",strings)); + await WriteAllTextAsync(string.Join("\r\n",strings)); } - public void WriteAllLines(string[] strings) + public void WriteAllLines(params string[] strings) { WriteAllText(string.Join("\n",strings)); } @@ -551,6 +551,11 @@ namespace Wabbajack.Common return Equals((Extension)obj); } + public override string ToString() + { + return _extension; + } + public override int GetHashCode() { return _extension != null ? _extension.GetHashCode() : 0; @@ -727,6 +732,7 @@ namespace Wabbajack.Common public static bool operator ==(FullPath a, FullPath b) { + if (a.Paths == null || b.Paths == null) return false; if (a.Base != b.Base || a.Paths.Length != b.Paths.Length) { return false; diff --git a/Wabbajack.Common/Utils.cs b/Wabbajack.Common/Utils.cs index d6725dcb..5be6d068 100644 --- a/Wabbajack.Common/Utils.cs +++ b/Wabbajack.Common/Utils.cs @@ -17,6 +17,8 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using ICSharpCode.SharpZipLib.BZip2; using IniParser; +using IniParser.Model.Configuration; +using IniParser.Parser; using Newtonsoft.Json; using ReactiveUI; using Wabbajack.Common.StatusFeed; @@ -50,13 +52,12 @@ namespace Wabbajack.Common static Utils() { - MessagePackInit(); - + LogFolder = Consts.LogsFolder; + LogFile = Consts.LogFile; Consts.LocalAppDataPath.CreateDirectory(); Consts.LogsFolder.CreateDirectory(); - LogFolder = Consts.LogsFolder; - LogFile = Consts.LogFile; + MessagePackInit(); _startTime = DateTime.Now; if (LogFile.Exists) @@ -65,7 +66,7 @@ namespace Wabbajack.Common LogFile.MoveTo(newPath, true); } - var logFiles = Consts.LogsFolder.EnumerateFiles(false).ToList(); + var logFiles = LogFolder.EnumerateFiles(false).ToList(); if (logFiles.Count >= Consts.MaxOldLogs) { Log($"Maximum amount of old logs reached ({logFiles.Count} >= {Consts.MaxOldLogs})"); @@ -156,6 +157,7 @@ namespace Wabbajack.Common public static void LogStraightToFile(string msg) { + if (LogFile == default) return; lock (_lock) { LogFile.AppendAllText($"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}\r\n"); @@ -315,6 +317,13 @@ namespace Wabbajack.Common } + private static IniDataParser IniParser() + { + var config = new IniParserConfiguration {AllowDuplicateKeys = true, AllowDuplicateSections = true}; + var parser = new IniDataParser(config); + return parser; + } + /// /// Loads INI data from the given filename and returns a dynamic type that @@ -324,7 +333,7 @@ namespace Wabbajack.Common /// public static dynamic LoadIniFile(this AbsolutePath file) { - return new DynamicIniData(new FileIniDataParser().ReadFile((string)file)); + return new DynamicIniData(new FileIniDataParser(IniParser()).ReadFile((string)file)); } /// @@ -334,7 +343,7 @@ namespace Wabbajack.Common /// public static dynamic LoadIniString(this string file) { - return new DynamicIniData(new FileIniDataParser().ReadData(new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(file))))); + return new DynamicIniData(new FileIniDataParser(IniParser()).ReadData(new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(file))))); } diff --git a/Wabbajack.Common/WorkQueue.cs b/Wabbajack.Common/WorkQueue.cs index bc794504..bc19521e 100644 --- a/Wabbajack.Common/WorkQueue.cs +++ b/Wabbajack.Common/WorkQueue.cs @@ -93,8 +93,10 @@ namespace Wabbajack.Common private async Task AddNewThreadsIfNeeded(int desired) { + var started = DateTime.Now; using (await _lock.Wait()) { + var end = DateTime.Now - started; DesiredNumWorkers = desired; while (DesiredNumWorkers > _tasks.Count) { @@ -141,8 +143,10 @@ namespace Wabbajack.Common if (DesiredNumWorkers >= _tasks.Count) continue; // Noticed that we may need to shut down, lock and check again + var start = DateTime.Now; using (await _lock.Wait()) { + var end = DateTime.Now - start; // Check if another thread shut down before this one and got us back to the desired amount already if (DesiredNumWorkers >= _tasks.Count) continue; diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index a982c52e..4e793b56 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -206,7 +206,7 @@ namespace Wabbajack.Lib Info("Building a list of archives based on the files required"); var hashes = InstallDirectives.OfType() - .Select(a => a.Hash) + .Select(a => a.ArchiveHashPath.BaseHash) .Distinct(); var archives = IndexedArchives.OrderByDescending(f => f.File.LastModified) diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index 2ba35dec..aa252c46 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -101,7 +101,7 @@ namespace Wabbajack.Lib ModList.Directives .Select(d => OutputFolder.Combine(d.To.Parent)) .Distinct() - .Do(f => OutputFolder.CreateDirectory()); + .Do(f => f.CreateDirectory()); } public async Task InstallArchives() @@ -336,12 +336,12 @@ namespace Wabbajack.Lib await OutputFolder.EnumerateFiles() .PMap(Queue, UpdateTracker, f => { - var relative_to = f.RelativeTo(OutputFolder); - Utils.Status($"Checking if ModList file {relative_to}"); - if (indexed.ContainsKey(relative_to) || f.InFolder(DownloadFolder)) + var relativeTo = f.RelativeTo(OutputFolder); + Utils.Status($"Checking if ModList file {relativeTo}"); + if (indexed.ContainsKey(relativeTo) || f.InFolder(DownloadFolder)) return; - Utils.Log($"Deleting {relative_to} it's not part of this ModList"); + Utils.Log($"Deleting {relativeTo} it's not part of this ModList"); f.Delete(); }); @@ -350,6 +350,7 @@ namespace Wabbajack.Lib .Select(f => f.RelativeTo(OutputFolder)) // We ignore the last part of the path, so we need a dummy file name .Append(DownloadFolder.Combine("_")) + .Where(f => f.InFolder(OutputFolder)) .SelectMany(path => { // Get all the folders and all the folder parents diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs index 79b93495..38fea0ff 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs @@ -27,7 +27,8 @@ namespace Wabbajack.Lib.CompilationSteps public override async ValueTask Run(RawSourceFile source) { - if (!_allEnabledMods.Any(mod => source.AbsolutePath.InFolder(mod))) + if (!source.AbsolutePath.InFolder(_mo2Compiler.MO2ModsFolder)) return null; + if (_allEnabledMods.Any(mod => source.AbsolutePath.InFolder(mod))) return null; var r = source.EvolveTo(); r.Reason = "Disabled Mod"; diff --git a/Wabbajack.Lib/Data.cs b/Wabbajack.Lib/Data.cs index 80223fc5..629ee077 100644 --- a/Wabbajack.Lib/Data.cs +++ b/Wabbajack.Lib/Data.cs @@ -140,6 +140,7 @@ namespace Wabbajack.Lib [Union(4, typeof(InlineFile))] [Union(5, typeof(PatchedFromArchive))] [Union(6, typeof(RemappedInlineFile))] + [Union(7, typeof(CleanedESM))] public abstract class Directive { [Key(0)] @@ -185,13 +186,17 @@ namespace Wabbajack.Lib /// /// File meant to be extracted before the installation /// + [MessagePackObject] public class PropertyFile : InlineFile { + [Key(4)] public PropertyType Type; } + [MessagePackObject] public class CleanedESM : InlineFile { + [Key(4)] public Hash SourceESMHash; } diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 8b1cf7be..d01dc66e 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -66,7 +66,7 @@ namespace Wabbajack.Lib { get { - if (_mo2DownloadsFolder != null) return _mo2DownloadsFolder; + if (_mo2DownloadsFolder != default) return _mo2DownloadsFolder; if (MO2Ini != null) if (MO2Ini.Settings != null) if (MO2Ini.Settings.download_directory != null) @@ -105,7 +105,7 @@ namespace Wabbajack.Lib if (cancel.IsCancellationRequested) return false; await VFS.IntegrateFromFile(VFSCacheName); - var roots = new List() + var roots = new List { MO2Folder, GamePath, MO2DownloadsFolder }; @@ -312,7 +312,7 @@ namespace Wabbajack.Lib Author = ModListAuthor ?? "", Description = ModListDescription ?? "", Readme = (string)ModListReadme, - Image = ModListImage.FileName, + Image = ModListImage != default ? ModListImage.FileName : default, Website = ModListWebsite != null ? new Uri(ModListWebsite) : null }; @@ -362,7 +362,7 @@ namespace Wabbajack.Lib async Task HasInvalidMeta(AbsolutePath filename) { var metaname = filename.WithExtension(Consts.MetaFileExtension); - if (metaname.Exists) return true; + if (!metaname.Exists) return true; return await DownloadDispatcher.ResolveArchive(metaname.LoadIniFile()) == null; } @@ -443,7 +443,7 @@ namespace Wabbajack.Lib }); var groups = InstallDirectives.OfType() - .Where(p => p.PatchID == null) + .Where(p => p.PatchID == default) .GroupBy(p => p.ArchiveHashPath.BaseHash) .ToList(); diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index 3d3f616f..1f30867a 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -330,7 +330,7 @@ namespace Wabbajack.Lib { var config = new IniParserConfiguration {AllowDuplicateKeys = true, AllowDuplicateSections = true}; foreach (var file in OutputFolder.Combine("profiles").EnumerateFiles() - .Where(f => ((string)f.FileName).EndsWith("*refs.ini"))) + .Where(f => ((string)f.FileName).EndsWith("refs.ini"))) { try { diff --git a/Wabbajack.Test/ACompilerTest.cs b/Wabbajack.Test/ACompilerTest.cs index eb3dfa1e..92f39091 100644 --- a/Wabbajack.Test/ACompilerTest.cs +++ b/Wabbajack.Test/ACompilerTest.cs @@ -13,15 +13,17 @@ namespace Wabbajack.Test public ITestOutputHelper TestContext { get; set; } protected TestUtils utils { get; set; } - public ACompilerTest() + public ACompilerTest(ITestOutputHelper helper) { + TestContext = helper; Helpers.Init(); Consts.TestMode = true; utils = new TestUtils(); utils.Game = Game.SkyrimSpecialEdition; - Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f.ShortDescription)); + DateTime startTime = DateTime.Now; + Utils.LogMessages.Subscribe(f => TestContext.WriteLine($"{DateTime.Now - startTime} - {f.ShortDescription}")); } @@ -43,6 +45,7 @@ namespace Wabbajack.Test protected async Task CompileAndInstall(string profile) { var compiler = await ConfigureAndRunCompiler(profile); + Utils.Log("Finished Compiling"); await Install(compiler); return compiler.ModList; } @@ -66,7 +69,7 @@ namespace Wabbajack.Test await installer.Begin(); } - private SystemParameters CreateDummySystemParameters() + protected SystemParameters CreateDummySystemParameters() { return new SystemParameters { diff --git a/Wabbajack.Test/SanityTests.cs b/Wabbajack.Test/SanityTests.cs index 9a171094..7baeeda7 100644 --- a/Wabbajack.Test/SanityTests.cs +++ b/Wabbajack.Test/SanityTests.cs @@ -1,92 +1,96 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using Compression.BSA; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Wabbajack.Common; using Wabbajack.Lib; using Wabbajack.Lib.CompilationSteps.CompilationErrors; +using Xunit; +using Xunit.Abstractions; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; namespace Wabbajack.Test { - [TestClass] public class SanityTests : ACompilerTest { - [TestMethod] - public async Task TestDirectMatch() + + public SanityTests(ITestOutputHelper helper) : base(helper) + { + } + + + [Fact] + public async Task TestDirectMatch() { var profile = utils.AddProfile(); var mod = utils.AddMod(); - var test_pex = utils.AddModFile(mod, @"Data\scripts\test.pex", 10); + var testPex = utils.AddModFile(mod, @"Data\scripts\test.pex", 10); - utils.Configure(); + await utils.Configure(); utils.AddManualDownload( - new Dictionary {{"/baz/biz.pex", File.ReadAllBytes(test_pex)}}); + new Dictionary {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}}); await CompileAndInstall(profile); utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex"); } - [TestMethod] + [Fact] public async Task TestDirectMatchFromGameFolder() { var profile = utils.AddProfile(); var mod = utils.AddMod(); - var test_pex = utils.AddGameFile(@"enbstuff\test.pex", 10); + var testPex = utils.AddGameFile(@"enbstuff\test.pex", 10); - utils.Configure(); + await utils.Configure(); utils.AddManualDownload( - new Dictionary {{"/baz/biz.pex", File.ReadAllBytes(test_pex)}}); + new Dictionary {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}}); await CompileAndInstall(profile); utils.VerifyInstalledGameFile(@"enbstuff\test.pex"); } - [TestMethod] + [Fact] public async Task TestDirectMatchIsIgnoredWhenGameFolderFilesOverrideExists() { var profile = utils.AddProfile(); var mod = utils.AddMod(); - var test_pex = utils.AddGameFile(@"enbstuff\test.pex", 10); + var testPex = utils.AddGameFile(@"enbstuff\test.pex", 10); - utils.Configure(); + await utils.Configure(); - Directory.CreateDirectory(Path.Combine(utils.MO2Folder, Consts.GameFolderFilesDir)); + utils.MO2Folder.Combine(Consts.GameFolderFilesDir).CreateDirectory(); utils.AddManualDownload( - new Dictionary {{"/baz/biz.pex", File.ReadAllBytes(test_pex)}}); + new Dictionary {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}}); await CompileAndInstall(profile); - Assert.IsFalse(File.Exists(Path.Combine(utils.InstallFolder, Consts.GameFolderFilesDir, @"enbstuff\test.pex"))); + Assert.False(utils.InstallFolder.Combine(Consts.GameFolderFilesDir, (RelativePath)@"enbstuff\test.pex").IsFile); } - [TestMethod] + [Fact] public async Task TestDuplicateFilesAreCopied() { var profile = utils.AddProfile(); var mod = utils.AddMod(); - var test_pex = utils.AddModFile(mod, @"Data\scripts\test.pex", 10); + var testPex = utils.AddModFile(mod, @"Data\scripts\test.pex", 10); // Make a copy to make sure it gets picked up and moved around. - File.Copy(test_pex, test_pex + ".copy"); + testPex.CopyTo(testPex.WithExtension(new Extension(".copy"))); - utils.Configure(); + await utils.Configure(); utils.AddManualDownload( - new Dictionary { { "/baz/biz.pex", File.ReadAllBytes(test_pex) } }); + new Dictionary { { "/baz/biz.pex", await testPex.ReadAllBytesAsync() } }); await CompileAndInstall(profile); @@ -94,7 +98,7 @@ namespace Wabbajack.Test utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex.copy"); } - [TestMethod] + [Fact] public async Task TestUpdating() { @@ -104,14 +108,14 @@ namespace Wabbajack.Test var deleted = utils.AddModFile(mod, @"Data\scripts\deleted.pex", 10); var modified = utils.AddModFile(mod, @"Data\scripts\modified.pex", 10); - utils.Configure(); + await utils.Configure(); utils.AddManualDownload( new Dictionary { - { "/baz/unchanged.pex", File.ReadAllBytes(unchanged) }, - { "/baz/deleted.pex", File.ReadAllBytes(deleted) }, - { "/baz/modified.pex", File.ReadAllBytes(modified) }, + { "/baz/unchanged.pex", await unchanged.ReadAllBytesAsync() }, + { "/baz/deleted.pex", await deleted.ReadAllBytesAsync() }, + { "/baz/modified.pex", await modified.ReadAllBytesAsync() }, }); await CompileAndInstall(profile); @@ -120,51 +124,52 @@ namespace Wabbajack.Test utils.VerifyInstalledFile(mod, @"Data\scripts\deleted.pex"); utils.VerifyInstalledFile(mod, @"Data\scripts\modified.pex"); - var unchanged_path = utils.PathOfInstalledFile(mod, @"Data\scripts\unchanged.pex"); - var deleted_path = utils.PathOfInstalledFile(mod, @"Data\scripts\deleted.pex"); - var modified_path = utils.PathOfInstalledFile(mod, @"Data\scripts\modified.pex"); + var unchangedPath = utils.PathOfInstalledFile(mod, @"Data\scripts\unchanged.pex"); + var deletedPath = utils.PathOfInstalledFile(mod, @"Data\scripts\deleted.pex"); + var modifiedPath = utils.PathOfInstalledFile(mod, @"Data\scripts\modified.pex"); - var extra_path = utils.PathOfInstalledFile(mod, @"something_i_made.foo"); - File.WriteAllText(extra_path, "bleh"); + var extraPath = utils.PathOfInstalledFile(mod, @"something_i_made.foo"); + await extraPath.WriteAllTextAsync("bleh"); - var extra_folder = Path.Combine(Path.GetDirectoryName(utils.PathOfInstalledFile(mod, @"something_i_made.foo")), "folder_i_made"); - Directory.CreateDirectory(extra_folder); + var extraFolder = utils.PathOfInstalledFile(mod, @"something_i_made.foo").Parent.Combine("folder_i_made"); + extraFolder.CreateDirectory(); - Assert.IsTrue(Directory.Exists(extra_folder)); + Assert.True(extraFolder.IsDirectory); - var unchanged_modified = File.GetLastWriteTime(unchanged_path); - var modified_modified = File.GetLastWriteTime(modified_path); + var unchangedModified = unchangedPath.LastModified; - File.WriteAllText(modified_path, "random data"); - File.Delete(deleted_path); + await modifiedPath.WriteAllTextAsync("random data"); + var modifiedModified = modifiedPath.LastModified; - Assert.IsTrue(File.Exists(extra_path)); + deletedPath.Delete(); + Assert.True(extraPath.Exists); + await CompileAndInstall(profile); utils.VerifyInstalledFile(mod, @"Data\scripts\unchanged.pex"); utils.VerifyInstalledFile(mod, @"Data\scripts\deleted.pex"); utils.VerifyInstalledFile(mod, @"Data\scripts\modified.pex"); - Assert.AreEqual(unchanged_modified, File.GetLastWriteTime(unchanged_path)); - Assert.AreNotEqual(modified_modified, File.GetLastWriteTime(modified_path)); - Assert.IsFalse(File.Exists(extra_path)); - Assert.IsFalse(Directory.Exists(extra_folder)); + Assert.Equal(unchangedModified, unchangedPath.LastModified); + Assert.NotEqual(modifiedModified, modifiedPath.LastModified); + Assert.False(extraPath.Exists); + Assert.False(extraFolder.Exists); } - [TestMethod] + [Fact] public async Task CleanedESMTest() { var profile = utils.AddProfile(); var mod = utils.AddMod("Cleaned ESMs"); - var update_esm = utils.AddModFile(mod, @"Update.esm", 10); + var updateEsm = utils.AddModFile(mod, @"Update.esm", 10); - utils.Configure(); + await utils.Configure(); - var game_file = Path.Combine(utils.GameFolder, "Data", "Update.esm"); - utils.GenerateRandomFileData(game_file, 20); + var gameFile = utils.GameFolder.Combine("Data", "Update.esm"); + utils.GenerateRandomFileData(gameFile, 20); var modlist = await CompileAndInstall(profile); @@ -173,65 +178,62 @@ namespace Wabbajack.Test var compiler = await ConfigureAndRunCompiler(profile); // Update the file and verify that it throws an error. - utils.GenerateRandomFileData(game_file, 20); - var exception = await Assert.ThrowsExceptionAsync(async () => await Install(compiler)); - Assert.IsInstanceOfType(exception, typeof(InvalidGameESMError)); + utils.GenerateRandomFileData(gameFile, 20); + var exception = await Assert.ThrowsAsync(async () => await Install(compiler)); + Assert.IsAssignableFrom(exception); } - [TestMethod] + [Fact] public async Task SetScreenSizeTest() { var profile = utils.AddProfile(); var mod = utils.AddMod("dummy"); - utils.Configure(); - File.WriteAllLines(Path.Combine(utils.MO2Folder, "profiles", profile, "somegameprefs.ini"), - new List - { - // Beth inis are messy, let's make ours just as messy to catch some parse failures - "[Display]", - "foo=4", - "[Display]", - "STestFile=f", - "STestFile=", - "iSize H=3", - "iSize W=-200", - "[Display]", - "foo=4", - "[MEMORY]", - "VideoMemorySizeMb=22" - }); + await utils.Configure(); + await utils.MO2Folder.Combine("profiles", profile, "somegameprefs.ini").WriteAllLinesAsync( + // Beth inis are messy, let's make ours just as messy to catch some parse failures + "[Display]", + "foo=4", + "[Display]", + "STestFile=f", + "STestFile=", + "[Display]", + "foo=4", + "iSize H=50", + "iSize W=100", + "[MEMORY]", + "VideoMemorySizeMb=22"); var modlist = await CompileAndInstall(profile); - var ini = Path.Combine(utils.InstallFolder, "profiles", profile, "somegameprefs.ini").LoadIniFile(); + var ini = utils.InstallFolder.Combine("profiles", profile, "somegameprefs.ini").LoadIniFile(); - var sysinfo = SystemParametersConstructor.Create(); + var sysinfo = CreateDummySystemParameters(); - Assert.AreEqual(System.Windows.SystemParameters.PrimaryScreenHeight.ToString(), ini?.Display?["iSize H"]); - Assert.AreEqual(System.Windows.SystemParameters.PrimaryScreenWidth.ToString(), ini?.Display?["iSize W"]); - Assert.AreEqual(sysinfo.EnbLEVRAMSize.ToString(), ini?.MEMORY?["VideoMemorySizeMb"]); + Assert.Equal(sysinfo.ScreenHeight.ToString(), ini?.Display?["iSize H"]); + Assert.Equal(sysinfo.ScreenWidth.ToString(), ini?.Display?["iSize W"]); + Assert.Equal(sysinfo.EnbLEVRAMSize.ToString(), ini?.MEMORY?["VideoMemorySizeMb"]); } - [TestMethod] + [Fact] public async Task UnmodifiedInlinedFilesArePulledFromArchives() { var profile = utils.AddProfile(); var mod = utils.AddMod(); var ini = utils.AddModFile(mod, @"foo.ini", 10); - utils.Configure(); + await utils.Configure(); utils.AddManualDownload( - new Dictionary { { "/baz/biz.pex", File.ReadAllBytes(ini) } }); + new Dictionary { { "/baz/biz.pex", await ini.ReadAllBytesAsync() } }); var modlist = await CompileAndInstall(profile); - var directive = modlist.Directives.Where(m => m.To == $"mods\\{mod}\\foo.ini").FirstOrDefault(); + var directive = modlist.Directives.FirstOrDefault(m => m.To == (RelativePath)$"mods\\{mod}\\foo.ini"); - Assert.IsNotNull(directive); - Assert.IsInstanceOfType(directive, typeof(FromArchive)); + Assert.NotNull(directive); + Assert.IsAssignableFrom(directive); } - [TestMethod] + [Fact] public async Task ModifiedIniFilesArePatchedAgainstFileWithSameName() { var profile = utils.AddProfile(); @@ -239,26 +241,25 @@ namespace Wabbajack.Test var ini = utils.AddModFile(mod, @"foo.ini", 10); var meta = utils.AddModFile(mod, "meta.ini"); - utils.Configure(); + await utils.Configure(); var archive = utils.AddManualDownload( - new Dictionary { { "/baz/foo.ini", File.ReadAllBytes(ini) } }); + new Dictionary { { "/baz/foo.ini", await ini.ReadAllBytesAsync() } }); - File.WriteAllLines(meta, new[] - { + await meta.WriteAllLinesAsync( "[General]", - $"installationFile={archive}", - }); + $"installationFile={archive}"); // Modify after creating mod archive in the downloads folder - File.WriteAllText(ini, "Wabbajack, Wabbajack, Wabbajack!"); + await ini.WriteAllTextAsync("Wabbajack, Wabbajack, Wabbajack!"); var modlist = await CompileAndInstall(profile); - var directive = modlist.Directives.Where(m => m.To == $"mods\\{mod}\\foo.ini").FirstOrDefault(); + var directive = modlist.Directives.FirstOrDefault(m => m.To == (RelativePath)$"mods\\{mod}\\foo.ini"); - Assert.IsNotNull(directive); - Assert.IsInstanceOfType(directive, typeof(PatchedFromArchive)); + Assert.NotNull(directive); + Assert.IsAssignableFrom(directive); } + } } diff --git a/Wabbajack.Test/TestUtils.cs b/Wabbajack.Test/TestUtils.cs index ef65234e..5efdb7a1 100644 --- a/Wabbajack.Test/TestUtils.cs +++ b/Wabbajack.Test/TestUtils.cs @@ -44,13 +44,11 @@ namespace Wabbajack.Test public async Task Configure() { - await MO2Folder.Combine("ModOrganizer.ini").WriteAllLinesAsync(new [] - { - "[General]", - $"gameName={Game.MetaData().MO2Name}", - $"gamePath={((string)GameFolder).Replace("\\", "\\\\")}", - $"download_directory={DownloadsFolder}" - }); + await MO2Folder.Combine("ModOrganizer.ini").WriteAllLinesAsync( + "[General]", + $"gameName={Game.MetaData().MO2Name}", + $"gamePath={((string)GameFolder).Replace("\\", "\\\\")}", + $"download_directory={DownloadsFolder}"); DownloadsFolder.CreateDirectory(); GameFolder.Combine("Data").CreateDirectory(); @@ -157,12 +155,9 @@ namespace Wabbajack.Test }); DownloadsFolder.Combine(name + Consts.MetaFileExtension).WriteAllLines( - - new string[] - { "[General]", "manualURL=" - }); + ); return name; } @@ -173,7 +168,7 @@ namespace Wabbajack.Test Assert.True(src.Exists); var dest = InstallFolder.Combine((string)Consts.MO2ModFolderName, mod, file); - Assert.True(src.Exists); + Assert.True(dest.Exists, $"Destination {dest} doesn't exist"); var srcData = src.ReadAllBytes(); var destData = dest.ReadAllBytes(); diff --git a/Wabbajack.Test/Wabbajack.Test.csproj b/Wabbajack.Test/Wabbajack.Test.csproj index d3050e69..4d5f9691 100644 --- a/Wabbajack.Test/Wabbajack.Test.csproj +++ b/Wabbajack.Test/Wabbajack.Test.csproj @@ -20,8 +20,6 @@ - - diff --git a/Wabbajack.VirtualFileSystem/Context.cs b/Wabbajack.VirtualFileSystem/Context.cs index 6da9785f..5d6c8853 100644 --- a/Wabbajack.VirtualFileSystem/Context.cs +++ b/Wabbajack.VirtualFileSystem/Context.cs @@ -243,21 +243,15 @@ namespace Wabbajack.VirtualFileSystem public async Task BackfillMissing() { - var newFiles = _knownFiles.Where(f => f.Paths.Length == 0) - .GroupBy(f => f.BaseHash) - .ToDictionary(f => f.Key, s => new VirtualFile() - { - Name = s.First().Paths[0], - Hash = s.First().BaseHash, - Context = this - }); + var newFiles = _knownArchives.ToDictionary(kv => kv.Key, + kv => new VirtualFile {Name = kv.Value, Size = kv.Value.Size, Hash = kv.Key}); var parentchild = new Dictionary<(VirtualFile, RelativePath), VirtualFile>(); void BackFillOne(HashRelativePath file) { var parent = newFiles[file.BaseHash]; - foreach (var path in file.Paths.Skip(1)) + foreach (var path in file.Paths) { if (parentchild.TryGetValue((parent, path), out var foundParent)) { @@ -271,7 +265,7 @@ namespace Wabbajack.VirtualFileSystem parent = nf; } } - _knownFiles.Where(f => f.Paths.Length > 1).Do(BackFillOne); + _knownFiles.Where(f => f.Paths.Length > 0).Do(BackFillOne); var newIndex = await Index.Integrate(newFiles.Values.ToList()); diff --git a/Wabbajack.sln b/Wabbajack.sln index bac714d9..eb8e9c6a 100644 --- a/Wabbajack.sln +++ b/Wabbajack.sln @@ -38,7 +38,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.CLI", "Wabbajack. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.Launcher", "Wabbajack.Launcher\Wabbajack.Launcher.csproj", "{D6856DBF-C959-4867-A8A8-343DA2D2715E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Common.Test", "Wabbajack.Common.Test\Wabbajack.Common.Test.csproj", "{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.Common.Test", "Wabbajack.Common.Test\Wabbajack.Common.Test.csproj", "{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -124,14 +124,12 @@ Global {D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|Any CPU.Build.0 = Release|Any CPU {D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|x64.ActiveCfg = Release|Any CPU {D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|x64.Build.0 = Release|Any CPU - {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|Any CPU.Build.0 = Release|Any CPU - {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.ActiveCfg = Release|Any CPU - {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.Build.0 = Release|Any CPU + {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|Any CPU.ActiveCfg = Debug|x64 {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|x64.ActiveCfg = Debug|x64 {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|x64.Build.0 = Debug|x64 + {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|Any CPU.ActiveCfg = Release|x64 + {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.ActiveCfg = Release|x64 + {BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE