package user import ( "context" "testing" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "gorm.io/gorm" ) // MockUserModel 只实现 bindInviteCodeLogic 需要的方法 type MockUserModel struct { user.Model // 为了满足接口定义,嵌入 user.Model,未实现的方法会 panic users map[int64]*user.User } func (m *MockUserModel) FindOneByReferCode(ctx context.Context, referCode string) (*user.User, error) { for _, u := range m.users { if u.ReferCode == referCode { return u, nil } } return nil, gorm.ErrRecordNotFound } func (m *MockUserModel) Update(ctx context.Context, data *user.User, tx ...*gorm.DB) error { m.users[data.Id] = data return nil } func TestBindInviteCodeLogic_BindInviteCode(t *testing.T) { tests := []struct { name string currentUser user.User // 使用值类型,在 Run 中取地址,避免共享 initUsers map[int64]*user.User inviteCode string expectError bool expectedCode uint32 expectedMsg string }{ { name: "成功绑定邀请码", currentUser: user.User{Id: 1, ReferCode: "CODE1", RefererId: 0}, initUsers: map[int64]*user.User{ 1: {Id: 1, ReferCode: "CODE1", RefererId: 0}, 2: {Id: 2, ReferCode: "CODE2", RefererId: 0}, }, inviteCode: "CODE2", expectError: false, }, { name: "邀请码不存在", currentUser: user.User{Id: 1, ReferCode: "CODE1", RefererId: 0}, initUsers: map[int64]*user.User{ 1: {Id: 1, ReferCode: "CODE1", RefererId: 0}, }, inviteCode: "INVALID", expectError: true, expectedCode: xerr.InviteCodeError, expectedMsg: "无邀请码", }, { name: "不允许绑定自己", currentUser: user.User{Id: 1, ReferCode: "CODE1", RefererId: 0}, initUsers: map[int64]*user.User{ 1: {Id: 1, ReferCode: "CODE1", RefererId: 0}, }, inviteCode: "CODE1", expectError: true, expectedCode: xerr.InviteCodeError, expectedMsg: "不允许绑定自己", }, { name: "用户已经绑定过", currentUser: user.User{Id: 3, ReferCode: "CODE3", RefererId: 2}, initUsers: map[int64]*user.User{ 3: {Id: 3, ReferCode: "CODE3", RefererId: 2}, 2: {Id: 2, ReferCode: "CODE2", RefererId: 0}, }, inviteCode: "CODE2", expectError: true, expectedCode: xerr.UserExist, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // 初始化 Mock 数据 mockModel := &MockUserModel{ users: tt.initUsers, } svcCtx := &svc.ServiceContext{ UserModel: mockModel, } // 确保 User 对象在 Mock DB 中也存在(Update操作需要) // 其实 MockUserModel.Update 会更新 map,所以这里不需要额外操作, // 只要 initUsers 配置正确即可。 // 将当前用户注入 context (使用拷贝的指针) u := tt.currentUser ctx := context.WithValue(context.Background(), constant.CtxKeyUser, &u) l := NewBindInviteCodeLogic(ctx, svcCtx) err := l.BindInviteCode(&types.BindInviteCodeRequest{InviteCode: tt.inviteCode}) if tt.expectError { assert.Error(t, err) cause := errors.Cause(err) codeErr, ok := cause.(*xerr.CodeError) if !ok { // handle error } else { assert.Equal(t, tt.expectedCode, codeErr.GetErrCode()) if tt.expectedMsg != "" { assert.Contains(t, codeErr.GetErrMsg(), tt.expectedMsg) } } if tt.expectedMsg != "" { assert.Contains(t, err.Error(), tt.expectedMsg) } } else { assert.NoError(t, err) if tt.name == "成功绑定邀请码" { assert.Equal(t, int64(2), mockModel.users[1].RefererId) } } }) } }