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

guestbook_test.gno

2.80 Kb · 105 lines
  1package guestbook
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"gno.land/p/moul/kit/store/v0"
  8)
  9
 10// resetState clears package globals between tests (globals persist across
 11// test functions in the same package binary).
 12func resetState() {
 13	entries = store.Named("guestbook: entry")
 14}
 15
 16func TestAddEntryAppendsAndCounts(t *testing.T) {
 17	resetState()
 18
 19	addEntry("g1alice", "hello world", 100)
 20	addEntry("g1bob", "second entry", 101)
 21
 22	if got := Count(); got != 2 {
 23		t.Fatalf("Count() = %d, want 2", got)
 24	}
 25
 26	out := Render("")
 27	if !strings.Contains(out, "**Total signatures:** 2") {
 28		t.Errorf("Render missing total; got:\n%s", out)
 29	}
 30	if !strings.Contains(out, "hello world") {
 31		t.Errorf("Render missing first message; got:\n%s", out)
 32	}
 33	if !strings.Contains(out, "second entry") {
 34		t.Errorf("Render missing second message; got:\n%s", out)
 35	}
 36	if !strings.Contains(out, "100") || !strings.Contains(out, "101") {
 37		t.Errorf("Render missing heights; got:\n%s", out)
 38	}
 39}
 40
 41func TestRenderNewestFirst(t *testing.T) {
 42	resetState()
 43
 44	addEntry("g1alice", "AAA oldest", 1)
 45	addEntry("g1alice", "BBB newest", 2)
 46
 47	out := Render("")
 48	iNew := strings.Index(out, "BBB newest")
 49	iOld := strings.Index(out, "AAA oldest")
 50	if iNew < 0 || iOld < 0 {
 51		t.Fatalf("both messages must appear; got:\n%s", out)
 52	}
 53	if iNew > iOld {
 54		t.Errorf("newest entry should render before oldest; got:\n%s", out)
 55	}
 56}
 57
 58func TestRenderEmpty(t *testing.T) {
 59	resetState()
 60
 61	out := Render("")
 62	if !strings.Contains(out, "No one has signed yet") {
 63		t.Errorf("empty render should invite signing; got:\n%s", out)
 64	}
 65}
 66
 67func TestEmptyMessagePanics(t *testing.T) {
 68	resetState()
 69
 70	defer func() {
 71		if r := recover(); r == nil {
 72			t.Errorf("signing an empty message should panic")
 73		}
 74	}()
 75	addEntry("g1alice", "   ", 1)
 76}
 77
 78// A message must not be able to break out of its table cell. The escaping now
 79// lives in ui.Cell, so this asserts the realm's rendered output rather than a
 80// local helper.
 81func TestRenderEscapesMessage(t *testing.T) {
 82	resetState()
 83	defer resetState()
 84	addEntry("g1manfred47kzduec920z88wfr64ylksmdcedlf5", "a|b", 1)
 85	out := Render("")
 86	if strings.Contains(out, "| a|b |") {
 87		t.Errorf("an unescaped pipe would open a column:\n%s", out)
 88	}
 89	if !strings.Contains(out, `a\|b`) {
 90		t.Errorf("message should appear escaped:\n%s", out)
 91	}
 92}
 93
 94// v1 asserted that its own seqKey() ordered numerically. That held only below
 95// its width of 16: seqKey(10^16) is 17 characters and sorts before
 96// seqKey(10^16-1). The store key is 8 bytes for every id, so there is no
 97// ceiling to reach.
 98func TestSeqKeyOrders(t *testing.T) {
 99	if a, b := store.ID(2).Key(), store.ID(10).Key(); !(a < b) {
100		t.Error("id 2 should sort before id 10")
101	}
102	if a, b := store.ID(9999999999999999).Key(), store.ID(10000000000000000).Key(); !(a < b) {
103		t.Error("ordering should survive one past v1's width-16 ceiling")
104	}
105}