using AcDream.App.UI; using AcDream.App.UI.Layout; using AcDream.Core.Content; using AcDream.Core.Input; using AcDream.Content; using AcDream.UI.Abstractions.Input; namespace AcDream.App.Tests.UI.Layout; /// /// Production-shaped installed-DAT gate for #446. The Core conformance lane /// proves the 306 identities/defaults; this gate proves the actual retained /// screen can import its authored layout and row template and expose every one /// of those identities as a live three-slot row. /// [Trait("Lane", "InstalledDat")] public sealed class KeyboardConfigInstalledDatConformanceTests { [Fact] public void InstalledEorLayout_MountsEveryBindableActionAsALiveRow() { string? datDir = ResolveDatDir(); if (datDir is null) Assert.Fail("Lane=InstalledDat requires an installed retail DAT directory; see docs/release-gate.md."); using var dats = new AcDream.App.Tests.BoundedTestDatCollection(datDir); var strings = new DatStringResolver(dats); ElementInfo? info = LayoutImporter.ImportInfos( dats, KeyboardConfigController.LayoutId); Assert.NotNull(info); ImportedLayout layout = LayoutImporter.Build( info!, _ => (0u, 0, 0), datFont: null, fontResolve: null, strings.Resolve); RetailActionMapSnapshot? snapshot = RetailActionMapReader.Read( (IDatObjectSource)dats); Assert.NotNull(snapshot); KeyBindings live = KeyBindings.RetailDefaults(); KeyboardConfigController? controller = KeyboardConfigController.Bind( layout, snapshot!, templateResolver: (templateLayoutId, templateElementId) => { ElementInfo? template = LayoutImporter.ImportInfos( dats, templateLayoutId, templateElementId); return template is null ? null : LayoutImporter.Build( template, _ => (0u, 0, 0), datFont: null, fontResolve: null, strings.Resolve, templateLayoutId).Root; }, resolveString: (tableId, stringId) => strings.Resolve(tableId, stringId), new KeyboardConfigController.Bindings( CurrentForAction: action => live.ForAction(action).ToArray(), SetForAction: (_, _) => { }, CurrentForUnmapped: _ => Array.Empty(), SetForUnmapped: (_, _) => { }, BeginCapture: _ => { }, Save: () => { }, Toggle: () => { }, ResolveTemplate: (key, variables) => strings.ResolveTemplate(0x23000004u, key, variables), ShowMessage: _ => { }, ConfirmOverwrite: (_, _) => { }, CurrentKeymapFilename: () => "acdream.keymap", OpenLoadKeymap: completed => completed(), OpenSaveKeymap: completed => completed())); Assert.NotNull(controller); Assert.Equal(306, snapshot!.Rows.Count); Assert.Equal(snapshot.Rows.Count, controller!.Rows.Count); Assert.Equal(306, controller.Page.Rows.Count); Assert.All(controller.Rows, row => { Assert.NotNull(row.MappedAction); Assert.False(string.IsNullOrWhiteSpace(row.Label)); Assert.Equal(3, row.KeyButtons.Count); Assert.All(row.KeyButtons, button => { Assert.NotNull(button.OnClick); Assert.NotNull(button.OnRightClick); Assert.False(string.IsNullOrWhiteSpace(button.TooltipText)); }); }); Assert.Equal( snapshot.Rows.Select(static row => (row.InputMapId, row.ActionId)).ToHashSet(), controller.Rows.Select(static row => (row.InputMapId, row.ActionId)).ToHashSet()); uint key = DatStringResolver.ComputeHash("KEY"); uint action = DatStringResolver.ComputeHash("ACTION"); uint bindings = DatStringResolver.ComputeHash("BINDINGS"); Assert.Equal( "'Ctrl+M' is currently bound to a non user-bindable action. Please select a different binding.", strings.ResolveTemplate( 0x23000004u, "ID_ActionKeyMap_NonUserBindableBinding", new Dictionary { [key] = "Ctrl+M" })); Assert.Equal( "'A' is currently bound to 'Move Backward'. Do you wish to erase that binding?", strings.ResolveTemplate( 0x23000004u, "ID_ActionKeyMap_OverwriteExistingBinding", new Dictionary { [key] = "A", [action] = "Move Backward", })); Assert.Equal( "'A' conflicts with the following bindings:\n'Move Backward' ('A')\n'Turn Right' ('A')\nDo you wish to erase those bindings?", strings.ResolveTemplate( 0x23000004u, "ID_ActionKeyMap_OverwriteExistingBindings", new Dictionary { [key] = "A", [bindings] = "'Move Backward' ('A')\n'Turn Right' ('A')", })); foreach (uint buttonId in new[] { 0x10000027u, // Load File 0x10000029u, // Save As 0x1000002Au, // Defaults 0x1000002Bu, // Revert 0x1000002Cu, // OK 0x1000002Du, // Cancel }) { UiButton button = Assert.IsType(layout.FindElement(buttonId)); Assert.NotNull(button.OnClick); } UiText filename = Assert.IsType(layout.FindElement(0x10000028u)); Assert.Equal("acdream.keymap", Assert.Single(filename.LinesProvider()).Text); // The same installed catalog must contain the type-7 presenter retail's // Load File button opens: root 0x1F, menu 0x21, accept/reject 0x22/0x23. uint dialogLayoutId = RetailDataIdResolver.Resolve(dats, 2u, 5u); Assert.NotEqual(0u, dialogLayoutId); ElementInfo? menuInfo = LayoutImporter.ImportInfos( dats, dialogLayoutId, RetailConfirmationMenuDialogView.RootElementId); Assert.NotNull(menuInfo); ImportedLayout menuLayout = LayoutImporter.Build( menuInfo!, _ => (0u, 0, 0), null, null, strings.Resolve); Assert.IsType(menuLayout.Root); UiMenu catalogMenu = Assert.IsType(menuLayout.FindElement( RetailConfirmationMenuDialogView.MenuElementId)); Assert.NotEqual(0u, catalogMenu.NormalSprite); Assert.NotEqual(0u, catalogMenu.PressedSprite); Assert.NotEqual(0u, catalogMenu.PopupBgSprite); Assert.NotEqual(0u, catalogMenu.ItemNormalSprite); Assert.IsType(menuLayout.FindElement( RetailConfirmationMenuDialogView.AcceptButtonId)); Assert.IsType(menuLayout.FindElement( RetailConfirmationMenuDialogView.RejectButtonId)); } private static string? ResolveDatDir() { string? fromEnvironment = Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR"); if (!string.IsNullOrWhiteSpace(fromEnvironment) && Directory.Exists(fromEnvironment)) return fromEnvironment; string installed = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Documents", "Asheron's Call"); return Directory.Exists(installed) ? installed : null; } }