package usecase import ( "app-cloudep-member-server/pkg/domain" "app-cloudep-member-server/pkg/domain/config" "app-cloudep-member-server/pkg/domain/entity" "app-cloudep-member-server/pkg/domain/member" "app-cloudep-member-server/pkg/domain/usecase" mockRepo "app-cloudep-member-server/pkg/mock/repository" "app-cloudep-member-server/pkg/repository" "context" "errors" "testing" "code.30cm.net/digimon/library-go/errs" "code.30cm.net/digimon/library-go/errs/code" "github.com/stretchr/testify/assert" "github.com/zeromicro/go-zero/core/stores/mon" "go.uber.org/mock/gomock" "google.golang.org/protobuf/proto" ) func TestCreateUserAccount(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockAccountRepository := mockRepo.NewMockAccountRepository(mockCtrl) uc := MustMemberUseCase(MemberUseCaseParam{ Account: mockAccountRepository, Config: config.Config{ Bcrypt: struct{ Cost int }{Cost: 10}, }, }) tests := []struct { name string req usecase.CreateLoginUserRequest mockSetup func() expectErr bool }{ { name: "Successful account creation with Digimon platform", req: usecase.CreateLoginUserRequest{ LoginID: "testuser", Token: "plaintext-password", Platform: member.Digimon, }, mockSetup: func() { mockAccountRepository.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil) }, expectErr: false, }, { name: "Password encryption failure", req: usecase.CreateLoginUserRequest{ LoginID: "testuser", Token: "plaintext-password", Platform: member.Digimon, }, mockSetup: func() { HasPasswordFunc = func(password string, cost int) (string, error) { return "", errors.New("encryption error") } }, expectErr: true, }, { name: "Duplicate account insertion error", req: usecase.CreateLoginUserRequest{ LoginID: "testuser", Token: "plaintext-password", Platform: member.Digimon, }, mockSetup: func() { HasPasswordFunc = func(password string, cost int) (string, error) { return "encrypted-password", nil } mockAccountRepository.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(errors.New("duplicate account")) }, expectErr: true, }, { name: "Successful account creation with non-Digimon platform", req: usecase.CreateLoginUserRequest{ LoginID: "testuser", Platform: member.Google, }, mockSetup: func() { mockAccountRepository.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil) }, expectErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() err := uc.CreateUserAccount(context.Background(), tt.req) if tt.expectErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestGetUIDByAccount(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockAccountUIDRepo := mockRepo.NewMockAccountUIDRepository(mockCtrl) uc := MustMemberUseCase(MemberUseCaseParam{ AccountUID: mockAccountUIDRepo, Config: config.Config{ Bcrypt: struct{ Cost int }{Cost: 10}, }, }) tests := []struct { name string req usecase.GetUIDByAccountRequest mockSetup func() wantResp usecase.GetUIDByAccountResponse wantErr bool }{ { name: "Successfully found UID by account", req: usecase.GetUIDByAccountRequest{ Account: "testuser", }, mockSetup: func() { mockAccountUIDRepo.EXPECT(). FindUIDByLoginID(gomock.Any(), "testuser"). Return(&entity.AccountUID{UID: "12345"}, nil) }, wantResp: usecase.GetUIDByAccountResponse{ UID: "12345", Account: "testuser", }, wantErr: false, }, { name: "Account not found", req: usecase.GetUIDByAccountRequest{ Account: "notfounduser", }, mockSetup: func() { mockAccountUIDRepo.EXPECT(). FindUIDByLoginID(gomock.Any(), "notfounduser"). Return(nil, errs.NewError( code.CloudEPMember, code.CatResource, domain.FailedFindUIDByLoginIDErrorCode, "account not found", )) }, wantResp: usecase.GetUIDByAccountResponse{}, wantErr: true, }, { name: "Database error", req: usecase.GetUIDByAccountRequest{ Account: "erroruser", }, mockSetup: func() { mockAccountUIDRepo.EXPECT(). FindUIDByLoginID(gomock.Any(), "erroruser"). Return(nil, errors.New("database error")) }, wantResp: usecase.GetUIDByAccountResponse{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() resp, err := uc.GetUIDByAccount(context.Background(), tt.req) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) assert.Equal(t, tt.wantResp, resp) } }) } } func TestGetUserAccountInfo(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockAccountRepo := mockRepo.NewMockAccountRepository(mockCtrl) uc := MustMemberUseCase(MemberUseCaseParam{ Account: mockAccountRepo, Config: config.Config{ Bcrypt: struct{ Cost int }{Cost: 10}, }, }) tests := []struct { name string req usecase.GetUIDByAccountRequest mockSetup func() expected usecase.GetAccountInfoResponse wantErr bool errCode string }{ { name: "Successfully found account", req: usecase.GetUIDByAccountRequest{Account: "testuser"}, mockSetup: func() { mockAccountRepo.EXPECT(). FindOneByAccount(gomock.Any(), "testuser"). Return(&entity.Account{ LoginID: "testuser", Platform: 1, Token: "testtoken", }, nil) }, expected: usecase.GetAccountInfoResponse{ Data: usecase.CreateLoginUserRequest{ LoginID: "testuser", Platform: 1, Token: "testtoken", }, }, wantErr: false, }, { name: "Account not found", req: usecase.GetUIDByAccountRequest{Account: "notfounduser"}, mockSetup: func() { mockAccountRepo.EXPECT(). FindOneByAccount(gomock.Any(), "notfounduser"). Return(nil, mon.ErrNotFound) }, expected: usecase.GetAccountInfoResponse{}, wantErr: true, }, { name: "Database error", req: usecase.GetUIDByAccountRequest{Account: "erroruser"}, mockSetup: func() { mockAccountRepo.EXPECT(). FindOneByAccount(gomock.Any(), "erroruser"). Return(nil, errors.New("database error")) }, expected: usecase.GetAccountInfoResponse{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() resp, err := uc.GetUserAccountInfo(context.Background(), tt.req) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) assert.Equal(t, tt.expected, resp) } }) } } func TestGetUserInfo(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRepo := mockRepo.NewMockUserRepository(mockCtrl) uc := MustMemberUseCase(MemberUseCaseParam{ User: mockUserRepo, Config: config.Config{ Bcrypt: struct{ Cost int }{Cost: 10}, }, }) tests := []struct { name string req usecase.GetUserInfoRequest mockSetup func() expected usecase.UserInfo wantErr bool errCode string }{ { name: "Successfully found user by UID", req: usecase.GetUserInfoRequest{UID: "testUID"}, mockSetup: func() { mockUserRepo.EXPECT(). FindOneByUID(gomock.Any(), "testUID"). Return(&entity.User{ UID: "testUID", Nickname: proto.String("testNick"), Email: proto.String("test@example.com"), PreferredLanguage: "en", }, nil) }, expected: usecase.UserInfo{ CreateUserInfoRequest: usecase.CreateUserInfoRequest{ UID: "testUID", Nickname: proto.String("testNick"), Email: proto.String("test@example.com"), PreferredLanguage: "en", }, }, wantErr: false, }, { name: "User not found", req: usecase.GetUserInfoRequest{UID: "nonExistentUID"}, mockSetup: func() { mockUserRepo.EXPECT(). FindOneByUID(gomock.Any(), "nonExistentUID"). Return(nil, mon.ErrNotFound) }, expected: usecase.UserInfo{}, wantErr: true, }, { name: "Database error while querying user by UID", req: usecase.GetUserInfoRequest{UID: "errorUID"}, mockSetup: func() { mockUserRepo.EXPECT(). FindOneByUID(gomock.Any(), "errorUID"). Return(nil, errors.New("database error")) }, expected: usecase.UserInfo{}, wantErr: true, }, { name: "Successfully found user by Nickname", req: usecase.GetUserInfoRequest{NickName: "testNick"}, mockSetup: func() { mockUserRepo.EXPECT(). FindOneByNickName(gomock.Any(), "testNick"). Return(&entity.User{ UID: "testUID", Nickname: proto.String("testNick"), Email: proto.String("test@example.com"), }, nil) }, expected: usecase.UserInfo{ CreateUserInfoRequest: usecase.CreateUserInfoRequest{ UID: "testUID", Nickname: proto.String("testNick"), Email: proto.String("test@example.com"), }, }, wantErr: false, }, { name: "Invalid request, no UID or Nickname", req: usecase.GetUserInfoRequest{}, mockSetup: func() { // No setup needed for invalid request }, expected: usecase.UserInfo{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() resp, err := uc.GetUserInfo(context.Background(), tt.req) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) assert.Equal(t, tt.expected, resp) } }) } } func TestUpdateUserToken(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockAccountRepo := mockRepo.NewMockAccountRepository(mockCtrl) uc := MustMemberUseCase(MemberUseCaseParam{ Account: mockAccountRepo, }) HasPasswordFunc = func(password string, cost int) (string, error) { if password == "fail" { return "", errors.New("encryption error") } return "encrypted-password", nil } tests := []struct { name string req usecase.UpdateTokenRequest mockSetup func() wantErr bool errCode string }{ { name: "Successful token update", req: usecase.UpdateTokenRequest{Account: "testAccount", Token: "newPassword"}, mockSetup: func() { mockAccountRepo.EXPECT(). UpdateTokenByLoginID(gomock.Any(), "testAccount", "encrypted-password"). Return(nil) }, wantErr: false, }, { name: "Password encryption failure", req: usecase.UpdateTokenRequest{Account: "testAccount", Token: "fail"}, mockSetup: func() { // No repo call expected }, wantErr: true, }, { name: "Account not found", req: usecase.UpdateTokenRequest{Account: "nonExistentAccount", Token: "newPassword"}, mockSetup: func() { mockAccountRepo.EXPECT(). UpdateTokenByLoginID(gomock.Any(), "nonExistentAccount", "encrypted-password"). Return(mon.ErrNotFound) }, wantErr: true, }, { name: "Database error during token update", req: usecase.UpdateTokenRequest{Account: "errorAccount", Token: "newPassword"}, mockSetup: func() { mockAccountRepo.EXPECT(). UpdateTokenByLoginID(gomock.Any(), "errorAccount", "encrypted-password"). Return(errors.New("database error")) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() err := uc.UpdateUserToken(context.Background(), tt.req) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestMemberUseCase_UpdateUserInfo(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRepo := mockRepo.NewMockUserRepository(mockCtrl) uc := MustMemberUseCase(MemberUseCaseParam{ User: mockUserRepo, }) tests := []struct { name string req *usecase.UpdateUserInfoRequest mockSetup func() wantErr bool }{ { name: "Successful update", req: &usecase.UpdateUserInfoRequest{ UID: "testUID", Nickname: proto.String("UpdatedNick"), FullName: proto.String("Updated Name"), AvatarURL: proto.String("http://example.com/avatar.png"), }, mockSetup: func() { mockUserRepo.EXPECT(). UpdateUserDetailsByUID(gomock.Any(), gomock.Any()). Return(nil) }, wantErr: false, }, { name: "User not found", req: &usecase.UpdateUserInfoRequest{ UID: "nonExistentUID", }, mockSetup: func() { mockUserRepo.EXPECT(). UpdateUserDetailsByUID(gomock.Any(), gomock.Any()). Return(repository.ErrNotFound) }, wantErr: true, }, { name: "Database error", req: &usecase.UpdateUserInfoRequest{ UID: "errorUID", }, mockSetup: func() { mockUserRepo.EXPECT(). UpdateUserDetailsByUID(gomock.Any(), gomock.Any()). Return(errors.New("database error")) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() err := uc.UpdateUserInfo(context.Background(), tt.req) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestMemberUseCase_UpdateStatus(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRepo := mockRepo.NewMockUserRepository(mockCtrl) uc := MustMemberUseCase(MemberUseCaseParam{ User: mockUserRepo, }) tests := []struct { name string req usecase.UpdateStatusRequest mockSetup func() wantErr bool }{ { name: "Successful status update", req: usecase.UpdateStatusRequest{UID: "testUID", Status: member.AccountStatusActive}, mockSetup: func() { mockUserRepo.EXPECT(). UpdateStatus(gomock.Any(), "testUID", gomock.Any()). Return(nil) }, wantErr: false, }, { name: "User not found", req: usecase.UpdateStatusRequest{UID: "nonExistentUID", Status: member.AccountStatusActive}, mockSetup: func() { mockUserRepo.EXPECT(). UpdateStatus(gomock.Any(), "nonExistentUID", gomock.Any()). Return(repository.ErrNotFound) }, wantErr: true, }, { name: "Database error", req: usecase.UpdateStatusRequest{UID: "errorUID", Status: member.AccountStatusUninitialized}, mockSetup: func() { mockUserRepo.EXPECT(). UpdateStatus(gomock.Any(), "errorUID", gomock.Any()). Return(errors.New("database error")) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() err := uc.UpdateStatus(context.Background(), tt.req) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestMemberUseCase_ListMember(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRepo := mockRepo.NewMockUserRepository(mockCtrl) uc := MustMemberUseCase(MemberUseCaseParam{ User: mockUserRepo, }) tests := []struct { name string req usecase.ListUserInfoRequest mockSetup func() wantErr bool }{ { name: "Successful member listing", req: usecase.ListUserInfoRequest{ PageSize: 10, PageIndex: 1, }, mockSetup: func() { mockUserRepo.EXPECT(). ListMembers(gomock.Any(), gomock.Any()). Return([]*entity.User{ {UID: "testUID1"}, {UID: "testUID2"}, }, int64(2), nil) }, wantErr: false, }, { name: "Database error", req: usecase.ListUserInfoRequest{ PageSize: 10, PageIndex: 1, }, mockSetup: func() { mockUserRepo.EXPECT(). ListMembers(gomock.Any(), gomock.Any()). Return(nil, int64(0), errors.New("database error")) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() resp, err := uc.ListMember(context.Background(), tt.req) if tt.wantErr { assert.Error(t, err) assert.Empty(t, resp.Data) } else { assert.NoError(t, err) assert.NotEmpty(t, resp.Data) } }) } }