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.
101 lines
3.2 KiB
Go
101 lines
3.2 KiB
Go
package engine
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"gitea.iliadenisov.ru/developer/scrabble-solver/board"
|
|
"gitea.iliadenisov.ru/developer/scrabble-solver/scrabble"
|
|
)
|
|
|
|
// TestRegistryOpensEveryVariant checks that Open loads all three variants at the
|
|
// requested version and reports them through Latest and Versions.
|
|
func TestRegistryOpensEveryVariant(t *testing.T) {
|
|
for _, v := range Variants() {
|
|
version, solver, err := testReg.Latest(v)
|
|
if err != nil {
|
|
t.Fatalf("latest %s: %v", v, err)
|
|
}
|
|
if version != testVersion {
|
|
t.Errorf("latest %s version = %q, want %q", v, version, testVersion)
|
|
}
|
|
if solver == nil {
|
|
t.Errorf("latest %s solver is nil", v)
|
|
}
|
|
if got := testReg.Versions(v); len(got) != 1 || got[0] != testVersion {
|
|
t.Errorf("versions %s = %v, want [%q]", v, got, testVersion)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestRegistryValidatesKnownWords is the per-variant smoke test: a known word
|
|
// laid over the centre validates against the loaded dictionary, including the
|
|
// Эрудит variant.
|
|
func TestRegistryValidatesKnownWords(t *testing.T) {
|
|
cases := []struct {
|
|
variant Variant
|
|
word string
|
|
}{
|
|
{VariantEnglish, "cat"},
|
|
{VariantRussianScrabble, "кот"},
|
|
{VariantErudit, "кот"},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.variant.String(), func(t *testing.T) {
|
|
solver, err := testReg.Solver(tc.variant, testVersion)
|
|
if err != nil {
|
|
t.Fatalf("solver: %v", err)
|
|
}
|
|
rs := solver.Rules()
|
|
row, col := centre(rs)
|
|
ps := placementsForWord(t, rs, row, col, scrabble.Horizontal, tc.word)
|
|
if _, err := solver.ValidatePlay(board.New(rs.Rows, rs.Cols), scrabble.Horizontal, ps); err != nil {
|
|
t.Fatalf("validate %q against %s: %v", tc.word, tc.variant, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestRegistryUnknownLookups covers the not-found error taxonomy.
|
|
func TestRegistryUnknownLookups(t *testing.T) {
|
|
reg, err := Open(testDictDir(), testVersion, VariantEnglish)
|
|
if err != nil {
|
|
t.Fatalf("open scrabble_en-only registry: %v", err)
|
|
}
|
|
defer reg.Close()
|
|
|
|
if _, err := reg.Solver(VariantEnglish, "absent"); !errors.Is(err, ErrUnknownVersion) {
|
|
t.Errorf("solver with bad version: got %v, want ErrUnknownVersion", err)
|
|
}
|
|
if _, err := reg.Solver(VariantErudit, testVersion); !errors.Is(err, ErrUnknownVariant) {
|
|
t.Errorf("solver for unloaded variant: got %v, want ErrUnknownVariant", err)
|
|
}
|
|
if _, _, err := reg.Latest(VariantErudit); !errors.Is(err, ErrUnknownVariant) {
|
|
t.Errorf("latest for unloaded variant: got %v, want ErrUnknownVariant", err)
|
|
}
|
|
if got := reg.Versions(VariantErudit); got != nil {
|
|
t.Errorf("versions for unloaded variant = %v, want nil", got)
|
|
}
|
|
}
|
|
|
|
// TestRegistryCloseIdempotent verifies Close may be called more than once.
|
|
func TestRegistryCloseIdempotent(t *testing.T) {
|
|
reg, err := Open(testDictDir(), testVersion, VariantEnglish)
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
if err := reg.Close(); err != nil {
|
|
t.Fatalf("first close: %v", err)
|
|
}
|
|
if err := reg.Close(); err != nil {
|
|
t.Fatalf("second close: %v", err)
|
|
}
|
|
}
|
|
|
|
// TestRegistryOpenMissingDir fails when a dictionary file is absent.
|
|
func TestRegistryOpenMissingDir(t *testing.T) {
|
|
if _, err := Open(t.TempDir(), testVersion, VariantEnglish); err == nil {
|
|
t.Fatal("expected an error opening a registry over an empty directory")
|
|
}
|
|
}
|