todos_test.gno
3.31 Kb · 122 lines
1package todos
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/avl/v0"
8 "gno.land/p/nt/testutils/v0"
9)
10
11// reset clears package globals between tests (t.Run/subtests do not reset them).
12func reset() {
13 items = avl.Tree{}
14 nextID = 0
15}
16
17// TestAddToggleRemove exercises the full lifecycle through the crossing API.
18// Crossing test: takes `cur realm` and calls via cross(cur).
19func TestAddToggleRemove(cur realm, t *testing.T) {
20 reset()
21 alice := testutils.TestAddress("alice")
22 testing.SetRealm(testing.NewUserRealm(alice))
23
24 id1 := Add(cross(cur), "buy milk")
25 if id1 != 1 {
26 t.Fatalf("Add first id = %d, want 1", id1)
27 }
28 id2 := Add(cross(cur), "walk dog")
29 if id2 != 2 {
30 t.Fatalf("Add second id = %d, want 2", id2)
31 }
32
33 open, done := counts()
34 if open != 2 || done != 0 {
35 t.Fatalf("after adds: open=%d done=%d, want 2/0", open, done)
36 }
37
38 // Toggle #1 done.
39 Toggle(cross(cur), 1)
40 open, done = counts()
41 if open != 1 || done != 1 {
42 t.Fatalf("after toggle: open=%d done=%d, want 1/1", open, done)
43 }
44
45 // Toggle #1 back to open.
46 Toggle(cross(cur), 1)
47 open, done = counts()
48 if open != 2 || done != 0 {
49 t.Fatalf("after re-toggle: open=%d done=%d, want 2/0", open, done)
50 }
51
52 // Remove #1.
53 Remove(cross(cur), 1)
54 open, done = counts()
55 if open != 1 || done != 0 {
56 t.Fatalf("after remove: open=%d done=%d, want 1/0", open, done)
57 }
58 if items.Has(idKey(1)) {
59 t.Fatalf("item #1 still present after Remove")
60 }
61}
62
63// TestRender checks the Markdown output shape and counts. Render is not a
64// crossing function, so this is a plain test — but the Add calls that seed
65// state still need a realm, so it also takes `cur realm`.
66func TestRender(cur realm, t *testing.T) {
67 reset()
68
69 // Empty board.
70 empty := Render("")
71 if !strings.Contains(empty, "0 open · 0 done · 0 total") {
72 t.Fatalf("empty render missing zero counts:\n%s", empty)
73 }
74 if !strings.Contains(empty, "No items yet") {
75 t.Fatalf("empty render missing placeholder:\n%s", empty)
76 }
77
78 bob := testutils.TestAddress("bob")
79 testing.SetRealm(testing.NewUserRealm(bob))
80
81 Add(cross(cur), "first")
82 Add(cross(cur), "second")
83 Add(cross(cur), "third")
84 Toggle(cross(cur), 2) // mark #2 done
85
86 out := Render("")
87
88 // Counts line: 2 open, 1 done, 3 total.
89 if !strings.Contains(out, "2 open · 1 done · 3 total") {
90 t.Fatalf("render counts wrong:\n%s", out)
91 }
92 // Done checkbox for #2.
93 if !strings.Contains(out, "- [x] #2 second") {
94 t.Fatalf("render missing done item #2:\n%s", out)
95 }
96 // Open checkbox for #1.
97 if !strings.Contains(out, "- [ ] #1 first") {
98 t.Fatalf("render missing open item #1:\n%s", out)
99 }
100 // Newest first: #3 must appear before #1.
101 if strings.Index(out, "#3 third") > strings.Index(out, "#1 first") {
102 t.Fatalf("render not newest-first:\n%s", out)
103 }
104 // Author short form present.
105 if !strings.Contains(out, "(g1") {
106 t.Fatalf("render missing author short address:\n%s", out)
107 }
108}
109
110// TestIDKeyOrdering verifies idKey produces lexicographically-ordered keys so
111// avl iteration matches numeric id order. Non-crossing: plain signature.
112func TestIDKeyOrdering(t *testing.T) {
113 if idKey(2) >= idKey(10) {
114 t.Fatalf("idKey(2)=%q should sort before idKey(10)=%q", idKey(2), idKey(10))
115 }
116 if idKey(9) >= idKey(100) {
117 t.Fatalf("idKey(9)=%q should sort before idKey(100)=%q", idKey(9), idKey(100))
118 }
119 if len(idKey(1)) != 12 {
120 t.Fatalf("idKey width = %d, want 12", len(idKey(1)))
121 }
122}