package snake import Fixtures.* class M04RandomSuite extends munit.FunSuite: // Same values as the JS and F# tracks: if mulberry32 drifts (signed math, missing unsigned conversion), these fail. cases("m04-random").foreach { c => test(s"nextUint32: ${c("name").str}") { val e = c("expected").arr assertEquals(Random.nextUint32.run(c("args")(0).num.toLong), (e(0).num.toLong, e(1).num.toLong)) } } cases("m04-int-below").foreach { c => test(s"intBelow: ${c("name").str}") { val a = c("args") val e = c("expected").arr assertEquals(Random.intBelow(a(0).num.toInt).run(a(1).num.toLong), (e(0).num.toInt, e(1).num.toLong)) } } test("the recorded steps chain: each step starts from the previous step's seed") { val cs = cases("m04-random") cs.zipWithIndex.foreach { (c, i) => if !c("name").str.endsWith("-step-1") then assertEquals(c("args")(0).num.toLong, cs(i - 1)("expected")(1).num.toLong) } } test("pure returns its value and leaves the seed alone") { assertEquals(Random.pure("x").run(99L), ("x", 99L)) } test("map applies f to the value and keeps the seed from the underlying step") { val (v, s) = Random.nextUint32.run(5L) assertEquals(Random.nextUint32.map(_ + 1).run(5L), (v + 1, s)) } test("map with the identity function changes nothing") { assertEquals(Random.nextUint32.map(identity).run(5L), Random.nextUint32.run(5L)) } test("flatMap threads the seed through both steps") { val (a, s1) = Random.nextUint32.run(5L) val (b, s2) = Random.nextUint32.run(s1) val both = Random.nextUint32.flatMap(x => Random.nextUint32.map(y => (x, y))) assertEquals(both.run(5L), ((a, b), s2)) } test("flatMap with pure on the left or right changes nothing") { assertEquals( Random.pure(3L).flatMap(x => Random.nextUint32.map(_ + x)).run(5L), Random.nextUint32.map(_ + 3L).run(5L) ) assertEquals(Random.nextUint32.flatMap(Random.pure).run(5L), Random.nextUint32.run(5L)) } test("intBelow always lands in [0, n)") { def draws(n: Int, seed: Long, count: Int): List[Int] = if count == 0 then Nil else val (v, s) = Random.intBelow(n).run(seed) v :: draws(n, s, count - 1) List(1, 2, 7, 400).foreach { n => draws(n, 123L, 50).foreach(v => assert(v >= 0 && v < n, s"$v not in [0, $n)")) } } test("running a Random does not mutate anything: same seed, same answer") { assertEquals(Random.nextUint32.run(8L), Random.nextUint32.run(8L)) }