clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

main
puzzletea / games / takuzu / elo_test.go
elo_test.go 3.2K
1package takuzu23import (4 "context"5 "fmt"6 "reflect"7 "testing"89 "github.com/FelineStateMachine/puzzletea/difficulty"10)1112func TestSpawnEloRejectsInvalidElo(t *testing.T) {13 mode := NewMode("Elo", "test", 8, 0.4)1415 tests := []difficulty.Elo{16 difficulty.MinElo - 1,17 difficulty.SoftCapElo + 1,18 }19 for _, elo := range tests {20 t.Run(fmt.Sprint(elo), func(t *testing.T) {21 gamer, report, err := mode.SpawnElo("seed", elo)22 if err == nil {23 t.Fatalf("SpawnElo(%d) error = nil, want invalid Elo error", elo)24 }25 if gamer != nil {26 t.Fatalf("SpawnElo(%d) gamer = %#v, want nil", elo, gamer)27 }28 if !reflect.DeepEqual(report, difficulty.Report{}) {29 t.Fatalf("SpawnElo(%d) report = %#v, want zero report", elo, report)30 }31 })32 }33}3435func TestSpawnEloContextCanceled(t *testing.T) {36 mode := NewMode("Elo", "test", 8, 0.4)37 ctx, cancel := context.WithCancel(context.Background())38 cancel()3940 gamer, report, err := mode.SpawnEloContext(ctx, "seed", 1200)41 if err == nil {42 t.Fatal("SpawnEloContext returned nil error for canceled context")43 }44 if gamer != nil {45 t.Fatalf("gamer = %#v, want nil", gamer)46 }47 if !reflect.DeepEqual(report, difficulty.Report{}) {48 t.Fatalf("report = %#v, want zero report", report)49 }50}5152func TestSpawnEloDeterministicForSameSeedAndElo(t *testing.T) {53 mode := NewMode("Elo", "test", 8, 0.4)54 const seed = "takuzu-deterministic"55 const elo = difficulty.Elo(1700)5657 gamerA, reportA, err := mode.SpawnElo(seed, elo)58 if err != nil {59 t.Fatalf("first SpawnElo returned error: %v", err)60 }61 gamerB, reportB, err := mode.SpawnElo(seed, elo)62 if err != nil {63 t.Fatalf("second SpawnElo returned error: %v", err)64 }6566 saveA, err := gamerA.GetSave()67 if err != nil {68 t.Fatalf("first GetSave returned error: %v", err)69 }70 saveB, err := gamerB.GetSave()71 if err != nil {72 t.Fatalf("second GetSave returned error: %v", err)73 }7475 if string(saveA) != string(saveB) {76 t.Fatalf("SpawnElo saves differ for same seed and Elo:\n%s\n%s", saveA, saveB)77 }78 if !reflect.DeepEqual(reportA, reportB) {79 t.Fatalf("report mismatch for same seed/Elo:\n%#v\n\n%#v", reportA, reportB)80 }81}8283func TestSpawnEloPopulatesDifficultyReport(t *testing.T) {84 mode := NewMode("Elo", "test", 8, 0.4)85 const target = difficulty.Elo(2200)8687 gamer, report, err := mode.SpawnElo("report-fields", target)88 if err != nil {89 t.Fatalf("SpawnElo returned error: %v", err)90 }91 if gamer == nil {92 t.Fatal("SpawnElo returned nil gamer")93 }94 if report.TargetElo != target {95 t.Fatalf("TargetElo = %d, want %d", report.TargetElo, target)96 }97 if err := difficulty.ValidateElo(report.ActualElo); err != nil {98 t.Fatalf("ActualElo = %d is invalid: %v", report.ActualElo, err)99 }100 if report.Confidence == "" {101 t.Fatal("Confidence is empty")102 }103104 requiredMetrics := map[string]float64{105 "size": 1,106 "cells": 1,107 "clue_count": 1,108 "empty_count": 1,109 "clue_density": 0,110 "target_prefilled": 0,111 "solution_count": 1,112 "solver_nodes": 1,113 "branches": 0,114 "max_depth": 0,115 }116 for key, min := range requiredMetrics {117 got, ok := report.Metrics[key]118 if !ok {119 t.Fatalf("Metrics[%q] missing from %#v", key, report.Metrics)120 }121 if got < min {122 t.Fatalf("Metrics[%q] = %f, want >= %f", key, got, min)123 }124 }125}