github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/misc_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "database/sql" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 "net/http/httptest" 10 "os" 11 "runtime/debug" 12 "strconv" 13 "testing" 14 "time" 15 16 c "github.com/Azareal/Gosora/common" 17 "github.com/Azareal/Gosora/common/gauth" 18 "github.com/Azareal/Gosora/common/phrases" 19 "github.com/Azareal/Gosora/routes" 20 "github.com/pkg/errors" 21 ) 22 23 func miscinit(t *testing.T) { 24 if err := gloinit(); err != nil { 25 t.Fatal(err) 26 } 27 } 28 29 func recordMustExist(t *testing.T, err error, errmsg string, args ...interface{}) { 30 if err == ErrNoRows { 31 debug.PrintStack() 32 t.Errorf(errmsg, args...) 33 } else if err != nil { 34 debug.PrintStack() 35 t.Fatal(err) 36 } 37 } 38 39 func recordMustNotExist(t *testing.T, err error, errmsg string, args ...interface{}) { 40 if err == nil { 41 debug.PrintStack() 42 t.Errorf(errmsg, args...) 43 } else if err != ErrNoRows { 44 debug.PrintStack() 45 t.Fatal(err) 46 } 47 } 48 49 func TestUserStore(t *testing.T) { 50 miscinit(t) 51 if !c.PluginsInited { 52 c.InitPlugins() 53 } 54 55 var err error 56 uc := c.NewMemoryUserCache(c.Config.UserCacheCapacity) 57 c.Users, err = c.NewDefaultUserStore(uc) 58 expectNilErr(t, err) 59 uc.Flush() 60 userStoreTest(t, 2) 61 c.Users, err = c.NewDefaultUserStore(nil) 62 expectNilErr(t, err) 63 userStoreTest(t, 5) 64 } 65 func userStoreTest(t *testing.T, newUserID int) { 66 uc := c.Users.GetCache() 67 // Go doesn't have short-circuiting, so this'll allow us to do one liner tests 68 cacheLength := func(uc c.UserCache) int { 69 if uc == nil { 70 return 0 71 } 72 return uc.Length() 73 } 74 isCacheLengthZero := func(uc c.UserCache) bool { 75 return cacheLength(uc) == 0 76 } 77 ex, exf := exp(t), expf(t) 78 exf(isCacheLengthZero(uc), "The initial ucache length should be zero, not %d", cacheLength(uc)) 79 80 _, err := c.Users.Get(-1) 81 recordMustNotExist(t, err, "UID #-1 shouldn't exist") 82 exf(isCacheLengthZero(uc), "We found %d items in the user cache and it's supposed to be empty", cacheLength(uc)) 83 _, err = c.Users.Get(0) 84 recordMustNotExist(t, err, "UID #0 shouldn't exist") 85 exf(isCacheLengthZero(uc), "We found %d items in the user cache and it's supposed to be empty", cacheLength(uc)) 86 87 user, err := c.Users.Get(1) 88 recordMustExist(t, err, "Couldn't find UID #1") 89 90 expectW := func(cond, expec bool, prefix, suffix string) { 91 midfix := "should not be" 92 if expec { 93 midfix = "should be" 94 } 95 ex(cond, prefix+" "+midfix+" "+suffix) 96 } 97 98 // TODO: Add email checks too? Do them separately? 99 expectUser := func(u *c.User, uid int, name string, group int, super, admin, mod, banned bool) { 100 exf(u.ID == uid, "u.ID should be %d. Got '%d' instead.", uid, u.ID) 101 exf(u.Name == name, "u.Name should be '%s', not '%s'", name, u.Name) 102 expectW(u.Group == group, true, u.Name, "in group"+strconv.Itoa(group)) 103 expectW(u.IsSuperAdmin == super, super, u.Name, "a super admin") 104 expectW(u.IsAdmin == admin, admin, u.Name, "an admin") 105 expectW(u.IsSuperMod == mod, mod, u.Name, "a super mod") 106 expectW(u.IsMod == mod, mod, u.Name, "a mod") 107 expectW(u.IsBanned == banned, banned, u.Name, "banned") 108 } 109 expectUser(user, 1, "Admin", 1, true, true, true, false) 110 111 user, err = c.Users.GetByName("Admin") 112 recordMustExist(t, err, "Couldn't find user 'Admin'") 113 expectUser(user, 1, "Admin", 1, true, true, true, false) 114 us, err := c.Users.BulkGetByName([]string{"Admin"}) 115 recordMustExist(t, err, "Couldn't find user 'Admin'") 116 exf(len(us) == 1, "len(us) should be 1, not %d", len(us)) 117 expectUser(us[0], 1, "Admin", 1, true, true, true, false) 118 119 _, err = c.Users.Get(newUserID) 120 recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't exist", newUserID)) 121 122 // TODO: GetByName tests for newUserID 123 124 if uc != nil { 125 expectIntToBeX(t, uc.Length(), 1, "User cache length should be 1, not %d") 126 _, err = uc.Get(-1) 127 recordMustNotExist(t, err, "UID #-1 shouldn't exist, even in the cache") 128 _, err = uc.Get(0) 129 recordMustNotExist(t, err, "UID #0 shouldn't exist, even in the cache") 130 user, err = uc.Get(1) 131 recordMustExist(t, err, "Couldn't find UID #1 in the cache") 132 133 exf(user.ID == 1, "user.ID does not match the requested UID. Got '%d' instead.", user.ID) 134 exf(user.Name == "Admin", "user.Name should be 'Admin', not '%s'", user.Name) 135 136 _, err = uc.Get(newUserID) 137 recordMustNotExist(t, err, "UID #%d shouldn't exist, even in the cache", newUserID) 138 uc.Flush() 139 expectIntToBeX(t, uc.Length(), 0, "User cache length should be 0, not %d") 140 } 141 142 // TODO: Lock onto the specific error type. Is this even possible without sacrificing the detailed information in the error message? 143 bulkGetMapEmpty := func(id int) { 144 userList, _ := c.Users.BulkGetMap([]int{id}) 145 exf(len(userList) == 0, "The userList length should be 0, not %d", len(userList)) 146 exf(isCacheLengthZero(uc), "User cache length should be 0, not %d", cacheLength(uc)) 147 } 148 bulkGetMapEmpty(-1) 149 bulkGetMapEmpty(0) 150 151 userList, _ := c.Users.BulkGetMap([]int{1}) 152 exf(len(userList) == 1, "Returned map should have one result (UID #1), not %d", len(userList)) 153 user, ok := userList[1] 154 if !ok { 155 t.Error("We couldn't find UID #1 in the returned map") 156 t.Error("userList", userList) 157 return 158 } 159 exf(user.ID == 1, "user.ID does not match the requested UID. Got '%d' instead.", user.ID) 160 161 if uc != nil { 162 expectIntToBeX(t, uc.Length(), 1, "User cache length should be 1, not %d") 163 user, err = uc.Get(1) 164 recordMustExist(t, err, "Couldn't find UID #1 in the cache") 165 166 exf(user.ID == 1, "user.ID does not match the requested UID. Got '%d' instead.", user.ID) 167 uc.Flush() 168 } 169 170 ex(!c.Users.Exists(-1), "UID #-1 shouldn't exist") 171 ex(!c.Users.Exists(0), "UID #0 shouldn't exist") 172 ex(c.Users.Exists(1), "UID #1 should exist") 173 exf(!c.Users.Exists(newUserID), "UID #%d shouldn't exist", newUserID) 174 175 exf(isCacheLengthZero(uc), "User cache length should be 0, not %d", cacheLength(uc)) 176 expectIntToBeX(t, c.Users.Count(), 1, "The number of users should be 1, not %d") 177 searchUser := func(name, email string, gid, count int) { 178 f := func(name, email string, gid, count int, m string) { 179 expectIntToBeX(t, c.Users.CountSearch(name, email, gid), count, "The number of users for "+m+", not %d") 180 } 181 f(name, email, 0, count, fmt.Sprintf("name '%s' and email '%s' should be %d", name, email, count)) 182 f(name, "", 0, count, fmt.Sprintf("name '%s' should be %d", name, count)) 183 f("", email, 0, count, fmt.Sprintf("email '%s' should be %d", email, count)) 184 185 f2 := func(name, email string, gid, offset int, m string, args ...interface{}) { 186 ulist, err := c.Users.SearchOffset(name, email, gid, offset, 15) 187 expectNilErr(t, err) 188 expectIntToBeX(t, len(ulist), count, "The number of users for "+fmt.Sprintf(m, args...)+", not %d") 189 } 190 f2(name, email, 0, 0, "name '%s' and email '%s' should be %d", name, email, count) 191 f2(name, "", 0, 0, "name '%s' should be %d", name, count) 192 f2("", email, 0, 0, "email '%s' should be %d", email, count) 193 194 count = 0 195 f2(name, email, 0, 10, "name '%s' and email '%s' should be %d", name, email, count) 196 f2(name, "", 0, 10, "name '%s' should be %d", name, count) 197 f2("", email, 0, 10, "email '%s' should be %d", email, count) 198 199 f2(name, email, 999, 0, "name '%s' and email '%s' should be %d", name, email, 0) 200 f2(name, "", 999, 0, "name '%s' should be %d", name, 0) 201 f2("", email, 999, 0, "email '%s' should be %d", email, 0) 202 203 f2(name, email, 999, 10, "name '%s' and email '%s' should be %d", name, email, 0) 204 f2(name, "", 999, 10, "name '%s' should be %d", name, 0) 205 f2("", email, 999, 10, "email '%s' should be %d", email, 0) 206 } 207 searchUser("Sam", "sam@localhost.loc", 0, 0) 208 // TODO: CountSearch gid test 209 210 awaitingActivation := 5 211 // TODO: Write tests for the registration validators 212 uid, err := c.Users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, false) 213 expectNilErr(t, err) 214 exf(uid == newUserID, "The UID of the new user should be %d not %d", newUserID, uid) 215 exf(c.Users.Exists(newUserID), "UID #%d should exist", newUserID) 216 expectIntToBeX(t, c.Users.Count(), 2, "The number of users should be 2, not %d") 217 searchUser("Sam", "sam@localhost.loc", 0, 1) 218 // TODO: CountSearch gid test 219 220 user, err = c.Users.Get(newUserID) 221 recordMustExist(t, err, "Couldn't find UID #%d", newUserID) 222 expectUser(user, newUserID, "Sam", 5, false, false, false, false) 223 224 if uc != nil { 225 expectIntToBeX(t, uc.Length(), 1, "User cache length should be 1, not %d") 226 user, err = uc.Get(newUserID) 227 recordMustExist(t, err, "Couldn't find UID #%d in the cache", newUserID) 228 exf(user.ID == newUserID, "user.ID does not match the requested UID. Got '%d' instead.", user.ID) 229 } 230 231 userList, _ = c.Users.BulkGetMap([]int{1, uid}) 232 exf(len(userList) == 2, "Returned map should have 2 results, not %d", len(userList)) 233 // TODO: More tests on userList 234 235 { 236 userList, _ := c.Users.BulkGetByName([]string{"Admin", "Sam"}) 237 exf(len(userList) == 2, "Returned list should have 2 results, not %d", len(userList)) 238 } 239 240 if uc != nil { 241 expectIntToBeX(t, uc.Length(), 2, "User cache length should be 2, not %d") 242 user, err = uc.Get(1) 243 recordMustExist(t, err, "Couldn't find UID #%d in the cache", 1) 244 exf(user.ID == 1, "user.ID does not match the requested UID. Got '%d' instead.", user.ID) 245 user, err = uc.Get(newUserID) 246 recordMustExist(t, err, "Couldn't find UID #%d in the cache", newUserID) 247 exf(user.ID == newUserID, "user.ID does not match the requested UID. Got '%d' instead.", user.ID) 248 uc.Flush() 249 } 250 251 user, err = c.Users.Get(newUserID) 252 recordMustExist(t, err, "Couldn't find UID #%d", newUserID) 253 expectUser(user, newUserID, "Sam", 5, false, false, false, false) 254 255 if uc != nil { 256 expectIntToBeX(t, uc.Length(), 1, "User cache length should be 1, not %d") 257 user, err = uc.Get(newUserID) 258 recordMustExist(t, err, "Couldn't find UID #%d in the cache", newUserID) 259 exf(user.ID == newUserID, "user.ID does not match the requested UID. Got '%d' instead.", user.ID) 260 } 261 262 expectNilErr(t, user.Activate()) 263 expectIntToBeX(t, user.Group, 5, "Sam should still be in group 5 in this copy") 264 265 // ? - What if we change the caching mechanism so it isn't hard purged and reloaded? We'll deal with that when we come to it, but for now, this is a sign of a cache bug 266 afterUserFlush := func(uid int) { 267 if uc != nil { 268 expectIntToBeX(t, uc.Length(), 0, "User cache length should be 0, not %d") 269 _, err = uc.Get(uid) 270 recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", uid) 271 } 272 } 273 afterUserFlush(newUserID) 274 275 user, err = c.Users.Get(newUserID) 276 recordMustExist(t, err, "Couldn't find UID #%d", newUserID) 277 expectUser(user, newUserID, "Sam", c.Config.DefaultGroup, false, false, false, false) 278 279 // Permanent ban 280 duration, _ := time.ParseDuration("0") 281 282 // TODO: Attempt a double ban, double activation, and double unban 283 expectNilErr(t, user.Ban(duration, 1)) 284 exf(user.Group == c.Config.DefaultGroup, "Sam should be in group %d, not %d", c.Config.DefaultGroup, user.Group) 285 afterUserFlush(newUserID) 286 287 user, err = c.Users.Get(newUserID) 288 recordMustExist(t, err, "Couldn't find UID #%d", newUserID) 289 expectUser(user, newUserID, "Sam", c.BanGroup, false, false, false, true) 290 291 // TODO: Do tests against the scheduled updates table and the task system to make sure the ban exists there and gets revoked when it should 292 293 expectNilErr(t, user.Unban()) 294 expectIntToBeX(t, user.Group, c.BanGroup, "Sam should still be in the ban group in this copy") 295 afterUserFlush(newUserID) 296 297 user, err = c.Users.Get(newUserID) 298 recordMustExist(t, err, "Couldn't find UID #%d", newUserID) 299 expectUser(user, newUserID, "Sam", c.Config.DefaultGroup, false, false, false, false) 300 301 reportsForumID := 1 // TODO: Use the constant in common? 302 generalForumID := 2 303 dummyResponseRecorder := httptest.NewRecorder() 304 bytesBuffer := bytes.NewBuffer([]byte("")) 305 dummyRequest1 := httptest.NewRequest("", "/forum/"+strconv.Itoa(reportsForumID), bytesBuffer) 306 dummyRequest2 := httptest.NewRequest("", "/forum/"+strconv.Itoa(generalForumID), bytesBuffer) 307 var user2 *c.User 308 309 changeGroupTest := func(oldGroup, newGroup int) { 310 expectNilErr(t, user.ChangeGroup(newGroup)) 311 // ! I don't think ChangeGroup should be changing the value of user... Investigate this. 312 ex(oldGroup == user.Group, "Someone's mutated this pointer elsewhere") 313 314 user, err = c.Users.Get(newUserID) 315 recordMustExist(t, err, "Couldn't find UID #%d", newUserID) 316 user2 = c.BlankUser() 317 *user2 = *user 318 } 319 320 changeGroupTest2 := func(rank string, firstShouldBe, secondShouldBe bool) { 321 head, e := c.UserCheck(dummyResponseRecorder, dummyRequest1, user) 322 if e != nil { 323 t.Fatal(e) 324 } 325 head2, e := c.UserCheck(dummyResponseRecorder, dummyRequest2, user2) 326 if e != nil { 327 t.Fatal(e) 328 } 329 ferr := c.ForumUserCheck(head, dummyResponseRecorder, dummyRequest1, user, reportsForumID) 330 ex(ferr == nil, "There shouldn't be any errors in forumUserCheck") 331 ex(user.Perms.ViewTopic == firstShouldBe, rank+" should be able to access the reports forum") 332 ferr = c.ForumUserCheck(head2, dummyResponseRecorder, dummyRequest2, user2, generalForumID) 333 ex(ferr == nil, "There shouldn't be any errors in forumUserCheck") 334 ex(user2.Perms.ViewTopic == secondShouldBe, "Sam should be able to access the general forum") 335 } 336 337 changeGroupTest(c.Config.DefaultGroup, 1) 338 expectUser(user, newUserID, "Sam", 1, false, true, true, false) 339 changeGroupTest2("Admins", true, true) 340 341 changeGroupTest(1, 2) 342 expectUser(user, newUserID, "Sam", 2, false, false, true, false) 343 changeGroupTest2("Mods", true, true) 344 345 changeGroupTest(2, 3) 346 expectUser(user, newUserID, "Sam", 3, false, false, false, false) 347 changeGroupTest2("Members", false, true) 348 ex(user.Perms.ViewTopic != user2.Perms.ViewTopic, "user.Perms.ViewTopic and user2.Perms.ViewTopic should never match") 349 350 changeGroupTest(3, 4) 351 expectUser(user, newUserID, "Sam", 4, false, false, false, true) 352 changeGroupTest2("Members", false, true) 353 354 changeGroupTest(4, 5) 355 expectUser(user, newUserID, "Sam", 5, false, false, false, false) 356 changeGroupTest2("Members", false, true) 357 358 changeGroupTest(5, 6) 359 expectUser(user, newUserID, "Sam", 6, false, false, false, false) 360 changeGroupTest2("Members", false, true) 361 362 err = user.ChangeGroup(c.Config.DefaultGroup) 363 expectNilErr(t, err) 364 ex(user.Group == 6, "Someone's mutated this pointer elsewhere") 365 366 exf(user.LastIP == "", "user.LastIP should be blank not %s", user.LastIP) 367 expectNilErr(t, user.UpdateIP("::1")) 368 user, err = c.Users.Get(newUserID) 369 recordMustExist(t, err, "Couldn't find UID #%d", newUserID) 370 exf(user.LastIP == "::1", "user.LastIP should be %s not %s", "::1", user.LastIP) 371 expectNilErr(t, c.Users.ClearLastIPs()) 372 expectNilErr(t, c.Users.Reload(newUserID)) 373 user, err = c.Users.Get(newUserID) 374 recordMustExist(t, err, "Couldn't find UID #%d", newUserID) 375 exf(user.LastIP == "", "user.LastIP should be blank not %s", user.LastIP) 376 377 expectNilErr(t, user.Delete()) 378 exf(!c.Users.Exists(newUserID), "UID #%d should no longer exist", newUserID) 379 afterUserFlush(newUserID) 380 expectIntToBeX(t, c.Users.Count(), 1, "The number of users should be 1, not %d") 381 searchUser("Sam", "sam@localhost.loc", 0, 0) 382 // TODO: CountSearch gid test 383 384 _, err = c.Users.Get(newUserID) 385 recordMustNotExist(t, err, "UID #%d shouldn't exist", newUserID) 386 387 // And a unicode test, even though I doubt it'll fail 388 uid, err = c.Users.Create("γ΅γ ", "πππ", "sam@localhost.loc", awaitingActivation, false) 389 expectNilErr(t, err) 390 exf(uid == newUserID+1, "The UID of the new user should be %d", newUserID+1) 391 exf(c.Users.Exists(newUserID+1), "UID #%d should exist", newUserID+1) 392 393 user, err = c.Users.Get(newUserID + 1) 394 recordMustExist(t, err, "Couldn't find UID #%d", newUserID+1) 395 expectUser(user, newUserID+1, "γ΅γ ", 5, false, false, false, false) 396 397 expectNilErr(t, user.Delete()) 398 exf(!c.Users.Exists(newUserID+1), "UID #%d should no longer exist", newUserID+1) 399 400 // MySQL utf8mb4 username test 401 uid, err = c.Users.Create("πππ", "πππ", "sam@localhost.loc", awaitingActivation, false) 402 expectNilErr(t, err) 403 exf(uid == newUserID+2, "The UID of the new user should be %d", newUserID+2) 404 exf(c.Users.Exists(newUserID+2), "UID #%d should exist", newUserID+2) 405 406 user, err = c.Users.Get(newUserID + 2) 407 recordMustExist(t, err, "Couldn't find UID #%d", newUserID+1) 408 expectUser(user, newUserID+2, "πππ", 5, false, false, false, false) 409 410 expectNilErr(t, user.Delete()) 411 exf(!c.Users.Exists(newUserID+2), "UID #%d should no longer exist", newUserID+2) 412 413 // TODO: Add unicode login tests somewhere? Probably with the rest of the auth tests 414 // TODO: Add tests for the Cache* methods 415 } 416 417 // TODO: Add an error message to this? 418 func expectNilErr(t *testing.T, item error) { 419 if item != nil { 420 debug.PrintStack() 421 t.Fatal(item) 422 } 423 } 424 425 func expectIntToBeX(t *testing.T, item, expect int, errmsg string) { 426 if item != expect { 427 debug.PrintStack() 428 t.Fatalf(errmsg, item) 429 } 430 } 431 432 func expect(t *testing.T, item bool, errmsg string) { 433 if !item { 434 debug.PrintStack() 435 t.Fatal(errmsg) 436 } 437 } 438 439 func expectf(t *testing.T, item bool, errmsg string, args ...interface{}) { 440 if !item { 441 debug.PrintStack() 442 t.Fatalf(errmsg, args...) 443 } 444 } 445 446 func exp(t *testing.T) func(bool, string) { 447 return func(val bool, errmsg string) { 448 if !val { 449 debug.PrintStack() 450 t.Fatal(errmsg) 451 } 452 } 453 } 454 455 func expf(t *testing.T) func(bool, string, ...interface{}) { 456 return func(val bool, errmsg string, params ...interface{}) { 457 if !val { 458 debug.PrintStack() 459 t.Fatalf(errmsg, params...) 460 } 461 } 462 } 463 464 func TestPermsMiddleware(t *testing.T) { 465 miscinit(t) 466 if !c.PluginsInited { 467 c.InitPlugins() 468 } 469 470 dummyResponseRecorder := httptest.NewRecorder() 471 bytesBuffer := bytes.NewBuffer([]byte("")) 472 dummyRequest := httptest.NewRequest("", "/forum/1", bytesBuffer) 473 user := c.BlankUser() 474 ex := exp(t) 475 476 f := func(ff func(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError) bool { 477 ferr := ff(dummyResponseRecorder, dummyRequest, user) 478 return ferr == nil 479 } 480 481 ex(!f(c.SuperModOnly), "Blank users shouldn't be supermods") 482 user.IsSuperMod = false 483 ex(!f(c.SuperModOnly), "Non-supermods shouldn't be allowed through supermod gates") 484 user.IsSuperMod = true 485 ex(f(c.SuperModOnly), "Supermods should be allowed through supermod gates") 486 487 // TODO: Loop over the Control Panel routes and make sure only supermods can get in 488 489 user = c.BlankUser() 490 491 ex(!f(c.MemberOnly), "Blank users shouldn't be considered loggedin") 492 user.Loggedin = false 493 ex(!f(c.MemberOnly), "Guests shouldn't be able to access member areas") 494 user.Loggedin = true 495 ex(f(c.MemberOnly), "Logged in users should be able to access member areas") 496 497 // TODO: Loop over the /user/ routes and make sure only members can access the ones other than /user/username 498 499 user = c.BlankUser() 500 501 ex(!f(c.AdminOnly), "Blank users shouldn't be considered admins") 502 user.IsAdmin = false 503 ex(!f(c.AdminOnly), "Non-admins shouldn't be able to access admin areas") 504 user.IsAdmin = true 505 ex(f(c.AdminOnly), "Admins should be able to access admin areas") 506 507 user = c.BlankUser() 508 509 ex(!f(c.SuperAdminOnly), "Blank users shouldn't be considered super admins") 510 user.IsSuperAdmin = false 511 ex(!f(c.SuperAdminOnly), "Non-super admins shouldn't be allowed through the super admin gate") 512 user.IsSuperAdmin = true 513 ex(f(c.SuperAdminOnly), "Super admins should be allowed through super admin gates") 514 515 // TODO: Make sure only super admins can access the backups route 516 517 //dummyResponseRecorder = httptest.NewRecorder() 518 //bytesBuffer = bytes.NewBuffer([]byte("")) 519 //dummyRequest = httptest.NewRequest("", "/panel/backups/", bytesBuffer) 520 } 521 522 func TestTopicStore(t *testing.T) { 523 miscinit(t) 524 if !c.PluginsInited { 525 c.InitPlugins() 526 } 527 528 var err error 529 tcache := c.NewMemoryTopicCache(c.Config.TopicCacheCapacity) 530 c.Topics, err = c.NewDefaultTopicStore(tcache) 531 expectNilErr(t, err) 532 c.Config.DisablePostIP = false 533 topicStoreTest(t, 2, "::1") 534 c.Config.DisablePostIP = true 535 topicStoreTest(t, 3, "") 536 537 c.Topics, err = c.NewDefaultTopicStore(nil) 538 expectNilErr(t, err) 539 c.Config.DisablePostIP = false 540 topicStoreTest(t, 4, "::1") 541 c.Config.DisablePostIP = true 542 topicStoreTest(t, 5, "") 543 } 544 func topicStoreTest(t *testing.T, newID int, ip string) { 545 var topic *c.Topic 546 var err error 547 ex, exf := exp(t), expf(t) 548 549 _, err = c.Topics.Get(-1) 550 recordMustNotExist(t, err, "TID #-1 shouldn't exist") 551 _, err = c.Topics.Get(0) 552 recordMustNotExist(t, err, "TID #0 shouldn't exist") 553 554 topic, err = c.Topics.Get(1) 555 recordMustExist(t, err, "Couldn't find TID #1") 556 exf(topic.ID == 1, "topic.ID does not match the requested TID. Got '%d' instead.", topic.ID) 557 558 // TODO: Add BulkGetMap() to the TopicStore 559 560 ex(!c.Topics.Exists(-1), "TID #-1 shouldn't exist") 561 ex(!c.Topics.Exists(0), "TID #0 shouldn't exist") 562 ex(c.Topics.Exists(1), "TID #1 should exist") 563 564 count := c.Topics.Count() 565 exf(count == 1, "Global count for topics should be 1, not %d", count) 566 567 //Create(fid int, topicName string, content string, uid int, ip string) (tid int, err error) 568 tid, err := c.Topics.Create(2, "Test Topic", "Topic Content", 1, ip) 569 expectNilErr(t, err) 570 exf(tid == newID, "TID for the new topic should be %d, not %d", newID, tid) 571 exf(c.Topics.Exists(newID), "TID #%d should exist", newID) 572 573 count = c.Topics.Count() 574 exf(count == 2, "Global count for topics should be 2, not %d", count) 575 576 iFrag := func(cond bool) string { 577 if !cond { 578 return "n't" 579 } 580 return "" 581 } 582 583 testTopic := func(tid int, title, content string, createdBy int, ip string, parentID int, isClosed, sticky bool) { 584 topic, err = c.Topics.Get(tid) 585 recordMustExist(t, err, fmt.Sprintf("Couldn't find TID #%d", tid)) 586 exf(topic.ID == tid, "topic.ID does not match the requested TID. Got '%d' instead.", topic.ID) 587 exf(topic.GetID() == tid, "topic.ID does not match the requested TID. Got '%d' instead.", topic.GetID()) 588 exf(topic.Title == title, "The topic's name should be '%s', not %s", title, topic.Title) 589 exf(topic.Content == content, "The topic's body should be '%s', not %s", content, topic.Content) 590 exf(topic.CreatedBy == createdBy, "The topic's creator should be %d, not %d", createdBy, topic.CreatedBy) 591 exf(topic.IP == ip, "The topic's IP should be '%s', not %s", ip, topic.IP) 592 exf(topic.ParentID == parentID, "The topic's parent forum should be %d, not %d", parentID, topic.ParentID) 593 exf(topic.IsClosed == isClosed, "This topic should%s be locked", iFrag(topic.IsClosed)) 594 exf(topic.Sticky == sticky, "This topic should%s be sticky", iFrag(topic.Sticky)) 595 exf(topic.GetTable() == "topics", "The topic's table should be 'topics', not %s", topic.GetTable()) 596 } 597 598 tc := c.Topics.GetCache() 599 shouldNotBeIn := func(tid int) { 600 if tc != nil { 601 _, err = tc.Get(tid) 602 recordMustNotExist(t, err, "Topic cache should be empty") 603 } 604 } 605 if tc != nil { 606 _, err = tc.Get(newID) 607 expectNilErr(t, err) 608 } 609 610 testTopic(newID, "Test Topic", "Topic Content", 1, ip, 2, false, false) 611 612 expectNilErr(t, topic.Lock()) 613 shouldNotBeIn(newID) 614 testTopic(newID, "Test Topic", "Topic Content", 1, ip, 2, true, false) 615 616 expectNilErr(t, topic.Unlock()) 617 shouldNotBeIn(newID) 618 testTopic(newID, "Test Topic", "Topic Content", 1, ip, 2, false, false) 619 620 expectNilErr(t, topic.Stick()) 621 shouldNotBeIn(newID) 622 testTopic(newID, "Test Topic", "Topic Content", 1, ip, 2, false, true) 623 624 expectNilErr(t, topic.Unstick()) 625 shouldNotBeIn(newID) 626 testTopic(newID, "Test Topic", "Topic Content", 1, ip, 2, false, false) 627 628 expectNilErr(t, topic.MoveTo(1)) 629 shouldNotBeIn(newID) 630 testTopic(newID, "Test Topic", "Topic Content", 1, ip, 1, false, false) 631 // TODO: Add more tests for more *Topic methods 632 633 expectNilErr(t, c.Topics.ClearIPs()) 634 expectNilErr(t, c.Topics.Reload(topic.ID)) 635 testTopic(newID, "Test Topic", "Topic Content", 1, "", 1, false, false) 636 // TODO: Add more tests for more *Topic methods 637 638 expectNilErr(t, topic.Delete()) 639 shouldNotBeIn(newID) 640 641 _, err = c.Topics.Get(newID) 642 recordMustNotExist(t, err, fmt.Sprintf("TID #%d shouldn't exist", newID)) 643 exf(!c.Topics.Exists(newID), "TID #%d shouldn't exist", newID) 644 645 // TODO: Test topic creation and retrieving that created topic plus reload and inspecting the cache 646 } 647 648 func TestForumStore(t *testing.T) { 649 miscinit(t) 650 if !c.PluginsInited { 651 c.InitPlugins() 652 } 653 ex, exf := exp(t), expf(t) 654 // TODO: Test ForumStore.Reload 655 656 fcache, ok := c.Forums.(c.ForumCache) 657 ex(ok, "Unable to cast ForumStore to ForumCache") 658 ex(c.Forums.Count() == 2, "The forumstore global count should be 2") 659 ex(fcache.Length() == 2, "The forum cache length should be 2") 660 661 _, err := c.Forums.Get(-1) 662 recordMustNotExist(t, err, "FID #-1 shouldn't exist") 663 _, err = c.Forums.Get(0) 664 recordMustNotExist(t, err, "FID #0 shouldn't exist") 665 666 testForum := func(f *c.Forum, fid int, name string, active bool, desc string) { 667 exf(f.ID == fid, "forum.ID should be %d, not %d.", fid, f.ID) 668 // TODO: Check the preset and forum permissions 669 exf(f.Name == name, "forum.Name should be %s, not %s", name, f.Name) 670 str := "" 671 if !active { 672 str = "n't" 673 } 674 exf(f.Active == active, "The reports forum should%s be active", str) 675 exf(f.Desc == desc, "forum.Desc should be '%s' not '%s'", desc, f.Desc) 676 } 677 678 forum, err := c.Forums.Get(1) 679 recordMustExist(t, err, "Couldn't find FID #1") 680 expectDesc := "All the reports go here" 681 testForum(forum, 1, "Reports", false, expectDesc) 682 forum, err = c.Forums.BypassGet(1) 683 recordMustExist(t, err, "Couldn't find FID #1") 684 685 forum, err = c.Forums.Get(2) 686 recordMustExist(t, err, "Couldn't find FID #2") 687 forum, err = c.Forums.BypassGet(2) 688 recordMustExist(t, err, "Couldn't find FID #2") 689 expectDesc = "A place for general discussions which don't fit elsewhere" 690 testForum(forum, 2, "General", true, expectDesc) 691 692 // Forum reload test, kind of hacky but gets the job done 693 /* 694 CacheGet(id int) (*Forum, error) 695 CacheSet(forum *Forum) error 696 */ 697 ex(ok, "ForumCache should be available") 698 forum.Name = "nanana" 699 fcache.CacheSet(forum) 700 forum, err = c.Forums.Get(2) 701 recordMustExist(t, err, "Couldn't find FID #2") 702 exf(forum.Name == "nanana", "The faux name should be nanana not %s", forum.Name) 703 expectNilErr(t, c.Forums.Reload(2)) 704 forum, err = c.Forums.Get(2) 705 recordMustExist(t, err, "Couldn't find FID #2") 706 exf(forum.Name == "General", "The proper name should be 2 not %s", forum.Name) 707 708 ex(!c.Forums.Exists(-1), "FID #-1 shouldn't exist") 709 ex(!c.Forums.Exists(0), "FID #0 shouldn't exist") 710 ex(c.Forums.Exists(1), "FID #1 should exist") 711 ex(c.Forums.Exists(2), "FID #2 should exist") 712 ex(!c.Forums.Exists(3), "FID #3 shouldn't exist") 713 714 _, err = c.Forums.Create("", "", true, "all") 715 ex(err != nil, "A forum shouldn't be successfully created, if it has a blank name") 716 717 fid, err := c.Forums.Create("Test Forum", "", true, "all") 718 expectNilErr(t, err) 719 ex(fid == 3, "The first forum we create should have an ID of 3") 720 ex(c.Forums.Exists(3), "FID #2 should exist") 721 722 ex(c.Forums.Count() == 3, "The forumstore global count should be 3") 723 ex(fcache.Length() == 3, "The forum cache length should be 3") 724 725 forum, err = c.Forums.Get(3) 726 recordMustExist(t, err, "Couldn't find FID #3") 727 forum, err = c.Forums.BypassGet(3) 728 recordMustExist(t, err, "Couldn't find FID #3") 729 testForum(forum, 3, "Test Forum", true, "") 730 731 // TODO: More forum creation tests 732 733 expectNilErr(t, c.Forums.Delete(3)) 734 ex(forum.ID == 3, "forum pointer shenanigans") 735 ex(c.Forums.Count() == 2, "The forumstore global count should be 2") 736 ex(fcache.Length() == 2, "The forum cache length should be 2") 737 ex(!c.Forums.Exists(3), "FID #3 shouldn't exist after being deleted") 738 _, err = c.Forums.Get(3) 739 recordMustNotExist(t, err, "FID #3 shouldn't exist after being deleted") 740 _, err = c.Forums.BypassGet(3) 741 recordMustNotExist(t, err, "FID #3 shouldn't exist after being deleted") 742 743 ex(c.Forums.Delete(c.ReportForumID) != nil, "The reports forum shouldn't be deletable") 744 exf(c.Forums.Exists(c.ReportForumID), "FID #%d should still exist", c.ReportForumID) 745 _, err = c.Forums.Get(c.ReportForumID) 746 exf(err == nil, "FID #%d should still exist", c.ReportForumID) 747 _, err = c.Forums.BypassGet(c.ReportForumID) 748 exf(err == nil, "FID #%d should still exist", c.ReportForumID) 749 750 eforums := map[int]bool{1: true, 2: true} 751 { 752 forums, err := c.Forums.GetAll() 753 expectNilErr(t, err) 754 found := make(map[int]*c.Forum) 755 for _, forum := range forums { 756 _, ok := eforums[forum.ID] 757 exf(ok, "unknown forum #%d in forums", forum.ID) 758 found[forum.ID] = forum 759 } 760 for fid, _ := range eforums { 761 _, ok := found[fid] 762 exf(ok, "unable to find expected forum #%d in forums", fid) 763 } 764 } 765 766 { 767 fids, err := c.Forums.GetAllIDs() 768 expectNilErr(t, err) 769 found := make(map[int]bool) 770 for _, fid := range fids { 771 _, ok := eforums[fid] 772 exf(ok, "unknown fid #%d in fids", fid) 773 found[fid] = true 774 } 775 for fid, _ := range eforums { 776 _, ok := found[fid] 777 exf(ok, "unable to find expected fid #%d in fids", fid) 778 } 779 } 780 781 vforums := map[int]bool{2: true} 782 { 783 forums, err := c.Forums.GetAllVisible() 784 expectNilErr(t, err) 785 found := make(map[int]*c.Forum) 786 for _, forum := range forums { 787 _, ok := vforums[forum.ID] 788 exf(ok, "unknown forum #%d in forums", forum.ID) 789 found[forum.ID] = forum 790 } 791 for fid, _ := range vforums { 792 _, ok := found[fid] 793 exf(ok, "unable to find expected forum #%d in forums", fid) 794 } 795 } 796 797 { 798 fids, err := c.Forums.GetAllVisibleIDs() 799 expectNilErr(t, err) 800 found := make(map[int]bool) 801 for _, fid := range fids { 802 _, ok := vforums[fid] 803 exf(ok, "unknown fid #%d in fids", fid) 804 found[fid] = true 805 } 806 for fid, _ := range vforums { 807 _, ok := found[fid] 808 exf(ok, "unable to find expected fid #%d in fids", fid) 809 } 810 } 811 812 forum, err = c.Forums.Get(2) 813 expectNilErr(t, err) 814 prevTopicCount := forum.TopicCount 815 tid, err := c.Topics.Create(forum.ID, "Forum Meta Test", "Forum Meta Test", 1, "") 816 expectNilErr(t, err) 817 forum, err = c.Forums.Get(2) 818 expectNilErr(t, err) 819 exf(forum.TopicCount == (prevTopicCount+1), "forum.TopicCount should be %d not %d", prevTopicCount+1, forum.TopicCount) 820 exf(forum.LastTopicID == tid, "forum.LastTopicID should be %d not %d", tid, forum.LastTopicID) 821 exf(forum.LastPage == 1, "forum.LastPage should be %d not %d", 1, forum.LastPage) 822 823 // TODO: Test topic creation and forum topic metadata 824 825 // TODO: Test forum update 826 // TODO: Other forumstore stuff and forumcache? 827 } 828 829 // TODO: Implement this 830 func TestForumPermsStore(t *testing.T) { 831 miscinit(t) 832 if !c.PluginsInited { 833 c.InitPlugins() 834 } 835 ex := exp(t) 836 837 f := func(fid, gid int, msg string, inv ...bool) { 838 fp, err := c.FPStore.Get(fid, gid) 839 if err == ErrNoRows { 840 fp = c.BlankForumPerms() 841 } else { 842 expectNilErr(t, err) 843 } 844 vt := fp.ViewTopic 845 if len(inv) > 0 && inv[0] == true { 846 vt = !vt 847 } 848 ex(vt, msg) 849 } 850 851 // TODO: Test reporting 852 initialState := func() { 853 f(1, 1, "admins should be able to see reports") 854 f(1, 2, "mods should be able to see reports") 855 f(1, 3, "members should not be able to see reports", true) 856 f(1, 4, "banned users should not be able to see reports", true) 857 f(2, 1, "admins should be able to see general") 858 f(2, 3, "members should be able to see general") 859 f(2, 6, "guests should be able to see general") 860 } 861 initialState() 862 863 expectNilErr(t, c.FPStore.Reload(1)) 864 initialState() 865 expectNilErr(t, c.FPStore.Reload(2)) 866 initialState() 867 868 gid, err := c.Groups.Create("FP Test", "FP Test", false, false, false) 869 expectNilErr(t, err) 870 fid, err := c.Forums.Create("FP Test", "FP Test", true, "") 871 expectNilErr(t, err) 872 873 u := c.GuestUser.Copy() 874 rt := func(gid, fid int, shouldSucceed bool) { 875 w := httptest.NewRecorder() 876 bytesBuffer := bytes.NewBuffer([]byte("")) 877 sfid := strconv.Itoa(fid) 878 req := httptest.NewRequest("", "/forum/"+sfid, bytesBuffer) 879 u.Group = gid 880 h, err := c.UserCheck(w, req, &u) 881 expectNilErr(t, err) 882 rerr := routes.ViewForum(w, req, &u, h, sfid) 883 if shouldSucceed { 884 ex(rerr == nil, "ViewForum should succeed") 885 } else { 886 ex(rerr != nil, "ViewForum should not succeed") 887 } 888 } 889 rt(1, fid, false) 890 rt(2, fid, false) 891 rt(3, fid, false) 892 rt(4, fid, false) 893 rt(gid, fid, false) 894 895 fp, err := c.FPStore.GetCopy(fid, gid) 896 if err == sql.ErrNoRows { 897 fp = *c.BlankForumPerms() 898 } else if err != nil { 899 expectNilErr(t, err) 900 } 901 fmt.Printf("fp: %+v\n", fp) 902 903 f(fid, 1, "admins should not be able to see fp test", true) 904 f(fid, 2, "mods should not be able to see fp test", true) 905 f(fid, 3, "members should not be able to see fp test", true) 906 f(fid, 4, "banned users should not be able to see fp test", true) 907 f(fid, gid, "fp test should not be able to see fp test", true) 908 909 fp.ViewTopic = true 910 911 forum, err := c.Forums.Get(fid) 912 expectNilErr(t, err) 913 expectNilErr(t, forum.SetPerms(&fp, "custom", gid)) 914 915 rt(1, fid, false) 916 rt(2, fid, false) 917 rt(3, fid, false) 918 rt(4, fid, false) 919 rt(gid, fid, true) 920 921 fp, err = c.FPStore.GetCopy(fid, gid) 922 if err == sql.ErrNoRows { 923 fp = *c.BlankForumPerms() 924 } else if err != nil { 925 expectNilErr(t, err) 926 } 927 928 f(fid, 1, "admins should not be able to see fp test", true) 929 f(fid, 2, "mods should not be able to see fp test", true) 930 f(fid, 3, "members should not be able to see fp test", true) 931 f(fid, 4, "banned users should not be able to see fp test", true) 932 f(fid, gid, "fp test should be able to see fp test") 933 934 expectNilErr(t, c.Forums.Delete(fid)) 935 rt(1, fid, false) 936 rt(2, fid, false) 937 rt(3, fid, false) 938 rt(4, fid, false) 939 rt(gid, fid, false) 940 941 // TODO: Test changing forum permissions 942 } 943 944 // TODO: Test the group permissions 945 // TODO: Test group.CanSee for forum presets + group perms 946 func TestGroupStore(t *testing.T) { 947 miscinit(t) 948 if !c.PluginsInited { 949 c.InitPlugins() 950 } 951 ex, exf := exp(t), expf(t) 952 953 _, err := c.Groups.Get(-1) 954 recordMustNotExist(t, err, "GID #-1 shouldn't exist") 955 956 // TODO: Refactor the group store to remove GID #0 957 g, err := c.Groups.Get(0) 958 recordMustExist(t, err, "Couldn't find GID #0") 959 exf(g.ID == 0, "g.ID doesn't not match the requested GID. Got '%d' instead.", g.ID) 960 exf(g.Name == "Unknown", "GID #0 is named '%s' and not 'Unknown'", g.Name) 961 962 g, err = c.Groups.Get(1) 963 recordMustExist(t, err, "Couldn't find GID #1") 964 exf(g.ID == 1, "g.ID doesn't not match the requested GID. Got '%d' instead.'", g.ID) 965 ex(len(g.CanSee) > 0, "g.CanSee should not be zero") 966 967 ex(!c.Groups.Exists(-1), "GID #-1 shouldn't exist") 968 // 0 aka Unknown, for system posts and other oddities 969 ex(c.Groups.Exists(0), "GID #0 should exist") 970 ex(c.Groups.Exists(1), "GID #1 should exist") 971 972 isAdmin, isMod, isBanned := true, true, false 973 gid, err := c.Groups.Create("Testing", "Test", isAdmin, isMod, isBanned) 974 expectNilErr(t, err) 975 ex(c.Groups.Exists(gid), "The group we just made doesn't exist") 976 977 ff := func(i bool) string { 978 if !i { 979 return "n't" 980 } 981 return "" 982 } 983 f := func(gid int, isBanned, isMod, isAdmin bool) { 984 ex(g.ID == gid, "The group ID should match the requested ID") 985 exf(g.IsAdmin == isAdmin, "This should%s be an admin group", ff(isAdmin)) 986 exf(g.IsMod == isMod, "This should%s be a mod group", ff(isMod)) 987 exf(g.IsBanned == isBanned, "This should%s be a ban group", ff(isBanned)) 988 } 989 990 g, err = c.Groups.Get(gid) 991 expectNilErr(t, err) 992 f(gid, false, true, true) 993 ex(len(g.CanSee) == 0, "g.CanSee should be empty") 994 995 isAdmin, isMod, isBanned = false, true, true 996 gid, err = c.Groups.Create("Testing 2", "Test", isAdmin, isMod, isBanned) 997 expectNilErr(t, err) 998 ex(c.Groups.Exists(gid), "The group we just made doesn't exist") 999 1000 g, err = c.Groups.Get(gid) 1001 expectNilErr(t, err) 1002 f(gid, false, true, false) 1003 1004 // TODO: Make sure this pointer doesn't change once we refactor the group store to stop updating the pointer 1005 expectNilErr(t, g.ChangeRank(false, false, true)) 1006 1007 g, err = c.Groups.Get(gid) 1008 expectNilErr(t, err) 1009 f(gid, true, false, false) 1010 1011 expectNilErr(t, g.ChangeRank(true, true, true)) 1012 1013 g, err = c.Groups.Get(gid) 1014 expectNilErr(t, err) 1015 f(gid, false, true, true) 1016 ex(len(g.CanSee) == 0, "len(g.CanSee) should be 0") 1017 1018 expectNilErr(t, g.ChangeRank(false, true, true)) 1019 1020 forum, err := c.Forums.Get(2) 1021 expectNilErr(t, err) 1022 forumPerms, err := c.FPStore.GetCopy(2, gid) 1023 if err == sql.ErrNoRows { 1024 forumPerms = *c.BlankForumPerms() 1025 } else if err != nil { 1026 expectNilErr(t, err) 1027 } 1028 forumPerms.ViewTopic = true 1029 1030 err = forum.SetPerms(&forumPerms, "custom", gid) 1031 expectNilErr(t, err) 1032 1033 g, err = c.Groups.Get(gid) 1034 expectNilErr(t, err) 1035 f(gid, false, true, false) 1036 ex(g.CanSee != nil, "g.CanSee must not be nil") 1037 ex(len(g.CanSee) == 1, "len(g.CanSee) should not be one") 1038 ex(g.CanSee[0] == 2, "g.CanSee[0] should be 2") 1039 canSee := g.CanSee 1040 1041 // Make sure the data is static 1042 expectNilErr(t, c.Groups.Reload(gid)) 1043 1044 g, err = c.Groups.Get(gid) 1045 expectNilErr(t, err) 1046 f(gid, false, true, false) 1047 1048 // TODO: Don't enforce a specific order here 1049 canSeeTest := func(a, b []int) bool { 1050 if (a == nil) != (b == nil) { 1051 return false 1052 } 1053 if len(a) != len(b) { 1054 return false 1055 } 1056 for i := range a { 1057 if a[i] != b[i] { 1058 return false 1059 } 1060 } 1061 return true 1062 } 1063 1064 ex(canSeeTest(g.CanSee, canSee), "g.CanSee is not being reused") 1065 1066 // TODO: Test group deletion 1067 // TODO: Test group reload 1068 // TODO: Test group cache set 1069 } 1070 1071 func TestGroupPromotions(t *testing.T) { 1072 miscinit(t) 1073 if !c.PluginsInited { 1074 c.InitPlugins() 1075 } 1076 ex, exf := exp(t), expf(t) 1077 1078 _, err := c.GroupPromotions.Get(-1) 1079 recordMustNotExist(t, err, "GP #-1 shouldn't exist") 1080 _, err = c.GroupPromotions.Get(0) 1081 recordMustNotExist(t, err, "GP #0 shouldn't exist") 1082 _, err = c.GroupPromotions.Get(1) 1083 recordMustNotExist(t, err, "GP #1 shouldn't exist") 1084 expectNilErr(t, c.GroupPromotions.Delete(1)) 1085 1086 //GetByGroup(gid int) (gps []*GroupPromotion, err error) 1087 1088 testPromo := func(exid, from, to, level, posts, registeredFor int, shouldFail bool) { 1089 gpid, err := c.GroupPromotions.Create(from, to, false, level, posts, registeredFor) 1090 exf(gpid == exid, "gpid should be %d not %d", exid, gpid) 1091 //fmt.Println("gpid:", gpid) 1092 gp, err := c.GroupPromotions.Get(gpid) 1093 expectNilErr(t, err) 1094 exf(gp.ID == gpid, "gp.ID should be %d not %d", gpid, gp.ID) 1095 exf(gp.From == from, "gp.From should be %d not %d", from, gp.From) 1096 exf(gp.To == to, "gp.To should be %d not %d", to, gp.To) 1097 ex(!gp.TwoWay, "gp.TwoWay should be false not true") 1098 exf(gp.Level == level, "gp.Level should be %d not %d", level, gp.Level) 1099 exf(gp.Posts == posts, "gp.Posts should be %d not %d", posts, gp.Posts) 1100 exf(gp.MinTime == 0, "gp.MinTime should be %d not %d", 0, gp.MinTime) 1101 exf(gp.RegisteredFor == registeredFor, "gp.RegisteredFor should be %d not %d", registeredFor, gp.RegisteredFor) 1102 1103 uid, err := c.Users.Create("Lord_"+strconv.Itoa(gpid), "I_Rule", "", from, false) 1104 expectNilErr(t, err) 1105 u, err := c.Users.Get(uid) 1106 expectNilErr(t, err) 1107 exf(u.ID == uid, "u.ID should be %d not %d", uid, u.ID) 1108 exf(u.Group == from, "u.Group should be %d not %d", from, u.Group) 1109 err = c.GroupPromotions.PromoteIfEligible(u, u.Level, u.Posts, u.CreatedAt) 1110 expectNilErr(t, err) 1111 u.CacheRemove() 1112 u, err = c.Users.Get(uid) 1113 expectNilErr(t, err) 1114 exf(u.ID == uid, "u.ID should be %d not %d", uid, u.ID) 1115 if shouldFail { 1116 exf(u.Group == from, "u.Group should be (from-group) %d not %d", from, u.Group) 1117 } else { 1118 exf(u.Group == to, "u.Group should be (to-group)%d not %d", to, u.Group) 1119 } 1120 1121 expectNilErr(t, c.GroupPromotions.Delete(gpid)) 1122 _, err = c.GroupPromotions.Get(gpid) 1123 recordMustNotExist(t, err, fmt.Sprintf("GP #%d should no longer exist", gpid)) 1124 } 1125 testPromo(1, 1, 2, 0, 0, 0, false) 1126 testPromo(2, 1, 2, 5, 5, 0, true) 1127 testPromo(3, 1, 2, 0, 0, 1, true) 1128 } 1129 1130 func TestReplyStore(t *testing.T) { 1131 miscinit(t) 1132 if !c.PluginsInited { 1133 c.InitPlugins() 1134 } 1135 _, e := c.Rstore.Get(-1) 1136 recordMustNotExist(t, e, "RID #-1 shouldn't exist") 1137 _, e = c.Rstore.Get(0) 1138 recordMustNotExist(t, e, "RID #0 shouldn't exist") 1139 1140 c.Config.DisablePostIP = false 1141 testReplyStore(t, 2, "::1") 1142 c.Config.DisablePostIP = true 1143 testReplyStore(t, 5, "") 1144 } 1145 1146 func testReplyStore(t *testing.T, newID int, ip string) { 1147 ex, exf := exp(t), expf(t) 1148 replyTest2 := func(r *c.Reply, e error, rid, parentID, createdBy int, content, ip string) { 1149 expectNilErr(t, e) 1150 exf(r.ID == rid, "RID #%d has the wrong ID. It should be %d not %d", rid, rid, r.ID) 1151 exf(r.ParentID == parentID, "The parent topic of RID #%d should be %d not %d", rid, parentID, r.ParentID) 1152 exf(r.CreatedBy == createdBy, "The creator of RID #%d should be %d not %d", rid, createdBy, r.CreatedBy) 1153 exf(r.Content == content, "The contents of RID #%d should be '%s' not %s", rid, content, r.Content) 1154 exf(r.IP == ip, "The IP of RID#%d should be '%s' not %s", rid, ip, r.IP) 1155 } 1156 1157 replyTest := func(rid, parentID, createdBy int, content, ip string) { 1158 r, e := c.Rstore.Get(rid) 1159 replyTest2(r, e, rid, parentID, createdBy, content, ip) 1160 r, e = c.Rstore.GetCache().Get(rid) 1161 replyTest2(r, e, rid, parentID, createdBy, content, ip) 1162 } 1163 replyTest(1, 1, 1, "A reply!", "") 1164 1165 // ! This is hard to do deterministically as the system may pre-load certain items but let's give it a try: 1166 //_, err = c.Rstore.GetCache().Get(1) 1167 //recordMustNotExist(t, err, "RID #1 shouldn't be in the cache") 1168 1169 _, err := c.Rstore.Get(newID) 1170 recordMustNotExist(t, err, "RID #2 shouldn't exist") 1171 1172 newPostCount := 1 1173 tid, err := c.Topics.Create(2, "Reply Test Topic", "Reply Test Topic", 1, "") 1174 expectNilErr(t, err) 1175 1176 topic, err := c.Topics.Get(tid) 1177 expectNilErr(t, err) 1178 exf(topic.PostCount == newPostCount, "topic.PostCount should be %d, not %d", newPostCount, topic.PostCount) 1179 exf(topic.LastReplyID == 0, "topic.LastReplyID should be %d not %d", 0, topic.LastReplyID) 1180 ex(topic.CreatedAt == topic.LastReplyAt, "topic.LastReplyAt should equal it's topic.CreatedAt") 1181 exf(topic.LastReplyBy == 1, "topic.LastReplyBy should be %d not %d", 1, topic.LastReplyBy) 1182 1183 _, err = c.Rstore.GetCache().Get(newID) 1184 recordMustNotExist(t, err, "RID #%d shouldn't be in the cache", newID) 1185 1186 time.Sleep(2 * time.Second) 1187 1188 uid, err := c.Users.Create("Reply Topic Test User"+strconv.Itoa(newID), "testpassword", "", 2, true) 1189 expectNilErr(t, err) 1190 rid, err := c.Rstore.Create(topic, "Fofofo", ip, uid) 1191 expectNilErr(t, err) 1192 exf(rid == newID, "The next reply ID should be %d not %d", newID, rid) 1193 exf(topic.PostCount == newPostCount, "The old topic in memory's post count should be %d, not %d", newPostCount+1, topic.PostCount) 1194 // TODO: Test the reply count on the topic 1195 exf(topic.LastReplyID == 0, "topic.LastReplyID should be %d not %d", 0, topic.LastReplyID) 1196 ex(topic.CreatedAt == topic.LastReplyAt, "topic.LastReplyAt should equal it's topic.CreatedAt") 1197 1198 replyTest(newID, tid, uid, "Fofofo", ip) 1199 1200 topic, err = c.Topics.Get(tid) 1201 expectNilErr(t, err) 1202 exf(topic.PostCount == newPostCount+1, "topic.PostCount should be %d, not %d", newPostCount+1, topic.PostCount) 1203 exf(topic.LastReplyID == rid, "topic.LastReplyID should be %d not %d", rid, topic.LastReplyID) 1204 ex(topic.CreatedAt != topic.LastReplyAt, "topic.LastReplyAt should not equal it's topic.CreatedAt") 1205 exf(topic.LastReplyBy == uid, "topic.LastReplyBy should be %d not %d", uid, topic.LastReplyBy) 1206 1207 expectNilErr(t, topic.CreateActionReply("destroy", ip, 1)) 1208 exf(topic.PostCount == newPostCount+1, "The old topic in memory's post count should be %d, not %d", newPostCount+1, topic.PostCount) 1209 replyTest(newID+1, tid, 1, "", ip) 1210 // TODO: Check the actionType field of the reply, this might not be loaded by TopicStore, maybe we should add it there? 1211 1212 topic, err = c.Topics.Get(tid) 1213 expectNilErr(t, err) 1214 exf(topic.PostCount == newPostCount+2, "topic.PostCount should be %d, not %d", newPostCount+2, topic.PostCount) 1215 exf(topic.LastReplyID != rid, "topic.LastReplyID should not be %d", rid) 1216 arid := topic.LastReplyID 1217 1218 // TODO: Expand upon this 1219 rid, err = c.Rstore.Create(topic, "hiii", ip, 1) 1220 expectNilErr(t, err) 1221 replyTest(rid, topic.ID, 1, "hiii", ip) 1222 1223 reply, err := c.Rstore.Get(rid) 1224 expectNilErr(t, err) 1225 expectNilErr(t, reply.SetPost("huuu")) 1226 exf(reply.Content == "hiii", "topic.Content should be hiii, not %s", reply.Content) 1227 1228 reply, err = c.Rstore.Get(rid) 1229 replyTest2(reply, err, rid, topic.ID, 1, "huuu", ip) 1230 expectNilErr(t, c.Rstore.ClearIPs()) 1231 _ = c.Rstore.GetCache().Remove(rid) 1232 replyTest(rid, topic.ID, 1, "huuu", "") 1233 1234 expectNilErr(t, reply.Delete()) 1235 // No pointer shenanigans x.x 1236 // TODO: Log reply.ID and rid in cases of pointer shenanigans? 1237 ex(reply.ID == rid, "pointer shenanigans") 1238 1239 _, err = c.Rstore.GetCache().Get(rid) 1240 recordMustNotExist(t, err, fmt.Sprintf("RID #%d shouldn't be in the cache", rid)) 1241 _, err = c.Rstore.Get(rid) 1242 recordMustNotExist(t, err, fmt.Sprintf("RID #%d shouldn't exist", rid)) 1243 1244 topic, err = c.Topics.Get(tid) 1245 expectNilErr(t, err) 1246 exf(topic.LastReplyID == arid, "topic.LastReplyID should be %d not %d", arid, topic.LastReplyID) 1247 1248 // TODO: Write a test for this 1249 //(topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUser, ogdesc string, err error) 1250 1251 // TODO: Add tests for *Reply 1252 // TODO: Add tests for ReplyCache 1253 } 1254 1255 func TestLikes(t *testing.T) { 1256 miscinit(t) 1257 if !c.PluginsInited { 1258 c.InitPlugins() 1259 } 1260 _, exf := exp(t), expf(t) 1261 bulkExists := func(iids []int, sentBy int, targetType string, expCount int) { 1262 ids, e := c.Likes.BulkExists(iids, sentBy, "replies") 1263 //recordMustNotExist(t, e, "no likes should be found") 1264 expectNilErr(t, e) 1265 exf(len(ids) == expCount, "len ids should be %d", expCount) 1266 1267 idMap := make(map[int]struct{}) 1268 for _, id := range ids { 1269 idMap[id] = struct{}{} 1270 } 1271 for _, iid := range iids { 1272 _, ok := idMap[iid] 1273 exf(ok, "missing iid %d in idMap", iid) 1274 } 1275 1276 idCount := 0 1277 expectNilErr(t, c.Likes.BulkExistsFunc(iids, sentBy, targetType, func(_ int) error { 1278 idCount++ 1279 return nil 1280 })) 1281 exf(idCount == expCount, "idCount should be %d not %d", expCount, idCount) 1282 } 1283 1284 uid := 1 1285 bulkExists([]int{}, uid, "replies", 0) 1286 1287 topic, e := c.Topics.Get(1) 1288 expectNilErr(t, e) 1289 rid, e := c.Rstore.Create(topic, "hiii", "", uid) 1290 expectNilErr(t, e) 1291 r, e := c.Rstore.Get(rid) 1292 expectNilErr(t, e) 1293 expectNilErr(t, r.Like(uid)) 1294 bulkExists([]int{rid}, uid, "replies", 1) 1295 1296 rid2, e := c.Rstore.Create(topic, "hi 2 u 2", "", uid) 1297 expectNilErr(t, e) 1298 r2, e := c.Rstore.Get(rid2) 1299 expectNilErr(t, e) 1300 expectNilErr(t, r2.Like(uid)) 1301 bulkExists([]int{rid, rid2}, uid, "replies", 2) 1302 1303 expectNilErr(t, r.Unlike(uid)) 1304 bulkExists([]int{rid2}, uid, "replies", 1) 1305 expectNilErr(t, r2.Unlike(uid)) 1306 bulkExists([]int{}, uid, "replies", 0) 1307 1308 //BulkExists(ids []int, sentBy int, targetType string) (eids []int, err error) 1309 1310 expectNilErr(t, topic.Like(1, uid)) 1311 expectNilErr(t, topic.Unlike(uid)) 1312 } 1313 1314 func TestAttachments(t *testing.T) { 1315 miscinit(t) 1316 if !c.PluginsInited { 1317 c.InitPlugins() 1318 } 1319 ex, exf := exp(t), expf(t) 1320 1321 filename := "n0-48.png" 1322 srcFile := "./test_data/" + filename 1323 destFile := "./attachs/" + filename 1324 1325 ft := func(e error) { 1326 if e != nil && e != sql.ErrNoRows { 1327 t.Error(e) 1328 } 1329 } 1330 1331 ex(c.Attachments.Count() == 0, "the number of attachments should be 0") 1332 ex(c.Attachments.CountIn("topics", 1) == 0, "the number of attachments in topic 1 should be 0") 1333 exf(c.Attachments.CountInPath(filename) == 0, "the number of attachments with path '%s' should be 0", filename) 1334 _, e := c.Attachments.FGet(1) 1335 ft(e) 1336 ex(e == sql.ErrNoRows, ".FGet should have no results") 1337 _, e = c.Attachments.Get(1) 1338 ft(e) 1339 ex(e == sql.ErrNoRows, ".Get should have no results") 1340 _, e = c.Attachments.MiniGetList("topics", 1) 1341 ft(e) 1342 ex(e == sql.ErrNoRows, ".MiniGetList should have no results") 1343 _, e = c.Attachments.BulkMiniGetList("topics", []int{1}) 1344 ft(e) 1345 ex(e == sql.ErrNoRows, ".BulkMiniGetList should have no results") 1346 1347 simUpload := func() { 1348 // Sim an upload, try a proper upload through the proper pathway later on 1349 _, e = os.Stat(destFile) 1350 if e != nil && !os.IsNotExist(e) { 1351 expectNilErr(t, e) 1352 } else if e == nil { 1353 expectNilErr(t, os.Remove(destFile)) 1354 } 1355 1356 input, e := ioutil.ReadFile(srcFile) 1357 expectNilErr(t, e) 1358 expectNilErr(t, ioutil.WriteFile(destFile, input, 0644)) 1359 } 1360 simUpload() 1361 1362 tid, e := c.Topics.Create(2, "Attach Test", "Filler Body", 1, "") 1363 expectNilErr(t, e) 1364 aid, e := c.Attachments.Add(2, "forums", tid, "topics", 1, filename, "") 1365 expectNilErr(t, e) 1366 exf(aid == 1, "aid should be 1 not %d", aid) 1367 expectNilErr(t, c.Attachments.AddLinked("topics", tid)) 1368 ex(c.Attachments.Count() == 1, "the number of attachments should be 1") 1369 exf(c.Attachments.CountIn("topics", tid) == 1, "the number of attachments in topic %d should be 1", tid) 1370 exf(c.Attachments.CountInPath(filename) == 1, "the number of attachments with path '%s' should be 1", filename) 1371 1372 et := func(a *c.MiniAttachment, aid, sid, oid, uploadedBy int, path, extra, ext string) { 1373 exf(a.ID == aid, "ID should be %d not %d", aid, a.ID) 1374 exf(a.SectionID == sid, "SectionID should be %d not %d", sid, a.SectionID) 1375 exf(a.OriginID == oid, "OriginID should be %d not %d", oid, a.OriginID) 1376 exf(a.UploadedBy == uploadedBy, "UploadedBy should be %d not %d", uploadedBy, a.UploadedBy) 1377 exf(a.Path == path, "Path should be %s not %s", path, a.Path) 1378 exf(a.Extra == extra, "Extra should be %s not %s", extra, a.Extra) 1379 ex(a.Image, "Image should be true") 1380 exf(a.Ext == ext, "Ext should be %s not %s", ext, a.Ext) 1381 } 1382 et2 := func(a *c.Attachment, aid, sid, oid, uploadedBy int, path, extra, ext string) { 1383 exf(a.ID == aid, "ID should be %d not %d", aid, a.ID) 1384 exf(a.SectionID == sid, "SectionID should be %d not %d", sid, a.SectionID) 1385 exf(a.OriginID == oid, "OriginID should be %d not %d", oid, a.OriginID) 1386 exf(a.UploadedBy == uploadedBy, "UploadedBy should be %d not %d", uploadedBy, a.UploadedBy) 1387 exf(a.Path == path, "Path should be %s not %s", path, a.Path) 1388 exf(a.Extra == extra, "Extra should be %s not %s", extra, a.Extra) 1389 ex(a.Image, "Image should be true") 1390 exf(a.Ext == ext, "Ext should be %s not %s", ext, a.Ext) 1391 } 1392 1393 f2 := func(aid, sid, oid int, extra string, topic bool) { 1394 var tbl string 1395 if topic { 1396 tbl = "topics" 1397 } else { 1398 tbl = "replies" 1399 } 1400 fa, e := c.Attachments.FGet(aid) 1401 expectNilErr(t, e) 1402 et2(fa, aid, sid, oid, 1, filename, extra, "png") 1403 1404 a, e := c.Attachments.Get(aid) 1405 expectNilErr(t, e) 1406 et(a, aid, sid, oid, 1, filename, extra, "png") 1407 1408 alist, e := c.Attachments.MiniGetList(tbl, oid) 1409 expectNilErr(t, e) 1410 exf(len(alist) == 1, "len(alist) should be 1 not %d", len(alist)) 1411 a = alist[0] 1412 et(a, aid, sid, oid, 1, filename, extra, "png") 1413 1414 amap, e := c.Attachments.BulkMiniGetList(tbl, []int{oid}) 1415 expectNilErr(t, e) 1416 exf(len(amap) == 1, "len(amap) should be 1 not %d", len(amap)) 1417 alist, ok := amap[oid] 1418 if !ok { 1419 t.Logf("key %d not found in amap", oid) 1420 } 1421 exf(len(alist) == 1, "len(alist) should be 1 not %d", len(alist)) 1422 a = alist[0] 1423 et(a, aid, sid, oid, 1, filename, extra, "png") 1424 } 1425 1426 topic, e := c.Topics.Get(tid) 1427 expectNilErr(t, e) 1428 exf(topic.AttachCount == 1, "topic.AttachCount should be 1 not %d", topic.AttachCount) 1429 f2(aid, 2, tid, "", true) 1430 expectNilErr(t, topic.MoveTo(1)) 1431 f2(aid, 1, tid, "", true) 1432 expectNilErr(t, c.Attachments.MoveTo(2, tid, "topics")) 1433 f2(aid, 2, tid, "", true) 1434 1435 // TODO: ShowAttachment test 1436 1437 deleteTest := func(aid, oid int, topic bool) { 1438 var tbl string 1439 if topic { 1440 tbl = "topics" 1441 } else { 1442 tbl = "replies" 1443 } 1444 //expectNilErr(t, c.Attachments.Delete(aid)) 1445 expectNilErr(t, c.DeleteAttachment(aid)) 1446 ex(c.Attachments.Count() == 0, "the number of attachments should be 0") 1447 exf(c.Attachments.CountIn(tbl, oid) == 0, "the number of attachments in topic %d should be 0", tid) 1448 exf(c.Attachments.CountInPath(filename) == 0, "the number of attachments with path '%s' should be 0", filename) 1449 _, e = c.Attachments.FGet(aid) 1450 ft(e) 1451 ex(e == sql.ErrNoRows, ".FGet should have no results") 1452 _, e = c.Attachments.Get(aid) 1453 ft(e) 1454 ex(e == sql.ErrNoRows, ".Get should have no results") 1455 _, e = c.Attachments.MiniGetList(tbl, oid) 1456 ft(e) 1457 ex(e == sql.ErrNoRows, ".MiniGetList should have no results") 1458 _, e = c.Attachments.BulkMiniGetList(tbl, []int{oid}) 1459 ft(e) 1460 ex(e == sql.ErrNoRows, ".BulkMiniGetList should have no results") 1461 } 1462 deleteTest(aid, tid, true) 1463 topic, e = c.Topics.Get(tid) 1464 expectNilErr(t, e) 1465 exf(topic.AttachCount == 0, "topic.AttachCount should be 0 not %d", topic.AttachCount) 1466 1467 simUpload() 1468 rid, e := c.Rstore.Create(topic, "Reply Filler", "", 1) 1469 expectNilErr(t, e) 1470 aid, e = c.Attachments.Add(2, "forums", rid, "replies", 1, filename, strconv.Itoa(topic.ID)) 1471 expectNilErr(t, e) 1472 exf(aid == 2, "aid should be 2 not %d", aid) 1473 expectNilErr(t, c.Attachments.AddLinked("replies", rid)) 1474 r, e := c.Rstore.Get(rid) 1475 expectNilErr(t, e) 1476 exf(r.AttachCount == 1, "r.AttachCount should be 1 not %d", r.AttachCount) 1477 f2(aid, 2, rid, strconv.Itoa(topic.ID), false) 1478 expectNilErr(t, c.Attachments.MoveTo(1, rid, "replies")) 1479 f2(aid, 1, rid, strconv.Itoa(topic.ID), false) 1480 deleteTest(aid, rid, false) 1481 r, e = c.Rstore.Get(rid) 1482 expectNilErr(t, e) 1483 exf(r.AttachCount == 0, "r.AttachCount should be 0 not %d", r.AttachCount) 1484 1485 // TODO: Path overlap tests 1486 } 1487 1488 func TestPolls(t *testing.T) { 1489 miscinit(t) 1490 if !c.PluginsInited { 1491 c.InitPlugins() 1492 } 1493 ex, exf := exp(t), expf(t) 1494 1495 shouldNotExist := func(id int) { 1496 exf(!c.Polls.Exists(id), "poll %d should not exist", id) 1497 _, e := c.Polls.Get(id) 1498 recordMustNotExist(t, e, fmt.Sprintf("poll %d shouldn't exist", id)) 1499 } 1500 shouldNotExist(-1) 1501 shouldNotExist(0) 1502 shouldNotExist(1) 1503 exf(c.Polls.Count() == 0, "count should be %d not %d", 0, c.Polls.Count()) 1504 1505 tid, e := c.Topics.Create(2, "Poll Test", "Filler Body", 1, "") 1506 expectNilErr(t, e) 1507 topic, e := c.Topics.Get(tid) 1508 expectNilErr(t, e) 1509 exf(topic.Poll == 0, "t.Poll should be %d not %d", 0, topic.Poll) 1510 /*Options map[int]string 1511 Results map[int]int // map[optionIndex]points 1512 QuickOptions []PollOption // TODO: Fix up the template transpiler so we don't need to use this hack anymore 1513 }*/ 1514 pollType := 0 // Basic single choice 1515 pid, e := c.Polls.Create(topic, pollType, map[int]string{0: "item 1", 1: "item 2", 2: "item 3"}) 1516 expectNilErr(t, e) 1517 exf(pid == 1, "poll id should be 1 not %d", pid) 1518 ex(c.Polls.Exists(1), "poll 1 should exist") 1519 exf(c.Polls.Count() == 1, "count should be %d not %d", 1, c.Polls.Count()) 1520 topic, e = c.Topics.BypassGet(tid) 1521 expectNilErr(t, e) 1522 exf(topic.Poll == pid, "t.Poll should be %d not %d", pid, topic.Poll) 1523 1524 testPoll := func(p *c.Poll, id, parentID int, parentTable string, ptype int, antiCheat bool, voteCount int) { 1525 ef := exf 1526 ef(p.ID == id, "p.ID should be %d not %d", id, p.ID) 1527 ef(p.ParentID == parentID, "p.ParentID should be %d not %d", parentID, p.ParentID) 1528 ef(p.ParentTable == parentTable, "p.ParentID should be %s not %s", parentTable, p.ParentTable) 1529 ef(p.Type == ptype, "p.ParentID should be %d not %d", ptype, p.Type) 1530 s := "false" 1531 if p.AntiCheat { 1532 s = "true" 1533 } 1534 ef(p.AntiCheat == antiCheat, "p.AntiCheat should be ", s) 1535 // TODO: More fields 1536 ef(p.VoteCount == voteCount, "p.VoteCount should be %d not %d", voteCount, p.VoteCount) 1537 } 1538 1539 p, e := c.Polls.Get(1) 1540 expectNilErr(t, e) 1541 testPoll(p, 1, tid, "topics", 0, false, 0) 1542 1543 expectNilErr(t, p.CastVote(0, 1, "")) 1544 expectNilErr(t, c.Polls.Reload(p.ID)) 1545 p, e = c.Polls.Get(1) 1546 expectNilErr(t, e) 1547 testPoll(p, 1, tid, "topics", 0, false, 1) 1548 1549 var vslice []int 1550 expectNilErr(t, p.Resultsf(func(votes int) error { 1551 vslice = append(vslice, votes) 1552 return nil 1553 })) 1554 //fmt.Printf("vslice: %+v\n", vslice) 1555 exf(vslice[0] == 1, "vslice[0] should be %d not %d", 0, vslice[0]) 1556 exf(vslice[1] == 0, "vslice[1] should be %d not %d", 1, vslice[1]) 1557 exf(vslice[2] == 0, "vslice[2] should be %d not %d", 0, vslice[2]) 1558 1559 expectNilErr(t, p.CastVote(2, 1, "")) 1560 expectNilErr(t, c.Polls.Reload(p.ID)) 1561 p, e = c.Polls.Get(1) 1562 expectNilErr(t, e) 1563 testPoll(p, 1, tid, "topics", 0, false, 2) 1564 1565 vslice = nil 1566 expectNilErr(t, p.Resultsf(func(votes int) error { 1567 vslice = append(vslice, votes) 1568 return nil 1569 })) 1570 //fmt.Printf("vslice: %+v\n", vslice) 1571 exf(vslice[0] == 1, "vslice[0] should be %d not %d", 1, vslice[0]) 1572 exf(vslice[1] == 0, "vslice[1] should be %d not %d", 0, vslice[1]) 1573 exf(vslice[2] == 1, "vslice[2] should be %d not %d", 1, vslice[2]) 1574 1575 expectNilErr(t, c.Polls.ClearIPs()) 1576 // TODO: Test to see if it worked 1577 1578 expectNilErr(t, p.Delete()) 1579 ex(!c.Polls.Exists(1), "poll 1 should no longer exist") 1580 _, e = c.Polls.Get(1) 1581 recordMustNotExist(t, e, "poll 1 should no longer exist") 1582 exf(c.Polls.Count() == 0, "count should be %d not %d", 0, c.Polls.Count()) 1583 topic, e = c.Topics.BypassGet(tid) 1584 expectNilErr(t, e) 1585 exf(topic.Poll == pid, "t.Poll should be %d not %d", pid, topic.Poll) 1586 1587 expectNilErr(t, topic.SetPoll(999)) 1588 topic, e = c.Topics.BypassGet(tid) 1589 expectNilErr(t, e) 1590 exf(topic.Poll == pid, "t.Poll should be %d not %d", pid, topic.Poll) 1591 1592 expectNilErr(t, topic.SetPoll(0)) 1593 topic, e = c.Topics.BypassGet(tid) 1594 expectNilErr(t, e) 1595 exf(topic.Poll == pid, "t.Poll should be %d not %d", pid, topic.Poll) 1596 1597 expectNilErr(t, topic.RemovePoll()) 1598 topic, e = c.Topics.BypassGet(tid) 1599 expectNilErr(t, e) 1600 exf(topic.Poll == 0, "t.Poll should be %d not %d", 0, topic.Poll) 1601 } 1602 1603 func TestSearch(t *testing.T) { 1604 miscinit(t) 1605 if !c.PluginsInited { 1606 c.InitPlugins() 1607 } 1608 exf := expf(t) 1609 1610 title := "search" 1611 body := "bab bab bab bab" 1612 q := "search" 1613 tid, e := c.Topics.Create(2, title, body, 1, "") 1614 expectNilErr(t, e) 1615 1616 tids, e := c.RepliesSearch.Query(q, []int{2}) 1617 //fmt.Printf("tids: %+v\n", tids) 1618 expectNilErr(t, e) 1619 exf(len(tids) == 1, "len(tids) should be 1 not %d", len(tids)) 1620 1621 topic, e := c.Topics.Get(tids[0]) 1622 expectNilErr(t, e) 1623 exf(topic.ID == tid, "topic.ID should be %d not %d", tid, topic.ID) 1624 exf(topic.Title == title, "topic.Title should be %s not %s", title, topic.Title) 1625 1626 tids, e = c.RepliesSearch.Query(q, []int{1, 2}) 1627 //fmt.Printf("tids: %+v\n", tids) 1628 expectNilErr(t, e) 1629 exf(len(tids) == 1, "len(tids) should be 1 not %d", len(tids)) 1630 1631 q = "bab" 1632 tids, e = c.RepliesSearch.Query(q, []int{1, 2}) 1633 //fmt.Printf("tids: %+v\n", tids) 1634 expectNilErr(t, e) 1635 exf(len(tids) == 1, "len(tids) should be 1 not %d", len(tids)) 1636 } 1637 1638 func TestProfileReplyStore(t *testing.T) { 1639 miscinit(t) 1640 if !c.PluginsInited { 1641 c.InitPlugins() 1642 } 1643 1644 _, e := c.Prstore.Get(-1) 1645 recordMustNotExist(t, e, "PRID #-1 shouldn't exist") 1646 _, e = c.Prstore.Get(0) 1647 recordMustNotExist(t, e, "PRID #0 shouldn't exist") 1648 _, e = c.Prstore.Get(1) 1649 recordMustNotExist(t, e, "PRID #1 shouldn't exist") 1650 1651 c.Config.DisablePostIP = false 1652 testProfileReplyStore(t, 1, "::1") 1653 c.Config.DisablePostIP = true 1654 testProfileReplyStore(t, 2, "") 1655 } 1656 func testProfileReplyStore(t *testing.T, newID int, ip string) { 1657 exf := expf(t) 1658 // ? - Commented this one out as strong constraints like this put an unreasonable load on the database, we only want errors if a delete which should succeed fails 1659 //profileReply := c.BlankProfileReply(1) 1660 //e = profileReply.Delete() 1661 //expect(t,e != nil,"You shouldn't be able to delete profile replies which don't exist") 1662 1663 profileID := 1 1664 prid, e := c.Prstore.Create(profileID, "Haha", 1, ip) 1665 expectNilErr(t, e) 1666 exf(prid == newID, "The first profile reply should have an ID of %d", newID) 1667 1668 pr, e := c.Prstore.Get(newID) 1669 expectNilErr(t, e) 1670 exf(pr.ID == newID, "The profile reply should have an ID of %d not %d", newID, pr.ID) 1671 exf(pr.ParentID == 1, "The parent ID of the profile reply should be 1 not %d", pr.ParentID) 1672 exf(pr.Content == "Haha", "The profile reply's contents should be 'Haha' not '%s'", pr.Content) 1673 exf(pr.CreatedBy == 1, "The profile reply's creator should be 1 not %d", pr.CreatedBy) 1674 exf(pr.IP == ip, "The profile reply's IP should be '%s' not '%s'", ip, pr.IP) 1675 1676 expectNilErr(t, c.Prstore.ClearIPs()) 1677 1678 pr, e = c.Prstore.Get(newID) 1679 expectNilErr(t, e) 1680 exf(pr.ID == newID, "The profile reply should have an ID of %d not %d", newID, pr.ID) 1681 exf(pr.ParentID == 1, "The parent ID of the profile reply should be 1 not %d", pr.ParentID) 1682 exf(pr.Content == "Haha", "The profile reply's contents should be 'Haha' not '%s'", pr.Content) 1683 exf(pr.CreatedBy == 1, "The profile reply's creator should be 1 not %d", pr.CreatedBy) 1684 ip = "" 1685 exf(pr.IP == ip, "The profile reply's IP should be '%s' not '%s'", ip, pr.IP) 1686 1687 expectNilErr(t, pr.Delete()) 1688 _, e = c.Prstore.Get(newID) 1689 exf(e != nil, "PRID #%d shouldn't exist after being deleted", newID) 1690 1691 // TODO: Test pr.SetBody() and pr.Creator() 1692 } 1693 1694 func TestConvos(t *testing.T) { 1695 miscinit(t) 1696 if !c.PluginsInited { 1697 c.InitPlugins() 1698 } 1699 ex, exf := exp(t), expf(t) 1700 1701 sf := func(i interface{}, e error) error { 1702 return e 1703 } 1704 mf := func(e error, msg string, exists bool) { 1705 if !exists { 1706 recordMustNotExist(t, e, msg) 1707 } else { 1708 recordMustExist(t, e, msg) 1709 } 1710 } 1711 gu := func(uid, offset int, exists bool) { 1712 s := "" 1713 if !exists { 1714 s = " not" 1715 } 1716 mf(sf(c.Convos.GetUser(uid, offset)), fmt.Sprintf("convo getuser %d %d should%s exist", uid, offset, s), exists) 1717 } 1718 gue := func(uid, offset int, exists bool) { 1719 s := "" 1720 if !exists { 1721 s = " not" 1722 } 1723 mf(sf(c.Convos.GetUserExtra(uid, offset)), fmt.Sprintf("convo getuserextra %d %d should%s exist", uid, offset, s), exists) 1724 } 1725 1726 ex(c.Convos.GetUserCount(-1) == 0, "getusercount should be 0") 1727 ex(c.Convos.GetUserCount(0) == 0, "getusercount should be 0") 1728 mf(sf(c.Convos.Get(-1)), "convo -1 should not exist", false) 1729 mf(sf(c.Convos.Get(0)), "convo 0 should not exist", false) 1730 gu(-1, -1, false) 1731 gu(-1, 0, false) 1732 gu(0, 0, false) 1733 gue(-1, -1, false) 1734 gue(-1, 0, false) 1735 gue(0, 0, false) 1736 1737 nf := func(cid, count int) { 1738 ex := count > 0 1739 s := "" 1740 if !ex { 1741 s = " not" 1742 } 1743 mf(sf(c.Convos.Get(cid)), fmt.Sprintf("convo %d should%s exist", cid, s), ex) 1744 gu(1, 0, ex) 1745 gu(1, 5, false) // invariant may change in future tests 1746 1747 exf(c.Convos.GetUserCount(1) == count, "getusercount should be %d", count) 1748 gue(1, 0, ex) 1749 gue(1, 5, false) // invariant may change in future tests 1750 exf(c.Convos.Count() == count, "convos count should be %d", count) 1751 } 1752 nf(1, 0) 1753 1754 awaitingActivation := 5 1755 uid, err := c.Users.Create("Saturn", "ReallyBadPassword", "", awaitingActivation, false) 1756 expectNilErr(t, err) 1757 1758 cid, err := c.Convos.Create("hehe", 1, []int{uid}) 1759 expectNilErr(t, err) 1760 ex(cid == 1, "cid should be 1") 1761 ex(c.Convos.Count() == 1, "convos count should be 1") 1762 1763 co, err := c.Convos.Get(cid) 1764 expectNilErr(t, err) 1765 ex(co.ID == 1, "co.ID should be 1") 1766 ex(co.CreatedBy == 1, "co.CreatedBy should be 1") 1767 // TODO: CreatedAt test 1768 ex(co.LastReplyBy == 1, "co.LastReplyBy should be 1") 1769 // TODO: LastReplyAt test 1770 expectIntToBeX(t, co.PostsCount(), 1, "postscount should be 1, not %d") 1771 ex(co.Has(uid), "saturn should be in the conversation") 1772 ex(!co.Has(9999), "uid 9999 should not be in the conversation") 1773 uids, err := co.Uids() 1774 expectNilErr(t, err) 1775 expectIntToBeX(t, len(uids), 2, "uids length should be 2, not %d") 1776 exf(uids[0] == uid, "uids[0] should be %d, not %d", uid, uids[0]) 1777 exf(uids[1] == 1, "uids[1] should be %d, not %d", 1, uids[1]) 1778 nf(cid, 1) 1779 1780 expectNilErr(t, c.Convos.Delete(cid)) 1781 expectIntToBeX(t, co.PostsCount(), 0, "postscount should be 0, not %d") 1782 ex(!co.Has(uid), "saturn should not be in a deleted conversation") 1783 uids, err = co.Uids() 1784 expectNilErr(t, err) 1785 expectIntToBeX(t, len(uids), 0, "uids length should be 0, not %d") 1786 nf(cid, 0) 1787 1788 // TODO: More tests 1789 1790 // Block tests 1791 1792 ok, err := c.UserBlocks.IsBlockedBy(1, 1) 1793 expectNilErr(t, err) 1794 ex(!ok, "there shouldn't be any blocks") 1795 ok, err = c.UserBlocks.BulkIsBlockedBy([]int{1}, 1) 1796 expectNilErr(t, err) 1797 ex(!ok, "there shouldn't be any blocks") 1798 bf := func(blocker, offset, perPage, expectLen, blockee int) { 1799 l, err := c.UserBlocks.BlockedByOffset(blocker, offset, perPage) 1800 expectNilErr(t, err) 1801 exf(len(l) == expectLen, "there should be %d users blocked by %d not %d", expectLen, blocker, len(l)) 1802 if len(l) > 0 { 1803 exf(l[0] == blockee, "blocked uid should be %d not %d", blockee, l[0]) 1804 } 1805 } 1806 nbf := func(blocker, blockee int) { 1807 ok, err := c.UserBlocks.IsBlockedBy(1, 2) 1808 expectNilErr(t, err) 1809 ex(!ok, "there shouldn't be any blocks") 1810 ok, err = c.UserBlocks.BulkIsBlockedBy([]int{1}, 2) 1811 expectNilErr(t, err) 1812 ex(!ok, "there shouldn't be any blocks") 1813 expectIntToBeX(t, c.UserBlocks.BlockedByCount(1), 0, "blockedbycount for 1 should be 1, not %d") 1814 bf(1, 0, 1, 0, 0) 1815 bf(1, 0, 15, 0, 0) 1816 bf(1, 1, 15, 0, 0) 1817 bf(1, 5, 15, 0, 0) 1818 } 1819 nbf(1, 2) 1820 1821 expectNilErr(t, c.UserBlocks.Add(1, 2)) 1822 ok, err = c.UserBlocks.IsBlockedBy(1, 2) 1823 expectNilErr(t, err) 1824 ex(ok, "2 should be blocked by 1") 1825 expectIntToBeX(t, c.UserBlocks.BlockedByCount(1), 1, "blockedbycount for 1 should be 1, not %d") 1826 bf(1, 0, 1, 1, 2) 1827 bf(1, 0, 15, 1, 2) 1828 bf(1, 1, 15, 0, 0) 1829 bf(1, 5, 15, 0, 0) 1830 1831 // Double add test 1832 expectNilErr(t, c.UserBlocks.Add(1, 2)) 1833 ok, err = c.UserBlocks.IsBlockedBy(1, 2) 1834 expectNilErr(t, err) 1835 ex(ok, "2 should be blocked by 1") 1836 //expectIntToBeX(t, c.UserBlocks.BlockedByCount(1), 1, "blockedbycount for 1 should be 1, not %d") // todo: fix this 1837 //bf(1, 0, 1, 1, 2) // todo: fix this 1838 //bf(1, 0, 15, 1, 2) // todo: fix this 1839 //bf(1, 1, 15, 0, 0) // todo: fix this 1840 bf(1, 5, 15, 0, 0) 1841 1842 expectNilErr(t, c.UserBlocks.Remove(1, 2)) 1843 nbf(1, 2) 1844 // Double remove test 1845 expectNilErr(t, c.UserBlocks.Remove(1, 2)) 1846 nbf(1, 2) 1847 1848 // TODO: Self-block test 1849 1850 // TODO: More Block tests 1851 } 1852 1853 func TestActivityStream(t *testing.T) { 1854 miscinit(t) 1855 ex, exf := exp(t), expf(t) 1856 1857 ex(c.Activity.Count() == 0, "activity stream count should be 0") 1858 gNone := func(id int) { 1859 _, e := c.Activity.Get(id) 1860 recordMustNotExist(t, e, "activity item "+strconv.Itoa(id)+" shouldn't exist") 1861 } 1862 gNone(-1) 1863 gNone(0) 1864 gNone(1) 1865 countAsid := func(asid, count int) { 1866 exf(c.ActivityMatches.CountAsid(asid) == count, "activity stream matches count for asid %d should be %d not %d", asid, count, c.ActivityMatches.CountAsid(asid)) 1867 } 1868 countAsid(-1, 0) 1869 countAsid(0, 0) 1870 countAsid(1, 0) 1871 1872 a := c.Alert{ActorID: 1, TargetUserID: 1, Event: "like", ElementType: "topic", ElementID: 1} 1873 id, e := c.Activity.Add(a) 1874 expectNilErr(t, e) 1875 ex(id == 1, "new activity item id should be 1") 1876 1877 ex(c.Activity.Count() == 1, "activity stream count should be 1") 1878 al, e := c.Activity.Get(1) 1879 expectNilErr(t, e) 1880 exf(al.ASID == id, "alert asid should be %d not %d", id, al.ASID) 1881 ex(al.ActorID == 1, "alert actorid should be 1") 1882 ex(al.TargetUserID == 1, "alert targetuserid should be 1") 1883 ex(al.Event == "like", "alert event type should be like") 1884 ex(al.ElementType == "topic", "alert element type should be topic") 1885 ex(al.ElementID == 1, "alert element id should be 1") 1886 1887 countAsid(id, 0) 1888 1889 tuid, e := c.Users.Create("Activity Target", "Activity Target", "", 1, true) 1890 expectNilErr(t, e) 1891 expectNilErr(t, c.ActivityMatches.Add(tuid, 1)) 1892 countAsid(id, 1) 1893 expectNilErr(t, c.ActivityMatches.Delete(tuid, id)) 1894 countAsid(id, 0) 1895 1896 expectNilErr(t, c.ActivityMatches.Add(tuid, 1)) 1897 countAsid(id, 1) 1898 changed, e := c.ActivityMatches.DeleteAndCountChanged(tuid, id) 1899 expectNilErr(t, e) 1900 exf(changed == 1, "changed should be %d not %d", 1, changed) 1901 countAsid(id, 0) 1902 1903 expectNilErr(t, c.ActivityMatches.Add(tuid, 1)) 1904 countAsid(id, 1) 1905 1906 // TODO: Add more tests 1907 1908 expectNilErr(t, c.Activity.Delete(id)) 1909 ex(c.Activity.Count() == 0, "activity stream count should be 0") 1910 gNone(id) 1911 countAsid(id, 0) 1912 1913 // TODO: More tests 1914 } 1915 1916 func TestLogs(t *testing.T) { 1917 ex, exf := exp(t), expf(t) 1918 miscinit(t) 1919 gTests := func(s c.LogStore, phrase string) { 1920 ex(s.Count() == 0, "There shouldn't be any "+phrase) 1921 logs, err := s.GetOffset(0, 25) 1922 expectNilErr(t, err) 1923 ex(len(logs) == 0, "The log slice should be empty") 1924 } 1925 gTests(c.ModLogs, "modlogs") 1926 gTests(c.AdminLogs, "adminlogs") 1927 1928 gTests2 := func(s c.LogStore, phrase string) { 1929 err := s.Create("something", 0, "bumblefly", "::1", 1) 1930 expectNilErr(t, err) 1931 count := s.Count() 1932 exf(count == 1, "store.Count should return one, not %d", count) 1933 logs, err := s.GetOffset(0, 25) 1934 recordMustExist(t, err, "We should have at-least one "+phrase) 1935 ex(len(logs) == 1, "The length of the log slice should be one") 1936 1937 l := logs[0] 1938 ex(l.Action == "something", "l.Action is not something") 1939 ex(l.ElementID == 0, "l.ElementID is not 0") 1940 ex(l.ElementType == "bumblefly", "l.ElementType is not bumblefly") 1941 ex(l.IP == "::1", "l.IP is not ::1") 1942 ex(l.ActorID == 1, "l.ActorID is not 1") 1943 // TODO: Add a test for log.DoneAt? Maybe throw in some dates and times which are clearly impossible but which may occur due to timezone bugs? 1944 } 1945 gTests2(c.ModLogs, "modlog") 1946 gTests2(c.AdminLogs, "adminlog") 1947 } 1948 1949 func TestRegLogs(t *testing.T) { 1950 miscinit(t) 1951 if !c.PluginsInited { 1952 c.InitPlugins() 1953 } 1954 exf := expf(t) 1955 1956 mustNone := func() { 1957 exf(c.RegLogs.Count() == 0, "count should be %d not %d", 0, c.RegLogs.Count()) 1958 items, e := c.RegLogs.GetOffset(0, 10) 1959 expectNilErr(t, e) 1960 exf(len(items) == 0, "len(items) should be %d not %d", 0, len(items)) 1961 expectNilErr(t, c.RegLogs.Purge()) 1962 exf(c.RegLogs.Count() == 0, "count should be %d not %d", 0, c.RegLogs.Count()) 1963 items, e = c.RegLogs.GetOffset(0, 10) 1964 expectNilErr(t, e) 1965 exf(len(items) == 0, "len(items) should be %d not %d", 0, len(items)) 1966 } 1967 mustNone() 1968 1969 regLog := &c.RegLogItem{Username: "Aa", Email: "aa@example.com", FailureReason: "fake", Success: false, IP: ""} 1970 id, e := regLog.Create() 1971 exf(id == 1, "id should be %d not %d", 1, id) 1972 expectNilErr(t, e) 1973 1974 exf(c.RegLogs.Count() == 1, "count should be %d not %d", 1, c.RegLogs.Count()) 1975 items, e := c.RegLogs.GetOffset(0, 10) 1976 expectNilErr(t, e) 1977 exf(len(items) == 1, "len(items) should be %d not %d", 1, len(items)) 1978 // TODO: Add more tests 1979 1980 expectNilErr(t, c.RegLogs.DeleteOlderThanDays(2)) 1981 1982 exf(c.RegLogs.Count() == 1, "count should be %d not %d", 1, c.RegLogs.Count()) 1983 items, e = c.RegLogs.GetOffset(0, 10) 1984 expectNilErr(t, e) 1985 exf(len(items) == 1, "len(items) should be %d not %d", 1, len(items)) 1986 // TODO: Add more tests 1987 1988 // TODO: Commit() test? 1989 dayAgo := time.Now().AddDate(0, 0, -5) 1990 items[0].DoneAt = dayAgo.Format("2006-01-02 15:04:05") 1991 expectNilErr(t, items[0].Commit()) 1992 1993 exf(c.RegLogs.Count() == 1, "count should be %d not %d", 1, c.RegLogs.Count()) 1994 items, e = c.RegLogs.GetOffset(0, 10) 1995 expectNilErr(t, e) 1996 exf(len(items) == 1, "len(items) should be %d not %d", 1, len(items)) 1997 // TODO: Add more tests 1998 1999 expectNilErr(t, c.RegLogs.DeleteOlderThanDays(2)) 2000 mustNone() 2001 2002 regLog = &c.RegLogItem{Username: "Aa", Email: "aa@example.com", FailureReason: "fake", Success: false, IP: ""} 2003 id, e = regLog.Create() 2004 exf(id == 2, "id should be %d not %d", 2, id) 2005 expectNilErr(t, e) 2006 2007 exf(c.RegLogs.Count() == 1, "count should be %d not %d", 1, c.RegLogs.Count()) 2008 items, e = c.RegLogs.GetOffset(0, 10) 2009 expectNilErr(t, e) 2010 exf(len(items) == 1, "len(items) should be %d not %d", 1, len(items)) 2011 // TODO: Add more tests 2012 2013 expectNilErr(t, c.RegLogs.Purge()) 2014 mustNone() 2015 2016 // TODO: Add more tests 2017 } 2018 2019 func TestLoginLogs(t *testing.T) { 2020 miscinit(t) 2021 if !c.PluginsInited { 2022 c.InitPlugins() 2023 } 2024 ex, exf := exp(t), expf(t) 2025 uid, e := c.Users.Create("Log Test", "Log Test", "", 1, true) 2026 expectNilErr(t, e) 2027 2028 exf(c.LoginLogs.CountUser(-1) == 0, "countuser(-1) should be %d not %d", 0, c.LoginLogs.CountUser(-1)) 2029 exf(c.LoginLogs.CountUser(0) == 0, "countuser(0) should be %d not %d", 0, c.LoginLogs.CountUser(0)) 2030 exf(c.LoginLogs.CountUser(1) == 0, "countuser(1) should be %d not %d", 0, c.LoginLogs.CountUser(1)) 2031 goNone := func(uid, offset, perPage int) { 2032 items, e := c.LoginLogs.GetOffset(uid, offset, perPage) 2033 expectNilErr(t, e) 2034 exf(len(items) == 0, "len(items) should be %d not %d", 0, len(items)) 2035 } 2036 goNone(-1, 0, 10) 2037 goNone(0, 0, 10) 2038 goNone(1, 0, 10) 2039 goNone(1, 1, 10) 2040 goNone(1, 0, 0) 2041 2042 mustNone := func() { 2043 exf(c.LoginLogs.Count() == 0, "count should be %d not %d", 0, c.LoginLogs.Count()) 2044 exf(c.LoginLogs.CountUser(uid) == 0, "countuser(%d) should be %d not %d", uid, 0, c.LoginLogs.CountUser(uid)) 2045 goNone(uid, 0, 10) 2046 goNone(uid, 1, 10) 2047 goNone(uid, 0, 0) 2048 } 2049 mustNone() 2050 2051 logItem := &c.LoginLogItem{UID: uid, Success: true, IP: ""} 2052 _, e = logItem.Create() 2053 expectNilErr(t, e) 2054 2055 exf(c.LoginLogs.Count() == 1, "count should be %d not %d", 1, c.LoginLogs.Count()) 2056 exf(c.LoginLogs.CountUser(uid) == 1, "countuser(%d) should be %d not %d", uid, 1, c.LoginLogs.CountUser(uid)) 2057 items, e := c.LoginLogs.GetOffset(uid, 0, 10) 2058 expectNilErr(t, e) 2059 exf(len(items) == 1, "len(items) should be %d not %d", 1, len(items)) 2060 // TODO: More tests 2061 exf(items[0].UID == uid, "UID should be %d not %d", uid, items[0].UID) 2062 ex(items[0].Success, "Success should be true") 2063 ex(items[0].IP == "", "IP should be blank") 2064 goNone(uid, 1, 10) 2065 goNone(uid, 0, 0) 2066 2067 dayAgo := time.Now().AddDate(0, 0, -5) 2068 items[0].DoneAt = dayAgo.Format("2006-01-02 15:04:05") 2069 prevDoneAt := items[0].DoneAt 2070 expectNilErr(t, items[0].Commit()) 2071 2072 items, e = c.LoginLogs.GetOffset(uid, 0, 10) 2073 expectNilErr(t, e) 2074 exf(len(items) == 1, "len(items) should be %d not %d", 1, len(items)) 2075 // TODO: More tests 2076 exf(items[0].UID == uid, "UID should be %d not %d", uid, items[0].UID) 2077 ex(items[0].Success, "Success should be true") 2078 ex(items[0].IP == "", "IP should be blank") 2079 exf(items[0].DoneAt == prevDoneAt, "DoneAt should be %s not %s", prevDoneAt, items[0].DoneAt) 2080 goNone(uid, 1, 10) 2081 goNone(uid, 0, 0) 2082 2083 expectNilErr(t, c.LoginLogs.DeleteOlderThanDays(2)) 2084 mustNone() 2085 2086 logItem = &c.LoginLogItem{UID: uid, Success: true, IP: ""} 2087 _, e = logItem.Create() 2088 expectNilErr(t, e) 2089 2090 exf(c.LoginLogs.Count() == 1, "count should be %d not %d", 1, c.LoginLogs.Count()) 2091 exf(c.LoginLogs.CountUser(uid) == 1, "countuser(%d) should be %d not %d", uid, 1, c.LoginLogs.CountUser(uid)) 2092 items, e = c.LoginLogs.GetOffset(uid, 0, 10) 2093 expectNilErr(t, e) 2094 exf(len(items) == 1, "len(items) should be %d not %d", 1, len(items)) 2095 // TODO: More tests 2096 exf(items[0].UID == uid, "UID should be %d not %d", uid, items[0].UID) 2097 ex(items[0].Success, "Success should be true") 2098 ex(items[0].IP == "", "IP should be blank") 2099 goNone(uid, 1, 10) 2100 goNone(uid, 0, 0) 2101 2102 expectNilErr(t, c.LoginLogs.Purge()) 2103 mustNone() 2104 } 2105 2106 func TestPluginManager(t *testing.T) { 2107 miscinit(t) 2108 if !c.PluginsInited { 2109 c.InitPlugins() 2110 } 2111 ex := exp(t) 2112 2113 _, ok := c.Plugins["fairy-dust"] 2114 ex(!ok, "Plugin fairy-dust shouldn't exist") 2115 pl, ok := c.Plugins["bbcode"] 2116 ex(ok, "Plugin bbcode should exist") 2117 ex(!pl.Installable, "Plugin bbcode shouldn't be installable") 2118 ex(!pl.Installed, "Plugin bbcode shouldn't be 'installed'") 2119 ex(!pl.Active, "Plugin bbcode shouldn't be active") 2120 active, e := pl.BypassActive() 2121 expectNilErr(t, e) 2122 ex(!active, "Plugin bbcode shouldn't be active in the database either") 2123 hasPlugin, e := pl.InDatabase() 2124 expectNilErr(t, e) 2125 ex(!hasPlugin, "Plugin bbcode shouldn't exist in the database") 2126 // TODO: Add some test cases for SetActive and SetInstalled before calling AddToDatabase 2127 2128 expectNilErr(t, pl.AddToDatabase(true, false)) 2129 ex(!pl.Installable, "Plugin bbcode shouldn't be installable") 2130 ex(!pl.Installed, "Plugin bbcode shouldn't be 'installed'") 2131 ex(pl.Active, "Plugin bbcode should be active") 2132 active, e = pl.BypassActive() 2133 expectNilErr(t, e) 2134 ex(active, "Plugin bbcode should be active in the database too") 2135 hasPlugin, e = pl.InDatabase() 2136 expectNilErr(t, e) 2137 ex(hasPlugin, "Plugin bbcode should exist in the database") 2138 ex(pl.Init != nil, "Plugin bbcode should have an init function") 2139 expectNilErr(t, pl.Init(pl)) 2140 2141 expectNilErr(t, pl.SetActive(true)) 2142 ex(!pl.Installable, "Plugin bbcode shouldn't be installable") 2143 ex(!pl.Installed, "Plugin bbcode shouldn't be 'installed'") 2144 ex(pl.Active, "Plugin bbcode should still be active") 2145 active, e = pl.BypassActive() 2146 expectNilErr(t, e) 2147 ex(active, "Plugin bbcode should still be active in the database too") 2148 hasPlugin, e = pl.InDatabase() 2149 expectNilErr(t, e) 2150 ex(hasPlugin, "Plugin bbcode should still exist in the database") 2151 2152 expectNilErr(t, pl.SetActive(false)) 2153 ex(!pl.Installable, "Plugin bbcode shouldn't be installable") 2154 ex(!pl.Installed, "Plugin bbcode shouldn't be 'installed'") 2155 ex(!pl.Active, "Plugin bbcode shouldn't be active") 2156 active, e = pl.BypassActive() 2157 expectNilErr(t, e) 2158 ex(!active, "Plugin bbcode shouldn't be active in the database") 2159 hasPlugin, e = pl.InDatabase() 2160 expectNilErr(t, e) 2161 ex(hasPlugin, "Plugin bbcode should still exist in the database") 2162 ex(pl.Deactivate != nil, "Plugin bbcode should have an init function") 2163 pl.Deactivate(pl) // Returns nothing 2164 2165 // Not installable, should not be mutated 2166 ex(pl.SetInstalled(true) == c.ErrPluginNotInstallable, "Plugin was set as installed despite not being installable") 2167 ex(!pl.Installable, "Plugin bbcode shouldn't be installable") 2168 ex(!pl.Installed, "Plugin bbcode shouldn't be 'installed'") 2169 ex(!pl.Active, "Plugin bbcode shouldn't be active") 2170 active, e = pl.BypassActive() 2171 expectNilErr(t, e) 2172 ex(!active, "Plugin bbcode shouldn't be active in the database either") 2173 hasPlugin, e = pl.InDatabase() 2174 expectNilErr(t, e) 2175 ex(hasPlugin, "Plugin bbcode should still exist in the database") 2176 2177 ex(pl.SetInstalled(false) == c.ErrPluginNotInstallable, "Plugin was set as not installed despite not being installable") 2178 ex(!pl.Installable, "Plugin bbcode shouldn't be installable") 2179 ex(!pl.Installed, "Plugin bbcode shouldn't be 'installed'") 2180 ex(!pl.Active, "Plugin bbcode shouldn't be active") 2181 active, e = pl.BypassActive() 2182 expectNilErr(t, e) 2183 ex(!active, "Plugin bbcode shouldn't be active in the database either") 2184 hasPlugin, e = pl.InDatabase() 2185 expectNilErr(t, e) 2186 ex(hasPlugin, "Plugin bbcode should still exist in the database") 2187 2188 // This isn't really installable, but we want to get a few tests done before getting plugins which are stateful 2189 pl.Installable = true 2190 expectNilErr(t, pl.SetInstalled(true)) 2191 ex(pl.Installable, "Plugin bbcode should be installable") 2192 ex(pl.Installed, "Plugin bbcode should be 'installed'") 2193 ex(!pl.Active, "Plugin bbcode shouldn't be active") 2194 active, e = pl.BypassActive() 2195 expectNilErr(t, e) 2196 ex(!active, "Plugin bbcode shouldn't be active in the database either") 2197 hasPlugin, e = pl.InDatabase() 2198 expectNilErr(t, e) 2199 ex(hasPlugin, "Plugin bbcode should still exist in the database") 2200 2201 expectNilErr(t, pl.SetInstalled(false)) 2202 ex(pl.Installable, "Plugin bbcode should be installable") 2203 ex(!pl.Installed, "Plugin bbcode shouldn't be 'installed'") 2204 ex(!pl.Active, "Plugin bbcode shouldn't be active") 2205 active, e = pl.BypassActive() 2206 expectNilErr(t, e) 2207 ex(!active, "Plugin bbcode shouldn't be active in the database either") 2208 hasPlugin, e = pl.InDatabase() 2209 expectNilErr(t, e) 2210 ex(hasPlugin, "Plugin bbcode should still exist in the database") 2211 2212 // Bugs sometimes arise when we try to delete a hook when there are multiple, so test for that 2213 // TODO: Do a finer grained test for that case...? A bigger test might catch more odd cases with multiple plugins 2214 pl2, ok := c.Plugins["markdown"] 2215 ex(ok, "Plugin markdown should exist") 2216 ex(!pl2.Installable, "Plugin markdown shouldn't be installable") 2217 ex(!pl2.Installed, "Plugin markdown shouldn't be 'installed'") 2218 ex(!pl2.Active, "Plugin markdown shouldn't be active") 2219 active, e = pl2.BypassActive() 2220 expectNilErr(t, e) 2221 ex(!active, "Plugin markdown shouldn't be active in the database either") 2222 hasPlugin, e = pl2.InDatabase() 2223 expectNilErr(t, e) 2224 ex(!hasPlugin, "Plugin markdown shouldn't exist in the database") 2225 2226 expectNilErr(t, pl2.AddToDatabase(true, false)) 2227 expectNilErr(t, pl2.Init(pl2)) 2228 expectNilErr(t, pl.SetActive(true)) 2229 expectNilErr(t, pl.Init(pl)) 2230 pl2.Deactivate(pl2) 2231 expectNilErr(t, pl2.SetActive(false)) 2232 pl.Deactivate(pl) 2233 expectNilErr(t, pl.SetActive(false)) 2234 2235 // Hook tests 2236 ht := func() *c.HookTable { 2237 return c.GetHookTable() 2238 } 2239 ex(ht().Sshook("haha", "ho") == "ho", "Sshook shouldn't have anything bound to it yet") 2240 handle := func(in string) (out string) { 2241 return in + "hi" 2242 } 2243 pl.AddHook("haha", handle) 2244 ex(ht().Sshook("haha", "ho") == "hohi", "Sshook didn't give hohi") 2245 pl.RemoveHook("haha", handle) 2246 ex(ht().Sshook("haha", "ho") == "ho", "Sshook shouldn't have anything bound to it anymore") 2247 2248 /*ex(ht().Hook("haha", "ho") == "ho", "Hook shouldn't have anything bound to it yet") 2249 handle2 := func(inI interface{}) (out interface{}) { 2250 return inI.(string) + "hi" 2251 } 2252 pl.AddHook("hehe", handle2) 2253 ex(ht().Hook("hehe", "ho").(string) == "hohi", "Hook didn't give hohi") 2254 pl.RemoveHook("hehe", handle2) 2255 ex(ht().Hook("hehe", "ho").(string) == "ho", "Hook shouldn't have anything bound to it anymore")*/ 2256 2257 // TODO: Add tests for more hook types 2258 } 2259 2260 func TestPhrases(t *testing.T) { 2261 getPhrase := phrases.GetPermPhrase 2262 tp := func(name, expects string) { 2263 res := getPhrase(name) 2264 expect(t, res == expects, "Not the expected phrase, got '"+res+"' instead") 2265 } 2266 tp("BanUsers", "Can ban users") 2267 tp("NoSuchPerm", "{lang.perms[NoSuchPerm]}") 2268 tp("ViewTopic", "Can view topics") 2269 tp("NoSuchPerm", "{lang.perms[NoSuchPerm]}") 2270 2271 // TODO: Cover the other phrase types, also try switching between languages to see if anything strange happens 2272 } 2273 2274 func TestMetaStore(t *testing.T) { 2275 ex, exf := exp(t), expf(t) 2276 m, e := c.Meta.Get("magic") 2277 ex(m == "", "meta var magic should be empty") 2278 recordMustNotExist(t, e, "meta var magic should not exist") 2279 2280 expectVal := func(name, expect string) { 2281 m, e = c.Meta.Get(name) 2282 expectNilErr(t, e) 2283 exf(m == expect, "meta var %s should be %s", name, expect) 2284 } 2285 2286 expectNilErr(t, c.Meta.Set("magic", "lol")) 2287 expectVal("magic", "lol") 2288 expectNilErr(t, c.Meta.Set("magic", "wha")) 2289 expectVal("magic", "wha") 2290 2291 m, e = c.Meta.Get("giggle") 2292 ex(m == "", "meta var giggle should be empty") 2293 recordMustNotExist(t, e, "meta var giggle should not exist") 2294 2295 expectNilErr(t, c.Meta.SetInt("magic", 1)) 2296 expectVal("magic", "1") 2297 expectNilErr(t, c.Meta.SetInt64("magic", 5)) 2298 expectVal("magic", "5") 2299 } 2300 2301 func TestPages(t *testing.T) { 2302 ex := exp(t) 2303 ex(c.Pages.Count() == 0, "Page count should be 0") 2304 _, e := c.Pages.Get(1) 2305 recordMustNotExist(t, e, "Page 1 should not exist yet") 2306 expectNilErr(t, c.Pages.Delete(-1)) 2307 expectNilErr(t, c.Pages.Delete(0)) 2308 expectNilErr(t, c.Pages.Delete(1)) 2309 _, e = c.Pages.Get(1) 2310 recordMustNotExist(t, e, "Page 1 should not exist yet") 2311 //e = c.Pages.Reload(1) 2312 //recordMustNotExist(t,e,"Page 1 should not exist yet") 2313 2314 ipage := c.BlankCustomPage() 2315 ipage.Name = "test" 2316 ipage.Title = "Test" 2317 ipage.Body = "A test page" 2318 pid, e := ipage.Create() 2319 expectNilErr(t, e) 2320 ex(pid == 1, "The first page should have an ID of 1") 2321 ex(c.Pages.Count() == 1, "Page count should be 1") 2322 2323 test := func(pid int, ep *c.CustomPage) { 2324 p, e := c.Pages.Get(pid) 2325 expectNilErr(t, e) 2326 ex(p.Name == ep.Name, "The page name should be "+ep.Name) 2327 ex(p.Title == ep.Title, "The page title should be "+ep.Title) 2328 ex(p.Body == ep.Body, "The page body should be "+ep.Body) 2329 } 2330 test(1, ipage) 2331 2332 opage, err := c.Pages.Get(1) 2333 expectNilErr(t, err) 2334 opage.Name = "t" 2335 opage.Title = "T" 2336 opage.Body = "testing" 2337 expectNilErr(t, opage.Commit()) 2338 2339 test(1, opage) 2340 2341 expectNilErr(t, c.Pages.Delete(1)) 2342 ex(c.Pages.Count() == 0, "Page count should be 0") 2343 _, e = c.Pages.Get(1) 2344 recordMustNotExist(t, e, "Page 1 should not exist") 2345 //e = c.Pages.Reload(1) 2346 //recordMustNotExist(t,e,"Page 1 should not exist") 2347 2348 // TODO: More tests 2349 } 2350 2351 func TestWordFilters(t *testing.T) { 2352 ex, exf := exp(t), expf(t) 2353 // TODO: Test the word filters and their store 2354 ex(c.WordFilters.Length() == 0, "Word filter list should be empty") 2355 ex(c.WordFilters.EstCount() == 0, "Word filter list should be empty") 2356 ex(c.WordFilters.Count() == 0, "Word filter list should be empty") 2357 filters, err := c.WordFilters.GetAll() 2358 expectNilErr(t, err) // TODO: Slightly confusing that we don't get ErrNoRow here 2359 ex(len(filters) == 0, "Word filter map should be empty") 2360 // TODO: Add a test for ParseMessage relating to word filters 2361 _, err = c.WordFilters.Get(1) 2362 recordMustNotExist(t, err, "filter 1 should not exist") 2363 2364 wfid, err := c.WordFilters.Create("imbecile", "lovely") 2365 expectNilErr(t, err) 2366 ex(wfid == 1, "The first word filter should have an ID of 1") 2367 ex(c.WordFilters.Length() == 1, "Word filter list should not be empty") 2368 ex(c.WordFilters.EstCount() == 1, "Word filter list should not be empty") 2369 ex(c.WordFilters.Count() == 1, "Word filter list should not be empty") 2370 2371 ftest := func(f *c.WordFilter, id int, find, replace string) { 2372 exf(f.ID == id, "Word filter ID should be %d, not %d", id, f.ID) 2373 exf(f.Find == find, "Word filter needle should be '%s', not '%s'", find, f.Find) 2374 exf(f.Replace == replace, "Word filter replacement should be '%s', not '%s'", replace, f.Replace) 2375 } 2376 2377 filters, err = c.WordFilters.GetAll() 2378 expectNilErr(t, err) 2379 ex(len(filters) == 1, "Word filter map should not be empty") 2380 ftest(filters[1], 1, "imbecile", "lovely") 2381 2382 filter, err := c.WordFilters.Get(1) 2383 expectNilErr(t, err) 2384 ftest(filter, 1, "imbecile", "lovely") 2385 2386 // Update 2387 expectNilErr(t, c.WordFilters.Update(1, "b", "a")) 2388 2389 ex(c.WordFilters.Length() == 1, "Word filter list should not be empty") 2390 ex(c.WordFilters.EstCount() == 1, "Word filter list should not be empty") 2391 ex(c.WordFilters.Count() == 1, "Word filter list should not be empty") 2392 2393 filters, err = c.WordFilters.GetAll() 2394 expectNilErr(t, err) 2395 ex(len(filters) == 1, "Word filter map should not be empty") 2396 ftest(filters[1], 1, "b", "a") 2397 2398 filter, err = c.WordFilters.Get(1) 2399 expectNilErr(t, err) 2400 ftest(filter, 1, "b", "a") 2401 2402 // TODO: Add a test for ParseMessage relating to word filters 2403 2404 expectNilErr(t, c.WordFilters.Delete(1)) 2405 2406 ex(c.WordFilters.Length() == 0, "Word filter list should be empty") 2407 ex(c.WordFilters.EstCount() == 0, "Word filter list should be empty") 2408 ex(c.WordFilters.Count() == 0, "Word filter list should be empty") 2409 filters, err = c.WordFilters.GetAll() 2410 expectNilErr(t, err) // TODO: Slightly confusing that we don't get ErrNoRow here 2411 ex(len(filters) == 0, "Word filter map should be empty") 2412 _, err = c.WordFilters.Get(1) 2413 recordMustNotExist(t, err, "filter 1 should not exist") 2414 2415 // TODO: Any more tests we could do? 2416 } 2417 2418 func TestMFAStore(t *testing.T) { 2419 exf := expf(t) 2420 2421 mustNone := func() { 2422 _, e := c.MFAstore.Get(-1) 2423 recordMustNotExist(t, e, "mfa uid -1 should not exist") 2424 _, e = c.MFAstore.Get(0) 2425 recordMustNotExist(t, e, "mfa uid 0 should not exist") 2426 _, e = c.MFAstore.Get(1) 2427 recordMustNotExist(t, e, "mfa uid 1 should not exist") 2428 } 2429 mustNone() 2430 2431 secret, e := c.GenerateGAuthSecret() 2432 expectNilErr(t, e) 2433 expectNilErr(t, c.MFAstore.Create(secret, 1)) 2434 _, e = c.MFAstore.Get(0) 2435 recordMustNotExist(t, e, "mfa uid 0 should not exist") 2436 var scratches []string 2437 it, e := c.MFAstore.Get(1) 2438 test := func(j int) { 2439 expectNilErr(t, e) 2440 exf(it.UID == 1, "UID should be 1 not %d", it.UID) 2441 exf(it.Secret == secret, "Secret should be '%s' not %s", secret, it.Secret) 2442 exf(len(it.Scratch) == 8, "Scratch should be 8 not %d", len(it.Scratch)) 2443 for i, scratch := range it.Scratch { 2444 exf(scratch != "", "scratch %d should not be empty", i) 2445 if scratches != nil { 2446 if j == i { 2447 exf(scratches[i] != scratch, "scratches[%d] should not be %s", i, scratches[i]) 2448 } else { 2449 exf(scratches[i] == scratch, "scratches[%d] should be %s not %s", i, scratches[i], scratch) 2450 } 2451 } 2452 } 2453 scratches = make([]string, 8) 2454 copy(scratches, it.Scratch) 2455 } 2456 test(0) 2457 for i := 0; i < len(scratches); i++ { 2458 expectNilErr(t, it.BurnScratch(i)) 2459 it, e = c.MFAstore.Get(1) 2460 test(i) 2461 } 2462 token, e := gauth.GetTOTPToken(secret) 2463 expectNilErr(t, e) 2464 expectNilErr(t, c.Auth.ValidateMFAToken(token, 1)) 2465 expectNilErr(t, it.Delete()) 2466 mustNone() 2467 } 2468 2469 // TODO: Expand upon the valid characters which can go in URLs? 2470 func TestSlugs(t *testing.T) { 2471 l := &MEPairList{nil} 2472 c.Config.BuildSlugs = true // Flip this switch, otherwise all the tests will fail 2473 2474 l.Add("Unknown", "unknown") 2475 l.Add("Unknown2", "unknown2") 2476 l.Add("Unknown ", "unknown") 2477 l.Add("Unknown 2", "unknown-2") 2478 l.Add("Unknown 2", "unknown-2") 2479 l.Add("Admin Alice", "admin-alice") 2480 l.Add("Admin_Alice", "adminalice") 2481 l.Add("Admin_Alice-", "adminalice") 2482 l.Add("-Admin_Alice-", "adminalice") 2483 l.Add("-Admin@Alice-", "adminalice") 2484 l.Add("-AdminπAlice-", "adminalice") 2485 l.Add("u", "u") 2486 l.Add("", "untitled") 2487 l.Add(" ", "untitled") 2488 l.Add("-", "untitled") 2489 l.Add("--", "untitled") 2490 l.Add("Γ©", "Γ©") 2491 l.Add("-Γ©-", "Γ©") 2492 l.Add("-δ½ ε₯½-", "untitled") 2493 l.Add("-γγ«γ‘γ―-", "untitled") 2494 2495 for _, item := range l.Items { 2496 t.Log("Testing string '" + item.Msg + "'") 2497 res := c.NameToSlug(item.Msg) 2498 if res != item.Expects { 2499 t.Error("Bad output:", "'"+res+"'") 2500 t.Error("Expected:", item.Expects) 2501 } 2502 } 2503 } 2504 2505 func TestWidgets(t *testing.T) { 2506 ex, exf := exp(t), expf(t) 2507 _, e := c.Widgets.Get(1) 2508 recordMustNotExist(t, e, "There shouldn't be any widgets by default") 2509 widgets := c.Docks.RightSidebar.Items 2510 exf(len(widgets) == 0, "RightSidebar should have 0 items, not %d", len(widgets)) 2511 2512 widget := &c.Widget{Position: 0, Side: "rightSidebar", Type: "simple", Enabled: true, Location: "global"} 2513 ewidget := &c.WidgetEdit{widget, map[string]string{"Name": "Test", "Text": "Testing"}} 2514 wid, e := ewidget.Create() 2515 expectNilErr(t, e) 2516 ex(wid == 1, "wid should be 1") 2517 2518 wtest := func(w, w2 *c.Widget) { 2519 ex(w.Position == w2.Position, "wrong position") 2520 ex(w.Side == w2.Side, "wrong side") 2521 ex(w.Type == w2.Type, "wrong type") 2522 ex(w.Enabled == w2.Enabled, "wrong enabled") 2523 ex(w.Location == w2.Location, "wrong location") 2524 } 2525 2526 // TODO: Do a test for the widget body 2527 widget2, e := c.Widgets.Get(1) 2528 expectNilErr(t, e) 2529 wtest(widget, widget2) 2530 2531 widgets = c.Docks.RightSidebar.Items 2532 exf(len(widgets) == 1, "RightSidebar should have 1 item, not %d", len(widgets)) 2533 wtest(widget, widgets[0]) 2534 2535 widget2.Enabled = false 2536 ewidget = &c.WidgetEdit{widget2, map[string]string{"Name": "Test", "Text": "Testing"}} 2537 expectNilErr(t, ewidget.Commit()) 2538 2539 widget2, e = c.Widgets.Get(1) 2540 expectNilErr(t, e) 2541 widget.Enabled = false 2542 wtest(widget, widget2) 2543 2544 widgets = c.Docks.RightSidebar.Items 2545 exf(len(widgets) == 1, "RightSidebar should have 1 item, not %d", len(widgets)) 2546 widget.Enabled = false 2547 wtest(widget, widgets[0]) 2548 2549 expectNilErr(t, widget2.Delete()) 2550 2551 _, e = c.Widgets.Get(1) 2552 recordMustNotExist(t, e, "There shouldn't be any widgets anymore") 2553 widgets = c.Docks.RightSidebar.Items 2554 exf(len(widgets) == 0, "RightSidebar should have 0 items, not %d", len(widgets)) 2555 } 2556 2557 /*type ForumActionStoreInt interface { 2558 Get(faid int) (*ForumAction, error) 2559 GetInForum(fid int) ([]*ForumAction, error) 2560 GetAll() ([]*ForumAction, error) 2561 GetNewTopicActions(fid int) ([]*ForumAction, error) 2562 2563 Add(fa *ForumAction) (int, error) 2564 Delete(faid int) error 2565 Exists(faid int) bool 2566 Count() int 2567 CountInForum(fid int) int 2568 2569 DailyTick() error 2570 }*/ 2571 2572 func TestForumActions(t *testing.T) { 2573 ex, exf, s := exp(t), expf(t), c.ForumActionStore 2574 2575 count := s.CountInForum(-1) 2576 exf(count == 0, "count should be %d not %d", 0, count) 2577 count = s.CountInForum(0) 2578 exf(count == 0, "count in 0 should be %d not %d", 0, count) 2579 ex(!s.Exists(-1), "faid -1 should not exist") 2580 ex(!s.Exists(0), "faid 0 should not exist") 2581 _, e := s.Get(-1) 2582 recordMustNotExist(t, e, "faid -1 should not exist") 2583 _, e = s.Get(0) 2584 recordMustNotExist(t, e, "faid 0 should not exist") 2585 2586 noActions := func(fid, faid int) { 2587 /*sfid, */ sfaid := /*strconv.Itoa(fid), */ strconv.Itoa(faid) 2588 count := s.Count() 2589 exf(count == 0, "count should be %d not %d", 0, count) 2590 count = s.CountInForum(fid) 2591 exf(count == 0, "count in %d should be %d not %d", fid, 0, count) 2592 exf(!s.Exists(faid), "faid %d should not exist", faid) 2593 _, e := s.Get(faid) 2594 recordMustNotExist(t, e, "faid "+sfaid+" should not exist") 2595 //exf(fa == nil, "fa should be nil not %+v", fa) 2596 fas, e := s.GetInForum(fid) 2597 //recordMustNotExist(t, e, "fid "+sfid+" should not have any actions") 2598 expectNilErr(t, e) // TODO: Why does this not return ErrNoRows? 2599 exf(len(fas) == 0, "len(fas) should be %d not %d", 0, len(fas)) 2600 fas, e = s.GetAll() 2601 //recordMustNotExist(t, e, "there should not be any actions") 2602 expectNilErr(t, e) // TODO: Why does this not return ErrNoRows? 2603 exf(len(fas) == 0, "len(fas) should be %d not %d", 0, len(fas)) 2604 fas, e = s.GetNewTopicActions(fid) 2605 //recordMustNotExist(t, e, "fid "+sfid+" should not have any new topic actions") 2606 expectNilErr(t, e) // TODO: Why does this not return ErrNoRows? 2607 exf(len(fas) == 0, "len(fas) should be %d not %d", 0, len(fas)) 2608 } 2609 noActions(1, 1) 2610 2611 fid, e := c.Forums.Create("Forum Action Test", "Forum Action Test", true, "") 2612 expectNilErr(t, e) 2613 noActions(fid, 1) 2614 2615 faid, e := c.ForumActionStore.Add(&c.ForumAction{ 2616 Forum: fid, 2617 RunOnTopicCreation: false, 2618 RunDaysAfterTopicCreation: 1, 2619 RunDaysAfterTopicLastReply: 0, 2620 Action: c.ForumActionLock, 2621 Extra: "", 2622 }) 2623 expectNilErr(t, e) 2624 exf(faid == 1, "faid should be %d not %d", 1, faid) 2625 count = s.Count() 2626 exf(count == 1, "count should be %d not %d", 1, count) 2627 count = s.CountInForum(fid) 2628 exf(count == 1, "count in %d should be %d not %d", fid, 1, count) 2629 exf(s.Exists(faid), "faid %d should exist", faid) 2630 2631 fa, e := s.Get(faid) 2632 expectNilErr(t, e) 2633 exf(fa.ID == faid, "fa.ID should be %d not %d", faid, fa.ID) 2634 exf(fa.Forum == fid, "fa.Forum should be %d not %d", fid, fa.Forum) 2635 exf(fa.RunOnTopicCreation == false, "fa.RunOnTopicCreation should be false") 2636 exf(fa.RunDaysAfterTopicCreation == 1, "fa.RunDaysAfterTopicCreation should be %d not %d", 1, fa.RunDaysAfterTopicCreation) 2637 exf(fa.RunDaysAfterTopicLastReply == 0, "fa.RunDaysAfterTopicLastReply should be %d not %d", 0, fa.RunDaysAfterTopicLastReply) 2638 exf(fa.Action == c.ForumActionLock, "fa.Action should be %d not %d", c.ForumActionLock, fa.Action) 2639 exf(fa.Extra == "", "fa.Extra should be '%s' not '%s'", "", fa.Extra) 2640 2641 tid, e := c.Topics.Create(fid, "Forum Action Topic", "Forum Action Topic", 1, "") 2642 expectNilErr(t, e) 2643 topic, e := c.Topics.Get(tid) 2644 expectNilErr(t, e) 2645 ex(!topic.IsClosed, "topic.IsClosed should be false") 2646 dayAgo := time.Now().AddDate(0, 0, -5) 2647 expectNilErr(t, topic.TestSetCreatedAt(dayAgo)) 2648 expectNilErr(t, fa.Run()) 2649 topic, e = c.Topics.Get(tid) 2650 expectNilErr(t, e) 2651 ex(topic.IsClosed, "topic.IsClosed should be true") 2652 /*_, e = c.Rstore.Create(topic, "Forum Action Reply", "", 1) 2653 expectNilErr(t, e)*/ 2654 2655 tid, e = c.Topics.Create(fid, "Forum Action Topic 2", "Forum Action Topic 2", 1, "") 2656 expectNilErr(t, e) 2657 topic, e = c.Topics.Get(tid) 2658 expectNilErr(t, e) 2659 ex(!topic.IsClosed, "topic.IsClosed should be false") 2660 expectNilErr(t, fa.Run()) 2661 topic, e = c.Topics.Get(tid) 2662 expectNilErr(t, e) 2663 ex(!topic.IsClosed, "topic.IsClosed should be false") 2664 2665 _ = tid 2666 2667 expectNilErr(t, s.Delete(faid)) 2668 noActions(fid, faid) 2669 2670 // TODO: Bulk lock tests 2671 faid, e = c.ForumActionStore.Add(&c.ForumAction{ 2672 Forum: fid, 2673 RunOnTopicCreation: false, 2674 RunDaysAfterTopicCreation: 2, 2675 RunDaysAfterTopicLastReply: 0, 2676 Action: c.ForumActionLock, 2677 Extra: "", 2678 }) 2679 expectNilErr(t, e) 2680 2681 var l []int 2682 addTopic := func() { 2683 tid, e = c.Topics.Create(fid, "Forum Action Topic 2", "Forum Action Topic 2", 1, "") 2684 expectNilErr(t, e) 2685 topic, e := c.Topics.Get(tid) 2686 expectNilErr(t, e) 2687 ex(!topic.IsClosed, "topic.IsClosed should be false") 2688 dayAgo := time.Now().AddDate(0, 0, -5) 2689 expectNilErr(t, topic.TestSetCreatedAt(dayAgo)) 2690 l = append(l, tid) 2691 } 2692 lTest := func() { 2693 for _, ll := range l { 2694 to, e := c.Topics.Get(ll) 2695 expectNilErr(t, e) 2696 ex(to.IsClosed, "to.IsClosed should be true") 2697 } 2698 l = nil 2699 } 2700 2701 addTopic() 2702 addTopic() 2703 addTopic() 2704 addTopic() 2705 addTopic() 2706 addTopic() 2707 addTopic() 2708 addTopic() 2709 addTopic() 2710 addTopic() 2711 expectNilErr(t, fa.Run()) 2712 lTest() 2713 // TODO: Create a method on the *ForumAction to get the count of topics which it could be run on and add a test to verify the count is as expected. 2714 2715 addTopic() 2716 addTopic() 2717 addTopic() 2718 addTopic() 2719 addTopic() 2720 addTopic() 2721 addTopic() 2722 addTopic() 2723 addTopic() 2724 addTopic() 2725 addTopic() 2726 expectNilErr(t, fa.Run()) 2727 lTest() 2728 // TODO: Create a method on the *ForumAction to get the count of topics which it could be run on and add a test to verify the count is as expected. 2729 } 2730 2731 func TestTopicList(t *testing.T) { 2732 ex, exf := exp(t), expf(t) 2733 fid, err := c.Forums.Create("Test Forum", "Desc for test forum", true, "") 2734 expectNilErr(t, err) 2735 tint := c.TopicList.(c.TopicListIntTest) 2736 2737 testPagi := func(p c.Paginator, pageList []int, page, lastPage int) { 2738 exf(len(p.PageList) == len(pageList), "len(pagi.PageList) should be %d not %d", len(pageList), len(p.PageList)) 2739 for i, page := range pageList { 2740 exf(p.PageList[i] == page, "pagi.PageList[%d] should be %d not %d", i, page, p.PageList[i]) 2741 } 2742 exf(p.Page == page, "pagi.Page should be %d not %d", page, p.Page) 2743 exf(p.LastPage == lastPage, "pagi.LastPage should be %d not %d", lastPage, p.LastPage) 2744 } 2745 test := func(topicList []*c.TopicsRow, pagi c.Paginator, listLen int, pagi2 c.Paginator, tid1 int) { 2746 exf(len(topicList) == listLen, "len(topicList) should be %d not %d", listLen, len(topicList)) 2747 if len(topicList) > 0 { 2748 topic := topicList[0] 2749 exf(topic.ID == tid1, "topic.ID should be %d not %d", tid1, topic.ID) 2750 } 2751 testPagi(pagi, pagi2.PageList, pagi2.Page, pagi2.LastPage) 2752 } 2753 noTopics := func(topicList []*c.TopicsRow, pagi c.Paginator) { 2754 exf(len(topicList) == 0, "len(topicList) should be 0 not %d", len(topicList)) 2755 testPagi(pagi, []int{}, 1, 1) 2756 } 2757 noTopicsOnPage2 := func(topicList []*c.TopicsRow, pagi c.Paginator) { 2758 exf(len(topicList) == 0, "len(topicList) should be 0 not %d", len(topicList)) 2759 testPagi(pagi, []int{1}, 2, 1) 2760 } 2761 2762 forum, err := c.Forums.Get(fid) 2763 expectNilErr(t, err) 2764 2765 isAdmin, isMod, isBanned := false, false, false 2766 gid, err := c.Groups.Create("Topic List Test", "Test", isAdmin, isMod, isBanned) 2767 expectNilErr(t, err) 2768 ex(c.Groups.Exists(gid), "The group we just made doesn't exist") 2769 2770 fp, err := c.FPStore.GetCopy(fid, gid) 2771 if err == sql.ErrNoRows { 2772 fp = *c.BlankForumPerms() 2773 } else if err != nil { 2774 expectNilErr(t, err) 2775 } 2776 fp.ViewTopic = true 2777 2778 forum, err = c.Forums.Get(fid) 2779 expectNilErr(t, err) 2780 expectNilErr(t, forum.SetPerms(&fp, "custom", gid)) 2781 2782 g, err := c.Groups.Get(gid) 2783 expectNilErr(t, err) 2784 2785 noTopicsTests := func() { 2786 rr := func(page, orderby int) { 2787 topicList, forumList, pagi, err := c.TopicList.GetListByGroup(g, page, orderby, []int{fid}) 2788 expectNilErr(t, err) 2789 noTopics(topicList, pagi) 2790 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2791 } 2792 rr(1, 0) 2793 rr(2, 0) 2794 rr(1, 1) 2795 rr(2, 1) 2796 2797 topicList, pagi, err := c.TopicList.GetListByForum(forum, 1, 0) 2798 expectNilErr(t, err) 2799 noTopics(topicList, pagi) 2800 2801 topicList, pagi, err = tint.RawGetListByForum(forum, 1, 0) 2802 expectNilErr(t, err) 2803 noTopics(topicList, pagi) 2804 2805 topicList, forumList, pagi, err := c.TopicList.GetList(1, 0, []int{fid}) 2806 expectNilErr(t, err) 2807 noTopics(topicList, pagi) 2808 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2809 2810 topicList, forumList, pagi, err = c.TopicList.GetListByCanSee([]int{fid}, 1, 0, []int{fid}) 2811 expectNilErr(t, err) 2812 noTopics(topicList, pagi) 2813 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2814 2815 topicList, forumList, pagi, err = c.TopicList.GetListByCanSee([]int{}, 1, 0, []int{fid}) 2816 expectNilErr(t, err) 2817 noTopics(topicList, pagi) 2818 // TODO: Why is there a discrepency between this and GetList()? 2819 exf(len(forumList) == 0, "len(forumList) should be 0 not %d", len(forumList)) 2820 } 2821 noTopicsTests() 2822 2823 tid, err := c.Topics.Create(fid, "New Topic", "New Topic Body", 1, "") 2824 expectNilErr(t, err) 2825 2826 topicList, forumList, pagi, err := c.TopicList.GetListByGroup(g, 1, 0, []int{fid}) 2827 expectNilErr(t, err) 2828 test(topicList, pagi, 1, c.Paginator{[]int{1}, 1, 1}, tid) 2829 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2830 2831 topicList, forumList, pagi, err = c.TopicList.GetListByGroup(g, 2, 0, []int{fid}) 2832 expectNilErr(t, err) 2833 noTopics(topicList, pagi) 2834 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2835 2836 topicList, forumList, pagi, err = c.TopicList.GetListByGroup(g, 1, 1, []int{fid}) 2837 expectNilErr(t, err) 2838 test(topicList, pagi, 1, c.Paginator{[]int{1}, 1, 1}, tid) 2839 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2840 2841 topicList, forumList, pagi, err = c.TopicList.GetListByGroup(g, 2, 1, []int{fid}) 2842 expectNilErr(t, err) 2843 noTopicsOnPage2(topicList, pagi) 2844 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2845 2846 topicList, pagi, err = tint.RawGetListByForum(forum, 1, 0) 2847 expectNilErr(t, err) 2848 test(topicList, pagi, 1, c.Paginator{[]int{1}, 1, 1}, tid) 2849 2850 topicList, pagi, err = tint.RawGetListByForum(forum, 0, 0) 2851 expectNilErr(t, err) 2852 test(topicList, pagi, 1, c.Paginator{[]int{1}, 1, 1}, tid) 2853 2854 expectNilErr(t, tint.Tick()) 2855 forum, err = c.Forums.Get(fid) 2856 expectNilErr(t, err) 2857 topicList, pagi, err = c.TopicList.GetListByForum(forum, 1, 0) 2858 expectNilErr(t, err) 2859 test(topicList, pagi, 1, c.Paginator{[]int{1}, 1, 1}, tid) 2860 2861 topicList, forumList, pagi, err = c.TopicList.GetList(1, 0, []int{fid}) 2862 expectNilErr(t, err) 2863 test(topicList, pagi, 1, c.Paginator{[]int{1}, 1, 1}, tid) 2864 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2865 2866 topicList, forumList, pagi, err = c.TopicList.GetListByCanSee([]int{fid}, 1, 0, []int{fid}) 2867 expectNilErr(t, err) 2868 test(topicList, pagi, 1, c.Paginator{[]int{1}, 1, 1}, tid) 2869 exf(len(forumList) == 1, "len(forumList) should be 1 not %d", len(forumList)) 2870 2871 topicList, forumList, pagi, err = c.TopicList.GetListByCanSee([]int{}, 1, 0, []int{fid}) 2872 expectNilErr(t, err) 2873 noTopics(topicList, pagi) 2874 exf(len(forumList) == 0, "len(forumList) should be 0 not %d", len(forumList)) 2875 2876 topic, err := c.Topics.Get(tid) 2877 expectNilErr(t, err) 2878 expectNilErr(t, topic.Delete()) 2879 2880 forum, err = c.Forums.Get(fid) 2881 expectNilErr(t, err) 2882 noTopicsTests() 2883 2884 // TODO: More tests 2885 2886 _ = ex 2887 } 2888 2889 func TestUtils(t *testing.T) { 2890 ee := func(email, eemail string) { 2891 cemail := c.CanonEmail(email) 2892 expectf(t, cemail == eemail, "%s should be %s", cemail, eemail) 2893 } 2894 ee("test@example.com", "test@example.com") 2895 ee("test.test@example.com", "test.test@example.com") 2896 ee("", "") 2897 ee("ddd", "ddd") 2898 ee("test.test@gmail.com", "testtest@gmail.com") 2899 ee("TEST.test@gmail.com", "testtest@gmail.com") 2900 ee("test.TEST.test@gmail.com", "testtesttest@gmail.com") 2901 ee("test..TEST.test@gmail.com", "testtesttest@gmail.com") 2902 ee("TEST.test@example.com", "test.test@example.com") 2903 ee("test.TEST.test@example.com", "test.test.test@example.com") 2904 // TODO: Exotic unicode email types? Are there those? 2905 2906 // TODO: More utils.go tests 2907 } 2908 2909 func TestWeakPassword(t *testing.T) { 2910 ex := exp(t) 2911 /*weakPass := func(password, name, email string) func(error,string,...interface{}) { 2912 err := c.WeakPassword(password, name, email) 2913 return func(expectErr error, m string, p ...interface{}) { 2914 m = fmt.Sprintf("pass=%s, user=%s, email=%s ", password, name, email) + m 2915 expect(t, err == expectErr, fmt.Sprintf(m,p...)) 2916 } 2917 }*/ 2918 nilErrStr := func(e error) error { 2919 if e == nil { 2920 e = errors.New("nil") 2921 } 2922 return e 2923 } 2924 weakPass := func(password, name, email string) func(error) { 2925 err := c.WeakPassword(password, name, email) 2926 e := nilErrStr(err) 2927 m := fmt.Sprintf("pass=%s, user=%s, email=%s ", password, name, email) 2928 return func(expectErr error) { 2929 ee := nilErrStr(expectErr) 2930 ex(err == expectErr, m+fmt.Sprintf("err should be '%s' not '%s'", ee, e)) 2931 } 2932 } 2933 2934 //weakPass("test", "test", "test@example.com")(c.ErrWeakPasswordContains,"err should be ErrWeakPasswordContains not '%s'") 2935 weakPass("", "draw", "test@example.com")(c.ErrWeakPasswordNone) 2936 weakPass("test", "draw", "test@example.com")(c.ErrWeakPasswordShort) 2937 weakPass("testtest", "draw", "test@example.com")(c.ErrWeakPasswordContains) 2938 weakPass("testdraw", "draw", "test@example.com")(c.ErrWeakPasswordNameInPass) 2939 weakPass("test@example.com", "draw", "test@example.com")(c.ErrWeakPasswordEmailInPass) 2940 weakPass("meet@example.com2", "draw", "")(c.ErrWeakPasswordNoUpper) 2941 weakPass("Meet@example.com2", "draw", "")(nil) 2942 weakPass("test2", "draw", "test@example.com")(c.ErrWeakPasswordShort) 2943 weakPass("test22222222", "draw", "test@example.com")(c.ErrWeakPasswordContains) 2944 weakPass("superman", "draw", "test@example.com")(c.ErrWeakPasswordCommon) 2945 weakPass("Superman", "draw", "test@example.com")(c.ErrWeakPasswordCommon) 2946 weakPass("Superma2", "draw", "test@example.com")(nil) 2947 weakPass("superman2", "draw", "test@example.com")(c.ErrWeakPasswordCommon) 2948 weakPass("Superman2", "draw", "test@example.com")(c.ErrWeakPasswordCommon) 2949 weakPass("superman22", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper) 2950 weakPass("K\\@<^s}1", "draw", "test@example.com")(nil) 2951 weakPass("K\\@<^s}r", "draw", "test@example.com")(c.ErrWeakPasswordNoNumbers) 2952 weakPass("k\\@<^s}1", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper) 2953 weakPass("aaaaaaaa", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper) 2954 weakPass("aA1aA1aA1", "draw", "test@example.com")(c.ErrWeakPasswordUniqueChars) 2955 weakPass("abababab", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper) 2956 weakPass("11111111111111111111", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper) 2957 weakPass("aaaaaaaaaaAAAAAAAAAA", "draw", "test@example.com")(c.ErrWeakPasswordUniqueChars) 2958 weakPass("-:u/nMxb,A!n=B;H\\sjM", "draw", "test@example.com")(nil) 2959 } 2960 2961 func TestAuth(t *testing.T) { 2962 ex := exp(t) 2963 // bcrypt likes doing stupid things, so this test will probably fail 2964 realPassword := "Madame Cassandra's Mystic Orb" 2965 t.Logf("Set realPassword to '%s'", realPassword) 2966 t.Log("Hashing the real password with bcrypt") 2967 hashedPassword, _, err := c.BcryptGeneratePassword(realPassword) 2968 if err != nil { 2969 t.Error(err) 2970 } 2971 passwordTest(t, realPassword, hashedPassword) 2972 // TODO: Peek at the prefix to verify this is a bcrypt hash 2973 2974 t.Log("Hashing the real password") 2975 hashedPassword2, _, err := c.GeneratePassword(realPassword) 2976 if err != nil { 2977 t.Error(err) 2978 } 2979 passwordTest(t, realPassword, hashedPassword2) 2980 // TODO: Peek at the prefix to verify this is a bcrypt hash 2981 2982 _, err, _ = c.Auth.Authenticate("None", "password") 2983 errmsg := "Name None shouldn't exist" 2984 if err != nil { 2985 errmsg += "\n" + err.Error() 2986 } 2987 ex(err == c.ErrNoUserByName, errmsg) 2988 2989 uid, err, _ := c.Auth.Authenticate("Admin", "password") 2990 expectNilErr(t, err) 2991 expectf(t, uid == 1, "Default admin uid should be 1 not %d", uid) 2992 2993 _, err, _ = c.Auth.Authenticate("Sam", "ReallyBadPassword") 2994 errmsg = "Name Sam shouldn't exist" 2995 if err != nil { 2996 errmsg += "\n" + err.Error() 2997 } 2998 ex(err == c.ErrNoUserByName, errmsg) 2999 3000 admin, err := c.Users.Get(1) 3001 expectNilErr(t, err) 3002 // TODO: Move this into the user store tests to provide better coverage? E.g. To see if the installer and the user creator initialise the field differently 3003 ex(admin.Session == "", "Admin session should be blank") 3004 3005 session, err := c.Auth.CreateSession(1) 3006 expectNilErr(t, err) 3007 ex(session != "", "Admin session shouldn't be blank") 3008 // TODO: Test the actual length set in the setting in addition to this "too short" test 3009 // TODO: We might be able to push up this minimum requirement 3010 ex(len(session) > 10, "Admin session shouldn't be too short") 3011 ex(admin.Session != session, "Old session should not match new one") 3012 admin, err = c.Users.Get(1) 3013 expectNilErr(t, err) 3014 ex(admin.Session == session, "Sessions should match") 3015 3016 // TODO: Create a user with a unicode password and see if we can login as them 3017 // TODO: Tests for SessionCheck, GetCookies, and ForceLogout 3018 // TODO: Tests for MFA Verification 3019 } 3020 3021 // TODO: Vary the salts? Keep in mind that some algorithms store the salt in the hash therefore the salt string may be blank 3022 func passwordTest(t *testing.T, realPassword, hashedPassword string) { 3023 if len(hashedPassword) < 10 { 3024 t.Error("Hash too short") 3025 } 3026 salt := "" 3027 password := realPassword 3028 t.Logf("Testing password '%s'", password) 3029 t.Logf("Testing salt '%s'", salt) 3030 err := c.CheckPassword(hashedPassword, password, salt) 3031 if err == c.ErrMismatchedHashAndPassword { 3032 t.Error("The two don't match") 3033 } else if err == c.ErrPasswordTooLong { 3034 t.Error("CheckPassword thinks the password is too long") 3035 } else if err != nil { 3036 t.Error(err) 3037 } 3038 3039 password = "hahaha" 3040 t.Logf("Testing password '%s'", password) 3041 t.Logf("Testing salt '%s'", salt) 3042 err = c.CheckPassword(hashedPassword, password, salt) 3043 if err == c.ErrPasswordTooLong { 3044 t.Error("CheckPassword thinks the password is too long") 3045 } else if err == nil { 3046 t.Error("The two shouldn't match!") 3047 } 3048 3049 password = "Madame Cassandra's Mystic" 3050 t.Logf("Testing password '%s'", password) 3051 t.Logf("Testing salt '%s'", salt) 3052 err = c.CheckPassword(hashedPassword, password, salt) 3053 expect(t, err != c.ErrPasswordTooLong, "CheckPassword thinks the password is too long") 3054 expect(t, err != nil, "The two shouldn't match!") 3055 } 3056 3057 func TestUserPrivacy(t *testing.T) { 3058 pu, u := c.BlankUser(), &c.GuestUser 3059 pu.ID = 1 3060 ex, exf := exp(t), expf(t) 3061 ex(!pu.Privacy.NoPresence, "pu.Privacy.NoPresence should be false") 3062 ex(!u.Privacy.NoPresence, "u.Privacy.NoPresence should be false") 3063 3064 var msg string 3065 test := func(expects bool, level int) { 3066 pu.Privacy.ShowComments = level 3067 val := c.PrivacyCommentsShow(pu, u) 3068 var bit string 3069 if !expects { 3070 bit = " not" 3071 val = !val 3072 } 3073 exf(val, "%s should%s be able to see comments on level %d", msg, bit, level) 3074 } 3075 // 0 = default, 1 = public, 2 = registered, 3 = friends, 4 = self, 5 = disabled 3076 3077 msg = "guest users" 3078 test(true, 0) 3079 test(true, 1) 3080 test(false, 2) 3081 test(false, 3) 3082 test(false, 4) 3083 test(false, 5) 3084 3085 u = c.BlankUser() 3086 msg = "blank users" 3087 test(true, 0) 3088 test(true, 1) 3089 test(false, 2) 3090 //test(false,3) 3091 test(false, 4) 3092 test(false, 5) 3093 3094 u.Loggedin = true 3095 msg = "registered users" 3096 test(true, 0) 3097 test(true, 1) 3098 test(true, 2) 3099 test(false, 3) 3100 test(false, 4) 3101 test(false, 5) 3102 3103 u.IsBanned = true 3104 msg = "banned users" 3105 test(true, 0) 3106 test(true, 1) 3107 test(true, 2) 3108 test(false, 3) 3109 test(false, 4) 3110 test(false, 5) 3111 u.IsBanned = false 3112 3113 u.IsMod = true 3114 msg = "mods" 3115 test(true, 0) 3116 test(true, 1) 3117 test(true, 2) 3118 test(false, 3) 3119 test(false, 4) 3120 test(false, 5) 3121 u.IsMod = false 3122 3123 u.IsSuperMod = true 3124 msg = "super mods" 3125 test(true, 0) 3126 test(true, 1) 3127 test(true, 2) 3128 test(false, 3) 3129 test(false, 4) 3130 test(false, 5) 3131 u.IsSuperMod = false 3132 3133 u.IsAdmin = true 3134 msg = "admins" 3135 test(true, 0) 3136 test(true, 1) 3137 test(true, 2) 3138 test(false, 3) 3139 test(false, 4) 3140 test(false, 5) 3141 u.IsAdmin = false 3142 3143 u.IsSuperAdmin = true 3144 msg = "super admins" 3145 test(true, 0) 3146 test(true, 1) 3147 test(true, 2) 3148 test(false, 3) 3149 test(false, 4) 3150 test(false, 5) 3151 u.IsSuperAdmin = false 3152 3153 u.ID = 1 3154 test(true, 0) 3155 test(true, 1) 3156 test(true, 2) 3157 test(true, 3) 3158 test(true, 4) 3159 test(false, 5) 3160 } 3161 3162 type METri struct { 3163 Name string // Optional, this is here for tests involving invisible characters so we know what's going in 3164 Msg string 3165 Expects string 3166 } 3167 3168 type METriList struct { 3169 Items []METri 3170 } 3171 3172 func (l *METriList) Add(args ...string) { 3173 if len(args) < 2 { 3174 panic("need 2 or more args") 3175 } 3176 if len(args) > 2 { 3177 l.Items = append(l.Items, METri{args[0], args[1], args[2]}) 3178 } else { 3179 l.Items = append(l.Items, METri{"", args[0], args[1]}) 3180 } 3181 } 3182 3183 type CountTest struct { 3184 Name string 3185 Msg string 3186 Expects int 3187 } 3188 3189 type CountTestList struct { 3190 Items []CountTest 3191 } 3192 3193 func (l *CountTestList) Add(name, msg string, expects int) { 3194 l.Items = append(l.Items, CountTest{name, msg, expects}) 3195 } 3196 3197 func TestWordCount(t *testing.T) { 3198 l := &CountTestList{nil} 3199 l.Add("blank", "", 0) 3200 l.Add("single-letter", "h", 1) 3201 l.Add("single-kana", "γ", 1) 3202 l.Add("single-letter-words", "h h", 2) 3203 l.Add("two-letter", "h", 1) 3204 l.Add("two-kana", "γγ―", 1) 3205 l.Add("two-letter-words", "hh hh", 2) 3206 l.Add("", "h,h", 2) 3207 l.Add("", "h,,h", 2) 3208 l.Add("", "h, h", 2) 3209 l.Add("", " h, h", 2) 3210 l.Add("", "h, h ", 2) 3211 l.Add("", " h, h ", 2) 3212 l.Add("", "h, h", 2) 3213 l.Add("", "h\nh", 2) 3214 l.Add("", "h\"h", 2) 3215 l.Add("", "h[r]h", 3) 3216 l.Add("", "γ,γ", 2) 3217 l.Add("", "γγγ", 2) 3218 l.Add("", "γ\nγ", 2) 3219 l.Add("", "γβγ", 2) 3220 l.Add("", "γγγγγ", 3) 3221 3222 for _, item := range l.Items { 3223 res := c.WordCount(item.Msg) 3224 if res != item.Expects { 3225 if item.Name != "" { 3226 t.Error("Name: ", item.Name) 3227 } 3228 t.Error("Testing string '" + item.Msg + "'") 3229 t.Error("Bad output:", res) 3230 t.Error("Expected:", item.Expects) 3231 } 3232 } 3233 } 3234 3235 func TestTick(t *testing.T) { 3236 expectNilErr(t, c.StartupTasks()) 3237 expectNilErr(t, c.Dailies()) 3238 3239 expectNilErr(t, c.Tasks.HalfSec.Run()) 3240 expectNilErr(t, c.Tasks.Sec.Run()) 3241 expectNilErr(t, c.Tasks.FifteenMin.Run()) 3242 expectNilErr(t, c.Tasks.Hour.Run()) 3243 expectNilErr(t, c.Tasks.Day.Run()) 3244 3245 thumbChan := make(chan bool) 3246 expectNilErr(t, tickLoop(thumbChan)) 3247 expectNilErr(t, c.CTickLoop.HalfSecf()) 3248 expectNilErr(t, c.CTickLoop.Secf()) 3249 expectNilErr(t, c.CTickLoop.FifteenMinf()) 3250 expectNilErr(t, c.CTickLoop.Hourf()) 3251 expectNilErr(t, c.CTickLoop.Dayf()) 3252 } 3253 3254 func TestWSHub(t *testing.T) { 3255 ex, exf, h := exp(t), expf(t), &c.WsHub 3256 exf(h.GuestCount() == 0, "GuestCount should be %d not %d", 0, h.GuestCount()) 3257 exf(h.UserCount() == 0, "UserCount should be %d not %d", 0, h.UserCount()) 3258 ex(!h.HasUser(-1), "HasUser(-1) should be false") 3259 ex(!h.HasUser(0), "HasUser(0) should be false") 3260 ex(!h.HasUser(1), "HasUser(1) should be false") 3261 3262 uid, e := c.Users.Create("WsHub Test", "WsHub Test", "", 1, true) 3263 expectNilErr(t, e) 3264 exf(!h.HasUser(uid), "HasUser(%d) should be false", uid) 3265 exf(len(h.AllUsers()) == 0, "len(AllUsers()) should be %d not %d", 0, len(h.AllUsers())) 3266 3267 f := func(uid, guestCount, userCount, allUserListLen int, hasUser bool) { 3268 exf(h.GuestCount() == guestCount, "GuestCount should be %d not %d", guestCount, h.GuestCount()) 3269 exf(h.UserCount() == userCount, "UserCount should be %d not %d", userCount, h.UserCount()) 3270 exf(len(h.AllUsers()) == allUserListLen, "len(AllUsers()) should be %d not %d", allUserListLen, len(h.AllUsers())) 3271 if hasUser { 3272 exf(h.HasUser(uid), "HasUser(%d) should be true", uid) 3273 } else { 3274 exf(!h.HasUser(uid), "HasUser(%d) should be false", uid) 3275 } 3276 } 3277 3278 u, e := c.Users.Get(uid) 3279 expectNilErr(t, e) 3280 wsUser, e := h.AddConn(u, nil) 3281 expectNilErr(t, e) 3282 f(uid, 0, 1, 1, true) 3283 3284 uid, e = c.Users.Create("WsHub Test 2", "WsHub Test 2", "", 1, true) 3285 expectNilErr(t, e) 3286 u2, e := c.Users.Get(uid) 3287 expectNilErr(t, e) 3288 wsUser2, e := h.AddConn(u2, nil) 3289 expectNilErr(t, e) 3290 f(uid, 0, 2, 2, true) 3291 3292 h.RemoveConn(wsUser2, nil) 3293 f(uid, 0, 1, 1, false) 3294 h.RemoveConn(wsUser2, nil) 3295 f(uid, 0, 1, 1, false) 3296 h.RemoveConn(wsUser, nil) 3297 f(uid, 0, 0, 0, false) 3298 3299 countSockets := func(wsUser *c.WSUser, expect int) { 3300 exf(wsUser.CountSockets() == expect, "CountSockets() should be %d not %d", expect, wsUser.CountSockets()) 3301 } 3302 wsUser2, e = h.AddConn(u2, nil) 3303 expectNilErr(t, e) 3304 f(uid, 0, 1, 1, true) 3305 countSockets(wsUser2, 1) 3306 wsUser2.RemoveSocket(nil) 3307 f(uid, 0, 1, 1, true) 3308 countSockets(wsUser2, 0) 3309 h.RemoveConn(wsUser2, nil) 3310 f(uid, 0, 0, 0, false) 3311 countSockets(wsUser2, 0) 3312 3313 wsUser2, e = h.AddConn(u2, nil) 3314 expectNilErr(t, e) 3315 f(uid, 0, 1, 1, true) 3316 countSockets(wsUser2, 1) 3317 expectNilErr(t, wsUser2.Ping()) 3318 f(uid, 0, 1, 1, true) 3319 countSockets(wsUser2, 0) 3320 h.RemoveConn(wsUser2, nil) 3321 f(uid, 0, 0, 0, false) 3322 countSockets(wsUser2, 0) 3323 3324 // TODO: Add more tests 3325 }