You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

user_test.go 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package user_test
  4. import (
  5. "context"
  6. "fmt"
  7. "math/rand"
  8. "strings"
  9. "testing"
  10. "time"
  11. "code.gitea.io/gitea/models/auth"
  12. "code.gitea.io/gitea/models/db"
  13. "code.gitea.io/gitea/models/unittest"
  14. user_model "code.gitea.io/gitea/models/user"
  15. "code.gitea.io/gitea/modules/auth/password/hash"
  16. "code.gitea.io/gitea/modules/optional"
  17. "code.gitea.io/gitea/modules/setting"
  18. "code.gitea.io/gitea/modules/structs"
  19. "code.gitea.io/gitea/modules/timeutil"
  20. "github.com/stretchr/testify/assert"
  21. )
  22. func TestOAuth2Application_LoadUser(t *testing.T) {
  23. assert.NoError(t, unittest.PrepareTestDatabase())
  24. app := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: 1})
  25. user, err := user_model.GetUserByID(db.DefaultContext, app.UID)
  26. assert.NoError(t, err)
  27. assert.NotNil(t, user)
  28. }
  29. func TestGetUserEmailsByNames(t *testing.T) {
  30. assert.NoError(t, unittest.PrepareTestDatabase())
  31. // ignore none active user email
  32. assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user9"}))
  33. assert.ElementsMatch(t, []string{"user8@example.com", "user5@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user5"}))
  34. assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "org7"}))
  35. }
  36. func TestCanCreateOrganization(t *testing.T) {
  37. assert.NoError(t, unittest.PrepareTestDatabase())
  38. admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
  39. assert.True(t, admin.CanCreateOrganization())
  40. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  41. assert.True(t, user.CanCreateOrganization())
  42. // Disable user create organization permission.
  43. user.AllowCreateOrganization = false
  44. assert.False(t, user.CanCreateOrganization())
  45. setting.Admin.DisableRegularOrgCreation = true
  46. user.AllowCreateOrganization = true
  47. assert.True(t, admin.CanCreateOrganization())
  48. assert.False(t, user.CanCreateOrganization())
  49. }
  50. func TestSearchUsers(t *testing.T) {
  51. assert.NoError(t, unittest.PrepareTestDatabase())
  52. testSuccess := func(opts *user_model.SearchUserOptions, expectedUserOrOrgIDs []int64) {
  53. users, _, err := user_model.SearchUsers(db.DefaultContext, opts)
  54. assert.NoError(t, err)
  55. cassText := fmt.Sprintf("ids: %v, opts: %v", expectedUserOrOrgIDs, opts)
  56. if assert.Len(t, users, len(expectedUserOrOrgIDs), "case: %s", cassText) {
  57. for i, expectedID := range expectedUserOrOrgIDs {
  58. assert.EqualValues(t, expectedID, users[i].ID, "case: %s", cassText)
  59. }
  60. }
  61. }
  62. // test orgs
  63. testOrgSuccess := func(opts *user_model.SearchUserOptions, expectedOrgIDs []int64) {
  64. opts.Type = user_model.UserTypeOrganization
  65. testSuccess(opts, expectedOrgIDs)
  66. }
  67. testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1, PageSize: 2}},
  68. []int64{3, 6})
  69. testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 2, PageSize: 2}},
  70. []int64{7, 17})
  71. testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 3, PageSize: 2}},
  72. []int64{19, 25})
  73. testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 4, PageSize: 2}},
  74. []int64{26, 41})
  75. testOrgSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 5, PageSize: 2}},
  76. []int64{})
  77. // test users
  78. testUserSuccess := func(opts *user_model.SearchUserOptions, expectedUserIDs []int64) {
  79. opts.Type = user_model.UserTypeIndividual
  80. testSuccess(opts, expectedUserIDs)
  81. }
  82. testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
  83. []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
  84. testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(false)},
  85. []int64{9})
  86. testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
  87. []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
  88. testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
  89. []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
  90. // order by name asc default
  91. testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
  92. []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
  93. testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: optional.Some(true)},
  94. []int64{1})
  95. testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: optional.Some(true)},
  96. []int64{29})
  97. testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: optional.Some(true)},
  98. []int64{37})
  99. testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: optional.Some(true)},
  100. []int64{24})
  101. }
  102. func TestEmailNotificationPreferences(t *testing.T) {
  103. assert.NoError(t, unittest.PrepareTestDatabase())
  104. for _, test := range []struct {
  105. expected string
  106. userID int64
  107. }{
  108. {user_model.EmailNotificationsEnabled, 1},
  109. {user_model.EmailNotificationsEnabled, 2},
  110. {user_model.EmailNotificationsOnMention, 3},
  111. {user_model.EmailNotificationsOnMention, 4},
  112. {user_model.EmailNotificationsEnabled, 5},
  113. {user_model.EmailNotificationsEnabled, 6},
  114. {user_model.EmailNotificationsDisabled, 7},
  115. {user_model.EmailNotificationsEnabled, 8},
  116. {user_model.EmailNotificationsOnMention, 9},
  117. } {
  118. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.userID})
  119. assert.Equal(t, test.expected, user.EmailNotificationsPreference)
  120. }
  121. }
  122. func TestHashPasswordDeterministic(t *testing.T) {
  123. b := make([]byte, 16)
  124. u := &user_model.User{}
  125. algos := hash.RecommendedHashAlgorithms
  126. for j := 0; j < len(algos); j++ {
  127. u.PasswdHashAlgo = algos[j]
  128. for i := 0; i < 50; i++ {
  129. // generate a random password
  130. rand.Read(b)
  131. pass := string(b)
  132. // save the current password in the user - hash it and store the result
  133. u.SetPassword(pass)
  134. r1 := u.Passwd
  135. // run again
  136. u.SetPassword(pass)
  137. r2 := u.Passwd
  138. assert.NotEqual(t, r1, r2)
  139. assert.True(t, u.ValidatePassword(pass))
  140. }
  141. }
  142. }
  143. func BenchmarkHashPassword(b *testing.B) {
  144. // BenchmarkHashPassword ensures that it takes a reasonable amount of time
  145. // to hash a password - in order to protect from brute-force attacks.
  146. pass := "password1337"
  147. u := &user_model.User{Passwd: pass}
  148. b.ResetTimer()
  149. for i := 0; i < b.N; i++ {
  150. u.SetPassword(pass)
  151. }
  152. }
  153. func TestNewGitSig(t *testing.T) {
  154. users := make([]*user_model.User, 0, 20)
  155. err := db.GetEngine(db.DefaultContext).Find(&users)
  156. assert.NoError(t, err)
  157. for _, user := range users {
  158. sig := user.NewGitSig()
  159. assert.NotContains(t, sig.Name, "<")
  160. assert.NotContains(t, sig.Name, ">")
  161. assert.NotContains(t, sig.Name, "\n")
  162. assert.NotEqual(t, len(strings.TrimSpace(sig.Name)), 0)
  163. }
  164. }
  165. func TestDisplayName(t *testing.T) {
  166. users := make([]*user_model.User, 0, 20)
  167. err := db.GetEngine(db.DefaultContext).Find(&users)
  168. assert.NoError(t, err)
  169. for _, user := range users {
  170. displayName := user.DisplayName()
  171. assert.Equal(t, strings.TrimSpace(displayName), displayName)
  172. if len(strings.TrimSpace(user.FullName)) == 0 {
  173. assert.Equal(t, user.Name, displayName)
  174. }
  175. assert.NotEqual(t, len(strings.TrimSpace(displayName)), 0)
  176. }
  177. }
  178. func TestCreateUserInvalidEmail(t *testing.T) {
  179. user := &user_model.User{
  180. Name: "GiteaBot",
  181. Email: "GiteaBot@gitea.io\r\n",
  182. Passwd: ";p['////..-++']",
  183. IsAdmin: false,
  184. Theme: setting.UI.DefaultTheme,
  185. MustChangePassword: false,
  186. }
  187. err := user_model.CreateUser(db.DefaultContext, user)
  188. assert.Error(t, err)
  189. assert.True(t, user_model.IsErrEmailCharIsNotSupported(err))
  190. }
  191. func TestCreateUserEmailAlreadyUsed(t *testing.T) {
  192. assert.NoError(t, unittest.PrepareTestDatabase())
  193. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  194. // add new user with user2's email
  195. user.Name = "testuser"
  196. user.LowerName = strings.ToLower(user.Name)
  197. user.ID = 0
  198. err := user_model.CreateUser(db.DefaultContext, user)
  199. assert.Error(t, err)
  200. assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
  201. }
  202. func TestCreateUserCustomTimestamps(t *testing.T) {
  203. assert.NoError(t, unittest.PrepareTestDatabase())
  204. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  205. // Add new user with a custom creation timestamp.
  206. var creationTimestamp timeutil.TimeStamp = 12345
  207. user.Name = "testuser"
  208. user.LowerName = strings.ToLower(user.Name)
  209. user.ID = 0
  210. user.Email = "unique@example.com"
  211. user.CreatedUnix = creationTimestamp
  212. err := user_model.CreateUser(db.DefaultContext, user)
  213. assert.NoError(t, err)
  214. fetched, err := user_model.GetUserByID(context.Background(), user.ID)
  215. assert.NoError(t, err)
  216. assert.Equal(t, creationTimestamp, fetched.CreatedUnix)
  217. assert.Equal(t, creationTimestamp, fetched.UpdatedUnix)
  218. }
  219. func TestCreateUserWithoutCustomTimestamps(t *testing.T) {
  220. assert.NoError(t, unittest.PrepareTestDatabase())
  221. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  222. // There is no way to use a mocked time for the XORM auto-time functionality,
  223. // so use the real clock to approximate the expected timestamp.
  224. timestampStart := time.Now().Unix()
  225. // Add new user without a custom creation timestamp.
  226. user.Name = "Testuser"
  227. user.LowerName = strings.ToLower(user.Name)
  228. user.ID = 0
  229. user.Email = "unique@example.com"
  230. user.CreatedUnix = 0
  231. user.UpdatedUnix = 0
  232. err := user_model.CreateUser(db.DefaultContext, user)
  233. assert.NoError(t, err)
  234. timestampEnd := time.Now().Unix()
  235. fetched, err := user_model.GetUserByID(context.Background(), user.ID)
  236. assert.NoError(t, err)
  237. assert.LessOrEqual(t, timestampStart, fetched.CreatedUnix)
  238. assert.LessOrEqual(t, fetched.CreatedUnix, timestampEnd)
  239. assert.LessOrEqual(t, timestampStart, fetched.UpdatedUnix)
  240. assert.LessOrEqual(t, fetched.UpdatedUnix, timestampEnd)
  241. }
  242. func TestGetUserIDsByNames(t *testing.T) {
  243. assert.NoError(t, unittest.PrepareTestDatabase())
  244. // ignore non existing
  245. IDs, err := user_model.GetUserIDsByNames(db.DefaultContext, []string{"user1", "user2", "none_existing_user"}, true)
  246. assert.NoError(t, err)
  247. assert.Equal(t, []int64{1, 2}, IDs)
  248. // ignore non existing
  249. IDs, err = user_model.GetUserIDsByNames(db.DefaultContext, []string{"user1", "do_not_exist"}, false)
  250. assert.Error(t, err)
  251. assert.Equal(t, []int64(nil), IDs)
  252. }
  253. func TestGetMaileableUsersByIDs(t *testing.T) {
  254. assert.NoError(t, unittest.PrepareTestDatabase())
  255. results, err := user_model.GetMaileableUsersByIDs(db.DefaultContext, []int64{1, 4}, false)
  256. assert.NoError(t, err)
  257. assert.Len(t, results, 1)
  258. if len(results) > 1 {
  259. assert.Equal(t, results[0].ID, 1)
  260. }
  261. results, err = user_model.GetMaileableUsersByIDs(db.DefaultContext, []int64{1, 4}, true)
  262. assert.NoError(t, err)
  263. assert.Len(t, results, 2)
  264. if len(results) > 2 {
  265. assert.Equal(t, results[0].ID, 1)
  266. assert.Equal(t, results[1].ID, 4)
  267. }
  268. }
  269. func TestNewUserRedirect(t *testing.T) {
  270. // redirect to a completely new name
  271. assert.NoError(t, unittest.PrepareTestDatabase())
  272. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
  273. assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername"))
  274. unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
  275. LowerName: user.LowerName,
  276. RedirectUserID: user.ID,
  277. })
  278. unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
  279. LowerName: "olduser1",
  280. RedirectUserID: user.ID,
  281. })
  282. }
  283. func TestNewUserRedirect2(t *testing.T) {
  284. // redirect to previously used name
  285. assert.NoError(t, unittest.PrepareTestDatabase())
  286. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
  287. assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "olduser1"))
  288. unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
  289. LowerName: user.LowerName,
  290. RedirectUserID: user.ID,
  291. })
  292. unittest.AssertNotExistsBean(t, &user_model.Redirect{
  293. LowerName: "olduser1",
  294. RedirectUserID: user.ID,
  295. })
  296. }
  297. func TestNewUserRedirect3(t *testing.T) {
  298. // redirect for a previously-unredirected user
  299. assert.NoError(t, unittest.PrepareTestDatabase())
  300. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  301. assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername"))
  302. unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
  303. LowerName: user.LowerName,
  304. RedirectUserID: user.ID,
  305. })
  306. }
  307. func TestGetUserByOpenID(t *testing.T) {
  308. assert.NoError(t, unittest.PrepareTestDatabase())
  309. _, err := user_model.GetUserByOpenID(db.DefaultContext, "https://unknown")
  310. if assert.Error(t, err) {
  311. assert.True(t, user_model.IsErrUserNotExist(err))
  312. }
  313. user, err := user_model.GetUserByOpenID(db.DefaultContext, "https://user1.domain1.tld")
  314. if assert.NoError(t, err) {
  315. assert.Equal(t, int64(1), user.ID)
  316. }
  317. user, err = user_model.GetUserByOpenID(db.DefaultContext, "https://domain1.tld/user2/")
  318. if assert.NoError(t, err) {
  319. assert.Equal(t, int64(2), user.ID)
  320. }
  321. }
  322. func TestFollowUser(t *testing.T) {
  323. assert.NoError(t, unittest.PrepareTestDatabase())
  324. testSuccess := func(follower, followed *user_model.User) {
  325. assert.NoError(t, user_model.FollowUser(db.DefaultContext, follower, followed))
  326. unittest.AssertExistsAndLoadBean(t, &user_model.Follow{UserID: follower.ID, FollowID: followed.ID})
  327. }
  328. user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  329. user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
  330. user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
  331. testSuccess(user4, user2)
  332. testSuccess(user5, user2)
  333. assert.NoError(t, user_model.FollowUser(db.DefaultContext, user2, user2))
  334. unittest.CheckConsistencyFor(t, &user_model.User{})
  335. }
  336. func TestUnfollowUser(t *testing.T) {
  337. assert.NoError(t, unittest.PrepareTestDatabase())
  338. testSuccess := func(followerID, followedID int64) {
  339. assert.NoError(t, user_model.UnfollowUser(db.DefaultContext, followerID, followedID))
  340. unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: followerID, FollowID: followedID})
  341. }
  342. testSuccess(4, 2)
  343. testSuccess(5, 2)
  344. testSuccess(2, 2)
  345. unittest.CheckConsistencyFor(t, &user_model.User{})
  346. }
  347. func TestIsUserVisibleToViewer(t *testing.T) {
  348. assert.NoError(t, unittest.PrepareTestDatabase())
  349. user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) // admin, public
  350. user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // normal, public
  351. user20 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}) // public, same team as user31
  352. user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}) // public, is restricted
  353. user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31}) // private, same team as user20
  354. user33 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 33}) // limited, follows 31
  355. test := func(u, viewer *user_model.User, expected bool) {
  356. name := func(u *user_model.User) string {
  357. if u == nil {
  358. return "<nil>"
  359. }
  360. return u.Name
  361. }
  362. assert.Equal(t, expected, user_model.IsUserVisibleToViewer(db.DefaultContext, u, viewer), "user %v should be visible to viewer %v: %v", name(u), name(viewer), expected)
  363. }
  364. // admin viewer
  365. test(user1, user1, true)
  366. test(user20, user1, true)
  367. test(user31, user1, true)
  368. test(user33, user1, true)
  369. // non admin viewer
  370. test(user4, user4, true)
  371. test(user20, user4, true)
  372. test(user31, user4, false)
  373. test(user33, user4, true)
  374. test(user4, nil, true)
  375. // public user
  376. test(user4, user20, true)
  377. test(user4, user31, true)
  378. test(user4, user33, true)
  379. // limited user
  380. test(user33, user33, true)
  381. test(user33, user4, true)
  382. test(user33, user29, false)
  383. test(user33, nil, false)
  384. // private user
  385. test(user31, user31, true)
  386. test(user31, user4, false)
  387. test(user31, user20, true)
  388. test(user31, user29, false)
  389. test(user31, user33, true)
  390. test(user31, nil, false)
  391. }
  392. func Test_ValidateUser(t *testing.T) {
  393. oldSetting := setting.Service.AllowedUserVisibilityModesSlice
  394. defer func() {
  395. setting.Service.AllowedUserVisibilityModesSlice = oldSetting
  396. }()
  397. setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, true}
  398. kases := map[*user_model.User]bool{
  399. {ID: 1, Visibility: structs.VisibleTypePublic}: true,
  400. {ID: 2, Visibility: structs.VisibleTypeLimited}: false,
  401. {ID: 2, Visibility: structs.VisibleTypePrivate}: true,
  402. }
  403. for kase, expected := range kases {
  404. assert.EqualValues(t, expected, nil == user_model.ValidateUser(kase), fmt.Sprintf("case: %+v", kase))
  405. }
  406. }
  407. func Test_NormalizeUserFromEmail(t *testing.T) {
  408. testCases := []struct {
  409. Input string
  410. Expected string
  411. IsNormalizedValid bool
  412. }{
  413. {"test", "test", true},
  414. {"Sinéad.O'Connor", "Sinead.OConnor", true},
  415. {"Æsir", "AEsir", true},
  416. // \u00e9\u0065\u0301
  417. {"éé", "ee", true},
  418. {"Awareness Hub", "Awareness-Hub", true},
  419. {"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters
  420. {".bad.", ".bad.", false},
  421. {"new😀user", "new😀user", false}, // No plans to support
  422. }
  423. for _, testCase := range testCases {
  424. normalizedName, err := user_model.NormalizeUserName(testCase.Input)
  425. assert.NoError(t, err)
  426. assert.EqualValues(t, testCase.Expected, normalizedName)
  427. if testCase.IsNormalizedValid {
  428. assert.NoError(t, user_model.IsUsableUsername(normalizedName))
  429. } else {
  430. assert.Error(t, user_model.IsUsableUsername(normalizedName))
  431. }
  432. }
  433. }