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.

talk_test.gno

4.76 Kb · 136 lines
  1package wiki
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"gno.land/p/nt/uassert/v0"
  8)
  9
 10func comment(t *testing.T, w *Wiki, n int, author address, title, body string, replyTo uint64) *Comment {
 11	t.Helper()
 12	now, h := at(n)
 13	c, err := w.Comment(author, now, h, title, body, replyTo)
 14	uassert.NoError(t, err, title)
 15	return c
 16}
 17
 18func TestCommentThreads(t *testing.T) {
 19	w := New(3, DefaultMaxBody)
 20	edit(t, w, 1, alice, "A", "the article\n", "")
 21
 22	root1 := comment(t, w, 2, alice, "A", "First point.\n", 0)
 23	root2 := comment(t, w, 3, bob, "A", "Second point.\n", 0)
 24	reply := comment(t, w, 4, mod, "A", "Answering the first.\n", root1.ID)
 25
 26	title := MustParseTitle("A")
 27	uassert.Equal(t, 3, w.NumComments(title))
 28
 29	threads := w.Comments(title, 0, 10)
 30	uassert.Equal(t, 2, len(threads), "replies do not count as threads")
 31	uassert.Equal(t, uint64(root1.ID), threads[0].Root.ID)
 32	uassert.Equal(t, 1, len(threads[0].Replies))
 33	uassert.Equal(t, uint64(reply.ID), threads[0].Replies[0].ID)
 34	uassert.Equal(t, uint64(root2.ID), threads[1].Root.ID)
 35	uassert.Equal(t, 0, len(threads[1].Replies))
 36
 37	uassert.Equal(t, 1, len(w.Comments(title, 1, 10)), "offset skips whole threads")
 38}
 39
 40func TestCommentRejectsBadInput(t *testing.T) {
 41	w := New(3, DefaultMaxBody)
 42	edit(t, w, 1, alice, "A", "the article\n", "")
 43	now, h := at(2)
 44
 45	_, err := w.Comment(alice, now, h, "Missing page", "hi\n", 0)
 46	uassert.ErrorIs(t, err, ErrNoSuchPage, "a discussion needs a page to be about")
 47
 48	_, err = w.Comment(alice, now, h, "A", "", 0)
 49	uassert.ErrorIs(t, err, ErrEmptyComment)
 50
 51	_, err = w.Comment(alice, now, h, "A", strings.Repeat("x", MaxCommentLen+1), 0)
 52	uassert.ErrorIs(t, err, ErrCommentTooLong)
 53
 54	_, err = w.Comment(alice, now, h, "A", "hi\n", 999)
 55	uassert.ErrorIs(t, err, ErrNoSuchComment)
 56}
 57
 58// TestRepliesNestOneLevel pins MaxReplyDepth. Unbounded nesting means
 59// unbounded recursive rendering, which is the shape the query gas ceiling
 60// punishes hardest.
 61func TestRepliesNestOneLevel(t *testing.T) {
 62	w := New(3, DefaultMaxBody)
 63	edit(t, w, 1, alice, "A", "the article\n", "")
 64	root := comment(t, w, 2, alice, "A", "root\n", 0)
 65	reply := comment(t, w, 3, bob, "A", "reply\n", root.ID)
 66
 67	now, h := at(4)
 68	_, err := w.Comment(mod, now, h, "A", "reply to a reply\n", reply.ID)
 69	uassert.ErrorIs(t, err, ErrReplyToReply)
 70}
 71
 72func TestHideComment(t *testing.T) {
 73	w := New(3, DefaultMaxBody)
 74	edit(t, w, 1, alice, "A", "the article\n", "")
 75	before := w.Stats().BytesHeld
 76	c := comment(t, w, 2, bob, "A", "unpleasant\n", 0)
 77	uassert.Equal(t, before+len("unpleasant\n"), w.Stats().BytesHeld,
 78		"a comment costs its author the bytes it adds")
 79
 80	released, err := w.HideComment("A", c.ID)
 81	uassert.NoError(t, err)
 82	uassert.Equal(t, len("unpleasant\n"), released)
 83	uassert.Equal(t, before, w.Stats().BytesHeld)
 84
 85	threads := w.Comments(MustParseTitle("A"), 0, 10)
 86	uassert.Equal(t, 1, len(threads), "a hidden message stays in the thread")
 87	uassert.True(t, threads[0].Root.Hidden)
 88	uassert.Equal(t, "", threads[0].Root.Body)
 89
 90	// Hiding twice must not double-count the refund.
 91	released, err = w.HideComment("A", c.ID)
 92	uassert.NoError(t, err)
 93	uassert.Equal(t, 0, released)
 94	uassert.Equal(t, before, w.Stats().BytesHeld)
 95}
 96
 97func TestRenderTalk(t *testing.T) {
 98	w := New(3, DefaultMaxBody)
 99	edit(t, w, 1, alice, "A", "the article\n", "")
100	root := comment(t, w, 2, alice, "A", "Is [[B]] the right link?\n", 0)
101	comment(t, w, 3, bob, "A", "Yes.\n", root.ID)
102	hidden := comment(t, w, 4, mod, "A", "spam\n", 0)
103	w.HideComment("A", hidden.ID)
104
105	p, _ := w.Page("A")
106	c := Ctx{Base: "/r/nym-moultest123/x/wiki/v0", Exists: w.Exists}
107	out := RenderTalk(c, w, p, 0, 10, act)
108
109	uassert.True(t, strings.Contains(out, "# Discussion: A"))
110	uassert.True(t, strings.Contains(out, "func=Comment"), "an add-a-message action")
111	uassert.True(t, strings.Contains(out, "Yes."), "replies render under their root")
112	uassert.True(t, strings.Contains(out, "removed by a steward"))
113	uassert.False(t, strings.Contains(out, "spam"), "a hidden body is gone from the render")
114
115	// A comment is user markdown too: it goes through the sanitizer, and it
116	// is NOT a wikilink slot, so brackets stay literal rather than linking.
117	uassert.True(t, strings.Contains(out, `\[\[B\]\]`), out)
118}
119
120func TestRenderTalkEmpty(t *testing.T) {
121	w := New(3, DefaultMaxBody)
122	edit(t, w, 1, alice, "A", "the article\n", "")
123	p, _ := w.Page("A")
124	out := RenderTalk(Ctx{Base: "/r/nym-moultest123/x/wiki/v0"}, w, p, 0, 10, nil)
125	uassert.True(t, strings.Contains(out, "No messages yet"))
126}
127
128func TestArticleLinksToItsDiscussion(t *testing.T) {
129	w := New(3, DefaultMaxBody)
130	edit(t, w, 1, alice, "A", "the article\n", "")
131	comment(t, w, 2, alice, "A", "hi\n", 0)
132
133	p, _ := w.Page("A")
134	out := RenderArticle(Ctx{Base: "/r/nym-moultest123/x/wiki/v0"}, w, p, nil)
135	uassert.True(t, strings.Contains(out, "[discussion](/r/nym-moultest123/x/wiki/v0:A/talk) (1)"), out)
136}