summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop.Tests/M6bTests.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-20 15:54:00 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-20 15:54:00 +0800
commit3aa0049bb092694b5168d99bc6ac893b1db4740a (patch)
treeb3cf6a0e21442780cd72e8f6a842a4f3db1cecca /src/LivingVillage.Desktop.Tests/M6bTests.fs
parent9724663602b4b1eb755bf334c475dc2c80e4b386 (diff)
downloadliving-village-3aa0049bb092694b5168d99bc6ac893b1db4740a.tar.gz
feat(m6b): add playable menu and save flow
[Change Nature] - This commit adds the M6b desktop menu and persistence integration. [New Capability] - Provide new game, continue, settings, controls, load error, save, load, and exit flows. - Provide a bounded autoplay flow covering menu navigation and persistence. [Implementation] - Add pure menu state transitions and focused M6b coverage. - Connect menu commands to simulation controls, WorldSave, view resets, and rendering. [Impact] - Desktop runtime gains the playable M6b front end without changing out-of-scope files. - Release focused and solution test suites remain passing.
Diffstat (limited to 'src/LivingVillage.Desktop.Tests/M6bTests.fs')
-rw-r--r--src/LivingVillage.Desktop.Tests/M6bTests.fs82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop.Tests/M6bTests.fs b/src/LivingVillage.Desktop.Tests/M6bTests.fs
new file mode 100644
index 0000000..6ae0634
--- /dev/null
+++ b/src/LivingVillage.Desktop.Tests/M6bTests.fs
@@ -0,0 +1,82 @@
+namespace LivingVillage.Desktop.Tests
+
+open Microsoft.VisualStudio.TestTools.UnitTesting
+open LivingVillage.Kernel
+open LivingVillage.Desktop
+
+[<TestClass>]
+type M6bMenuTests () =
+
+ [<TestMethod>]
+ member _.MainMenuHasRequiredOrderAndStartsAtNewGame () =
+ let state = MenuState.create SimulationControl.initial false
+
+ Assert.AreEqual<MenuPage>(MainMenu, state.Page)
+ Assert.AreEqual<MenuItem list>(
+ [ NewGameItem; LoadItem; SettingsItem; ControlsItem; ExitItem ],
+ MenuState.items state)
+ Assert.AreEqual<int>(0, state.Selected)
+
+ [<TestMethod>]
+ member _.SelectionWrapsAndConfirmProducesNewGameCommand () =
+ let state = MenuState.create SimulationControl.initial false
+ let wrapped = MenuState.move Up state
+ let confirmed = MenuState.update Confirm wrapped |> snd
+
+ Assert.AreEqual<MenuItem>(ExitItem, MenuState.selectedItem wrapped)
+ Assert.AreEqual<MenuCommand>(ExitGame, confirmed)
+ let newGameState, newGameCommand = MenuState.update Confirm state
+ Assert.AreEqual<MenuPage>(MainMenu, newGameState.Page)
+ Assert.AreEqual<MenuCommand>(StartNewGame, newGameCommand)
+
+ [<TestMethod>]
+ member _.SettingsCanSelectEveryExistingSimulationMode () =
+ let initial = MenuState.create SimulationControl.initial false
+ let settings, _ = MenuState.update Confirm (MenuState.move Down (MenuState.move Down initial))
+ let oneX, oneXCommand = MenuState.update Confirm settings
+ let twoX, twoXCommand = MenuState.update Confirm (MenuState.move Down settings)
+ let fiveX, fiveXCommand = MenuState.update Confirm (MenuState.move Down (MenuState.move Down settings))
+ let paused, pausedCommand = MenuState.update Confirm (MenuState.move Down (MenuState.move Down (MenuState.move Down settings)))
+
+ Assert.AreEqual<MenuPage>(Settings, settings.Page)
+ Assert.AreEqual<MenuCommand>(ApplySettings { Paused = false; Speed = OneX }, oneXCommand)
+ Assert.AreEqual<MenuCommand>(ApplySettings { Paused = false; Speed = TwoX }, twoXCommand)
+ Assert.AreEqual<MenuCommand>(ApplySettings { Paused = false; Speed = FiveX }, fiveXCommand)
+ Assert.AreEqual<MenuCommand>(ApplySettings { Paused = true; Speed = OneX }, pausedCommand)
+ Assert.AreEqual<MenuPage>(Settings, oneX.Page)
+
+ [<TestMethod>]
+ member _.EscapeReturnsToPreviousPageAndKeepsCurrentWorld () =
+ let playing = MenuState.create SimulationControl.initial true |> MenuState.enterGame
+ let settings = MenuState.openSettings playing
+ let returned, command = MenuState.update Back settings
+ let main = MenuState.openMain playing
+ let continued, continueCommand = MenuState.update Confirm main
+
+ Assert.AreEqual<MenuPage>(Playing, returned.Page)
+ Assert.AreEqual<MenuCommand>(NoCommand, command)
+ Assert.IsTrue(returned.HasCurrentWorld)
+ Assert.AreEqual<MenuPage>(MainMenu, main.Page)
+ Assert.AreEqual<MenuItem>(ContinueItem, MenuState.selectedItem main)
+ Assert.AreEqual<MenuPage>(Playing, continued.Page)
+ Assert.AreEqual<MenuCommand>(ContinueGame, continueCommand)
+
+ [<TestMethod>]
+ member _.ControlsPageExposesCompleteKeyboardBindings () =
+ let state = MenuState.openControls (MenuState.create SimulationControl.initial false)
+ let keys = MenuState.controlRows |> List.map (fun row -> row.Keys)
+
+ Assert.AreEqual<MenuPage>(Controls, state.Page)
+ Assert.AreEqual<string list>(
+ [ "WASD"; "E"; "1-6"; "Q"; "TAB"; "C"; "L"; "P"; "F1/F2/F3"; "F6"; "F7"; "ESC"; "UP/DOWN"; "ENTER" ],
+ keys)
+
+ [<TestMethod>]
+ member _.LoadFailureIsAnExplicitPageAndBackReturnsToMenu () =
+ let failed = MenuState.showLoadError "missing save" (MenuState.create SimulationControl.initial false)
+ let returned, command = MenuState.update Back failed
+
+ Assert.AreEqual<MenuPage>(LoadError, failed.Page)
+ Assert.AreEqual<string option>(Some "missing save", failed.Error)
+ Assert.AreEqual<MenuPage>(MainMenu, returned.Page)
+ Assert.AreEqual<MenuCommand>(NoCommand, command)