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.

quotes_test.gno

3.00 Kb · 110 lines
  1package quotes
  2
  3import (
  4	"strings"
  5	"testing"
  6)
  7
  8// TestFeaturedIndexDeterministic verifies the rotating pick is a pure,
  9// deterministic function of (height, count): same inputs -> same index,
 10// always within [0, count).
 11func TestFeaturedIndexDeterministic(t *testing.T) {
 12	tests := []struct {
 13		name   string
 14		height int64
 15		count  int
 16		want   int
 17	}{
 18		{"zero height", 0, 4, 0},
 19		{"wraps at count", 4, 4, 0},
 20		{"mid range", 5, 4, 1},
 21		{"single quote always zero", 12345, 1, 0},
 22		{"empty list", 100, 0, -1},
 23		{"negative height normalized", -3, 4, 3},
 24		{"large height", 1_000_003, 3, 1},
 25	}
 26	for _, tt := range tests {
 27		t.Run(tt.name, func(t *testing.T) {
 28			got := featuredIndex(tt.height, tt.count)
 29			if got != tt.want {
 30				t.Errorf("featuredIndex(%d, %d) = %d, want %d",
 31					tt.height, tt.count, got, tt.want)
 32			}
 33			// For non-empty lists the index must be a valid slot.
 34			if tt.count > 0 && (got < 0 || got >= tt.count) {
 35				t.Errorf("featuredIndex(%d, %d) = %d, out of range [0,%d)",
 36					tt.height, tt.count, got, tt.count)
 37			}
 38		})
 39	}
 40
 41	// Determinism: repeated calls with identical inputs never diverge.
 42	for i := 0; i < 5; i++ {
 43		if featuredIndex(7, 4) != featuredIndex(7, 4) {
 44			t.Fatal("featuredIndex is not deterministic")
 45		}
 46	}
 47}
 48
 49// TestValidate covers the content rules enforced before a quote is stored.
 50func TestValidate(t *testing.T) {
 51	tests := []struct {
 52		name    string
 53		text    string
 54		wantErr error
 55	}{
 56		{"ok short", "hello world", nil},
 57		{"ok at limit", strings.Repeat("x", maxQuoteLen), nil},
 58		{"empty", "", errEmpty},
 59		{"too long", strings.Repeat("x", maxQuoteLen+1), errTooLong},
 60	}
 61	for _, tt := range tests {
 62		t.Run(tt.name, func(t *testing.T) {
 63			err := validate(tt.text)
 64			if err != tt.wantErr {
 65				t.Errorf("validate(%q) err = %v, want %v", tt.name, err, tt.wantErr)
 66			}
 67		})
 68	}
 69}
 70
 71// TestRenderSeeded checks that a fresh deploy (seeded board) renders the
 72// expected structure: title, a blockquote featured pick, and the full list
 73// containing every seeded quote.
 74func TestRenderSeeded(t *testing.T) {
 75	out := Render("")
 76
 77	if !strings.Contains(out, "# Quote of the Moment") {
 78		t.Error("missing title heading")
 79	}
 80	if !strings.Contains(out, "\n> ") {
 81		t.Error("featured quote is not rendered as a blockquote")
 82	}
 83	if !strings.Contains(out, "## All quotes (") {
 84		t.Error("missing full-list section")
 85	}
 86
 87	// Every seeded quote must appear in the listing.
 88	for _, q := range board {
 89		if !strings.Contains(out, q.text) {
 90			t.Errorf("rendered output missing seeded quote: %q", q.text)
 91		}
 92	}
 93
 94	// Seeded quotes have no author and should surface the house label.
 95	if !strings.Contains(out, "the board") {
 96		t.Error("seeded quotes should be attributed to \"the board\"")
 97	}
 98}
 99
100// TestSeededBoard confirms init populated the board and ids are sequential.
101func TestSeededBoard(t *testing.T) {
102	if len(board) < 3 {
103		t.Fatalf("expected at least 3 seeded quotes, got %d", len(board))
104	}
105	for i, q := range board {
106		if q.id != i {
107			t.Errorf("quote at position %d has id %d, want %d", i, q.id, i)
108		}
109	}
110}