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.

reactions_test.gno

6.24 Kb · 171 lines
  1package reactions
  2
  3import (
  4	"strconv"
  5	"strings"
  6	"testing"
  7
  8	rx "gno.land/p/nym-moultest123/reactions/v0"
  9	"gno.land/p/nt/testutils/v0"
 10	"gno.land/p/nt/uassert/v0"
 11)
 12
 13const homePage = "gno.land/r/nym-moultest123/home"
 14
 15var (
 16	alice = testutils.TestAddress("alice")
 17	bob   = testutils.TestAddress("bob")
 18)
 19
 20// reset clears realm state. Realm globals live for the whole test binary, and
 21// the Example runs after every Test, so everything that renders starts here.
 22func reset() { board = rx.NewBoard() }
 23
 24func TestReactAndUnreact(cur realm, t *testing.T) {
 25	reset()
 26
 27	testing.SetRealm(testing.NewUserRealm(alice))
 28	React(cross(cur), homePage, rx.KeyUp)
 29	testing.SetRealm(testing.NewUserRealm(bob))
 30	React(cross(cur), homePage, rx.KeyFire)
 31
 32	uassert.Equal(t, 2, Count(homePage))
 33	uassert.Equal(t, 1, CountOf(homePage, rx.KeyUp))
 34	uassert.Equal(t, rx.KeyUp, ReactionOf(homePage, alice))
 35	uassert.Equal(t, 1, Pages())
 36
 37	key, who, _ := Last(homePage)
 38	uassert.Equal(t, rx.KeyFire, key)
 39	uassert.Equal(t, bob, who)
 40
 41	testing.SetRealm(testing.NewUserRealm(alice))
 42	Unreact(cross(cur), homePage)
 43	uassert.Equal(t, 1, Count(homePage))
 44	uassert.Equal(t, "", ReactionOf(homePage, alice))
 45}
 46
 47func TestReadsOnAnUntouchedPageAreZero(t *testing.T) {
 48	reset()
 49	uassert.Equal(t, 0, Count("gno.land/r/nobody/here"))
 50	uassert.Equal(t, 0, CountOf("gno.land/r/nobody/here", rx.KeyUp))
 51	uassert.Equal(t, "", ReactionOf("gno.land/r/nobody/here", alice))
 52	key, _, _ := Last("gno.land/r/nobody/here")
 53	uassert.Equal(t, "", key)
 54}
 55
 56func TestReactRefusals(cur realm, t *testing.T) {
 57	reset()
 58	testing.SetRealm(testing.NewUserRealm(alice))
 59	uassert.AbortsWithMessage(t, cur, "reactions: no such reaction: poop", func() {
 60		React(cross(cur), homePage, "poop")
 61	})
 62
 63	testing.SetRealm(testing.NewUserRealm(alice))
 64	uassert.AbortsWithMessage(t, cur, "reactions: not a page key: not a path", func() {
 65		React(cross(cur), "not a path", rx.KeyUp)
 66	})
 67
 68	uassert.Equal(t, 0, Pages(), "a refused reaction creates no page")
 69}
 70
 71// TestUnreactAbortsRatherThanNoOp is the deliberate asymmetry: a misspelled
 72// page key on Unreact has to be visible, or a reader thinks they removed
 73// something they did not.
 74func TestUnreactAbortsRatherThanNoOp(cur realm, t *testing.T) {
 75	reset()
 76	testing.SetRealm(testing.NewUserRealm(alice))
 77	uassert.AbortsWithMessage(t, cur, "reactions: nothing to remove on "+homePage, func() {
 78		Unreact(cross(cur), homePage)
 79	})
 80}
 81
 82// TestRenderBlockForIsWhatTheBlockLinksTo pins the property a host realm
 83// depends on: every link in the embedded block points at THIS realm, not at
 84// the realm that embedded it, and carries the page key as an argument.
 85func TestRenderBlockForIsWhatTheBlockLinksTo(t *testing.T) {
 86	reset()
 87	got := RenderBlockFor(homePage)
 88	uassert.True(t, strings.Contains(got, "(/r/nym-moultest123/reactions/v0$help&func=React&"),
 89		"the txlink targets this realm")
 90	uassert.True(t, strings.Contains(got, "page=gno.land%2Fr%2Fmoul%2Fhome"),
 91		"and carries the host page as the parameter")
 92	uassert.False(t, strings.Contains(got, "/r/nym-moultest123/home$help"),
 93		"never the host realm, which has no React to call")
 94}
 95
 96// TestRenderBlockKeysOnTheCaller is the borrowed-read rule this realm's whole
 97// ergonomics rest on: RenderBlock has no cur realm parameter, so gno opens no
 98// frame for it and unsafe.CurrentRealm() reports whoever called.
 99//
