//go:build unit package service import ( "context" "testing" "github.com/Wei-Shaw/sub2api/internal/pkg/pagination" "github.com/stretchr/testify/require" ) // groupRepoStubForAdmin 用于测试 AdminService 的 GroupRepository Stub type groupRepoStubForAdmin struct { created *Group // 记录 Create 调用的参数 updated *Group // 记录 Update 调用的参数 getByID *Group // GetByID 返回值 getErr error // GetByID 返回的错误 } func (s *groupRepoStubForAdmin) Create(_ context.Context, g *Group) error { s.created = g return nil } func (s *groupRepoStubForAdmin) Update(_ context.Context, g *Group) error { s.updated = g return nil } func (s *groupRepoStubForAdmin) GetByID(_ context.Context, _ int64) (*Group, error) { if s.getErr != nil { return nil, s.getErr } return s.getByID, nil } func (s *groupRepoStubForAdmin) Delete(_ context.Context, _ int64) error { panic("unexpected Delete call") } func (s *groupRepoStubForAdmin) DeleteCascade(_ context.Context, _ int64) ([]int64, error) { panic("unexpected DeleteCascade call") } func (s *groupRepoStubForAdmin) List(_ context.Context, _ pagination.PaginationParams) ([]Group, *pagination.PaginationResult, error) { panic("unexpected List call") } func (s *groupRepoStubForAdmin) ListWithFilters(_ context.Context, _ pagination.PaginationParams, _, _ string, _ *bool) ([]Group, *pagination.PaginationResult, error) { panic("unexpected ListWithFilters call") } func (s *groupRepoStubForAdmin) ListActive(_ context.Context) ([]Group, error) { panic("unexpected ListActive call") } func (s *groupRepoStubForAdmin) ListActiveByPlatform(_ context.Context, _ string) ([]Group, error) { panic("unexpected ListActiveByPlatform call") } func (s *groupRepoStubForAdmin) ExistsByName(_ context.Context, _ string) (bool, error) { panic("unexpected ExistsByName call") } func (s *groupRepoStubForAdmin) GetAccountCount(_ context.Context, _ int64) (int64, error) { panic("unexpected GetAccountCount call") } func (s *groupRepoStubForAdmin) DeleteAccountGroupsByGroupID(_ context.Context, _ int64) (int64, error) { panic("unexpected DeleteAccountGroupsByGroupID call") } // TestAdminService_CreateGroup_WithImagePricing 测试创建分组时 ImagePrice 字段正确传递 func TestAdminService_CreateGroup_WithImagePricing(t *testing.T) { repo := &groupRepoStubForAdmin{} svc := &adminServiceImpl{groupRepo: repo} price1K := 0.10 price2K := 0.15 price4K := 0.30 input := &CreateGroupInput{ Name: "test-group", Description: "Test group", Platform: PlatformAntigravity, RateMultiplier: 1.0, ImagePrice1K: &price1K, ImagePrice2K: &price2K, ImagePrice4K: &price4K, } group, err := svc.CreateGroup(context.Background(), input) require.NoError(t, err) require.NotNil(t, group) // 验证 repo 收到了正确的字段 require.NotNil(t, repo.created) require.NotNil(t, repo.created.ImagePrice1K) require.NotNil(t, repo.created.ImagePrice2K) require.NotNil(t, repo.created.ImagePrice4K) require.InDelta(t, 0.10, *repo.created.ImagePrice1K, 0.0001) require.InDelta(t, 0.15, *repo.created.ImagePrice2K, 0.0001) require.InDelta(t, 0.30, *repo.created.ImagePrice4K, 0.0001) } // TestAdminService_CreateGroup_NilImagePricing 测试 ImagePrice 为 nil 时正常创建 func TestAdminService_CreateGroup_NilImagePricing(t *testing.T) { repo := &groupRepoStubForAdmin{} svc := &adminServiceImpl{groupRepo: repo} input := &CreateGroupInput{ Name: "test-group", Description: "Test group", Platform: PlatformAntigravity, RateMultiplier: 1.0, // ImagePrice 字段全部为 nil } group, err := svc.CreateGroup(context.Background(), input) require.NoError(t, err) require.NotNil(t, group) // 验证 ImagePrice 字段为 nil require.NotNil(t, repo.created) require.Nil(t, repo.created.ImagePrice1K) require.Nil(t, repo.created.ImagePrice2K) require.Nil(t, repo.created.ImagePrice4K) } // TestAdminService_UpdateGroup_WithImagePricing 测试更新分组时 ImagePrice 字段正确更新 func TestAdminService_UpdateGroup_WithImagePricing(t *testing.T) { existingGroup := &Group{ ID: 1, Name: "existing-group", Platform: PlatformAntigravity, Status: StatusActive, } repo := &groupRepoStubForAdmin{getByID: existingGroup} svc := &adminServiceImpl{groupRepo: repo} price1K := 0.12 price2K := 0.18 price4K := 0.36 input := &UpdateGroupInput{ ImagePrice1K: &price1K, ImagePrice2K: &price2K, ImagePrice4K: &price4K, } group, err := svc.UpdateGroup(context.Background(), 1, input) require.NoError(t, err) require.NotNil(t, group) // 验证 repo 收到了更新后的字段 require.NotNil(t, repo.updated) require.NotNil(t, repo.updated.ImagePrice1K) require.NotNil(t, repo.updated.ImagePrice2K) require.NotNil(t, repo.updated.ImagePrice4K) require.InDelta(t, 0.12, *repo.updated.ImagePrice1K, 0.0001) require.InDelta(t, 0.18, *repo.updated.ImagePrice2K, 0.0001) require.InDelta(t, 0.36, *repo.updated.ImagePrice4K, 0.0001) } // TestAdminService_UpdateGroup_PartialImagePricing 测试仅更新部分 ImagePrice 字段 func TestAdminService_UpdateGroup_PartialImagePricing(t *testing.T) { oldPrice2K := 0.15 existingGroup := &Group{ ID: 1, Name: "existing-group", Platform: PlatformAntigravity, Status: StatusActive, ImagePrice2K: &oldPrice2K, // 已有 2K 价格 } repo := &groupRepoStubForAdmin{getByID: existingGroup} svc := &adminServiceImpl{groupRepo: repo} // 只更新 1K 价格 price1K := 0.10 input := &UpdateGroupInput{ ImagePrice1K: &price1K, // ImagePrice2K 和 ImagePrice4K 为 nil,不更新 } group, err := svc.UpdateGroup(context.Background(), 1, input) require.NoError(t, err) require.NotNil(t, group) // 验证:1K 被更新,2K 保持原值,4K 仍为 nil require.NotNil(t, repo.updated) require.NotNil(t, repo.updated.ImagePrice1K) require.InDelta(t, 0.10, *repo.updated.ImagePrice1K, 0.0001) require.NotNil(t, repo.updated.ImagePrice2K) require.InDelta(t, 0.15, *repo.updated.ImagePrice2K, 0.0001) // 原值保持 require.Nil(t, repo.updated.ImagePrice4K) }