137 lines
3.8 KiB
Go
137 lines
3.8 KiB
Go
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)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|