26aa154547
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 37s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m8s
Squash the 12 goose migrations into one 00001_baseline.sql (there is no prod data; verified schema-identical to the chain via a pg_dump diff + the green integration suite) and rename the game-variant labels english/russian_scrabble/erudit -> scrabble_en/scrabble_ru/erudit_ru across the backend, the FlatBuffers wire values and the UI. dawg filenames and the Go enum identifiers are unchanged; the i18n display keys are kept. Adds PRERELEASE.md (the R1-R7 pre-release tracker), linked from CLAUDE.md. Contour DB wipe and the scrabble-dictionary tidy are follow-ups.
80 lines
2.4 KiB
Go
80 lines
2.4 KiB
Go
package game
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
|
||
"github.com/google/uuid"
|
||
|
||
"scrabble/backend/internal/engine"
|
||
)
|
||
|
||
func TestWriteGCG(t *testing.T) {
|
||
g := Game{
|
||
ID: uuid.MustParse("00000000-0000-7000-8000-000000000001"),
|
||
Variant: engine.VariantEnglish,
|
||
DictVersion: "v1",
|
||
Players: 2,
|
||
}
|
||
moves := []HistoryMove{
|
||
{
|
||
Seq: 0, Seat: 0, Action: "play", Score: 10, RunningTotal: 10,
|
||
Dir: "H", MainRow: 7, MainCol: 7,
|
||
Tiles: []engine.TileRecord{{Row: 7, Col: 7, Letter: "c"}, {Row: 7, Col: 8, Letter: "a"}, {Row: 7, Col: 9, Letter: "t"}},
|
||
Words: []string{"cat"}, Rack: []string{"c", "a", "t", "s", "e", "r", "?"},
|
||
},
|
||
{
|
||
Seq: 1, Seat: 1, Action: "play", Score: 2, RunningTotal: 2,
|
||
Dir: "V", MainRow: 7, MainCol: 8,
|
||
Tiles: []engine.TileRecord{{Row: 8, Col: 8, Letter: "s", Blank: true}},
|
||
Words: []string{"as"}, Rack: []string{"a", "s", "?", "e"},
|
||
},
|
||
{Seq: 2, Seat: 0, Action: "pass", RunningTotal: 10, Rack: []string{"x", "y", "z"}},
|
||
{Seq: 3, Seat: 1, Action: "exchange", RunningTotal: 2, Exchanged: []string{"q", "u"}, Rack: []string{"q", "u", "i"}},
|
||
{Seq: 4, Seat: 0, Action: "resign", RunningTotal: 10, Rack: []string{"a", "b"}},
|
||
{Seq: 5, Seat: 1, Action: "timeout", RunningTotal: 2, Rack: []string{"c"}},
|
||
}
|
||
|
||
out := writeGCG(g, []string{"Alice", "Bob"}, moves)
|
||
wantLines := []string{
|
||
"#character-encoding UTF-8",
|
||
"#player1 p1 Alice",
|
||
"#player2 p2 Bob",
|
||
"#lexicon scrabble_en/v1",
|
||
"#title game 00000000-0000-7000-8000-000000000001",
|
||
">p1: CATSER? 8H CAT +10 10",
|
||
">p2: AS?E I8 .s +2 2",
|
||
">p1: XYZ - +0 10",
|
||
">p2: QUI -QU +0 2",
|
||
"#note p1 resigned (rack AB)",
|
||
"#note p2 timed out (rack C)",
|
||
}
|
||
lines := strings.Split(strings.TrimRight(out, "\n"), "\n")
|
||
got := make(map[string]bool, len(lines))
|
||
for _, l := range lines {
|
||
got[l] = true
|
||
}
|
||
for _, want := range wantLines {
|
||
if !got[want] {
|
||
t.Errorf("GCG missing line %q\n--- full output ---\n%s", want, out)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestGCGTilesUppercasesCyrillic(t *testing.T) {
|
||
if got := gcgTiles([]string{"к", "о", "т", "?"}); got != "КОТ?" {
|
||
t.Errorf("gcgTiles = %q, want КОТ?", got)
|
||
}
|
||
}
|
||
|
||
func TestGCGPos(t *testing.T) {
|
||
across := gcgPos(HistoryMove{Dir: "H", MainRow: 7, MainCol: 6})
|
||
if across != "8G" {
|
||
t.Errorf("across pos = %q, want 8G", across)
|
||
}
|
||
down := gcgPos(HistoryMove{Dir: "V", MainRow: 6, MainCol: 7})
|
||
if down != "H7" {
|
||
t.Errorf("down pos = %q, want H7", down)
|
||
}
|
||
}
|