package coffee.liz.rookery import coffee.liz.rookery.model.DNF import coffee.liz.rookery.model.formatTime import coffee.liz.rookery.stats.Averages import coffee.liz.rookery.stats.StatKind import coffee.liz.rookery.stats.StatSummary import coffee.liz.rookery.stats.newPersonalBests import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull class StatsTest { @Test fun ao5TrimsBestAndWorst() { assertEquals(12000, Averages.average(listOf(10000, 11000, 12000, 13000, 20000))) assertEquals(12000, Averages.average(listOf(10000, 11000, 12000, 13000, DNF))) assertEquals(DNF, Averages.average(listOf(10000, 11000, 12000, DNF, DNF))) } @Test fun trimCounts() { assertEquals(1, Averages.trim(5)); assertEquals(1, Averages.trim(12)) assertEquals(3, Averages.trim(50)); assertEquals(5, Averages.trim(100)); assertEquals(50, Averages.trim(1000)) } @Test fun mo3AnyDnfIsDnf() { assertEquals(DNF, Averages.mean(listOf(1, 2, DNF))) assertEquals(2, Averages.mean(listOf(1, 2, 3))) } @Test fun slidingBestMatchesBruteForce() { val rng = kotlin.random.Random(42) val xs = List(300) { if (rng.nextInt(20) == 0) DNF else rng.nextLong(8000, 20000) } for (n in listOf(5, 12, 100)) { val brute = (0..xs.size - n).minOf { Averages.average(xs.subList(it, it + n)) } assertEquals(brute, Averages.best(xs, n)) } assertEquals((0..xs.size - 3).minOf { Averages.mean(xs.subList(it, it + 3)) }, Averages.best(xs, 3, mean = true)) } @Test fun personalBestsFromLatestSolve() { val before = listOf(15000L, 14000, 16000, 15500, 14500) val after = before + 11000L val pbs = newPersonalBests(StatSummary.of(before), StatSummary.of(after)).map { it.kind } assertEquals(listOf(StatKind.SINGLE, StatKind.MO3, StatKind.AO5), pbs) assertNull(newPersonalBests(StatSummary.of(after), StatSummary.of(after + 30000L)).firstOrNull { it.kind == StatKind.SINGLE }) } @Test fun formatting() { assertEquals("9.99", formatTime(9999)) assertEquals("10.00", formatTime(9999, round = true)) assertEquals("1:02.34", formatTime(62345)) assertEquals("DNF", formatTime(DNF)) } }