From 76609fcb3634350807a331478501114c8d9cbcf0 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Sat, 14 Mar 2026 11:50:37 +0100 Subject: [PATCH 1/2] cleanup --- AssetEditor.sln | 17 ++ AssetEditor/App.xaml.cs | 2 +- AssetEditor/AssetEditor.csproj | 1 + AssetEditor/DependencyInjectionContainer.cs | 7 - .../Services/DependencyInjectionConfig.cs | 1 + AssetEditor/Services/EditorManager.cs | 23 +- .../Ipc/IpcEditor}/AssetEditorIpcServer.cs | 8 +- .../IpcEditor/DependencyInjectionContainer.cs | 24 ++ Editors/Ipc/IpcEditor/Editors.Ipc.csproj | 16 ++ .../IpcEditor}/ExternalFileOpenExecutor.cs | 8 +- .../Ipc/IpcEditor}/ExternalPackFileLookup.cs | 4 +- .../Ipc/IpcEditor}/ExternalPackLoader.cs | 9 +- .../IpcEditor}/IExternalFileOpenExecutor.cs | 6 +- .../Ipc/IpcEditor}/IIpcRequestHandler.cs | 6 +- .../Ipc/IpcEditor}/IpcRequest.cs | 2 +- .../Ipc/IpcEditor}/IpcRequestHandler.cs | 7 +- .../Ipc/IpcEditor}/IpcResponse.cs | 2 +- .../Ipc/IpcEditor}/IpcUserNotifier.cs | 6 +- .../Ipc/IpcEditor}/PackPathResolver.cs | 4 +- .../Test.Ipc/ExternalFileOpenExecutorTests.cs | 59 +++++ .../Ipc/Test.Ipc/IpcRequestHandlerTests.cs | 238 ++++++++++++++++++ Editors/Ipc/Test.Ipc/PackPathResolverTests.cs | 39 +++ Editors/Ipc/Test.Ipc/Test.Ipc.csproj | 22 ++ .../ToolCreation/IEditorInterface.cs | 19 ++ .../Ipc/ExternalFileOpenExecutorTests.cs | 2 +- .../Ipc/IpcRequestHandlerTests.cs | 2 +- 26 files changed, 467 insertions(+), 67 deletions(-) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/AssetEditorIpcServer.cs (97%) create mode 100644 Editors/Ipc/IpcEditor/DependencyInjectionContainer.cs create mode 100644 Editors/Ipc/IpcEditor/Editors.Ipc.csproj rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/ExternalFileOpenExecutor.cs (93%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/ExternalPackFileLookup.cs (86%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/ExternalPackLoader.cs (96%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/IExternalFileOpenExecutor.cs (60%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/IIpcRequestHandler.cs (87%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/IpcRequest.cs (89%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/IpcRequestHandler.cs (96%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/IpcResponse.cs (92%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/IpcUserNotifier.cs (90%) rename {AssetEditor/Services/Ipc => Editors/Ipc/IpcEditor}/PackPathResolver.cs (96%) create mode 100644 Editors/Ipc/Test.Ipc/ExternalFileOpenExecutorTests.cs create mode 100644 Editors/Ipc/Test.Ipc/IpcRequestHandlerTests.cs create mode 100644 Editors/Ipc/Test.Ipc/PackPathResolverTests.cs create mode 100644 Editors/Ipc/Test.Ipc/Test.Ipc.csproj diff --git a/AssetEditor.sln b/AssetEditor.sln index b1c6a54de..0234a8c21 100644 --- a/AssetEditor.sln +++ b/AssetEditor.sln @@ -102,6 +102,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetEditorUpdater", "Asset EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetEditorTests", "Testing\AssetEditorTests\AssetEditorTests.csproj", "{4E51AFDA-E5D2-9D14-22C8-F790FE265A65}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ipc", "Ipc", "{60CD305C-A8D3-460D-9620-4B60E9BB0894}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Editors.Ipc", "Editors\Ipc\IpcEditor\Editors.Ipc.csproj", "{8F022F40-E780-42CD-BB81-D59E9DAFC111}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Ipc", "Editors\Ipc\Test.Ipc\Test.Ipc.csproj", "{34E82457-C19B-4EEF-B901-0E7CF1D97BCE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -240,6 +246,14 @@ Global {4E51AFDA-E5D2-9D14-22C8-F790FE265A65}.Debug|Any CPU.Build.0 = Debug|Any CPU {4E51AFDA-E5D2-9D14-22C8-F790FE265A65}.Release|Any CPU.ActiveCfg = Release|Any CPU {4E51AFDA-E5D2-9D14-22C8-F790FE265A65}.Release|Any CPU.Build.0 = Release|Any CPU + {8F022F40-E780-42CD-BB81-D59E9DAFC111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F022F40-E780-42CD-BB81-D59E9DAFC111}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F022F40-E780-42CD-BB81-D59E9DAFC111}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F022F40-E780-42CD-BB81-D59E9DAFC111}.Release|Any CPU.Build.0 = Release|Any CPU + {34E82457-C19B-4EEF-B901-0E7CF1D97BCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34E82457-C19B-4EEF-B901-0E7CF1D97BCE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34E82457-C19B-4EEF-B901-0E7CF1D97BCE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34E82457-C19B-4EEF-B901-0E7CF1D97BCE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -286,6 +300,9 @@ Global {0FCE7A0E-6478-A603-6491-6FE675F54000} = {3123DC8F-5FAD-45A9-8DCC-7C5E0E61FAEB} {E759BE6D-E0A4-46B8-A02A-E8573F579E2F} = {3123DC8F-5FAD-45A9-8DCC-7C5E0E61FAEB} {4E51AFDA-E5D2-9D14-22C8-F790FE265A65} = {18424B6A-CB8A-4CE1-935C-72459F31521B} + {60CD305C-A8D3-460D-9620-4B60E9BB0894} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0} + {8F022F40-E780-42CD-BB81-D59E9DAFC111} = {60CD305C-A8D3-460D-9620-4B60E9BB0894} + {34E82457-C19B-4EEF-B901-0E7CF1D97BCE} = {60CD305C-A8D3-460D-9620-4B60E9BB0894} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AB5968F3-98ED-4AFF-98EA-0DBEDCACADF2} diff --git a/AssetEditor/App.xaml.cs b/AssetEditor/App.xaml.cs index b436aebf1..73f294bd6 100644 --- a/AssetEditor/App.xaml.cs +++ b/AssetEditor/App.xaml.cs @@ -4,11 +4,11 @@ using System.Windows; using System.Windows.Threading; using AssetEditor.Services; -using AssetEditor.Services.Ipc; using AssetEditor.UiCommands; using AssetEditor.ViewModels; using AssetEditor.Views; using CommunityToolkit.Diagnostics; +using Editors.Ipc; using Microsoft.Extensions.DependencyInjection; using Shared.Core.DependencyInjection; using Shared.Core.DevConfig; diff --git a/AssetEditor/AssetEditor.csproj b/AssetEditor/AssetEditor.csproj index 872a8aec1..0f7f43d23 100644 --- a/AssetEditor/AssetEditor.csproj +++ b/AssetEditor/AssetEditor.csproj @@ -19,6 +19,7 @@ + diff --git a/AssetEditor/DependencyInjectionContainer.cs b/AssetEditor/DependencyInjectionContainer.cs index a8fde5af5..9633f055f 100644 --- a/AssetEditor/DependencyInjectionContainer.cs +++ b/AssetEditor/DependencyInjectionContainer.cs @@ -1,5 +1,4 @@ using AssetEditor.Services; -using AssetEditor.Services.Ipc; using AssetEditor.UiCommands; using AssetEditor.ViewModels; using AssetEditor.Views; @@ -31,12 +30,6 @@ public override void Register(IServiceCollection serviceCollection) serviceCollection.AddTransient(); serviceCollection.AddTransient(); serviceCollection.AddTransient(); - serviceCollection.AddTransient(); - serviceCollection.AddTransient(); - serviceCollection.AddTransient(); - serviceCollection.AddTransient(); - serviceCollection.AddTransient(); - serviceCollection.AddSingleton(); serviceCollection.AddTransient(); serviceCollection.AddTransient(); diff --git a/AssetEditor/Services/DependencyInjectionConfig.cs b/AssetEditor/Services/DependencyInjectionConfig.cs index 470e40da1..fd9bd917b 100644 --- a/AssetEditor/Services/DependencyInjectionConfig.cs +++ b/AssetEditor/Services/DependencyInjectionConfig.cs @@ -34,6 +34,7 @@ public DependencyInjectionConfig(bool loadResources = true) new Editor.VisualSkeletonEditor.DependencyInjectionContainer(), new Editors.AnimatioReTarget.DependencyInjectionContainer(), new Editors.Twui.DependencyInjectionContainer(), + new Editors.Ipc.DependencyInjectionContainer(), // Host application new DependencyInjectionContainer(), diff --git a/AssetEditor/Services/EditorManager.cs b/AssetEditor/Services/EditorManager.cs index e8efb3988..5da794368 100644 --- a/AssetEditor/Services/EditorManager.cs +++ b/AssetEditor/Services/EditorManager.cs @@ -15,21 +15,6 @@ namespace AssetEditor.Services { - public interface IEditorManager : IEditorCreator - { - IList GetAllEditors(); - int GetCurrentEditor(); - - public void CloseTool(IEditorInterface tool); - public bool ShouldBlockCloseCommand(IEditorInterface editor, bool hasUnsavedFiles); - - public void CloseOtherTools(IEditorInterface tool); - public void CloseAllTools(IEditorInterface tool); - public void CloseToolsToLeft(IEditorInterface tool); - public void CloseToolsToRight(IEditorInterface tool); - public bool Drop(IEditorInterface node, IEditorInterface targetNode = default, bool insertAfterTargetNode = default); - } - public partial class EditorManager : ObservableObject, IEditorManager { private readonly ILogger _logger = Logging.Create(); @@ -51,6 +36,14 @@ public EditorManager(IGlobalEventHub eventHub, IPackFileService packFileService, public IList GetAllEditors() => CurrentEditorsList; public int GetCurrentEditor() => SelectedEditorIndex; + + public void SetEditorAsCurrent(IEditorInterface editor) + { + var index = CurrentEditorsList.IndexOf(editor); + if (index >= 0) + SelectedEditorIndex = index; + } + public IEditorInterface CreateFromFile(PackFile file, EditorEnums? preferedEditor) { if (file == null) diff --git a/AssetEditor/Services/Ipc/AssetEditorIpcServer.cs b/Editors/Ipc/IpcEditor/AssetEditorIpcServer.cs similarity index 97% rename from AssetEditor/Services/Ipc/AssetEditorIpcServer.cs rename to Editors/Ipc/IpcEditor/AssetEditorIpcServer.cs index 1326f65ed..023198e6a 100644 --- a/AssetEditor/Services/Ipc/AssetEditorIpcServer.cs +++ b/Editors/Ipc/IpcEditor/AssetEditorIpcServer.cs @@ -1,16 +1,12 @@ -using System; -using System.IO; -using System.IO.Pipes; +using System.IO.Pipes; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; -using System.Threading; -using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Serilog; using Shared.Core.ErrorHandling; -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public class AssetEditorIpcServer : IDisposable { diff --git a/Editors/Ipc/IpcEditor/DependencyInjectionContainer.cs b/Editors/Ipc/IpcEditor/DependencyInjectionContainer.cs new file mode 100644 index 000000000..8d5e98394 --- /dev/null +++ b/Editors/Ipc/IpcEditor/DependencyInjectionContainer.cs @@ -0,0 +1,24 @@ +using Microsoft.Extensions.DependencyInjection; +using Shared.Core.DependencyInjection; +using Shared.Core.ToolCreation; + +namespace Editors.Ipc +{ + public class DependencyInjectionContainer : DependencyContainer + { + public override void Register(IServiceCollection serviceCollection) + { + serviceCollection.AddTransient(); + serviceCollection.AddTransient(); + serviceCollection.AddTransient(); + serviceCollection.AddTransient(); + serviceCollection.AddTransient(); + serviceCollection.AddSingleton(); + } + + public override void RegisterTools(IEditorDatabase factory) + { + + } + } +} diff --git a/Editors/Ipc/IpcEditor/Editors.Ipc.csproj b/Editors/Ipc/IpcEditor/Editors.Ipc.csproj new file mode 100644 index 000000000..590d8d600 --- /dev/null +++ b/Editors/Ipc/IpcEditor/Editors.Ipc.csproj @@ -0,0 +1,16 @@ + + + + net10.0-windows + enable + enable + + + + + + + + + + diff --git a/AssetEditor/Services/Ipc/ExternalFileOpenExecutor.cs b/Editors/Ipc/IpcEditor/ExternalFileOpenExecutor.cs similarity index 93% rename from AssetEditor/Services/Ipc/ExternalFileOpenExecutor.cs rename to Editors/Ipc/IpcEditor/ExternalFileOpenExecutor.cs index 0cb369b5b..14516a27c 100644 --- a/AssetEditor/Services/Ipc/ExternalFileOpenExecutor.cs +++ b/Editors/Ipc/IpcEditor/ExternalFileOpenExecutor.cs @@ -11,7 +11,7 @@ using Shared.Core.PackFiles.Models; using Shared.Core.ToolCreation; -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public class ExternalFileOpenExecutor : IExternalFileOpenExecutor { @@ -106,12 +106,10 @@ private bool TryImportIntoExistingKitbash(PackFile file) private void SelectEditor(IEditorInterface editor) { - if (_editorManager is not EditorManager concreteEditorManager) + if (_editorManager is not IEditorManager concreteEditorManager) return; - var index = concreteEditorManager.CurrentEditorsList.IndexOf(editor); - if (index >= 0) - concreteEditorManager.SelectedEditorIndex = index; + _editorManager.SetEditorAsCurrent(editor); } public static bool ShouldForceKitbash(PackFile file) diff --git a/AssetEditor/Services/Ipc/ExternalPackFileLookup.cs b/Editors/Ipc/IpcEditor/ExternalPackFileLookup.cs similarity index 86% rename from AssetEditor/Services/Ipc/ExternalPackFileLookup.cs rename to Editors/Ipc/IpcEditor/ExternalPackFileLookup.cs index 50272e5d4..df9f76eb6 100644 --- a/AssetEditor/Services/Ipc/ExternalPackFileLookup.cs +++ b/Editors/Ipc/IpcEditor/ExternalPackFileLookup.cs @@ -1,7 +1,7 @@ -using Shared.Core.PackFiles; +using Shared.Core.PackFiles; using Shared.Core.PackFiles.Models; -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public class ExternalPackFileLookup : IExternalPackFileLookup { diff --git a/AssetEditor/Services/Ipc/ExternalPackLoader.cs b/Editors/Ipc/IpcEditor/ExternalPackLoader.cs similarity index 96% rename from AssetEditor/Services/Ipc/ExternalPackLoader.cs rename to Editors/Ipc/IpcEditor/ExternalPackLoader.cs index 8ce3018f1..e688481df 100644 --- a/AssetEditor/Services/Ipc/ExternalPackLoader.cs +++ b/Editors/Ipc/IpcEditor/ExternalPackLoader.cs @@ -1,16 +1,11 @@ -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; using Serilog; using Shared.Core.ErrorHandling; using Shared.Core.PackFiles; using Shared.Core.PackFiles.Models; using Shared.Core.PackFiles.Utility; -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public class ExternalPackLoader : IExternalPackLoader { diff --git a/AssetEditor/Services/Ipc/IExternalFileOpenExecutor.cs b/Editors/Ipc/IpcEditor/IExternalFileOpenExecutor.cs similarity index 60% rename from AssetEditor/Services/Ipc/IExternalFileOpenExecutor.cs rename to Editors/Ipc/IpcEditor/IExternalFileOpenExecutor.cs index 455deb1de..8e3acbcb7 100644 --- a/AssetEditor/Services/Ipc/IExternalFileOpenExecutor.cs +++ b/Editors/Ipc/IpcEditor/IExternalFileOpenExecutor.cs @@ -1,8 +1,6 @@ -using System.Threading; -using System.Threading.Tasks; -using Shared.Core.PackFiles.Models; +using Shared.Core.PackFiles.Models; -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public interface IExternalFileOpenExecutor { diff --git a/AssetEditor/Services/Ipc/IIpcRequestHandler.cs b/Editors/Ipc/IpcEditor/IIpcRequestHandler.cs similarity index 87% rename from AssetEditor/Services/Ipc/IIpcRequestHandler.cs rename to Editors/Ipc/IpcEditor/IIpcRequestHandler.cs index 41da5d6bf..7a89fc9b4 100644 --- a/AssetEditor/Services/Ipc/IIpcRequestHandler.cs +++ b/Editors/Ipc/IpcEditor/IIpcRequestHandler.cs @@ -1,8 +1,6 @@ -using System.Threading; -using System.Threading.Tasks; -using Shared.Core.PackFiles.Models; +using Shared.Core.PackFiles.Models; -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public interface IIpcRequestHandler { diff --git a/AssetEditor/Services/Ipc/IpcRequest.cs b/Editors/Ipc/IpcEditor/IpcRequest.cs similarity index 89% rename from AssetEditor/Services/Ipc/IpcRequest.cs rename to Editors/Ipc/IpcEditor/IpcRequest.cs index c9632ade4..8083ae8e7 100644 --- a/AssetEditor/Services/Ipc/IpcRequest.cs +++ b/Editors/Ipc/IpcEditor/IpcRequest.cs @@ -1,4 +1,4 @@ -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public class IpcRequest { diff --git a/AssetEditor/Services/Ipc/IpcRequestHandler.cs b/Editors/Ipc/IpcEditor/IpcRequestHandler.cs similarity index 96% rename from AssetEditor/Services/Ipc/IpcRequestHandler.cs rename to Editors/Ipc/IpcEditor/IpcRequestHandler.cs index fdcf96080..2b252b434 100644 --- a/AssetEditor/Services/Ipc/IpcRequestHandler.cs +++ b/Editors/Ipc/IpcEditor/IpcRequestHandler.cs @@ -1,10 +1,7 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Serilog; +using Serilog; using Shared.Core.ErrorHandling; -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public class IpcRequestHandler : IIpcRequestHandler { diff --git a/AssetEditor/Services/Ipc/IpcResponse.cs b/Editors/Ipc/IpcEditor/IpcResponse.cs similarity index 92% rename from AssetEditor/Services/Ipc/IpcResponse.cs rename to Editors/Ipc/IpcEditor/IpcResponse.cs index 6f9510758..84453b6b0 100644 --- a/AssetEditor/Services/Ipc/IpcResponse.cs +++ b/Editors/Ipc/IpcEditor/IpcResponse.cs @@ -1,4 +1,4 @@ -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public class IpcResponse { diff --git a/AssetEditor/Services/Ipc/IpcUserNotifier.cs b/Editors/Ipc/IpcEditor/IpcUserNotifier.cs similarity index 90% rename from AssetEditor/Services/Ipc/IpcUserNotifier.cs rename to Editors/Ipc/IpcEditor/IpcUserNotifier.cs index e6ea5801f..1fe89a6f9 100644 --- a/AssetEditor/Services/Ipc/IpcUserNotifier.cs +++ b/Editors/Ipc/IpcEditor/IpcUserNotifier.cs @@ -1,9 +1,7 @@ -using System.Threading; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; using Shared.Core.Services; -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public class IpcUserNotifier : IIpcUserNotifier { diff --git a/AssetEditor/Services/Ipc/PackPathResolver.cs b/Editors/Ipc/IpcEditor/PackPathResolver.cs similarity index 96% rename from AssetEditor/Services/Ipc/PackPathResolver.cs rename to Editors/Ipc/IpcEditor/PackPathResolver.cs index c0e5ef7e3..6d30f3bbd 100644 --- a/AssetEditor/Services/Ipc/PackPathResolver.cs +++ b/Editors/Ipc/IpcEditor/PackPathResolver.cs @@ -1,6 +1,4 @@ -using System; - -namespace AssetEditor.Services.Ipc +namespace Editors.Ipc { public static class PackPathResolver { diff --git a/Editors/Ipc/Test.Ipc/ExternalFileOpenExecutorTests.cs b/Editors/Ipc/Test.Ipc/ExternalFileOpenExecutorTests.cs new file mode 100644 index 000000000..b6dad4499 --- /dev/null +++ b/Editors/Ipc/Test.Ipc/ExternalFileOpenExecutorTests.cs @@ -0,0 +1,59 @@ +using Editors.Ipc; +using Shared.Core.PackFiles.Models; + +namespace Test.Ipc +{ + + public class ExternalFileOpenExecutorTests + { + [Test] + public void ShouldForceKitbash_ReturnsTrue_ForWsmodel() + { + var file = PackFile.CreateFromBytes("arb_base_elephant_1.wsmodel", []); + + var result = ExternalFileOpenExecutor.ShouldForceKitbash(file); + + Assert.That(result, Is.True); + } + + [Test] + public void ShouldForceKitbash_ReturnsTrue_ForVariantMeshDefinition() + { + var file = PackFile.CreateFromBytes("arb_base_elephant.variantmeshdefinition", []); + + var result = ExternalFileOpenExecutor.ShouldForceKitbash(file); + + Assert.That(result, Is.True); + } + + [Test] + public void ShouldForceKitbash_ReturnsFalse_ForRigidModel() + { + var file = PackFile.CreateFromBytes("arb_base_elephant.rigid_model_v2", []); + + var result = ExternalFileOpenExecutor.ShouldForceKitbash(file); + + Assert.That(result, Is.False); + } + + [Test] + public void CanImportIntoKitbash_ReturnsTrue_ForRigidModel() + { + var file = PackFile.CreateFromBytes("arb_base_elephant.rigid_model_v2", []); + + var result = ExternalFileOpenExecutor.CanImportIntoKitbash(file); + + Assert.That(result, Is.True); + } + + [Test] + public void CanImportIntoKitbash_ReturnsFalse_ForUnsupportedFile() + { + var file = PackFile.CreateFromBytes("something.anim", []); + + var result = ExternalFileOpenExecutor.CanImportIntoKitbash(file); + + Assert.That(result, Is.False); + } + } +} diff --git a/Editors/Ipc/Test.Ipc/IpcRequestHandlerTests.cs b/Editors/Ipc/Test.Ipc/IpcRequestHandlerTests.cs new file mode 100644 index 000000000..f52759d56 --- /dev/null +++ b/Editors/Ipc/Test.Ipc/IpcRequestHandlerTests.cs @@ -0,0 +1,238 @@ +using Editors.Ipc; +using Shared.Core.PackFiles.Models; + +namespace AssetEditorTests.Ipc +{ + + + public class IpcRequestHandlerTests + { + [Test] + public async Task HandleAsync_ReturnsUnsupportedAction_ForUnknownAction() + { + var packLoader = new FakePackLoader(); + var lookup = new FakeLookup(); + var opener = new FakeOpenExecutor(); + var notifier = new FakeNotifier(); + var sut = new IpcRequestHandler(packLoader, lookup, opener, notifier); + + var result = await sut.HandleAsync(new IpcRequest { Action = "ping", Path = "x" }, CancellationToken.None); + + Assert.IsFalse(result.Ok); + Assert.AreEqual("Unsupported action", result.Error); + Assert.AreEqual(0, opener.OpenCallCount); + Assert.AreEqual(0, notifier.CallCount); + Assert.AreEqual(0, packLoader.CallCount); + } + + [Test] + public async Task HandleAsync_ReturnsError_ForEmptyPath() + { + var sut = new IpcRequestHandler(new FakePackLoader(), new FakeLookup(), new FakeOpenExecutor(), new FakeNotifier()); + + var result = await sut.HandleAsync(new IpcRequest { Action = "open", Path = " " }, CancellationToken.None); + + Assert.IsFalse(result.Ok); + Assert.AreEqual("Path is empty", result.Error); + } + + [Test] + public async Task HandleAsync_ReturnsNotFound_AndShowsDialog_WhenLookupFails() + { + var packLoader = new FakePackLoader(); + var lookup = new FakeLookup(); + var opener = new FakeOpenExecutor(); + var notifier = new FakeNotifier(); + var sut = new IpcRequestHandler(packLoader, lookup, opener, notifier); + + var result = await sut.HandleAsync(new IpcRequest + { + Action = "open", + Path = @"C:\tmp\variantmeshes\foo\bar.rigid_model_v2" + }, CancellationToken.None); + + Assert.IsFalse(result.Ok); + Assert.AreEqual("File not found", result.Error); + Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", result.NormalizedPath); + Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", lookup.LastRequestedPath); + Assert.AreEqual(1, notifier.CallCount); + Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", notifier.LastPath); + Assert.AreEqual(0, opener.OpenCallCount); + Assert.AreEqual(0, packLoader.CallCount); + } + + [Test] + public async Task HandleAsync_OpensFile_AndReturnsOk_WhenLookupSucceeds() + { + var packFile = PackFile.CreateFromBytes("bird.rigid_model_v2", []); + var packLoader = new FakePackLoader(); + var lookup = new FakeLookup { Result = packFile }; + var opener = new FakeOpenExecutor(); + var notifier = new FakeNotifier(); + var sut = new IpcRequestHandler(packLoader, lookup, opener, notifier); + + var result = await sut.HandleAsync(new IpcRequest + { + Action = "open", + Path = @"variantmeshes\foo\bird.rigid_model_v2" + }, CancellationToken.None); + + Assert.IsTrue(result.Ok); + Assert.AreEqual(1, opener.OpenCallCount); + Assert.AreSame(packFile, opener.LastFile); + Assert.IsTrue(opener.LastBringToFront); + Assert.IsFalse(opener.LastOpenInExistingKitbashTab); + Assert.AreEqual(0, notifier.CallCount); + Assert.AreEqual(0, packLoader.CallCount); + } + + [Test] + public async Task HandleAsync_DoesNotBringToFront_WhenBringToFrontFalse() + { + var packFile = PackFile.CreateFromBytes("bird.rigid_model_v2", []); + var packLoader = new FakePackLoader(); + var lookup = new FakeLookup { Result = packFile }; + var opener = new FakeOpenExecutor(); + var sut = new IpcRequestHandler(packLoader, lookup, opener, new FakeNotifier()); + + var result = await sut.HandleAsync(new IpcRequest + { + Action = "open", + Path = @"variantmeshes\foo\bird.rigid_model_v2", + BringToFront = false + }, CancellationToken.None); + + Assert.IsTrue(result.Ok); + Assert.AreEqual(1, opener.OpenCallCount); + Assert.IsFalse(opener.LastBringToFront); + Assert.IsFalse(opener.LastOpenInExistingKitbashTab); + Assert.AreEqual(0, packLoader.CallCount); + } + + [Test] + public async Task HandleAsync_LoadsPackFromDisk_WhenPackPathProvided() + { + var packFile = PackFile.CreateFromBytes("arb_base_elephant.rigid_model_v2", []); + var packLoader = new FakePackLoader(); + var lookup = new FakeLookup { Result = packFile }; + var opener = new FakeOpenExecutor(); + var sut = new IpcRequestHandler(packLoader, lookup, opener, new FakeNotifier()); + + var result = await sut.HandleAsync(new IpcRequest + { + Action = "open", + Path = "variantmeshes/wh_variantmodels/el1/arb/arb_new_elephants/arb_base_elephant/arb_base_elephant.rigid_model_v2", + PackPathOnDisk = "k:/SteamLibrary/steamapps/common/Total War WARHAMMER III/data/ovn_araby.pack" + }, CancellationToken.None); + + Assert.IsTrue(result.Ok); + Assert.AreEqual(1, packLoader.CallCount); + Assert.AreEqual("k:/SteamLibrary/steamapps/common/Total War WARHAMMER III/data/ovn_araby.pack", packLoader.LastPackPath); + Assert.AreEqual(1, opener.OpenCallCount); + Assert.IsFalse(opener.LastOpenInExistingKitbashTab); + } + + [Test] + public async Task HandleAsync_ReturnsFailure_WhenPackLoadFails() + { + var packLoader = new FakePackLoader + { + Result = PackLoadResult.Fail("Pack file load failed") + }; + var lookup = new FakeLookup(); + var opener = new FakeOpenExecutor(); + var notifier = new FakeNotifier(); + var sut = new IpcRequestHandler(packLoader, lookup, opener, notifier); + + var result = await sut.HandleAsync(new IpcRequest + { + Action = "open", + Path = @"variantmeshes\foo\bird.rigid_model_v2", + PackPathOnDisk = @"k:\mods\ovn_araby.pack" + }, CancellationToken.None); + + Assert.IsFalse(result.Ok); + Assert.AreEqual("Pack file load failed", result.Error); + Assert.AreEqual(1, packLoader.CallCount); + Assert.AreEqual(0, opener.OpenCallCount); + Assert.AreEqual(0, notifier.CallCount); + } + + [Test] + public async Task HandleAsync_PassesOpenInExistingKitbashTabFlag_ToExecutor() + { + var packFile = PackFile.CreateFromBytes("arb_base_elephant_1.wsmodel", []); + var packLoader = new FakePackLoader(); + var lookup = new FakeLookup { Result = packFile }; + var opener = new FakeOpenExecutor(); + var sut = new IpcRequestHandler(packLoader, lookup, opener, new FakeNotifier()); + + var result = await sut.HandleAsync(new IpcRequest + { + Action = "open", + Path = @"variantmeshes\foo\arb_base_elephant_1.wsmodel", + OpenInExistingKitbashTab = true + }, CancellationToken.None); + + Assert.IsTrue(result.Ok); + Assert.AreEqual(1, opener.OpenCallCount); + Assert.IsTrue(opener.LastOpenInExistingKitbashTab); + } + + private class FakeLookup : IExternalPackFileLookup + { + public PackFile? Result { get; set; } + public string? LastRequestedPath { get; private set; } + + public PackFile? FindByPath(string path) + { + LastRequestedPath = path; + return Result; + } + } + + private class FakePackLoader : IExternalPackLoader + { + public int CallCount { get; private set; } + public string? LastPackPath { get; private set; } + public PackLoadResult Result { get; set; } = PackLoadResult.Ok(); + + public Task EnsureLoadedAsync(string packPathOnDisk, CancellationToken cancellationToken) + { + CallCount++; + LastPackPath = packPathOnDisk; + return Task.FromResult(Result); + } + } + + private class FakeOpenExecutor : IExternalFileOpenExecutor + { + public int OpenCallCount { get; private set; } + public PackFile? LastFile { get; private set; } + public bool LastBringToFront { get; private set; } + public bool LastOpenInExistingKitbashTab { get; private set; } + + public Task OpenAsync(PackFile file, bool bringToFront, bool openInExistingKitbashTab, CancellationToken cancellationToken) + { + OpenCallCount++; + LastFile = file; + LastBringToFront = bringToFront; + LastOpenInExistingKitbashTab = openInExistingKitbashTab; + return Task.CompletedTask; + } + } + + private class FakeNotifier : IIpcUserNotifier + { + public int CallCount { get; private set; } + public string? LastPath { get; private set; } + + public Task ShowExternalOpenFailedAsync(string normalizedPath, CancellationToken cancellationToken) + { + CallCount++; + LastPath = normalizedPath; + return Task.CompletedTask; + } + } + } +} diff --git a/Editors/Ipc/Test.Ipc/PackPathResolverTests.cs b/Editors/Ipc/Test.Ipc/PackPathResolverTests.cs new file mode 100644 index 000000000..abd4d6557 --- /dev/null +++ b/Editors/Ipc/Test.Ipc/PackPathResolverTests.cs @@ -0,0 +1,39 @@ +using Editors.Ipc; + +namespace Test.Ipc +{ + public class PackPathResolverTests + { + [Test] + public void ResolvePackPath_ExtractsVariantMeshesSuffix_FromAbsolutePath() + { + var input = @"C:\games\wh3\data\variantmeshes\wh_variantmodels\bi1\cth\bird.rigid_model_v2"; + var result = PackPathResolver.ResolvePackPath(input); + Assert.That(result, Is.EqualTo(@"variantmeshes\wh_variantmodels\bi1\cth\bird.rigid_model_v2")); + } + + [Test] + public void ResolvePackPath_NormalizesForwardSlashes_AndQuotes() + { + var input = "\"variantmeshes/wh_variantmodels/bi1/cth/bird.rigid_model_v2\""; + var result = PackPathResolver.ResolvePackPath(input); + Assert.That(result, Is.EqualTo(@"variantmeshes\wh_variantmodels\bi1\cth\bird.rigid_model_v2")); + } + + [Test] + public void ResolvePackPath_CollapsesRepeatedBackslashes() + { + var input = @"variantmeshes\\wh_variantmodels\\bi1\\cth\\bird.rigid_model_v2"; + var result = PackPathResolver.ResolvePackPath(input); + Assert.That(result, Is.EqualTo(@"variantmeshes\wh_variantmodels\bi1\cth\bird.rigid_model_v2")); + } + + [Test] + public void ResolvePackPath_ReturnsInput_WhenNoKnownRootFound() + { + var input = @"custom_folder\mesh.rigid_model_v2"; + var result = PackPathResolver.ResolvePackPath(input); + Assert.That(input, Is.EqualTo(result)); + } + } +} diff --git a/Editors/Ipc/Test.Ipc/Test.Ipc.csproj b/Editors/Ipc/Test.Ipc/Test.Ipc.csproj new file mode 100644 index 000000000..145032178 --- /dev/null +++ b/Editors/Ipc/Test.Ipc/Test.Ipc.csproj @@ -0,0 +1,22 @@ + + + + net10.0-windows + true + enable + enable + + + + + + + + + + + + + + + diff --git a/Shared/SharedCore/ToolCreation/IEditorInterface.cs b/Shared/SharedCore/ToolCreation/IEditorInterface.cs index 0926db3e9..720652b4b 100644 --- a/Shared/SharedCore/ToolCreation/IEditorInterface.cs +++ b/Shared/SharedCore/ToolCreation/IEditorInterface.cs @@ -28,4 +28,23 @@ public interface IEditorCreator IEditorInterface Create(EditorEnums editor, Action? onInitializeCallback = null); Window CreateWindow(PackFile packFile, EditorEnums? preferedEditor = null); } + + public interface IEditorManager : IEditorCreator + { + IList GetAllEditors(); + int GetCurrentEditor(); + void SetEditorAsCurrent(IEditorInterface editor); + + public void CloseTool(IEditorInterface tool); + public bool ShouldBlockCloseCommand(IEditorInterface editor, bool hasUnsavedFiles); + + public void CloseOtherTools(IEditorInterface tool); + public void CloseAllTools(IEditorInterface tool); + public void CloseToolsToLeft(IEditorInterface tool); + public void CloseToolsToRight(IEditorInterface tool); + public bool Drop(IEditorInterface node, IEditorInterface targetNode = default, bool insertAfterTargetNode = default); + + + + } } diff --git a/Testing/AssetEditorTests/Ipc/ExternalFileOpenExecutorTests.cs b/Testing/AssetEditorTests/Ipc/ExternalFileOpenExecutorTests.cs index 2c5489cc8..dcd57f1c7 100644 --- a/Testing/AssetEditorTests/Ipc/ExternalFileOpenExecutorTests.cs +++ b/Testing/AssetEditorTests/Ipc/ExternalFileOpenExecutorTests.cs @@ -1,4 +1,4 @@ -using AssetEditor.Services.Ipc; +using Editors.Ipc; using Shared.Core.PackFiles.Models; namespace AssetEditorTests.Ipc diff --git a/Testing/AssetEditorTests/Ipc/IpcRequestHandlerTests.cs b/Testing/AssetEditorTests/Ipc/IpcRequestHandlerTests.cs index 389038b67..40a7c345f 100644 --- a/Testing/AssetEditorTests/Ipc/IpcRequestHandlerTests.cs +++ b/Testing/AssetEditorTests/Ipc/IpcRequestHandlerTests.cs @@ -1,4 +1,4 @@ -using AssetEditor.Services.Ipc; +using Editors.Ipc; using Shared.Core.PackFiles.Models; namespace AssetEditorTests.Ipc From 8e7962749d13119d1a8bd53ef44e21ade3c25437 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Sat, 14 Mar 2026 12:00:33 +0100 Subject: [PATCH 2/2] Fixes --- .../Ipc/Test.Ipc/IpcRequestHandlerTests.cs | 84 +++---- Editors/Ipc/Test.Ipc/Test.Ipc.csproj | 9 +- .../Ipc/ExternalFileOpenExecutorTests.cs | 59 ----- .../Ipc/IpcRequestHandlerTests.cs | 237 ------------------ .../Ipc/PackPathResolverTests.cs | 48 ---- 5 files changed, 47 insertions(+), 390 deletions(-) delete mode 100644 Testing/AssetEditorTests/Ipc/ExternalFileOpenExecutorTests.cs delete mode 100644 Testing/AssetEditorTests/Ipc/IpcRequestHandlerTests.cs delete mode 100644 Testing/AssetEditorTests/Ipc/PackPathResolverTests.cs diff --git a/Editors/Ipc/Test.Ipc/IpcRequestHandlerTests.cs b/Editors/Ipc/Test.Ipc/IpcRequestHandlerTests.cs index f52759d56..24e9c6135 100644 --- a/Editors/Ipc/Test.Ipc/IpcRequestHandlerTests.cs +++ b/Editors/Ipc/Test.Ipc/IpcRequestHandlerTests.cs @@ -1,10 +1,8 @@ using Editors.Ipc; using Shared.Core.PackFiles.Models; -namespace AssetEditorTests.Ipc +namespace Test.Ipc { - - public class IpcRequestHandlerTests { [Test] @@ -18,11 +16,11 @@ public async Task HandleAsync_ReturnsUnsupportedAction_ForUnknownAction() var result = await sut.HandleAsync(new IpcRequest { Action = "ping", Path = "x" }, CancellationToken.None); - Assert.IsFalse(result.Ok); - Assert.AreEqual("Unsupported action", result.Error); - Assert.AreEqual(0, opener.OpenCallCount); - Assert.AreEqual(0, notifier.CallCount); - Assert.AreEqual(0, packLoader.CallCount); + Assert.That(result.Ok, Is.False); + Assert.That(result.Error, Is.EqualTo("Unsupported action")); + Assert.That(opener.OpenCallCount, Is.Zero); + Assert.That(notifier.CallCount, Is.Zero); + Assert.That(packLoader.CallCount, Is.Zero); } [Test] @@ -32,8 +30,8 @@ public async Task HandleAsync_ReturnsError_ForEmptyPath() var result = await sut.HandleAsync(new IpcRequest { Action = "open", Path = " " }, CancellationToken.None); - Assert.IsFalse(result.Ok); - Assert.AreEqual("Path is empty", result.Error); + Assert.That(result.Ok, Is.False); + Assert.That(result.Error, Is.EqualTo("Path is empty")); } [Test] @@ -51,14 +49,14 @@ public async Task HandleAsync_ReturnsNotFound_AndShowsDialog_WhenLookupFails() Path = @"C:\tmp\variantmeshes\foo\bar.rigid_model_v2" }, CancellationToken.None); - Assert.IsFalse(result.Ok); - Assert.AreEqual("File not found", result.Error); - Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", result.NormalizedPath); - Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", lookup.LastRequestedPath); - Assert.AreEqual(1, notifier.CallCount); - Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", notifier.LastPath); - Assert.AreEqual(0, opener.OpenCallCount); - Assert.AreEqual(0, packLoader.CallCount); + Assert.That(result.Ok, Is.False); + Assert.That(result.Error, Is.EqualTo("File not found")); + Assert.That(result.NormalizedPath, Is.EqualTo(@"variantmeshes\foo\bar.rigid_model_v2")); + Assert.That(lookup.LastRequestedPath, Is.EqualTo(@"variantmeshes\foo\bar.rigid_model_v2")); + Assert.That(notifier.CallCount, Is.EqualTo(1)); + Assert.That(notifier.LastPath, Is.EqualTo(@"variantmeshes\foo\bar.rigid_model_v2")); + Assert.That(opener.OpenCallCount, Is.Zero); + Assert.That(packLoader.CallCount, Is.Zero); } [Test] @@ -77,13 +75,13 @@ public async Task HandleAsync_OpensFile_AndReturnsOk_WhenLookupSucceeds() Path = @"variantmeshes\foo\bird.rigid_model_v2" }, CancellationToken.None); - Assert.IsTrue(result.Ok); - Assert.AreEqual(1, opener.OpenCallCount); - Assert.AreSame(packFile, opener.LastFile); - Assert.IsTrue(opener.LastBringToFront); - Assert.IsFalse(opener.LastOpenInExistingKitbashTab); - Assert.AreEqual(0, notifier.CallCount); - Assert.AreEqual(0, packLoader.CallCount); + Assert.That(result.Ok, Is.True); + Assert.That(opener.OpenCallCount, Is.EqualTo(1)); + Assert.That(opener.LastFile, Is.SameAs(packFile)); + Assert.That(opener.LastBringToFront, Is.True); + Assert.That(opener.LastOpenInExistingKitbashTab, Is.False); + Assert.That(notifier.CallCount, Is.Zero); + Assert.That(packLoader.CallCount, Is.Zero); } [Test] @@ -102,11 +100,11 @@ public async Task HandleAsync_DoesNotBringToFront_WhenBringToFrontFalse() BringToFront = false }, CancellationToken.None); - Assert.IsTrue(result.Ok); - Assert.AreEqual(1, opener.OpenCallCount); - Assert.IsFalse(opener.LastBringToFront); - Assert.IsFalse(opener.LastOpenInExistingKitbashTab); - Assert.AreEqual(0, packLoader.CallCount); + Assert.That(result.Ok, Is.True); + Assert.That(opener.OpenCallCount, Is.EqualTo(1)); + Assert.That(opener.LastBringToFront, Is.False); + Assert.That(opener.LastOpenInExistingKitbashTab, Is.False); + Assert.That(packLoader.CallCount, Is.Zero); } [Test] @@ -125,11 +123,11 @@ public async Task HandleAsync_LoadsPackFromDisk_WhenPackPathProvided() PackPathOnDisk = "k:/SteamLibrary/steamapps/common/Total War WARHAMMER III/data/ovn_araby.pack" }, CancellationToken.None); - Assert.IsTrue(result.Ok); - Assert.AreEqual(1, packLoader.CallCount); - Assert.AreEqual("k:/SteamLibrary/steamapps/common/Total War WARHAMMER III/data/ovn_araby.pack", packLoader.LastPackPath); - Assert.AreEqual(1, opener.OpenCallCount); - Assert.IsFalse(opener.LastOpenInExistingKitbashTab); + Assert.That(result.Ok, Is.True); + Assert.That(packLoader.CallCount, Is.EqualTo(1)); + Assert.That(packLoader.LastPackPath, Is.EqualTo("k:/SteamLibrary/steamapps/common/Total War WARHAMMER III/data/ovn_araby.pack")); + Assert.That(opener.OpenCallCount, Is.EqualTo(1)); + Assert.That(opener.LastOpenInExistingKitbashTab, Is.False); } [Test] @@ -151,11 +149,11 @@ public async Task HandleAsync_ReturnsFailure_WhenPackLoadFails() PackPathOnDisk = @"k:\mods\ovn_araby.pack" }, CancellationToken.None); - Assert.IsFalse(result.Ok); - Assert.AreEqual("Pack file load failed", result.Error); - Assert.AreEqual(1, packLoader.CallCount); - Assert.AreEqual(0, opener.OpenCallCount); - Assert.AreEqual(0, notifier.CallCount); + Assert.That(result.Ok, Is.False); + Assert.That(result.Error, Is.EqualTo("Pack file load failed")); + Assert.That(packLoader.CallCount, Is.EqualTo(1)); + Assert.That(opener.OpenCallCount, Is.Zero); + Assert.That(notifier.CallCount, Is.Zero); } [Test] @@ -174,9 +172,9 @@ public async Task HandleAsync_PassesOpenInExistingKitbashTabFlag_ToExecutor() OpenInExistingKitbashTab = true }, CancellationToken.None); - Assert.IsTrue(result.Ok); - Assert.AreEqual(1, opener.OpenCallCount); - Assert.IsTrue(opener.LastOpenInExistingKitbashTab); + Assert.That(result.Ok, Is.True); + Assert.That(opener.OpenCallCount, Is.EqualTo(1)); + Assert.That(opener.LastOpenInExistingKitbashTab, Is.True); } private class FakeLookup : IExternalPackFileLookup diff --git a/Editors/Ipc/Test.Ipc/Test.Ipc.csproj b/Editors/Ipc/Test.Ipc/Test.Ipc.csproj index 145032178..68a842903 100644 --- a/Editors/Ipc/Test.Ipc/Test.Ipc.csproj +++ b/Editors/Ipc/Test.Ipc/Test.Ipc.csproj @@ -2,11 +2,10 @@ net10.0-windows - true enable enable - + @@ -15,8 +14,12 @@ + + + + - + \ No newline at end of file diff --git a/Testing/AssetEditorTests/Ipc/ExternalFileOpenExecutorTests.cs b/Testing/AssetEditorTests/Ipc/ExternalFileOpenExecutorTests.cs deleted file mode 100644 index dcd57f1c7..000000000 --- a/Testing/AssetEditorTests/Ipc/ExternalFileOpenExecutorTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Editors.Ipc; -using Shared.Core.PackFiles.Models; - -namespace AssetEditorTests.Ipc -{ - [TestClass] - public class ExternalFileOpenExecutorTests - { - [TestMethod] - public void ShouldForceKitbash_ReturnsTrue_ForWsmodel() - { - var file = PackFile.CreateFromBytes("arb_base_elephant_1.wsmodel", []); - - var result = ExternalFileOpenExecutor.ShouldForceKitbash(file); - - Assert.IsTrue(result); - } - - [TestMethod] - public void ShouldForceKitbash_ReturnsTrue_ForVariantMeshDefinition() - { - var file = PackFile.CreateFromBytes("arb_base_elephant.variantmeshdefinition", []); - - var result = ExternalFileOpenExecutor.ShouldForceKitbash(file); - - Assert.IsTrue(result); - } - - [TestMethod] - public void ShouldForceKitbash_ReturnsFalse_ForRigidModel() - { - var file = PackFile.CreateFromBytes("arb_base_elephant.rigid_model_v2", []); - - var result = ExternalFileOpenExecutor.ShouldForceKitbash(file); - - Assert.IsFalse(result); - } - - [TestMethod] - public void CanImportIntoKitbash_ReturnsTrue_ForRigidModel() - { - var file = PackFile.CreateFromBytes("arb_base_elephant.rigid_model_v2", []); - - var result = ExternalFileOpenExecutor.CanImportIntoKitbash(file); - - Assert.IsTrue(result); - } - - [TestMethod] - public void CanImportIntoKitbash_ReturnsFalse_ForUnsupportedFile() - { - var file = PackFile.CreateFromBytes("something.anim", []); - - var result = ExternalFileOpenExecutor.CanImportIntoKitbash(file); - - Assert.IsFalse(result); - } - } -} diff --git a/Testing/AssetEditorTests/Ipc/IpcRequestHandlerTests.cs b/Testing/AssetEditorTests/Ipc/IpcRequestHandlerTests.cs deleted file mode 100644 index 40a7c345f..000000000 --- a/Testing/AssetEditorTests/Ipc/IpcRequestHandlerTests.cs +++ /dev/null @@ -1,237 +0,0 @@ -using Editors.Ipc; -using Shared.Core.PackFiles.Models; - -namespace AssetEditorTests.Ipc -{ - [TestClass] - public class IpcRequestHandlerTests - { - [TestMethod] - public async Task HandleAsync_ReturnsUnsupportedAction_ForUnknownAction() - { - var packLoader = new FakePackLoader(); - var lookup = new FakeLookup(); - var opener = new FakeOpenExecutor(); - var notifier = new FakeNotifier(); - var sut = new IpcRequestHandler(packLoader, lookup, opener, notifier); - - var result = await sut.HandleAsync(new IpcRequest { Action = "ping", Path = "x" }, CancellationToken.None); - - Assert.IsFalse(result.Ok); - Assert.AreEqual("Unsupported action", result.Error); - Assert.AreEqual(0, opener.OpenCallCount); - Assert.AreEqual(0, notifier.CallCount); - Assert.AreEqual(0, packLoader.CallCount); - } - - [TestMethod] - public async Task HandleAsync_ReturnsError_ForEmptyPath() - { - var sut = new IpcRequestHandler(new FakePackLoader(), new FakeLookup(), new FakeOpenExecutor(), new FakeNotifier()); - - var result = await sut.HandleAsync(new IpcRequest { Action = "open", Path = " " }, CancellationToken.None); - - Assert.IsFalse(result.Ok); - Assert.AreEqual("Path is empty", result.Error); - } - - [TestMethod] - public async Task HandleAsync_ReturnsNotFound_AndShowsDialog_WhenLookupFails() - { - var packLoader = new FakePackLoader(); - var lookup = new FakeLookup(); - var opener = new FakeOpenExecutor(); - var notifier = new FakeNotifier(); - var sut = new IpcRequestHandler(packLoader, lookup, opener, notifier); - - var result = await sut.HandleAsync(new IpcRequest - { - Action = "open", - Path = @"C:\tmp\variantmeshes\foo\bar.rigid_model_v2" - }, CancellationToken.None); - - Assert.IsFalse(result.Ok); - Assert.AreEqual("File not found", result.Error); - Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", result.NormalizedPath); - Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", lookup.LastRequestedPath); - Assert.AreEqual(1, notifier.CallCount); - Assert.AreEqual(@"variantmeshes\foo\bar.rigid_model_v2", notifier.LastPath); - Assert.AreEqual(0, opener.OpenCallCount); - Assert.AreEqual(0, packLoader.CallCount); - } - - [TestMethod] - public async Task HandleAsync_OpensFile_AndReturnsOk_WhenLookupSucceeds() - { - var packFile = PackFile.CreateFromBytes("bird.rigid_model_v2", []); - var packLoader = new FakePackLoader(); - var lookup = new FakeLookup { Result = packFile }; - var opener = new FakeOpenExecutor(); - var notifier = new FakeNotifier(); - var sut = new IpcRequestHandler(packLoader, lookup, opener, notifier); - - var result = await sut.HandleAsync(new IpcRequest - { - Action = "open", - Path = @"variantmeshes\foo\bird.rigid_model_v2" - }, CancellationToken.None); - - Assert.IsTrue(result.Ok); - Assert.AreEqual(1, opener.OpenCallCount); - Assert.AreSame(packFile, opener.LastFile); - Assert.IsTrue(opener.LastBringToFront); - Assert.IsFalse(opener.LastOpenInExistingKitbashTab); - Assert.AreEqual(0, notifier.CallCount); - Assert.AreEqual(0, packLoader.CallCount); - } - - [TestMethod] - public async Task HandleAsync_DoesNotBringToFront_WhenBringToFrontFalse() - { - var packFile = PackFile.CreateFromBytes("bird.rigid_model_v2", []); - var packLoader = new FakePackLoader(); - var lookup = new FakeLookup { Result = packFile }; - var opener = new FakeOpenExecutor(); - var sut = new IpcRequestHandler(packLoader, lookup, opener, new FakeNotifier()); - - var result = await sut.HandleAsync(new IpcRequest - { - Action = "open", - Path = @"variantmeshes\foo\bird.rigid_model_v2", - BringToFront = false - }, CancellationToken.None); - - Assert.IsTrue(result.Ok); - Assert.AreEqual(1, opener.OpenCallCount); - Assert.IsFalse(opener.LastBringToFront); - Assert.IsFalse(opener.LastOpenInExistingKitbashTab); - Assert.AreEqual(0, packLoader.CallCount); - } - - [TestMethod] - public async Task HandleAsync_LoadsPackFromDisk_WhenPackPathProvided() - { - var packFile = PackFile.CreateFromBytes("arb_base_elephant.rigid_model_v2", []); - var packLoader = new FakePackLoader(); - var lookup = new FakeLookup { Result = packFile }; - var opener = new FakeOpenExecutor(); - var sut = new IpcRequestHandler(packLoader, lookup, opener, new FakeNotifier()); - - var result = await sut.HandleAsync(new IpcRequest - { - Action = "open", - Path = "variantmeshes/wh_variantmodels/el1/arb/arb_new_elephants/arb_base_elephant/arb_base_elephant.rigid_model_v2", - PackPathOnDisk = "k:/SteamLibrary/steamapps/common/Total War WARHAMMER III/data/ovn_araby.pack" - }, CancellationToken.None); - - Assert.IsTrue(result.Ok); - Assert.AreEqual(1, packLoader.CallCount); - Assert.AreEqual("k:/SteamLibrary/steamapps/common/Total War WARHAMMER III/data/ovn_araby.pack", packLoader.LastPackPath); - Assert.AreEqual(1, opener.OpenCallCount); - Assert.IsFalse(opener.LastOpenInExistingKitbashTab); - } - - [TestMethod] - public async Task HandleAsync_ReturnsFailure_WhenPackLoadFails() - { - var packLoader = new FakePackLoader - { - Result = PackLoadResult.Fail("Pack file load failed") - }; - var lookup = new FakeLookup(); - var opener = new FakeOpenExecutor(); - var notifier = new FakeNotifier(); - var sut = new IpcRequestHandler(packLoader, lookup, opener, notifier); - - var result = await sut.HandleAsync(new IpcRequest - { - Action = "open", - Path = @"variantmeshes\foo\bird.rigid_model_v2", - PackPathOnDisk = @"k:\mods\ovn_araby.pack" - }, CancellationToken.None); - - Assert.IsFalse(result.Ok); - Assert.AreEqual("Pack file load failed", result.Error); - Assert.AreEqual(1, packLoader.CallCount); - Assert.AreEqual(0, opener.OpenCallCount); - Assert.AreEqual(0, notifier.CallCount); - } - - [TestMethod] - public async Task HandleAsync_PassesOpenInExistingKitbashTabFlag_ToExecutor() - { - var packFile = PackFile.CreateFromBytes("arb_base_elephant_1.wsmodel", []); - var packLoader = new FakePackLoader(); - var lookup = new FakeLookup { Result = packFile }; - var opener = new FakeOpenExecutor(); - var sut = new IpcRequestHandler(packLoader, lookup, opener, new FakeNotifier()); - - var result = await sut.HandleAsync(new IpcRequest - { - Action = "open", - Path = @"variantmeshes\foo\arb_base_elephant_1.wsmodel", - OpenInExistingKitbashTab = true - }, CancellationToken.None); - - Assert.IsTrue(result.Ok); - Assert.AreEqual(1, opener.OpenCallCount); - Assert.IsTrue(opener.LastOpenInExistingKitbashTab); - } - - private class FakeLookup : IExternalPackFileLookup - { - public PackFile? Result { get; set; } - public string? LastRequestedPath { get; private set; } - - public PackFile? FindByPath(string path) - { - LastRequestedPath = path; - return Result; - } - } - - private class FakePackLoader : IExternalPackLoader - { - public int CallCount { get; private set; } - public string? LastPackPath { get; private set; } - public PackLoadResult Result { get; set; } = PackLoadResult.Ok(); - - public Task EnsureLoadedAsync(string packPathOnDisk, CancellationToken cancellationToken) - { - CallCount++; - LastPackPath = packPathOnDisk; - return Task.FromResult(Result); - } - } - - private class FakeOpenExecutor : IExternalFileOpenExecutor - { - public int OpenCallCount { get; private set; } - public PackFile? LastFile { get; private set; } - public bool LastBringToFront { get; private set; } - public bool LastOpenInExistingKitbashTab { get; private set; } - - public Task OpenAsync(PackFile file, bool bringToFront, bool openInExistingKitbashTab, CancellationToken cancellationToken) - { - OpenCallCount++; - LastFile = file; - LastBringToFront = bringToFront; - LastOpenInExistingKitbashTab = openInExistingKitbashTab; - return Task.CompletedTask; - } - } - - private class FakeNotifier : IIpcUserNotifier - { - public int CallCount { get; private set; } - public string? LastPath { get; private set; } - - public Task ShowExternalOpenFailedAsync(string normalizedPath, CancellationToken cancellationToken) - { - CallCount++; - LastPath = normalizedPath; - return Task.CompletedTask; - } - } - } -} diff --git a/Testing/AssetEditorTests/Ipc/PackPathResolverTests.cs b/Testing/AssetEditorTests/Ipc/PackPathResolverTests.cs deleted file mode 100644 index c0f0d1c60..000000000 --- a/Testing/AssetEditorTests/Ipc/PackPathResolverTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -using AssetEditor.Services.Ipc; - -namespace AssetEditorTests.Ipc -{ - [TestClass] - public class PackPathResolverTests - { - [TestMethod] - public void ResolvePackPath_ExtractsVariantMeshesSuffix_FromAbsolutePath() - { - var input = @"C:\games\wh3\data\variantmeshes\wh_variantmodels\bi1\cth\bird.rigid_model_v2"; - - var result = PackPathResolver.ResolvePackPath(input); - - Assert.AreEqual(@"variantmeshes\wh_variantmodels\bi1\cth\bird.rigid_model_v2", result); - } - - [TestMethod] - public void ResolvePackPath_NormalizesForwardSlashes_AndQuotes() - { - var input = "\"variantmeshes/wh_variantmodels/bi1/cth/bird.rigid_model_v2\""; - - var result = PackPathResolver.ResolvePackPath(input); - - Assert.AreEqual(@"variantmeshes\wh_variantmodels\bi1\cth\bird.rigid_model_v2", result); - } - - [TestMethod] - public void ResolvePackPath_CollapsesRepeatedBackslashes() - { - var input = @"variantmeshes\\wh_variantmodels\\bi1\\cth\\bird.rigid_model_v2"; - - var result = PackPathResolver.ResolvePackPath(input); - - Assert.AreEqual(@"variantmeshes\wh_variantmodels\bi1\cth\bird.rigid_model_v2", result); - } - - [TestMethod] - public void ResolvePackPath_ReturnsInput_WhenNoKnownRootFound() - { - var input = @"custom_folder\mesh.rigid_model_v2"; - - var result = PackPathResolver.ResolvePackPath(input); - - Assert.AreEqual(input, result); - } - } -}