feeds_test.gno

10.68 Kb ยท 529 lines
  1package social_feed
  2
  3import (
  4	"testing"
  5
  6	feedsv1 "gno.land/p/zenao/feeds/v1"
  7)
  8
  9func TestNewFeed(t *testing.T) {
 10	type input struct {
 11		slug         string
 12		crossNetwork bool
 13		authFunc     func() (string, bool)
 14	}
 15
 16	type output struct {
 17		feedId string
 18		panic  bool
 19	}
 20
 21	type test struct {
 22		input  input
 23		output output
 24	}
 25
 26	type testTable = map[string]test
 27
 28	tests := testTable{
 29		"valid feed": {
 30			input: input{
 31				slug:         "public",
 32				crossNetwork: false,
 33				authFunc:     nil,
 34			},
 35			output: output{
 36				feedId: alice.String() + ":public",
 37				panic:  false,
 38			},
 39		},
 40		"crossNetwork feed": {
 41			input: input{
 42				slug:         "public2",
 43				crossNetwork: true,
 44				authFunc:     nil,
 45			},
 46			output: output{
 47				feedId: alice.String() + ":public2",
 48				panic:  false,
 49			},
 50		},
 51		"authFunc feed": {
 52			input: input{
 53				slug:         "public3",
 54				crossNetwork: false,
 55				authFunc:     func() (string, bool) { return "", false },
 56			},
 57			output: output{
 58				feedId: alice.String() + ":public3",
 59				panic:  false,
 60			},
 61		},
 62		/*
 63			"crossNetwork feed with authFunc": {
 64				input: input{
 65					slug:         "public4",
 66					crossNetwork: true,
 67					authFunc:     func(string) bool { return false },
 68				},
 69				output: output{
 70					panic: true,
 71				},
 72			},
 73			"feed already exists": {
 74				input: input{
 75					slug:         "public",
 76					crossNetwork: false,
 77					authFunc:     nil,
 78				},
 79				output: output{
 80					panic: true,
 81				},
 82			},
 83		*/
 84	}
 85
 86	for name, test := range tests {
 87		t.Run(name, func(t *testing.T) {
 88			defer func() {
 89				if r := recover(); r != nil {
 90					if !test.output.panic {
 91						t.Fatalf("unexpected panic: %v", r)
 92					}
 93					return
 94				}
 95				if test.output.panic {
 96					t.Fatalf("expected panic, got none")
 97				}
 98			}()
 99
100			testing.SetContext(testing.Context{
101				CurrentRealm: testing.NewUserRealm(alice),
102			})
103			feedId := NewFeed(cross, test.input.slug, test.input.crossNetwork, test.input.authFunc)
104			if !test.output.panic && feedId != test.output.feedId {
105				t.Fatalf("expected feedId %q, got %q", test.output.feedId, feedId)
106			}
107		})
108	}
109}
110
111func TestGetFeedPosts(t *testing.T) {
112	setupTest()
113
114	type input struct {
115		feedId string
116		offset uint32
117		limit  uint32
118		tags   string
119		user   string
120	}
121
122	type output struct {
123		posts []*feedsv1.PostView
124		panic bool
125	}
126
127	type test struct {
128		input  input
129		output output
130	}
131
132	type testTable = map[string]test
133
134	posts := []*feedsv1.PostView{
135		{
136			Post: &feedsv1.Post{
137				Author:    alice.String(),
138				DeletedAt: 0,
139				Post: &feedsv1.StandardPost{
140					Content: "hello",
141				},
142				Tags: []string{"tag1", "tag2"},
143			},
144		},
145		{
146			Post: &feedsv1.Post{
147				Author:    alice.String(),
148				DeletedAt: 0,
149				Post: &feedsv1.LinkPost{
150					Uri: "https://example.com",
151				},
152				Tags: []string{"tag1"},
153			},
154		},
155		{
156			Post: &feedsv1.Post{
157				Author:    alice.String(),
158				DeletedAt: 0,
159				Post: &feedsv1.ImagePost{
160					Description: "an image",
161					ImageUri:    "https://example.com/image.jpg",
162				},
163			},
164		},
165	}
166
167	tests := testTable{
168		"valid feed": {
169			input: input{
170				feedId: alice.String() + ":public",
171				offset: 0,
172				limit:  10,
173				tags:   "",
174				user:   "",
175			},
176			output: output{
177				posts: posts,
178				panic: false,
179			},
180		},
181		"empty feed": {
182			input: input{
183				feedId: alice.String() + ":empty",
184				offset: 0,
185				limit:  10,
186				tags:   "",
187				user:   "",
188			},
189			output: output{
190				posts: []*feedsv1.PostView{},
191				panic: false,
192			},
193		},
194		/*
195			"invalid feed": {
196				input: input{
197					feedId: "",
198					offset: 0,
199					limit:  10,
200					tags:   "",
201					user:   "",
202				},
203				output: output{
204					panic: true,
205				},
206			},
207		*/
208		"limit 2": {
209			input: input{
210				feedId: alice.String() + ":public",
211				offset: 0,
212				limit:  2,
213				tags:   "",
214				user:   "",
215			},
216			output: output{
217				posts: posts[:2],
218				panic: false,
219			},
220		},
221		"offset 1": {
222			input: input{
223				feedId: alice.String() + ":public",
224				offset: 1,
225				limit:  10,
226				tags:   "",
227				user:   "",
228			},
229			output: output{
230				posts: posts[1:],
231				panic: false,
232			},
233		},
234		/*
235			"empty id": {
236				input: input{
237					feedId: "",
238					offset: 0,
239					limit:  10,
240					tags:   "",
241					user:   "",
242				},
243				output: output{
244					panic: true,
245				},
246			},
247		*/
248		"tag filter": {
249			input: input{
250				feedId: alice.String() + ":public",
251				offset: 0,
252				limit:  10,
253				tags:   "tag1",
254				user:   "",
255			},
256			output: output{
257				posts: posts[:2],
258				panic: false,
259			},
260		},
261		"tag filter 2": {
262			input: input{
263				feedId: alice.String() + ":public",
264				offset: 0,
265				limit:  10,
266				tags:   "tag2",
267				user:   "",
268			},
269			output: output{
270				posts: posts[:1],
271				panic: false,
272			},
273		},
274	}
275
276	testing.SetContext(testing.Context{
277		CurrentRealm: testing.NewUserRealm(alice),
278	})
279	//XXX post in reverse order so that the newest post is first
280	for i := len(posts) - 1; i >= 0; i-- {
281		NewPost(cross, alice.String()+":public", posts[i].Post)
282	}
283
284	for name, test := range tests {
285		t.Run(name, func(t *testing.T) {
286			if test.output.panic {
287				defer func() {
288					if r := recover(); r != nil {
289						return
290					}
291					t.Fatalf("expected panic, got none")
292				}()
293			}
294
295			res := GetFeedPosts(test.input.feedId, test.input.offset, test.input.limit, test.input.tags, test.input.user)
296			if len(res) != len(test.output.posts) {
297				t.Fatalf("expected %d posts, got %d", len(test.output.posts), len(res))
298			}
299			for i, postView := range res {
300				post := postView.Post
301				if post.Author != test.output.posts[i].Post.Author {
302					t.Errorf("expected author %q, got %q", test.output.posts[i].Post.Author, post.Author)
303				}
304				if post.DeletedAt != test.output.posts[i].Post.DeletedAt {
305					t.Errorf("expected deletedAt %d, got %d", test.output.posts[i].Post.DeletedAt, post.DeletedAt)
306				}
307				switch v := post.Post.(type) {
308				case *feedsv1.StandardPost:
309					if v.Content != test.output.posts[i].Post.Post.(*feedsv1.StandardPost).Content {
310						t.Errorf("expected content %q, got %q", test.output.posts[i].Post.Post.(*feedsv1.StandardPost).Content, v.Content)
311					}
312				case *feedsv1.LinkPost:
313					if v.Uri != test.output.posts[i].Post.Post.(*feedsv1.LinkPost).Uri {
314						t.Errorf("expected uri %q, got %q", test.output.posts[i].Post.Post.(*feedsv1.LinkPost).Uri, v.Uri)
315					}
316				case *feedsv1.ImagePost:
317					if v.Description != test.output.posts[i].Post.Post.(*feedsv1.ImagePost).Description {
318						t.Errorf("expected description %q, got %q", test.output.posts[i].Post.Post.(*feedsv1.ImagePost).Description, v.Description)
319					}
320					if v.ImageUri != test.output.posts[i].Post.Post.(*feedsv1.ImagePost).ImageUri {
321						t.Errorf("expected imageUri %q, got %q", test.output.posts[i].Post.Post.(*feedsv1.ImagePost).ImageUri, v.ImageUri)
322					}
323				}
324			}
325
326		})
327	}
328}
329
330func TestGetChildrenPosts(t *testing.T) {
331	setupTest()
332
333	type input struct {
334		parentId string
335		offset   uint32
336		limit    uint32
337		tags     string
338		user     string
339	}
340
341	type output struct {
342		posts []*feedsv1.PostView
343		panic bool
344	}
345
346	type test struct {
347		input  input
348		output output
349	}
350
351	type testTable = map[string]test
352
353	posts := []*feedsv1.Post{
354		{
355			Author:    alice.String(),
356			DeletedAt: 0,
357			ParentUri: "3",
358			Post: &feedsv1.StandardPost{
359				Content: "hello",
360			},
361		},
362		{
363			Author:    alice.String(),
364			DeletedAt: 0,
365			ParentUri: "1",
366			Post: &feedsv1.StandardPost{
367				Content: "hello 2",
368			},
369		},
370		{
371			Author:    alice.String(),
372			DeletedAt: 0,
373			ParentUri: "1",
374			Post: &feedsv1.StandardPost{
375				Content: "hello 5",
376			},
377			Tags: []string{"tag1"},
378		},
379		{
380			Author:    alice.String(),
381			DeletedAt: 0,
382			ParentUri: "1",
383			Post: &feedsv1.StandardPost{
384				Content: "hello 3",
385			},
386		},
387		{
388			Author:    alice.String(),
389			DeletedAt: 0,
390			Post: &feedsv1.StandardPost{
391				Content: "hello 4",
392			},
393		},
394	}
395
396	testing.SetContext(testing.Context{
397		CurrentRealm: testing.NewUserRealm(alice),
398	})
399	//XXX post in reverse order so that the newest post is first
400	for i := len(posts) - 1; i >= 0; i-- {
401		NewPost(cross, alice.String()+":public", posts[i])
402	}
403
404	expectedViews := []*feedsv1.PostView{
405		{
406			Post:          posts[0],
407			ChildrenCount: 0,
408		},
409		{
410			Post:          posts[1],
411			ChildrenCount: 0,
412		},
413		{
414			Post:          posts[2],
415			ChildrenCount: 1,
416		},
417		{
418			Post:          posts[3],
419			ChildrenCount: 0,
420		},
421	}
422
423	tests := testTable{
424		"valid parentId": {
425			input: input{
426				parentId: "1",
427				offset:   0,
428				limit:    10,
429				tags:     "",
430				user:     "",
431			},
432			output: output{
433				posts: expectedViews[1:],
434				panic: false,
435			},
436		},
437		"limit 1": {
438			input: input{
439				parentId: "1",
440				offset:   0,
441				limit:    1,
442				tags:     "",
443				user:     "",
444			},
445			output: output{
446				posts: expectedViews[1:2],
447				panic: false,
448			},
449		},
450		"tag filter": {
451			input: input{
452				parentId: "1",
453				offset:   0,
454				limit:    10,
455				tags:     "tag1",
456				user:     "",
457			},
458			output: output{
459				posts: expectedViews[2:3],
460				panic: false,
461			},
462		},
463		"nested parentId": {
464			input: input{
465				parentId: "3",
466				offset:   0,
467				limit:    10,
468				tags:     "",
469				user:     "",
470			},
471			output: output{
472				posts: expectedViews[0:1],
473				panic: false,
474			},
475		},
476		/*
477			"empty parentId": {
478				input: input{
479					parentId: "",
480					offset:   0,
481					limit:    10,
482					tags:     "",
483					user:     "",
484				},
485				output: output{
486					panic: true,
487				},
488			},
489		*/
490	}
491
492	for name, test := range tests {
493		t.Run(name, func(t *testing.T) {
494			if test.output.panic {
495				defer func() {
496					if r := recover(); r != nil {
497						return
498					}
499					t.Fatalf("expected panic, got none")
500				}()
501			}
502
503			res := GetChildrenPosts(test.input.parentId, test.input.offset, test.input.limit, test.input.tags, test.input.user)
504			if len(res) != len(test.output.posts) {
505				t.Fatalf("expected %d posts, got %d", len(test.output.posts), len(res))
506			}
507			for i, postView := range res {
508				post := postView.Post
509				if post.Author != test.output.posts[i].Post.Author {
510					t.Errorf("expected author %q, got %q", test.output.posts[i].Post.Author, post.Author)
511				}
512				if post.DeletedAt != test.output.posts[i].Post.DeletedAt {
513					t.Errorf("expected deletedAt %d, got %d", test.output.posts[i].Post.DeletedAt, post.DeletedAt)
514				}
515				switch v := post.Post.(type) {
516				case *feedsv1.StandardPost:
517					if v.Content != test.output.posts[i].Post.Post.(*feedsv1.StandardPost).Content {
518						t.Errorf("expected content %q, got %q", test.output.posts[i].Post.Post.(*feedsv1.StandardPost).Content, v.Content)
519					}
520				default:
521					t.Errorf("expected standard post, got %T", v)
522				}
523				if postView.ChildrenCount != test.output.posts[i].ChildrenCount {
524					t.Errorf("expected childrenCount %d, got %d on post id %d for parent id %s", test.output.posts[i].ChildrenCount, postView.ChildrenCount, post.LocalPostId, test.input.parentId)
525				}
526			}
527		})
528	}
529}