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}