wordle_test.gno
2.84 Kb Β· 110 lines
1package wordle
2
3import (
4 "strings"
5 "testing"
6)
7
8func TestScore(t *testing.T) {
9 tests := []struct {
10 name string
11 guess string
12 secret string
13 want string
14 }{
15 // all letters correct, correct spots.
16 {"all correct", "crane", "crane", "π©π©π©π©π©"},
17 // sβ¬ lπ¨ aπ¨ tπ¨ eπ© (secret t,a,b,l,e vs guess s,l,a,t,e)
18 {"present wrong spot", "slate", "table", "β¬π¨π¨π¨π©"},
19 // no shared letters at all.
20 {"all absent", "vivid", "champ", "β¬β¬β¬β¬β¬"},
21 }
22 for _, tt := range tests {
23 got := score(tt.guess, tt.secret)
24 if n := len([]rune(got)); n != wordLen {
25 t.Errorf("%s: score(%q,%q) produced %d tiles, want %d", tt.name, tt.guess, tt.secret, n, wordLen)
26 }
27 if got != tt.want {
28 t.Errorf("%s: score(%q,%q) = %q, want %q", tt.name, tt.guess, tt.secret, got, tt.want)
29 }
30 }
31}
32
33func TestScoreDuplicateLetters(t *testing.T) {
34 // guess "eerie" vs secret "there": guess e,e,r,i,e ; secret t,h,e,r,e
35 // greens: pos? e-t no, e-h no, r-e no, i-r no, e-e yes(pos4) π©
36 // secret remaining after greens: t,h,e,r (one e consumed at pos4)
37 // pos0 e: e available -> π¨, consume e (none left)
38 // pos1 e: no e left -> β¬
39 // pos2 r: r available -> π¨
40 // pos3 i: not present -> β¬
41 got := score("eerie", "there")
42 want := "π¨β¬π¨β¬π©"
43 if got != want {
44 t.Errorf("eerie/there: got %q want %q", got, want)
45 }
46}
47
48func TestIsFiveLetters(t *testing.T) {
49 tests := []struct {
50 in string
51 want bool
52 }{
53 {"crane", true},
54 {"CRANE", false}, // uppercase rejected (caller lowercases first)
55 {"cran", false}, // too short
56 {"cranes", false},// too long
57 {"cr4ne", false}, // digit
58 {"cr ne", false}, // space
59 {"", false},
60 }
61 for _, tt := range tests {
62 if got := isFiveLetters(tt.in); got != tt.want {
63 t.Errorf("isFiveLetters(%q) = %v, want %v", tt.in, got, tt.want)
64 }
65 }
66}
67
68func TestDayAndWordDeterminism(t *testing.T) {
69 // Same day index must yield the same word; word must be a dictionary entry.
70 d := dayIndex(blocksPerDay * 3)
71 if d != 3 {
72 t.Errorf("dayIndex: got %d want 3", d)
73 }
74 w1 := wordForDay(d)
75 w2 := wordForDay(d)
76 if w1 != w2 {
77 t.Errorf("wordForDay not deterministic: %q vs %q", w1, w2)
78 }
79 found := false
80 for _, w := range words {
81 if w == w1 {
82 found = true
83 break
84 }
85 }
86 if !found {
87 t.Errorf("wordForDay returned %q which is not in the dictionary", w1)
88 }
89 if !isFiveLetters(w1) {
90 t.Errorf("dictionary word %q is not 5 lowercase letters", w1)
91 }
92}
93
94func TestAllDictionaryWordsValid(t *testing.T) {
95 for _, w := range words {
96 if !isFiveLetters(w) {
97 t.Errorf("dictionary word %q is not exactly 5 lowercase letters", w)
98 }
99 }
100}
101
102func TestRenderContainsRules(t *testing.T) {
103 out := Render("")
104 if !strings.Contains(out, "Daily Word Puzzle") {
105 t.Errorf("Render missing title; got:\n%s", out)
106 }
107 if !strings.Contains(out, "Rules") {
108 t.Errorf("Render missing rules section; got:\n%s", out)
109 }
110}