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}