100// In-package there is no other realm to call from, so what this pins is the
101// half that can be pinned here: RenderBlock agrees with RenderBlockFor when
102// the caller IS this realm. The cross-realm half is measured in AGENTS.md
103// (2026-09-22) and is the same mechanism r/moul/config's TopBlock uses.
104func TestRenderBlockKeysOnTheCaller(t *testing.T) {
105	reset()
106	uassert.Equal(t, RenderBlockFor(realmPath), RenderBlock())
107	uassert.NotEqual(t, RenderBlockFor(homePage), RenderBlock(),
108		"and a different page is a different block")
109}
110
111func TestRenderPageView(cur realm, t *testing.T) {
112	reset()
113	testing.SetRealm(testing.NewUserRealm(alice))
114	React(cross(cur), homePage, rx.KeyUp)
115
116	got := Render(homePage)
117	uassert.True(t, strings.HasPrefix(got, "# gno\\.land/r/nym-moultest123/home\n"),
118		"the heading is the page key, escaped: ui.Inline backslashes the dot")
119	uassert.True(t, strings.Contains(got, "Last reaction: \U0001F44D by "))
120	uassert.True(t, strings.Contains(got, "Remove my reaction"))
121	uassert.True(t, strings.Contains(got, "[The board](/r/nym-moultest123/reactions/v0)"))
122}
123
124func TestRenderRejectsAPathThatIsNotAPageKey(t *testing.T) {
125	reset()
126	got := Render("[click](http://e.vil)")
127	uassert.True(t, strings.HasPrefix(got, "# Not a page\n"))
128	uassert.False(t, strings.Contains(got, "](http://e.vil)"),
129		"a render path is escaped before it is shown back")
130}
131
132// TestRenderHomeShowsTheBoard uses uassert rather than an Example because the
133// page contains consecutive blank lines, which gno collapses inside an
134// // Output: block.
135func TestRenderHomeShowsTheBoard(cur realm, t *testing.T) {
136	reset()
137	uassert.True(t, strings.Contains(Render(""), "*No page has been reacted to yet.*"))
138
139	testing.SetRealm(testing.NewUserRealm(alice))
140	React(cross(cur), homePage, rx.KeyParty)
141
142	got := Render("")
143	uassert.True(t, strings.Contains(got,
144		"| [gno\\.land/r/nym-moultest123/home](/r/nym-moultest123/reactions/v0:gno.land/r/nym-moultest123/home) | 1 |"),
145		"the cell text is escaped, the URL is not: they are different contexts")
146	uassert.True(t, strings.Contains(got, "import \"gno.land/r/nym-moultest123/reactions/v0\""),
147		"the homepage is the getting-started doc, and the snippet is copy-pasteable")
148	for _, k := range rx.Keys() {
149		uassert.True(t, strings.Contains(got, "| `"+k+"` | "+rx.Emoji(k)+" |"), k)
150	}
151}
152
153// TestBoardIndexIsCapped: the number of pages is unbounded, the index is not.
154func TestBoardIndexIsCapped(cur realm, t *testing.T) {
155	reset()
156	for i := 0; i < maxListed+3; i++ {
157		testing.SetRealm(testing.NewUserRealm(alice))
158		// Zero-padded, because avl keys sort as strings and ufmt has no width
159		// flags: "p9" would otherwise sort between "p10" and "p11".
160		n := strconv.Itoa(i)
161		if len(n) < 2 {
162			n = "0" + n
163		}
164		React(cross(cur), "gno.land/r/spam/p"+n, rx.KeyUp)
165	}
166	uassert.Equal(t, maxListed+3, Pages())
167
168	got := Render("")
169	uassert.Equal(t, maxListed, strings.Count(got, "(/r/nym-moultest123/reactions/v0:gno.land/r/spam/"))
170	uassert.True(t, strings.Contains(got, "28 pages in total, 25 shown."))
171}