Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

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}