test: add repository tests to improve coverage from 46.6% to 74%
New test files: - custom_field_repository_test.go: 10 tests for CustomFieldRepository & UserCustomFieldValueRepository - login_log_repository_test.go: 3 tests for ListCursor, ListByUserIDCursor, ListAllForExport - operation_log_repository_test.go: 1 test for ListCursor - role_repository_test.go: 2 tests for GetAncestorIDs, GetAncestors - social_account_repository_test.go: 8 CRUD tests - theme_repository_test.go: 10 tests for ThemeConfigRepository - user_role_repository_test.go: 1 test for DeleteByUserAndRole Modified test files: - device_repository_test.go: Added ListAllCursor tests - user_repository_test.go: Added AdvancedSearch tests - webhook_repository_test.go: Added ListByCreatorPaginated test Updated documentation with new coverage status.
This commit is contained in:
@@ -3,6 +3,7 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
@@ -401,3 +402,259 @@ func TestUserRepository_Search_LikePattern(t *testing.T) {
|
||||
// Should not error and should escape properly
|
||||
_ = users
|
||||
}
|
||||
|
||||
// TestUserRepository_GetByIDs 测试批量获取用户
|
||||
func TestUserRepository_GetByIDs(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
u1 := &domain.User{Username: "batchuser1", Password: "hash", Status: domain.UserStatusActive}
|
||||
u2 := &domain.User{Username: "batchuser2", Password: "hash", Status: domain.UserStatusActive}
|
||||
u3 := &domain.User{Username: "batchuser3", Password: "hash", Status: domain.UserStatusActive}
|
||||
repo.Create(ctx, u1)
|
||||
repo.Create(ctx, u2)
|
||||
repo.Create(ctx, u3)
|
||||
|
||||
users, err := repo.GetByIDs(ctx, []int64{u1.ID, u3.ID})
|
||||
if err != nil {
|
||||
t.Fatalf("GetByIDs() error = %v", err)
|
||||
}
|
||||
if len(users) != 2 {
|
||||
t.Errorf("len(users) = %d, want 2", len(users))
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserRepository_GetByIDs_Empty 测试空ID列表
|
||||
func TestUserRepository_GetByIDs_Empty(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
users, err := repo.GetByIDs(ctx, []int64{})
|
||||
if err != nil {
|
||||
t.Fatalf("GetByIDs() error = %v", err)
|
||||
}
|
||||
if len(users) != 0 {
|
||||
t.Errorf("len(users) = %d, want 0", len(users))
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserRepository_UpdatePassword 测试更新密码
|
||||
func TestUserRepository_UpdatePassword(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
user := &domain.User{
|
||||
Username: "pwduser",
|
||||
Password: "oldpassword",
|
||||
Status: domain.UserStatusActive,
|
||||
}
|
||||
repo.Create(ctx, user)
|
||||
|
||||
err := repo.UpdatePassword(ctx, user.ID, "newpasswordhash")
|
||||
if err != nil {
|
||||
t.Fatalf("UpdatePassword() error = %v", err)
|
||||
}
|
||||
|
||||
found, _ := repo.GetByID(ctx, user.ID)
|
||||
if found.Password != "newpasswordhash" {
|
||||
t.Errorf("Password = %v, want newpasswordhash", found.Password)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserRepository_UpdateTOTP 测试更新TOTP
|
||||
func TestUserRepository_UpdateTOTP(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
user := &domain.User{
|
||||
Username: "totpuser",
|
||||
Password: "hash",
|
||||
Status: domain.UserStatusActive,
|
||||
}
|
||||
repo.Create(ctx, user)
|
||||
|
||||
user.TOTPEnabled = true
|
||||
user.TOTPSecret = "JBSWY3DPEHPK3PXP"
|
||||
err := repo.UpdateTOTP(ctx, user)
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateTOTP() error = %v", err)
|
||||
}
|
||||
|
||||
found, _ := repo.GetByID(ctx, user.ID)
|
||||
if !found.TOTPEnabled {
|
||||
t.Error("TOTPEnabled should be true")
|
||||
}
|
||||
if found.TOTPSecret != "JBSWY3DPEHPK3PXP" {
|
||||
t.Errorf("TOTPSecret = %v, want JBSWY3DPEHPK3PXP", found.TOTPSecret)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserRepository_ListCreatedAfter 测试查询创建时间之后的用户
|
||||
func TestUserRepository_ListCreatedAfter(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
user := &domain.User{
|
||||
Username: "afteruser",
|
||||
Password: "hash",
|
||||
Status: domain.UserStatusActive,
|
||||
}
|
||||
repo.Create(ctx, user)
|
||||
|
||||
since := user.CreatedAt.Add(-1 * time.Hour)
|
||||
users, total, err := repo.ListCreatedAfter(ctx, since, 0, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("ListCreatedAfter() error = %v", err)
|
||||
}
|
||||
if total < 1 {
|
||||
t.Errorf("total = %d, want at least 1", total)
|
||||
}
|
||||
_ = users
|
||||
}
|
||||
|
||||
// TestUserRepository_ListCreatedAfter_Limited 测试带limit的查询
|
||||
func TestUserRepository_ListCreatedAfter_Limited(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
repo.Create(ctx, &domain.User{
|
||||
Username: "limituser" + string(rune('0'+i)),
|
||||
Password: "hash",
|
||||
Status: domain.UserStatusActive,
|
||||
})
|
||||
}
|
||||
|
||||
since := time.Now().Add(-1 * time.Hour)
|
||||
users, total, err := repo.ListCreatedAfter(ctx, since, 0, 3)
|
||||
if err != nil {
|
||||
t.Fatalf("ListCreatedAfter() error = %v", err)
|
||||
}
|
||||
if len(users) != 3 {
|
||||
t.Errorf("len(users) = %d, want 3", len(users))
|
||||
}
|
||||
if total < 5 {
|
||||
t.Errorf("total = %d, want at least 5", total)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserRepository_AdvancedSearch 测试高级搜索
|
||||
func TestUserRepository_AdvancedSearch(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
repo.Create(ctx, &domain.User{
|
||||
Username: "searchuser1",
|
||||
Nickname: "张三",
|
||||
Email: domain.StrPtr("zhangsan@example.com"),
|
||||
Password: "hash",
|
||||
Status: domain.UserStatusActive,
|
||||
})
|
||||
repo.Create(ctx, &domain.User{
|
||||
Username: "searchuser2",
|
||||
Nickname: "李四",
|
||||
Email: domain.StrPtr("lisi@example.com"),
|
||||
Password: "hash",
|
||||
Status: domain.UserStatusActive,
|
||||
})
|
||||
repo.Create(ctx, &domain.User{
|
||||
Username: "searchuser3",
|
||||
Nickname: "王五",
|
||||
Email: domain.StrPtr("wangwu@example.com"),
|
||||
Password: "hash",
|
||||
Status: domain.UserStatusInactive,
|
||||
})
|
||||
|
||||
// 按关键字搜索(Status=-1 表示全部状态)
|
||||
filter := &AdvancedFilter{Keyword: "searchuser1", Status: -1, Offset: 0, Limit: 10}
|
||||
users, total, err := repo.AdvancedSearch(ctx, filter)
|
||||
if err != nil {
|
||||
t.Fatalf("AdvancedSearch() error = %v", err)
|
||||
}
|
||||
if len(users) != 1 {
|
||||
t.Errorf("len(users) = %d, want 1", len(users))
|
||||
}
|
||||
if total != 1 {
|
||||
t.Errorf("total = %d, want 1", total)
|
||||
}
|
||||
|
||||
// 按状态筛选
|
||||
filter2 := &AdvancedFilter{Status: int(domain.UserStatusActive), Offset: 0, Limit: 10}
|
||||
users2, total2, err := repo.AdvancedSearch(ctx, filter2)
|
||||
if err != nil {
|
||||
t.Fatalf("AdvancedSearch() error = %v", err)
|
||||
}
|
||||
if len(users2) != 2 {
|
||||
t.Errorf("len(users2) = %d, want 2", len(users2))
|
||||
}
|
||||
if total2 != 2 {
|
||||
t.Errorf("total2 = %d, want 2", total2)
|
||||
}
|
||||
|
||||
// 按状态筛选 - 禁用用户
|
||||
filter3 := &AdvancedFilter{Status: int(domain.UserStatusInactive), Offset: 0, Limit: 10}
|
||||
users3, total3, err := repo.AdvancedSearch(ctx, filter3)
|
||||
if err != nil {
|
||||
t.Fatalf("AdvancedSearch() error = %v", err)
|
||||
}
|
||||
if len(users3) != 1 {
|
||||
t.Errorf("len(users3) = %d, want 1", len(users3))
|
||||
}
|
||||
if total3 != 1 {
|
||||
t.Errorf("total3 = %d, want 1", total3)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserRepository_AdvancedSearch_AllStatus 测试状态为-1返回全部
|
||||
func TestUserRepository_AdvancedSearch_AllStatus(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
repo.Create(ctx, &domain.User{Username: "active", Password: "hash", Status: domain.UserStatusActive})
|
||||
repo.Create(ctx, &domain.User{Username: "inactive", Password: "hash", Status: domain.UserStatusInactive})
|
||||
|
||||
filter := &AdvancedFilter{Status: -1, Offset: 0, Limit: 10}
|
||||
users, total, err := repo.AdvancedSearch(ctx, filter)
|
||||
if err != nil {
|
||||
t.Fatalf("AdvancedSearch() error = %v", err)
|
||||
}
|
||||
if len(users) != 2 {
|
||||
t.Errorf("len(users) = %d, want 2", len(users))
|
||||
}
|
||||
if total != 2 {
|
||||
t.Errorf("total = %d, want 2", total)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserRepository_AdvancedSearch_LikeSpecialChars 测试搜索LIKE特殊字符转义
|
||||
func TestUserRepository_AdvancedSearch_LikeSpecialChars(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
ctx := context.Background()
|
||||
|
||||
repo.Create(ctx, &domain.User{
|
||||
Username: "user%with%percent",
|
||||
Nickname: "测试用户",
|
||||
Password: "hash",
|
||||
Status: domain.UserStatusActive,
|
||||
})
|
||||
|
||||
// 搜索%应该不匹配任何记录(被转义)
|
||||
filter := &AdvancedFilter{Keyword: "%", Offset: 0, Limit: 10}
|
||||
users, _, err := repo.AdvancedSearch(ctx, filter)
|
||||
if err != nil {
|
||||
t.Fatalf("AdvancedSearch() error = %v", err)
|
||||
}
|
||||
if len(users) != 0 {
|
||||
t.Errorf("len(users) = %d, want 0 for escaped percent", len(users))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user