package repository import ( "context" "fmt" "sync/atomic" "testing" gormsqlite "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" _ "modernc.org/sqlite" "github.com/user-management-system/internal/domain" ) var socialAccountTestCounter int64 func openSocialAccountTestDB(t *testing.T) *gorm.DB { t.Helper() id := atomic.AddInt64(&socialAccountTestCounter, 1) dsn := fmt.Sprintf("file:socialaccounttestdb%d?mode=memory&cache=private", id) db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{ DriverName: "sqlite", DSN: dsn, }), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) if err != nil { t.Fatalf("打开测试数据库失败: %v", err) } if err := db.AutoMigrate(&domain.SocialAccount{}); err != nil { t.Fatalf("数据库迁移失败: %v", err) } return db } func setupSocialAccountTestDB(t *testing.T) *gorm.DB { return openSocialAccountTestDB(t) } func TestSocialAccountRepository_Create(t *testing.T) { db := setupSocialAccountTestDB(t) repo, err := NewSocialAccountRepository(db) if err != nil { t.Fatalf("NewSocialAccountRepository() error = %v", err) } ctx := context.Background() account := &domain.SocialAccount{ UserID: 1, Provider: "github", OpenID: "openid-123", Nickname: "testuser", Status: domain.SocialAccountStatusActive, } if err := repo.Create(ctx, account); err != nil { t.Fatalf("Create() error = %v", err) } if account.ID == 0 { t.Error("创建后账户ID不应为0") } } func TestSocialAccountRepository_GetByID(t *testing.T) { db := setupSocialAccountTestDB(t) repo, err := NewSocialAccountRepository(db) if err != nil { t.Fatalf("NewSocialAccountRepository() error = %v", err) } ctx := context.Background() account := &domain.SocialAccount{ UserID: 1, Provider: "github", OpenID: "openid-getbyid", Nickname: "getbyid-user", Status: domain.SocialAccountStatusActive, } repo.Create(ctx, account) found, err := repo.GetByID(ctx, account.ID) if err != nil { t.Fatalf("GetByID() error = %v", err) } if found.Nickname != "getbyid-user" { t.Errorf("Nickname = %v, want getbyid-user", found.Nickname) } } func TestSocialAccountRepository_GetByUserID(t *testing.T) { db := setupSocialAccountTestDB(t) repo, err := NewSocialAccountRepository(db) if err != nil { t.Fatalf("NewSocialAccountRepository() error = %v", err) } ctx := context.Background() repo.Create(ctx, &domain.SocialAccount{ UserID: 1, Provider: "github", OpenID: "openid-user1-1", Status: domain.SocialAccountStatusActive, }) repo.Create(ctx, &domain.SocialAccount{ UserID: 1, Provider: "wechat", OpenID: "openid-user1-2", Status: domain.SocialAccountStatusActive, }) repo.Create(ctx, &domain.SocialAccount{ UserID: 2, Provider: "github", OpenID: "openid-user2", Status: domain.SocialAccountStatusActive, }) accounts, err := repo.GetByUserID(ctx, 1) if err != nil { t.Fatalf("GetByUserID() error = %v", err) } if len(accounts) != 2 { t.Errorf("len(accounts) = %d, want 2", len(accounts)) } } func TestSocialAccountRepository_GetByProviderAndOpenID(t *testing.T) { db := setupSocialAccountTestDB(t) repo, err := NewSocialAccountRepository(db) if err != nil { t.Fatalf("NewSocialAccountRepository() error = %v", err) } ctx := context.Background() account := &domain.SocialAccount{ UserID: 1, Provider: "github", OpenID: "unique-openid-123", Nickname: "github-user", Status: domain.SocialAccountStatusActive, } repo.Create(ctx, account) found, err := repo.GetByProviderAndOpenID(ctx, "github", "unique-openid-123") if err != nil { t.Fatalf("GetByProviderAndOpenID() error = %v", err) } if found.UserID != 1 { t.Errorf("UserID = %d, want 1", found.UserID) } } func TestSocialAccountRepository_Update(t *testing.T) { db := setupSocialAccountTestDB(t) repo, err := NewSocialAccountRepository(db) if err != nil { t.Fatalf("NewSocialAccountRepository() error = %v", err) } ctx := context.Background() account := &domain.SocialAccount{ UserID: 1, Provider: "github", OpenID: "openid-update", Nickname: "before-update", Status: domain.SocialAccountStatusActive, } repo.Create(ctx, account) account.Nickname = "after-update" if err := repo.Update(ctx, account); err != nil { t.Fatalf("Update() error = %v", err) } found, _ := repo.GetByID(ctx, account.ID) if found.Nickname != "after-update" { t.Errorf("Nickname = %v, want after-update", found.Nickname) } } func TestSocialAccountRepository_Delete(t *testing.T) { db := setupSocialAccountTestDB(t) repo, err := NewSocialAccountRepository(db) if err != nil { t.Fatalf("NewSocialAccountRepository() error = %v", err) } ctx := context.Background() account := &domain.SocialAccount{ UserID: 1, Provider: "github", OpenID: "openid-delete", Status: domain.SocialAccountStatusActive, } repo.Create(ctx, account) if err := repo.Delete(ctx, account.ID); err != nil { t.Fatalf("Delete() error = %v", err) } } func TestSocialAccountRepository_DeleteByProviderAndUserID(t *testing.T) { db := setupSocialAccountTestDB(t) repo, err := NewSocialAccountRepository(db) if err != nil { t.Fatalf("NewSocialAccountRepository() error = %v", err) } ctx := context.Background() repo.Create(ctx, &domain.SocialAccount{ UserID: 1, Provider: "github", OpenID: "openid-del-provider", Status: domain.SocialAccountStatusActive, }) err = repo.DeleteByProviderAndUserID(ctx, "github", 1) if err != nil { t.Fatalf("DeleteByProviderAndUserID() error = %v", err) } accounts, _ := repo.GetByUserID(ctx, 1) if len(accounts) != 0 { t.Errorf("len(accounts) = %d, want 0 after delete", len(accounts)) } } func TestSocialAccountRepository_List(t *testing.T) { db := setupSocialAccountTestDB(t) repo, err := NewSocialAccountRepository(db) if err != nil { t.Fatalf("NewSocialAccountRepository() error = %v", err) } ctx := context.Background() repo.Create(ctx, &domain.SocialAccount{ UserID: 1, Provider: "github", OpenID: "openid-list-1", Status: domain.SocialAccountStatusActive, }) repo.Create(ctx, &domain.SocialAccount{ UserID: 2, Provider: "wechat", OpenID: "openid-list-2", Status: domain.SocialAccountStatusActive, }) accounts, total, err := repo.List(ctx, 0, 10) if err != nil { t.Fatalf("List() error = %v", err) } if len(accounts) != 2 { t.Errorf("len(accounts) = %d, want 2", len(accounts)) } if total != 2 { t.Errorf("total = %d, want 2", total) } }