clone

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

refactor/root-tui-model
puzzletea / session / session_test.go
session_test.go 4.2K
1package session23import (4 "path/filepath"5 "testing"6 "time"78 "github.com/FelineStateMachine/puzzletea/games/lightsout"9 "github.com/FelineStateMachine/puzzletea/store"10)1112func TestNormalizeSeed(t *testing.T) {13 tests := []struct {14 input string15 want string16 }{17 {input: "daily-challenge", want: "daily-challenge"},18 {input: "DailyChallenge", want: "dailyChallenge"},19 {input: "Week 01-2026 - #01", want: "week 01-2026 - #01"},20 {input: "seed-123", want: "seed-123"},21 }2223 for _, tt := range tests {24 if got := NormalizeSeed(tt.input); got != tt.want {25 t.Fatalf("NormalizeSeed(%q) = %q, want %q", tt.input, got, tt.want)26 }27 }28}2930func TestSeededNameDeterministic(t *testing.T) {31 seed := "zebra-seed"32 if got, want := SeededName(seed), SeededName(seed); got != want {33 t.Fatalf("SeededName(%q) = %q then %q", seed, got, want)34 }35}3637func TestSeededNameForGameDeterministicAndDistinct(t *testing.T) {38 seed := "zebra-seed"39 got := SeededNameForGame(seed, "Sudoku")40 if want := SeededNameForGame(seed, "Sudoku"); got != want {41 t.Fatalf("SeededNameForGame returned %q then %q", got, want)42 }43 if got == SeededName(seed) {44 t.Fatalf("SeededNameForGame(%q) should differ from SeededName(%q)", seed, seed)45 }46 if got == SeededNameForGame(seed, "Nonogram") {47 t.Fatal("different selected games should produce different seeded names")48 }49}5051func TestSeededNameForCreateLeafDeterministicAndDistinctByScope(t *testing.T) {52 seed := "create-seed"53 got := SeededNameForCreateLeaf(seed, "Nonogram", "nonogram/5x5", 1200)54 if want := SeededNameForCreateLeaf(seed, "Nonogram", "nonogram/5x5", 1200); got != want {55 t.Fatalf("SeededNameForCreateLeaf returned %q then %q", got, want)56 }57 if got == SeededNameForCreateLeaf(seed, "Nonogram", "nonogram/10x10", 1200) {58 t.Fatal("SeededNameForCreateLeaf should differ by leaf")59 }60 if got == SeededNameForCreateLeaf(seed, "Nonogram", "nonogram/5x5", 1300) {61 t.Fatal("SeededNameForCreateLeaf should differ by Elo")62 }63}6465func TestImportRecordReappliesTitle(t *testing.T) {66 g, err := lightsout.New(3, 3)67 if err != nil {68 t.Fatal(err)69 }70 save, err := g.GetSave()71 if err != nil {72 t.Fatal(err)73 }7475 loaded, err := ImportRecord(&store.GameRecord{76 Name: "saved-game",77 GameType: "Lights Out",78 SaveState: string(save),79 })80 if err != nil {81 t.Fatalf("ImportRecord returned error: %v", err)82 }83 if loaded == nil {84 t.Fatal("ImportRecord returned nil game")85 }86}8788func TestCreateRecordAndResumeAbandonedDeterministicRecord(t *testing.T) {89 s := openSessionTestStore(t)9091 g, err := lightsout.New(3, 3)92 if err != nil {93 t.Fatal(err)94 }95 rec, err := CreateRecord(s, g, "demo", "Lights Out", "Easy", store.NormalRunMetadata())96 if err != nil {97 t.Fatalf("CreateRecord returned error: %v", err)98 }99 if rec.ID == 0 {100 t.Fatal("CreateRecord did not populate ID")101 }102103 rec.Status = store.StatusAbandoned104 if err := s.UpdateStatus(rec.ID, store.StatusAbandoned); err != nil {105 t.Fatal(err)106 }107 if err := ResumeAbandonedDeterministicRecord(s, rec); err != nil {108 t.Fatalf("ResumeAbandonedDeterministicRecord returned error: %v", err)109 }110111 saved, err := s.GetDailyGame(rec.Name)112 if err != nil {113 t.Fatal(err)114 }115 if saved == nil {116 t.Fatal("expected saved record to exist")117 }118 if saved.Status != store.StatusInProgress {119 t.Fatalf("status = %q, want %q", saved.Status, store.StatusInProgress)120 }121}122123func TestCreateRecordUsesExplicitRunMetadata(t *testing.T) {124 s := openSessionTestStore(t)125126 g, err := lightsout.New(3, 3)127 if err != nil {128 t.Fatal(err)129 }130131 day := time.Date(2026, 2, 14, 15, 30, 0, 0, time.Local)132 rec, err := CreateRecord(s, g, "plain-name", "Lights Out", "Easy", store.DailyRunMetadata(day))133 if err != nil {134 t.Fatalf("CreateRecord returned error: %v", err)135 }136 if rec.RunKind != store.RunKindDaily {137 t.Fatalf("RunKind = %q, want %q", rec.RunKind, store.RunKindDaily)138 }139 if rec.RunDate == nil {140 t.Fatal("RunDate = nil, want daily date")141 }142 if got, want := rec.RunDate.Format("2006-01-02"), "2026-02-14"; got != want {143 t.Fatalf("RunDate = %q, want %q", got, want)144 }145}146147func openSessionTestStore(t *testing.T) *store.Store {148 t.Helper()149 s, err := store.Open(filepath.Join(t.TempDir(), "session.db"))150 if err != nil {151 t.Fatal(err)152 }153 t.Cleanup(func() { _ = s.Close() })154 return s155}