mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
186 lines
6.3 KiB
Go
186 lines
6.3 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package user_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hanzoai/git/models/db"
|
|
"github.com/hanzoai/git/models/unittest"
|
|
user_model "github.com/hanzoai/git/models/user"
|
|
"github.com/hanzoai/git/modules/util"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestBadge(t *testing.T) {
|
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
|
|
t.Run("GetBadgeNotExist", testGetBadgeNotExist)
|
|
t.Run("CreateBadgeAlreadyExists", testCreateBadgeAlreadyExists)
|
|
t.Run("GetBadgeUsers", testGetBadgeUsers)
|
|
t.Run("AddAndRemoveUserBadges", testAddAndRemoveUserBadges)
|
|
t.Run("SearchBadgesOrderingAndKeyword", testSearchBadgesOrderingAndKeyword)
|
|
}
|
|
|
|
func testGetBadgeNotExist(t *testing.T) {
|
|
badge, err := user_model.GetBadge(t.Context(), "does-not-exist")
|
|
assert.Nil(t, badge)
|
|
assert.Error(t, err)
|
|
assert.ErrorIs(t, err, util.ErrNotExist)
|
|
}
|
|
|
|
func testCreateBadgeAlreadyExists(t *testing.T) {
|
|
badge := &user_model.Badge{
|
|
Slug: "duplicate-badge-slug",
|
|
Description: "First",
|
|
}
|
|
assert.NoError(t, user_model.CreateBadge(t.Context(), badge))
|
|
|
|
err := user_model.CreateBadge(t.Context(), &user_model.Badge{
|
|
Slug: "duplicate-badge-slug",
|
|
Description: "Second",
|
|
})
|
|
assert.Error(t, err)
|
|
assert.ErrorIs(t, err, util.ErrAlreadyExist)
|
|
}
|
|
|
|
func testGetBadgeUsers(t *testing.T) {
|
|
// Create a test badge
|
|
badge := &user_model.Badge{
|
|
Slug: "test-badge-users",
|
|
Description: "Test Badge",
|
|
ImageURL: "test.png",
|
|
}
|
|
assert.NoError(t, user_model.CreateBadge(t.Context(), badge))
|
|
|
|
// Create test users and assign badges
|
|
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
|
|
assert.NoError(t, user_model.AddUserBadge(t.Context(), user1, badge))
|
|
assert.NoError(t, user_model.AddUserBadge(t.Context(), user2, badge))
|
|
defer func() {
|
|
assert.NoError(t, user_model.RemoveUserBadge(t.Context(), user1, badge))
|
|
assert.NoError(t, user_model.RemoveUserBadge(t.Context(), user2, badge))
|
|
}()
|
|
|
|
// Test getting users with pagination
|
|
opts := &user_model.GetBadgeUsersOptions{
|
|
BadgeSlug: badge.Slug,
|
|
ListOptions: db.ListOptions{
|
|
Page: 1,
|
|
PageSize: 1,
|
|
},
|
|
}
|
|
|
|
users, count, err := user_model.GetBadgeUsers(t.Context(), opts)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 2, count)
|
|
assert.Len(t, users, 1)
|
|
|
|
// Test second page
|
|
opts.Page = 2
|
|
users, count, err = user_model.GetBadgeUsers(t.Context(), opts)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 2, count)
|
|
assert.Len(t, users, 1)
|
|
|
|
// Test with non-existent badge
|
|
opts.BadgeSlug = "non-existent"
|
|
users, count, err = user_model.GetBadgeUsers(t.Context(), opts)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 0, count)
|
|
assert.Empty(t, users)
|
|
}
|
|
|
|
func testAddAndRemoveUserBadges(t *testing.T) {
|
|
badge1 := unittest.AssertExistsAndLoadBean(t, &user_model.Badge{ID: 1})
|
|
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
|
|
// Add a badge to user and verify that it is returned in the list
|
|
assert.NoError(t, user_model.AddUserBadge(t.Context(), user1, badge1))
|
|
badges, count, err := user_model.GetUserBadges(t.Context(), user1)
|
|
assert.Equal(t, int64(1), count)
|
|
assert.Equal(t, badge1.Slug, badges[0].Slug)
|
|
assert.NoError(t, err)
|
|
|
|
// Confirm that it is impossible to duplicate the same badge
|
|
err = user_model.AddUserBadge(t.Context(), user1, badge1)
|
|
assert.Error(t, err)
|
|
assert.ErrorIs(t, err, util.ErrAlreadyExist)
|
|
|
|
// Nothing happened to the existing badge
|
|
badges, count, err = user_model.GetUserBadges(t.Context(), user1)
|
|
assert.Equal(t, int64(1), count)
|
|
assert.Equal(t, badge1.Slug, badges[0].Slug)
|
|
assert.NoError(t, err)
|
|
|
|
// Remove a badge from user and verify that it is no longer in the list
|
|
assert.NoError(t, user_model.RemoveUserBadge(t.Context(), user1, badge1))
|
|
_, count, err = user_model.GetUserBadges(t.Context(), user1)
|
|
assert.Equal(t, int64(0), count)
|
|
assert.NoError(t, err)
|
|
|
|
// Removing empty or missing badge selections should be a no-op.
|
|
assert.NoError(t, user_model.RemoveUserBadges(t.Context(), user1, nil))
|
|
assert.NoError(t, user_model.RemoveUserBadges(t.Context(), user1, []*user_model.Badge{{Slug: "does-not-exist"}}))
|
|
}
|
|
|
|
func testSearchBadgesOrderingAndKeyword(t *testing.T) {
|
|
createdBadges := []*user_model.Badge{
|
|
{Slug: "badge-sort-b", Description: "Badge Sort B"},
|
|
{Slug: "badge-sort-c", Description: "Badge Sort C"},
|
|
{Slug: "badge-sort-a", Description: "Badge Sort A"},
|
|
{Slug: "badge-sort-case", Description: "MiXeDCaSeKeyword"},
|
|
}
|
|
for _, badge := range createdBadges {
|
|
assert.NoError(t, user_model.CreateBadge(t.Context(), badge))
|
|
}
|
|
|
|
opts := &user_model.SearchBadgeOptions{
|
|
ListOptions: db.ListOptions{ListAll: true},
|
|
Keyword: "badge-sort-",
|
|
OrderBy: db.SearchOrderBy("`badge`.id ASC"),
|
|
}
|
|
|
|
oldestFirst, count, err := user_model.SearchBadges(t.Context(), opts)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 4, count)
|
|
assert.Equal(t, []string{"badge-sort-b", "badge-sort-c", "badge-sort-a", "badge-sort-case"}, collectBadgeSlugs(oldestFirst))
|
|
|
|
opts.OrderBy = db.SearchOrderBy("`badge`.id DESC")
|
|
newestFirst, count, err := user_model.SearchBadges(t.Context(), opts)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 4, count)
|
|
assert.Equal(t, []string{"badge-sort-case", "badge-sort-a", "badge-sort-c", "badge-sort-b"}, collectBadgeSlugs(newestFirst))
|
|
|
|
opts.OrderBy = db.SearchOrderBy("`badge`.slug ASC")
|
|
alpha, count, err := user_model.SearchBadges(t.Context(), opts)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 4, count)
|
|
assert.Equal(t, []string{"badge-sort-a", "badge-sort-b", "badge-sort-c", "badge-sort-case"}, collectBadgeSlugs(alpha))
|
|
|
|
opts.OrderBy = db.SearchOrderBy("`badge`.slug DESC")
|
|
reverseAlpha, count, err := user_model.SearchBadges(t.Context(), opts)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 4, count)
|
|
assert.Equal(t, []string{"badge-sort-case", "badge-sort-c", "badge-sort-b", "badge-sort-a"}, collectBadgeSlugs(reverseAlpha))
|
|
|
|
opts.Keyword = "mixedcasekeyword"
|
|
opts.OrderBy = db.SearchOrderBy("`badge`.slug ASC")
|
|
caseInsensitive, count, err := user_model.SearchBadges(t.Context(), opts)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 1, count)
|
|
assert.Equal(t, []string{"badge-sort-case"}, collectBadgeSlugs(caseInsensitive))
|
|
}
|
|
|
|
func collectBadgeSlugs(badges []*user_model.Badge) []string {
|
|
slugs := make([]string, 0, len(badges))
|
|
for _, badge := range badges {
|
|
slugs = append(slugs, badge.Slug)
|
|
}
|
|
return slugs
|
|
}
|