package repository import ( "context" "testing" "gorm.io/gorm" "github.com/user-management-system/internal/domain" ) func setupTestDB(t *testing.T) *gorm.DB { return openTestDB(t) } // TestUserRepository_Create 测试创建用户 func TestUserRepository_Create(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user := &domain.User{ Username: "testuser", Email: domain.StrPtr("test@example.com"), Phone: domain.StrPtr("13800138000"), Password: "hashedpassword", Status: domain.UserStatusActive, } if err := repo.Create(ctx, user); err != nil { t.Fatalf("Create() error = %v", err) } if user.ID == 0 { t.Error("创建后用户ID不应为0") } } // TestUserRepository_GetByUsername 测试根据用户名查询 func TestUserRepository_GetByUsername(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user := &domain.User{ Username: "findme", Email: domain.StrPtr("findme@example.com"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user) found, err := repo.GetByUsername(ctx, "findme") if err != nil { t.Fatalf("GetByUsername() error = %v", err) } if found.Username != "findme" { t.Errorf("Username = %v, want findme", found.Username) } _, err = repo.GetByUsername(ctx, "notexist") if err == nil { t.Error("查找不存在的用户应返回错误") } } // TestUserRepository_GetByEmail 测试根据邮箱查询 func TestUserRepository_GetByEmail(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user := &domain.User{ Username: "emailuser", Email: domain.StrPtr("email@example.com"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user) found, err := repo.GetByEmail(ctx, "email@example.com") if err != nil { t.Fatalf("GetByEmail() error = %v", err) } if domain.DerefStr(found.Email) != "email@example.com" { t.Errorf("Email = %v, want email@example.com", domain.DerefStr(found.Email)) } } // TestUserRepository_Update 测试更新用户 func TestUserRepository_Update(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user := &domain.User{ Username: "updateme", Email: domain.StrPtr("update@example.com"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user) user.Nickname = "已更新" if err := repo.Update(ctx, user); err != nil { t.Fatalf("Update() error = %v", err) } found, _ := repo.GetByID(ctx, user.ID) if found.Nickname != "已更新" { t.Errorf("Nickname = %v, want 已更新", found.Nickname) } } // TestUserRepository_Delete 测试删除用户 func TestUserRepository_Delete(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user := &domain.User{ Username: "deleteme", Email: domain.StrPtr("delete@example.com"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user) if err := repo.Delete(ctx, user.ID); err != nil { t.Fatalf("Delete() error = %v", err) } _, err := repo.GetByID(ctx, user.ID) if err == nil { t.Error("删除后查询应返回错误") } } // TestUserRepository_ExistsBy 测试存在性检查 func TestUserRepository_ExistsBy(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user := &domain.User{ Username: "existsuser", Email: domain.StrPtr("exists@example.com"), Phone: domain.StrPtr("13900139000"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user) ok, _ := repo.ExistsByUsername(ctx, "existsuser") if !ok { t.Error("ExistsByUsername 应返回 true") } ok, _ = repo.ExistsByEmail(ctx, "exists@example.com") if !ok { t.Error("ExistsByEmail 应返回 true") } ok, _ = repo.ExistsByPhone(ctx, "13900139000") if !ok { t.Error("ExistsByPhone 应返回 true") } ok, _ = repo.ExistsByUsername(ctx, "notexist") if ok { t.Error("不存在的用户 ExistsByUsername 应返回 false") } } // TestUserRepository_List 测试列表查询 func TestUserRepository_List(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() for i := 0; i < 5; i++ { repo.Create(ctx, &domain.User{ Username: "listuser" + string(rune('0'+i)), Password: "hash", Status: domain.UserStatusActive, }) } users, total, err := repo.List(ctx, 0, 10) if err != nil { t.Fatalf("List() error = %v", err) } if len(users) != 5 { t.Errorf("len(users) = %d, want 5", len(users)) } if total != 5 { t.Errorf("total = %d, want 5", total) } } // TestUserRepository_GetByPhone tests phone lookup func TestUserRepository_GetByPhone(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user := &domain.User{ Username: "phoneuser", Email: domain.StrPtr("phone@example.com"), Phone: domain.StrPtr("13700137000"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user) found, err := repo.GetByPhone(ctx, "13700137000") if err != nil { t.Fatalf("GetByPhone() error = %v", err) } if found.Username != "phoneuser" { t.Errorf("Username = %v, want phoneuser", found.Username) } } // TestUserRepository_ListByStatus tests status filtering func TestUserRepository_ListByStatus(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() repo.Create(ctx, &domain.User{ Username: "active1", Password: "hash", Status: domain.UserStatusActive, }) repo.Create(ctx, &domain.User{ Username: "active2", Password: "hash", Status: domain.UserStatusActive, }) repo.Create(ctx, &domain.User{ Username: "inactive1", Password: "hash", Status: domain.UserStatusInactive, }) users, total, err := repo.ListByStatus(ctx, domain.UserStatusActive, 0, 10) if err != nil { t.Fatalf("ListByStatus() 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_UpdateStatus tests status update func TestUserRepository_UpdateStatus(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user := &domain.User{ Username: "statususer", Email: domain.StrPtr("status@example.com"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user) err := repo.UpdateStatus(ctx, user.ID, domain.UserStatusInactive) if err != nil { t.Fatalf("UpdateStatus() error = %v", err) } found, _ := repo.GetByID(ctx, user.ID) if found.Status != domain.UserStatusInactive { t.Errorf("Status = %v, want Inactive", found.Status) } } // TestUserRepository_BatchUpdateStatus tests batch status update func TestUserRepository_BatchUpdateStatus(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user1 := &domain.User{ Username: "batch1", Email: domain.StrPtr("batch1@example.com"), Password: "hash", Status: domain.UserStatusActive, } user2 := &domain.User{ Username: "batch2", Email: domain.StrPtr("batch2@example.com"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user1) repo.Create(ctx, user2) err := repo.BatchUpdateStatus(ctx, []int64{user1.ID, user2.ID}, domain.UserStatusInactive) if err != nil { t.Fatalf("BatchUpdateStatus() error = %v", err) } found1, _ := repo.GetByID(ctx, user1.ID) found2, _ := repo.GetByID(ctx, user2.ID) if found1.Status != domain.UserStatusInactive || found2.Status != domain.UserStatusInactive { t.Error("BatchUpdateStatus failed") } } // TestUserRepository_BatchDelete tests batch delete func TestUserRepository_BatchDelete(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() user1 := &domain.User{ Username: "del1", Email: domain.StrPtr("del1@example.com"), Password: "hash", Status: domain.UserStatusActive, } user2 := &domain.User{ Username: "del2", Email: domain.StrPtr("del2@example.com"), Password: "hash", Status: domain.UserStatusActive, } repo.Create(ctx, user1) repo.Create(ctx, user2) err := repo.BatchDelete(ctx, []int64{user1.ID, user2.ID}) if err != nil { t.Fatalf("BatchDelete() error = %v", err) } _, err1 := repo.GetByID(ctx, user1.ID) _, err2 := repo.GetByID(ctx, user2.ID) if err1 == nil || err2 == nil { t.Error("BatchDelete should have deleted users") } } // TestUserRepository_Search tests user search func TestUserRepository_Search(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, }) users, total, err := repo.Search(ctx, "zhang", 0, 10) if err != nil { t.Fatalf("Search() 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) } } // TestUserRepository_Search_LikePattern tests search with LIKE special chars func TestUserRepository_Search_LikePattern(t *testing.T) { db := setupTestDB(t) repo := NewUserRepository(db) ctx := context.Background() repo.Create(ctx, &domain.User{ Username: "user%with%percent", Nickname: "测试用户", Email: domain.StrPtr("percent@example.com"), Password: "hash", Status: domain.UserStatusActive, }) // Search should handle LIKE special chars safely users, _, err := repo.Search(ctx, "%", 0, 10) if err != nil { t.Fatalf("Search() error = %v", err) } // Should not error and should escape properly _ = users }