post_test.gno

9.70 Kb · 385 lines
  1package boards2
  2
  3import (
  4	"std"
  5	"strings"
  6	"testing"
  7
  8	"gno.land/p/nt/testutils"
  9	"gno.land/p/nt/uassert"
 10	"gno.land/p/nt/ufmt"
 11)
 12
 13func TestPostFlag(t *testing.T) {
 14	addr := testutils.TestAddress("creator")
 15	post := createTestThread(t)
 16
 17	uassert.True(t, post.Flag(addr, "foo"))
 18	uassert.False(t, post.Flag(addr, "foo"), "should reject flag from duplicate user")
 19	uassert.Equal(t, post.FlagsCount(), 1)
 20}
 21
 22func TestPostRepost(t *testing.T) {
 23	// TODO: Improve this unit test
 24	addr := testutils.TestAddress("creatorDstBoard")
 25	perms := createBasicBoardPermissions(addr)
 26	cases := []struct {
 27		name, title, body string
 28		dstBoard          *Board
 29		thread            *Post
 30		setup             func() *Post
 31		err               string
 32	}{
 33		{
 34			name:     "repost thread",
 35			title:    "Repost Title",
 36			body:     "Repost body",
 37			dstBoard: newBoard(42, "dst123", addr, perms),
 38			setup:    func() *Post { return createTestThread(t) },
 39		},
 40		{
 41			name:  "invalid repost from reply",
 42			setup: func() *Post { return createTestReply(t) },
 43			err:   "post must be a thread to be reposted to another board",
 44		},
 45	}
 46
 47	for _, tc := range cases {
 48		t.Run(tc.name, func(t *testing.T) {
 49			var (
 50				repost  *Post
 51				creator = testutils.TestAddress("repostCreator")
 52				thread  = tc.setup()
 53			)
 54
 55			createRepost := func() {
 56				repost = thread.Repost(creator, tc.dstBoard, tc.title, tc.body)
 57			}
 58
 59			if tc.err != "" {
 60				uassert.PanicsWithMessage(t, tc.err, createRepost)
 61				return
 62			} else {
 63				uassert.NotPanics(t, createRepost)
 64			}
 65
 66			r, found := tc.dstBoard.GetThread(repost.ID)
 67			uassert.True(t, found)
 68			uassert.True(t, repost == r)
 69			uassert.Equal(t, tc.title, repost.Title)
 70			uassert.Equal(t, tc.body, repost.Body)
 71			uassert.Equal(t, uint(thread.Board.ID), uint(repost.RepostBoardID))
 72		})
 73	}
 74}
 75
 76func TestNewThread(t *testing.T) {
 77	testing.SetRealm(std.NewCodeRealm("gno.land/r/gnoland/boards2/v1"))
 78
 79	creator := testutils.TestAddress("creator")
 80	title := "Test Title"
 81	body := strings.Repeat("A", 82)
 82	boardID := BoardID(1)
 83	threadID := PostID(42)
 84	boardName := "test123"
 85	perms := createBasicBoardPermissions(creator)
 86	board := newBoard(boardID, boardName, creator, perms)
 87	url := ufmt.Sprintf(
 88		"/r/gnoland/boards2/v1:%s/%d",
 89		boardName,
 90		uint(threadID),
 91	)
 92	replyURL := ufmt.Sprintf(
 93		"/r/gnoland/boards2/v1$help&func=CreateReply&boardID=%d&body=&replyID=0&threadID=%d",
 94		uint(boardID),
 95		uint(threadID),
 96	)
 97	editURL := ufmt.Sprintf(
 98		"/r/gnoland/boards2/v1$help&func=EditThread&boardID=%d&body=%s&threadID=%d&title=%s",
 99		uint(boardID),
100		body,
101		uint(threadID),
102		strings.ReplaceAll(title, " ", "+"),
103	)
104	repostURL := ufmt.Sprintf(
105		"/r/gnoland/boards2/v1$help&func=CreateRepost&boardID=%d&body=&destinationBoardID=&threadID=%d&title=",
106		uint(boardID),
107		uint(threadID),
108	)
109	deleteURL := ufmt.Sprintf(
110		"/r/gnoland/boards2/v1$help&func=DeleteThread&boardID=%d&threadID=%d",
111		uint(boardID),
112		uint(threadID),
113	)
114	flagURL := ufmt.Sprintf(
115		"/r/gnoland/boards2/v1$help&func=FlagThread&boardID=%d&reason=&threadID=%d",
116		uint(boardID),
117		uint(threadID),
118	)
119
120	thread := newPost(board, threadID, threadID, creator, title, body)
121
122	uassert.True(t, thread.IsThread())
123	uassert.Equal(t, uint(threadID), uint(thread.ID))
124	uassert.False(t, thread.CreatedAt().IsZero())
125	uassert.True(t, thread.UpdatedAt.IsZero())
126	uassert.Equal(t, title, thread.Title)
127	uassert.Equal(t, body[:77]+"...", thread.Summary())
128	uassert.False(t, thread.HasReplies())
129	uassert.Equal(t, url, makeThreadURI(thread))
130	uassert.Equal(t, replyURL, makeCreateReplyURI(thread))
131	uassert.Equal(t, editURL, makeEditPostURI(thread))
132	uassert.Equal(t, repostURL, makeCreateRepostURI(thread))
133	uassert.Equal(t, deleteURL, makeDeletePostURI(thread))
134	uassert.Equal(t, flagURL, makeFlagURI(thread))
135}
136
137func TestThreadAddReply(t *testing.T) {
138	replier := testutils.TestAddress("replier")
139	thread := createTestThread(t)
140	threadID := uint(thread.ID)
141	body := "A reply"
142
143	reply := thread.AddReply(replier, body)
144
145	r, found := thread.GetReply(reply.ID)
146	uassert.True(t, found)
147	uassert.True(t, reply == r)
148	uassert.Equal(t, threadID+1, uint(reply.ID))
149	uassert.Equal(t, reply.Creator, replier)
150	uassert.Equal(t, reply.Body, body)
151	uassert.True(t, thread.HasReplies())
152}
153
154func TestThreadGetReply(t *testing.T) {
155	cases := []struct {
156		name   string
157		thread *Post
158		setup  func(thread *Post) (replyID PostID)
159		found  bool
160	}{
161		{
162			name:   "found",
163			thread: createTestThread(t),
164			setup: func(thread *Post) PostID {
165				reply := thread.AddReply(testutils.TestAddress("replier"), "")
166				return reply.ID
167			},
168			found: true,
169		},
170		{
171			name:   "not found",
172			thread: createTestThread(t),
173			setup:  func(*Post) PostID { return 42 },
174		},
175	}
176
177	for _, tc := range cases {
178		t.Run(tc.name, func(t *testing.T) {
179			replyID := tc.setup(tc.thread)
180
181			reply, found := tc.thread.GetReply(replyID)
182
183			uassert.Equal(t, tc.found, found)
184			if reply != nil {
185				uassert.Equal(t, uint(replyID), uint(reply.ID))
186			}
187		})
188	}
189}
190
191func TestThreadDeleteReply(t *testing.T) {
192	thread := createTestThread(t)
193	cases := []struct {
194		name  string
195		setup func() PostID
196		err   string
197	}{
198		{
199			name: "ok",
200			setup: func() PostID {
201				reply := thread.AddReply(testutils.TestAddress("replier"), "")
202				return reply.ID
203			},
204		},
205		{
206			name: "ok nested",
207			setup: func() PostID {
208				reply := thread.AddReply(testutils.TestAddress("replier"), "")
209				return reply.AddReply(testutils.TestAddress("replier2"), "").ID
210			},
211		},
212		{
213			name:  "invalid",
214			setup: func() PostID { return thread.ID },
215			err:   "expected an ID of an inner reply",
216		},
217		{
218			name:  "not found",
219			setup: func() PostID { return 42 },
220			err:   "reply not found in thread",
221		},
222	}
223
224	for _, tc := range cases {
225		t.Run(tc.name, func(t *testing.T) {
226			replyID := tc.setup()
227
228			err := thread.DeleteReply(replyID)
229
230			if tc.err != "" {
231				uassert.ErrorContains(t, err, tc.err)
232				return
233			}
234
235			uassert.NoError(t, err)
236			_, found := thread.GetReply(replyID)
237			uassert.False(t, found)
238		})
239	}
240}
241
242func TestThreadRenderSummary(t *testing.T) {
243	t.Skip("TODO: implement")
244}
245
246func TestThreadRender(t *testing.T) {
247	t.Skip("TODO: implement")
248}
249
250func TestThreadRenderInner(t *testing.T) {
251	t.Skip("TODO: implement")
252}
253
254func TestNewReply(t *testing.T) {
255	testing.SetRealm(std.NewCodeRealm("gno.land/r/gnoland/boards2/v1"))
256
257	creator := testutils.TestAddress("creator")
258	body := strings.Repeat("A", 82)
259	boardID := BoardID(1)
260	threadID := PostID(42)
261	parentID := PostID(1)
262	replyID := PostID(2)
263	boardName := "test123"
264	perms := createBasicBoardPermissions(creator)
265	board := newBoard(boardID, boardName, creator, perms)
266	url := ufmt.Sprintf(
267		"/r/gnoland/boards2/v1:%s/%d/%d",
268		boardName,
269		uint(threadID),
270		uint(replyID),
271	)
272	replyURL := ufmt.Sprintf(
273		"/r/gnoland/boards2/v1$help&func=CreateReply&boardID=%d&body=&replyID=%d&threadID=%d",
274		uint(boardID),
275		uint(replyID),
276		uint(threadID),
277	)
278	deleteURL := ufmt.Sprintf(
279		"/r/gnoland/boards2/v1$help&func=DeleteReply&boardID=%d&replyID=%d&threadID=%d",
280		uint(boardID),
281		uint(replyID),
282		uint(threadID),
283	)
284
285	reply := newPost(board, threadID, replyID, creator, "", body)
286	reply.ParentID = parentID
287
288	uassert.False(t, reply.IsThread())
289	uassert.Equal(t, uint(replyID), uint(reply.ID))
290	uassert.False(t, reply.CreatedAt().IsZero())
291	uassert.True(t, reply.UpdatedAt.IsZero())
292	uassert.False(t, reply.HasReplies())
293	uassert.Equal(t, body[:77]+"...", reply.Summary())
294	uassert.Equal(t, url, makeReplyURI(reply))
295	uassert.Equal(t, replyURL, makeCreateReplyURI(reply))
296	uassert.Equal(t, deleteURL, makeDeletePostURI(reply))
297}
298
299func TestReplyAddReply(t *testing.T) {
300	replier := testutils.TestAddress("replier")
301	thread := createTestThread(t)
302	parentReply := thread.AddReply(testutils.TestAddress("parentReplier"), "")
303	parentReplyID := uint(parentReply.ID)
304	body := "A child reply"
305
306	reply := parentReply.AddReply(replier, body)
307
308	r, found := thread.GetReply(reply.ID)
309	uassert.True(t, found)
310	uassert.True(t, reply == r)
311	uassert.Equal(t, parentReplyID, uint(reply.ParentID))
312	uassert.Equal(t, parentReplyID+1, uint(reply.ID))
313	uassert.Equal(t, reply.Creator, replier)
314	uassert.Equal(t, reply.Body, body)
315	uassert.False(t, reply.HasReplies())
316	uassert.True(t, parentReply.HasReplies())
317}
318
319func TestReplyGetReply(t *testing.T) {
320	thread := createTestThread(t)
321	parentReply := thread.AddReply(testutils.TestAddress("parentReplier"), "")
322	cases := []struct {
323		name  string
324		setup func() PostID
325		found bool
326	}{
327		{
328			name: "found",
329			setup: func() PostID {
330				reply := parentReply.AddReply(testutils.TestAddress("replier"), "")
331				return reply.ID
332			},
333			found: true,
334		},
335		{
336			name:  "not found",
337			setup: func() PostID { return 42 },
338		},
339	}
340
341	for _, tc := range cases {
342		t.Run(tc.name, func(t *testing.T) {
343			replyID := tc.setup()
344
345			reply, found := thread.GetReply(replyID)
346
347			uassert.Equal(t, tc.found, found)
348			if reply != nil {
349				uassert.Equal(t, uint(replyID), uint(reply.ID))
350			}
351		})
352	}
353}
354
355func TestReplyDeleteReply(t *testing.T) {
356	thread := createTestThread(t)
357	parentReply := thread.AddReply(testutils.TestAddress("replier"), "")
358	reply := parentReply.AddReply(testutils.TestAddress("replier2"), "")
359
360	// NOTE: Deleting a reply from a parent reply should eventually be suported
361	uassert.PanicsWithMessage(t, "cannot delete reply from a non-thread post", func() {
362		parentReply.DeleteReply(reply.ID)
363	})
364}
365
366func TestReplyRender(t *testing.T) {
367	t.Skip("TODO: implement")
368}
369
370func createTestThread(t *testing.T) *Post {
371	t.Helper()
372
373	creator := testutils.TestAddress("creator")
374	perms := createBasicBoardPermissions(creator)
375	board := newBoard(1, "test_board_123", creator, perms)
376	return board.AddThread(creator, "Title", "Body")
377}
378
379func createTestReply(t *testing.T) *Post {
380	t.Helper()
381
382	creator := testutils.TestAddress("replier")
383	thread := createTestThread(t)
384	return thread.AddReply(creator, "Test message")
385}