memeland_test.gno

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