memeland_test.gno
7.80 Kb ยท 283 lines
1package memeland
2
3import (
4 "std"
5 "strings"
6 "testing"
7 "time"
8
9 "gno.land/p/demo/testutils"
10 "gno.land/p/demo/uassert"
11 "gno.land/p/demo/ufmt"
12)
13
14func TestPostMeme(t *testing.T) {
15 m := NewMemeland()
16 id := m.PostMeme("Test meme data", time.Now().Unix())
17 uassert.NotEqual(t, "", string(id), "Expected valid ID, got empty string")
18}
19
20func TestGetPostsInRangePagination(t *testing.T) {
21 m := NewMemeland()
22 now := time.Now()
23
24 numOfPosts := 5
25 var memeData []string
26 for i := 1; i <= numOfPosts; i++ {
27 // Prepare meme data
28 nextTime := now.Add(time.Duration(i) * time.Minute)
29 data := ufmt.Sprintf("Meme #%d", i)
30 memeData = append(memeData, data)
31
32 m.PostMeme(data, nextTime.Unix())
33 }
34
35 // Get timestamps
36 beforeEarliest := now.Add(-1 * time.Minute)
37 afterLatest := now.Add(time.Duration(numOfPosts)*time.Minute + time.Minute)
38
39 testCases := []struct {
40 page int
41 pageSize int
42 expectedNumOfPosts int
43 }{
44 {page: 1, pageSize: 1, expectedNumOfPosts: 1}, // one per page
45 {page: 2, pageSize: 1, expectedNumOfPosts: 1}, // one on second page
46 {page: 1, pageSize: numOfPosts, expectedNumOfPosts: numOfPosts}, // all posts on single page
47 {page: 12, pageSize: 1, expectedNumOfPosts: 0}, // empty page
48 {page: 1, pageSize: numOfPosts + 1, expectedNumOfPosts: numOfPosts}, // page with fewer posts than its size
49 {page: 5, pageSize: numOfPosts / 5, expectedNumOfPosts: 1}, // evenly distribute posts per page
50 }
51
52 for _, tc := range testCases {
53 t.Run(ufmt.Sprintf("Page%d_Size%d", tc.page, tc.pageSize), func(t *testing.T) {
54 result := m.GetPostsInRange(beforeEarliest.Unix(), afterLatest.Unix(), tc.page, tc.pageSize, "DATE_CREATED")
55
56 // Count posts by how many times id: shows up in JSON string
57 postCount := strings.Count(result, `"id":"`)
58 uassert.Equal(t, tc.expectedNumOfPosts, postCount)
59 })
60 }
61}
62
63func TestGetPostsInRangeByTimestamp(t *testing.T) {
64 m := NewMemeland()
65 now := time.Now()
66
67 numOfPosts := 5
68 var memeData []string
69 for i := 1; i <= numOfPosts; i++ {
70 // Prepare meme data
71 nextTime := now.Add(time.Duration(i) * time.Minute)
72 data := ufmt.Sprintf("Meme #%d", i)
73 memeData = append(memeData, data)
74
75 m.PostMeme(data, nextTime.Unix())
76 }
77
78 // Get timestamps
79 beforeEarliest := now.Add(-1 * time.Minute)
80 afterLatest := now.Add(time.Duration(numOfPosts)*time.Minute + time.Minute)
81
82 // Default sort is by addition order/timestamp
83 jsonStr := m.GetPostsInRange(
84 beforeEarliest.Unix(), // start at earliest post
85 afterLatest.Unix(), // end at latest post
86 1, // first page
87 numOfPosts, // all memes on the page
88 "DATE_CREATED", // sort by newest first
89 )
90
91 uassert.NotEmpty(t, jsonStr, "Expected non-empty JSON string, got empty string")
92
93 // Count the number of posts returned in the JSON string as a rudimentary check for correct pagination/filtering
94 postCount := strings.Count(jsonStr, `"id":"`)
95 uassert.Equal(t, uint64(m.MemeCounter), uint64(postCount))
96
97 // Check if data is there
98 for _, expData := range memeData {
99 check := strings.Contains(jsonStr, expData)
100 uassert.True(t, check, ufmt.Sprintf("Expected %s in the JSON string, but counld't find it", expData))
101 }
102
103 // Check if ordering is correct, sort by created date
104 for i := 0; i < len(memeData)-2; i++ {
105 check := strings.Index(jsonStr, memeData[i]) >= strings.Index(jsonStr, memeData[i+1])
106 uassert.True(t, check, ufmt.Sprintf("Expected %s to be before %s, but was at %d, and %d", memeData[i], memeData[i+1], i, i+1))
107 }
108}
109
110func TestGetPostsInRangeByUpvote(t *testing.T) {
111 m := NewMemeland()
112 now := time.Now()
113
114 memeData1 := "Meme #1"
115 memeData2 := "Meme #2"
116
117 // Create posts at specific times for testing
118 id1 := m.PostMeme(memeData1, now.Unix())
119 id2 := m.PostMeme(memeData2, now.Add(time.Minute).Unix())
120
121 m.Upvote(id1)
122 m.Upvote(id2)
123
124 // Change caller so avoid double upvote panic
125 alice := testutils.TestAddress("alice")
126 testing.SetRealm(std.NewUserRealm(alice))
127 m.Upvote(id1)
128
129 // Final upvote count:
130 // Meme #1 - 2 upvote
131 // Meme #2 - 1 upvotes
132
133 // Get timestamps
134 beforeEarliest := now.Add(-time.Minute)
135 afterLatest := now.Add(time.Hour)
136
137 // Default sort is by addition order/timestamp
138 jsonStr := m.GetPostsInRange(
139 beforeEarliest.Unix(), // start at earliest post
140 afterLatest.Unix(), // end at latest post
141 1, // first page
142 2, // all memes on the page
143 "UPVOTES", // sort by upvote
144 )
145
146 uassert.NotEmpty(t, jsonStr, "Expected non-empty JSON string, got empty string")
147
148 // Count the number of posts returned in the JSON string as a rudimentary check for correct pagination/filtering
149 postCount := strings.Count(jsonStr, `"id":"`)
150 uassert.Equal(t, uint64(m.MemeCounter), uint64(postCount))
151
152 // Check if ordering is correct
153 check := strings.Index(jsonStr, "Meme #1") <= strings.Index(jsonStr, "Meme #2")
154 uassert.True(t, check, ufmt.Sprintf("Expected %s to be before %s", memeData1, memeData2))
155}
156
157func TestBadSortBy(t *testing.T) {
158 m := NewMemeland()
159 now := time.Now()
160
161 numOfPosts := 5
162 var memeData []string
163 for i := 1; i <= numOfPosts; i++ {
164 // Prepare meme data
165 nextTime := now.Add(time.Duration(i) * time.Minute)
166 data := ufmt.Sprintf("Meme #%d", i)
167 memeData = append(memeData, data)
168
169 m.PostMeme(data, nextTime.Unix())
170 }
171
172 // Get timestamps
173 beforeEarliest := now.Add(-1 * time.Minute)
174 afterLatest := now.Add(time.Duration(numOfPosts)*time.Minute + time.Minute)
175
176 tests := []struct {
177 name string
178 sortBy string
179 wantPanic string
180 }{
181 {
182 name: "Empty sortBy",
183 sortBy: "",
184 wantPanic: "runtime error: index out of range",
185 },
186 {
187 name: "Wrong sortBy",
188 sortBy: "random string",
189 wantPanic: "",
190 },
191 }
192
193 for _, tc := range tests {
194 t.Run(tc.name, func(t *testing.T) {
195 defer func() {
196 if r := recover(); r == nil {
197 t.Errorf("code did not panic when it should have")
198 }
199 }()
200
201 // Panics should be caught
202 _ = m.GetPostsInRange(beforeEarliest.Unix(), afterLatest.Unix(), 1, 1, tc.sortBy)
203 })
204 }
205}
206
207func TestNoPosts(t *testing.T) {
208 m := NewMemeland()
209
210 // Add a post to Memeland
211 now := time.Now().Unix()
212
213 jsonStr := m.GetPostsInRange(0, now, 1, 1, "DATE_CREATED")
214
215 uassert.Equal(t, jsonStr, "[]")
216}
217
218func TestUpvote(t *testing.T) {
219 m := NewMemeland()
220
221 // Add a post to Memeland
222 now := time.Now().Unix()
223 postID := m.PostMeme("Test meme data", now)
224
225 // Initial upvote count should be 0
226 post := m.getPost(postID)
227 uassert.Equal(t, 0, post.UpvoteTracker.Size())
228
229 // Upvote the post
230 upvoteResult := m.Upvote(postID)
231 uassert.Equal(t, "upvote successful", upvoteResult)
232
233 // Retrieve the post again and check the upvote count
234 post = m.getPost(postID)
235 uassert.Equal(t, 1, post.UpvoteTracker.Size())
236}
237
238func TestDelete(t *testing.T) {
239 alice := testutils.TestAddress("alice")
240 testing.SetRealm(std.NewUserRealm(alice))
241
242 // Alice is admin
243 m := NewMemeland()
244
245 // Set caller to Bob
246 bob := testutils.TestAddress("bob")
247 testing.SetRealm(std.NewUserRealm(bob))
248
249 // Bob adds post to Memeland
250 now := time.Now()
251 postID := m.PostMeme("Meme #1", now.Unix())
252
253 // Alice removes Bob's post
254 testing.SetRealm(std.NewUserRealm(alice))
255
256 id := m.RemovePost(postID)
257 uassert.Equal(t, postID, id, "post IDs not matching")
258 uassert.Equal(t, 0, len(m.Posts), "there should be 0 posts after removing")
259}
260
261func TestDeleteByNonAdmin(t *testing.T) {
262 alice := testutils.TestAddress("alice")
263 testing.SetRealm(std.NewUserRealm(alice))
264
265 m := NewMemeland()
266
267 // Add a post to Memeland
268 now := time.Now()
269 postID := m.PostMeme("Meme #1", now.Unix())
270
271 // Bob will try to delete meme posted by Alice, which should fail
272 bob := testutils.TestAddress("bob")
273 testing.SetRealm(std.NewUserRealm(bob))
274
275 defer func() {
276 if r := recover(); r == nil {
277 t.Errorf("code did not panic when it should have")
278 }
279 }()
280
281 // Should panic - caught by defer
282 m.RemovePost(postID)
283}