diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-20 21:16:49 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-20 21:16:49 +0800 |
| commit | c5ff7685e5b3ac5dc46fce74ef1b302de09af1e6 (patch) | |
| tree | c1fccb5d44bd6b055f5f1521ea259446e77057a5 /src/LivingVillage.Desktop.Tests | |
| parent | 5cb4970e2410a43e528b4b3e44dda15fac0a219a (diff) | |
| download | living-village-c5ff7685e5b3ac5dc46fce74ef1b302de09af1e6.tar.gz | |
feat(desktop): add Chinese village presentation prototype
[Change Nature]
- This commit adds a deterministic presentation-model feature, not MonoGame rendering.
[New Capability]
- Provide an immutable Jiangnan village scene with homes, waterways, paths, bridge, bamboo, and garden elements.
- Provide typed home transitions, four-way input mapping, tick animation, NPC styles, and Chinese stage-one labels.
[Implementation]
- Add the pure VillagePresentation module and six focused MSTest cases.
- Keep the model free of mutable global state and update only the required F# compile order.
[Impact]
- This commit affects the Desktop presentation and test projects only.
- Kernel behavior, Game.fs wiring, MonoGame drawing, and existing acceptance artifacts remain unchanged.
Diffstat (limited to 'src/LivingVillage.Desktop.Tests')
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj | 1 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/PrototypeTests.fs | 102 |
2 files changed, 103 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj index 405e8b5..569190a 100644 --- a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj +++ b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj @@ -9,6 +9,7 @@ <Compile Include="DesktopTests.fs" /> <Compile Include="M6aTests.fs" /> <Compile Include="M6bTests.fs" /> + <Compile Include="PrototypeTests.fs" /> </ItemGroup> <ItemGroup> diff --git a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs new file mode 100644 index 0000000..b959d70 --- /dev/null +++ b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs @@ -0,0 +1,102 @@ +namespace LivingVillage.Desktop.Tests + +open Microsoft.VisualStudio.TestTools.UnitTesting +open LivingVillage.Kernel.Sim +open LivingVillage.Desktop.VillagePresentation + +[<TestClass>] +type PrototypeTests () = + + [<TestMethod>] + member _.SceneContainsTheJiangnanPrototypeAndReachableHomeDoor () = + let first = createScene () + let second = createScene () + let requiredProps = + [ WhiteWallDarkTileHome + HomeDoor + RiverChannel + RiverBank + StoneBridge + StonePaving + Bamboo + VegetableGarden ] + + Assert.AreEqual<PrototypeScene>(first, second) + Assert.AreEqual<PrototypeScene>(scene, first) + Assert.IsTrue(first.Homes.Length > 0, "The prototype needs at least one home.") + Assert.IsTrue( + requiredProps + |> List.forall (fun prop -> first.Elements |> List.exists (fun element -> element.Prop = prop)), + "The scene is missing one or more required Jiangnan elements.") + + let home = first.Homes |> List.head + Assert.IsTrue(isNearHomeDoor first.InitialPlayerPosition home) + + [<TestMethod>] + member _.HomeEntryAndExitExposeExplicitSuccessAndFailureBranches () = + let scene = createScene () + let home = scene.Homes |> List.head + let entered = enterHome scene.InitialPlayerPosition Outside + + match entered with + | Ok (Inside enteredHome) -> + Assert.AreEqual<HomeId>(home.Id, enteredHome) + | Ok Outside -> Assert.Fail("Entering a home must produce Inside state.") + | Error failure -> Assert.Fail(sprintf "Expected entry to succeed, got %A." failure) + + match entered with + | Ok inside -> + match enterHome scene.InitialPlayerPosition inside with + | Error (AlreadyInsideHome homeId) -> Assert.AreEqual<HomeId>(home.Id, homeId) + | other -> Assert.Fail(sprintf "Expected AlreadyInsideHome, got %A." other) + | Error _ -> Assert.Fail("The first entry must succeed before checking the duplicate entry.") + + match exitHome (Inside home.Id) with + | Ok Outside -> () + | other -> Assert.Fail(sprintf "Expected exit to succeed, got %A." other) + + match exitHome Outside with + | Error NotInsideHome -> () + | other -> Assert.Fail(sprintf "Expected NotInsideHome, got %A." other) + + match exitHome (Inside(HomeId 999)) with + | Error(HomeNotFound(HomeId 999)) -> () + | other -> Assert.Fail(sprintf "Expected HomeNotFound, got %A." other) + + let farAway = { X = scene.InitialPlayerPosition.X + 20; Y = scene.InitialPlayerPosition.Y + 20 } + match enterHome farAway Outside with + | Error NotNearHomeDoor -> () + | other -> Assert.Fail(sprintf "Expected NotNearHomeDoor, got %A." other) + + [<TestMethod>] + member _.FourWayInputMapsToFourDirections () = + Assert.AreEqual<Direction option>(Some North, directionForInput UpInput) + Assert.AreEqual<Direction option>(Some South, directionForInput DownInput) + Assert.AreEqual<Direction option>(Some West, directionForInput LeftInput) + Assert.AreEqual<Direction option>(Some East, directionForInput RightInput) + Assert.AreEqual<Direction option>(None, directionForInput NoInput) + + [<TestMethod>] + member _.AnimationFrameChangesWithSimulationTick () = + let first = animationFrame (SimulationTick 0L) + let second = animationFrame (SimulationTick 4L) + let nextCycle = animationFrame (SimulationTick 8L) + + Assert.AreNotEqual<CharacterAnimationFrame>(first, second) + Assert.AreEqual<CharacterAnimationFrame>(first, nextCycle) + + [<TestMethod>] + member _.NpcIdProducesStableAndDistinctCharacterStyles () = + let first = characterStyle (NpcId 0) + let sameNpc = characterStyle (NpcId 0) + let second = characterStyle (NpcId 1) + + Assert.AreEqual<CharacterStyle>(first, sameNpc) + Assert.AreNotEqual<CharacterStyle>(first, second) + + [<TestMethod>] + member _.StageOneCopyProvidesChineseInteractionLabels () = + Assert.AreEqual<string>("互动", stageOneCopy.Interact) + Assert.AreEqual<string>("需求", stageOneCopy.Needs) + Assert.AreEqual<string>("交易", stageOneCopy.Trade) + Assert.AreEqual<string>("进入民居", stageOneCopy.EnterHome) |
