Files
miti99bot/internal/modules/wordle/compare_test.go
T
tiennm99 5980897475 feat(modules): port wordle module + per-subject locking
Phase 5b of go-port-cloud-run plan. Port 14855-word dictionary
(89 KB, byte-identical to JS source) and four wordle commands
(/wordle, /wordle_new, /wordle_giveup, /wordle_stats).

KV wire-format parity: GameState/Stats JSON match JS shape;
*int64 LastResultAt for null-value compatibility. Two real bugs
caught and fixed: (1) defaultRNG data race in handlers — switched
to math/rand.Intn (mutex-protected package-level); (2) Get→mutate→Put
logical race in groups — added per-subject sync.Mutex map to serialize
access. TTL deferred (Firestore has no expirationTtl equiv — Phase 11 GC).
2026-05-09 09:35:23 +07:00

91 lines
2.9 KiB
Go

package wordle
import (
"strings"
"testing"
)
// resultsLetters joins the .Result fields so test expectations stay readable.
func resultsLetters(rs []LetterScore) string {
out := make([]string, len(rs))
for i, r := range rs {
out[i] = r.Result
}
return strings.Join(out, ",")
}
func TestCompareWords_AllCorrect(t *testing.T) {
r := CompareWords("crane", "crane")
if got, want := resultsLetters(r), "correct,correct,correct,correct,correct"; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestCompareWords_AllWrong(t *testing.T) {
r := CompareWords("abcde", "fghij")
if got, want := resultsLetters(r), "wrong,wrong,wrong,wrong,wrong"; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestCompareWords_CorrectOverPartial(t *testing.T) {
// guess "slate" vs target "shale" → s correct, l partial, a correct,
// t wrong, e correct
r := CompareWords("slate", "shale")
if got, want := resultsLetters(r), "correct,partial,correct,wrong,correct"; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestCompareWords_DuplicateExcessLettersWrong(t *testing.T) {
// target "abbey", guess "babes": b@0 partial, a@1 partial, b@2 correct,
// e@3 correct, s@4 wrong
r := CompareWords("babes", "abbey")
if got, want := resultsLetters(r), "partial,partial,correct,correct,wrong"; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestCompareWords_DuplicateGuessSingleTarget(t *testing.T) {
// target "abide", guess "aahed": a@0 correct, a@1 wrong (pool exhausted),
// h wrong, e@3 partial, d@4 partial
r := CompareWords("aahed", "abide")
if got, want := resultsLetters(r), "correct,wrong,wrong,partial,partial"; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestCompareWords_DuplicatesBothSides(t *testing.T) {
// target "lever", guess "ebbed":
// pass1: e@3=e correct (consume e). pool=[l,e,v,r]
// pass2: e@0 partial (consume remaining e); b@1 wrong; b@2 wrong; d@4 wrong
r := CompareWords("ebbed", "lever")
if got, want := resultsLetters(r), "partial,wrong,wrong,correct,wrong"; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestCompareWords_AllSameTargetExhaustsPool(t *testing.T) {
// target "aaaaa", guess "aabbb" → both 'a's are positional matches; the
// remaining b's find nothing in the pool (already empty), so they're wrong.
// Locks the "pool exhausted before pass 2" branch.
r := CompareWords("aabbb", "aaaaa")
if got, want := resultsLetters(r), "correct,correct,wrong,wrong,wrong"; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestCompareWords_PreservesGuessLetters(t *testing.T) {
r := CompareWords("crane", "cloud")
letters := make([]string, len(r))
for i, x := range r {
letters[i] = x.Letter
}
want := []string{"c", "r", "a", "n", "e"}
for i := range want {
if letters[i] != want[i] {
t.Errorf("letter[%d] = %s, want %s", i, letters[i], want[i])
}
}
}