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}