feat(fsharp): m09 input/app/runtime and m10 extensions with tests

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-29 00:56:27 +01:00
co-authored by Claude Opus 5.5
parent e27372f017
commit 55f8b0b30f
14 changed files with 435 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
module Snake.Tests.M10Extensions
open Expecto
open Snake
open Snake.Model
open Snake.IO
open Snake.Stream
open Snake.Tests.Fixtures
open Snake.Tests.M09Helpers
let private frameTimes = [ 25L; 50L; 75L; 100L; 125L; 150L; 175L; 200L ]
[<Tests>]
let tests =
testList "M10 Extensions" [
yield! fixtureTests "m10-update" "update" (fun c ->
Expect.equal (Game.update (gameState (arg 0 c)) (action (arg 1 c))) (gameState (expected c)) "update")
yield! fixtureTests "m10-moves-every" "movesEvery" (fun c ->
Expect.equal (Game.movesEvery (num (arg 0 c))) (num (expected c)) "movesEvery")
yield! fixtureTests "m10-input" "keyToAction" (fun c ->
Expect.equal (Input.keyToAction (str (arg 0 c))) (opt action (expected c)) "keyToAction")
testCase "the animation clock runs every 25 ms" (fun () -> Expect.equal App.FRAME_MS 25L "FRAME_MS")
testCase "speedActions turns the clock into Frame actions every 25 ms" (fun () ->
Expect.equal (Stream.run (List.map Time frameTimes) App.speedActions) (List.replicate 8 Frame) "actions")
testCase "speedActions still turns keys into actions, including pause and restart" (fun () ->
Expect.equal
(Stream.run [ KeyDown " "; KeyDown "r"; KeyDown "ArrowUp" ] App.speedActions)
[ TogglePause; Restart; Turn Up ]
"actions")
testCase "main (seed 42) draws a moved snake after eight 25 ms frames" (fun () ->
let traced = IO.trace 42u (App.main ())
Expect.equal traced.Ops [ RandomSeed ] "ops"
let first, afterFirst = Stream.step (Time 0L) traced.Result
Expect.equal (drawn (List.head first)) (View.view (Spawn.newGame 42u)) "first drawing"
let drawings = Stream.run (List.map Time frameTimes) afterFirst
Expect.equal (List.length drawings) 8 "eight drawings"
let start = Spawn.newGame 42u
let moved =
{ start with
Snake = start.Snake |> List.map (fun p -> { p with X = p.X + 1 })
Frame = 8 }
Expect.equal (drawn drawings[7]) (View.view moved) "moved snake")
]