package usecase import ( "backend/pkg/permission/domain" "backend/pkg/permission/domain/entity" "backend/pkg/permission/domain/usecase" mockRepo "backend/pkg/permission/mock/repository" "context" "errors" "testing" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/v2/bson" "go.uber.org/mock/gomock" ) func TestUserRoleUseCase_Assign(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) uc := NewUserRoleUseCase(UserRoleUseCaseParam{ UserRoleRepo: mockUserRoleRepo, RoleRepo: mockRoleRepo, }) ctx := context.Background() tests := []struct { name string req usecase.AssignRoleRequest mockSetup func() wantErr bool }{ { name: "成功指派角色", req: usecase.AssignRoleRequest{ UserUID: "user123", RoleUID: "ROLE0000000001", Brand: "brand1", }, mockSetup: func() { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", Name: "管理員", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) mockUserRoleRepo.EXPECT().Exists(ctx, "user123").Return(false, nil) mockUserRoleRepo.EXPECT().Create(ctx, gomock.Any()).Return(nil) }, wantErr: false, }, { name: "角色不存在", req: usecase.AssignRoleRequest{ UserUID: "user456", RoleUID: "ROLE9999999999", }, mockSetup: func() { mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE9999999999").Return(nil, errors.New("not found")) }, wantErr: true, }, { name: "角色未啟用", req: usecase.AssignRoleRequest{ UserUID: "user789", RoleUID: "ROLE0000000002", }, mockSetup: func() { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000002", Name: "已停用角色", Status: domain.RecordInactive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000002").Return(role, nil) }, wantErr: true, }, { name: "使用者已有角色", req: usecase.AssignRoleRequest{ UserUID: "user999", RoleUID: "ROLE0000000001", }, mockSetup: func() { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", Name: "管理員", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) mockUserRoleRepo.EXPECT().Exists(ctx, "user999").Return(true, nil) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() _, err := uc.Assign(ctx, tt.req) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestUserRoleUseCase_Update(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) uc := NewUserRoleUseCase(UserRoleUseCaseParam{ UserRoleRepo: mockUserRoleRepo, RoleRepo: mockRoleRepo, }) ctx := context.Background() tests := []struct { name string userUID string newRoleID string mockSetup func() wantErr bool }{ { name: "成功更新角色", userUID: "user123", newRoleID: "ROLE0000000002", mockSetup: func() { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000002", Name: "新角色", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000002").Return(role, nil) updatedUserRole := &entity.UserRole{ ID: bson.NewObjectID(), Brand: "brand1", UID: "user123", RoleID: "ROLE0000000002", Status: domain.RecordActive, } mockUserRoleRepo.EXPECT().Update(ctx, "user123", "ROLE0000000002").Return(updatedUserRole, nil) }, wantErr: false, }, { name: "新角色不存在", userUID: "user456", newRoleID: "ROLE9999999999", mockSetup: func() { mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE9999999999").Return(nil, errors.New("not found")) }, wantErr: true, }, { name: "新角色未啟用", userUID: "user789", newRoleID: "ROLE0000000003", mockSetup: func() { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000003", Name: "已停用角色", Status: domain.RecordInactive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000003").Return(role, nil) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() result, err := uc.Update(ctx, tt.userUID, tt.newRoleID) if tt.wantErr { assert.Error(t, err) assert.Nil(t, result) } else { assert.NoError(t, err) assert.NotNil(t, result) } }) } } func TestUserRoleUseCase_Remove(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) uc := NewUserRoleUseCase(UserRoleUseCaseParam{ UserRoleRepo: mockUserRoleRepo, RoleRepo: mockRoleRepo, }) ctx := context.Background() tests := []struct { name string userUID string mockSetup func() wantErr bool }{ { name: "成功移除角色", userUID: "user123", mockSetup: func() { mockUserRoleRepo.EXPECT().Delete(ctx, "user123").Return(nil) }, wantErr: false, }, { name: "移除失敗", userUID: "user456", mockSetup: func() { mockUserRoleRepo.EXPECT().Delete(ctx, "user456").Return(errors.New("db error")) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() err := uc.Remove(ctx, tt.userUID) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestUserRoleUseCase_Get(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) uc := NewUserRoleUseCase(UserRoleUseCaseParam{ UserRoleRepo: mockUserRoleRepo, RoleRepo: mockRoleRepo, }) ctx := context.Background() tests := []struct { name string userUID string mockSetup func() wantNil bool wantErr bool }{ { name: "成功獲取使用者角色", userUID: "user123", mockSetup: func() { userRole := &entity.UserRole{ ID: bson.NewObjectID(), Brand: "brand1", UID: "user123", RoleID: "ROLE0000000001", Status: domain.RecordActive, } mockUserRoleRepo.EXPECT().Get(ctx, "user123").Return(userRole, nil) }, wantNil: false, wantErr: false, }, { name: "使用者無角色", userUID: "user456", mockSetup: func() { mockUserRoleRepo.EXPECT().Get(ctx, "user456").Return(nil, errors.New("not found")) }, wantNil: true, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() result, err := uc.Get(ctx, tt.userUID) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } if tt.wantNil { assert.Nil(t, result) } else { assert.NotNil(t, result) } }) } } func TestUserRoleUseCase_GetByRole(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) uc := NewUserRoleUseCase(UserRoleUseCaseParam{ UserRoleRepo: mockUserRoleRepo, RoleRepo: mockRoleRepo, }) ctx := context.Background() tests := []struct { name string roleUID string mockSetup func() wantCount int wantErr bool }{ { name: "成功獲取角色的所有使用者", roleUID: "ROLE0000000001", mockSetup: func() { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", Name: "管理員", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) userRoles := []*entity.UserRole{ {ID: bson.NewObjectID(), UID: "user1", RoleID: "ROLE0000000001"}, {ID: bson.NewObjectID(), UID: "user2", RoleID: "ROLE0000000001"}, } mockUserRoleRepo.EXPECT().GetByRoleID(ctx, gomock.Any()).Return(userRoles, nil) }, wantCount: 2, wantErr: false, }, { name: "角色不存在", roleUID: "ROLE9999999999", mockSetup: func() { mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE9999999999").Return(nil, errors.New("not found")) }, wantCount: 0, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() result, err := uc.GetByRole(ctx, tt.roleUID) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) assert.Len(t, result, tt.wantCount) } }) } } func TestUserRoleUseCase_List(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) uc := NewUserRoleUseCase(UserRoleUseCaseParam{ UserRoleRepo: mockUserRoleRepo, RoleRepo: mockRoleRepo, }) ctx := context.Background() tests := []struct { name string filter usecase.UserRoleFilterRequest mockSetup func() wantCount int wantErr bool }{ { name: "成功列出所有使用者角色", filter: usecase.UserRoleFilterRequest{ Brand: "brand1", }, mockSetup: func() { userRoles := []*entity.UserRole{ {ID: bson.NewObjectID(), UID: "user1", RoleID: "ROLE0000000001", Brand: "brand1"}, {ID: bson.NewObjectID(), UID: "user2", RoleID: "ROLE0000000002", Brand: "brand1"}, } mockUserRoleRepo.EXPECT().List(ctx, gomock.Any()).Return(userRoles, nil) }, wantCount: 2, wantErr: false, }, { name: "沒有使用者角色", filter: usecase.UserRoleFilterRequest{ Brand: "unknown", }, mockSetup: func() { mockUserRoleRepo.EXPECT().List(ctx, gomock.Any()).Return([]*entity.UserRole{}, nil) }, wantCount: 0, wantErr: false, }, { name: "Repository 錯誤", filter: usecase.UserRoleFilterRequest{ Brand: "brand1", }, mockSetup: func() { mockUserRoleRepo.EXPECT().List(ctx, gomock.Any()).Return(nil, errors.New("db error")) }, wantCount: 0, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() result, err := uc.List(ctx, tt.filter) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) assert.Len(t, result, tt.wantCount) } }) } }