package usecase import ( "backend/pkg/permission/domain" "backend/pkg/permission/domain/entity" "backend/pkg/permission/domain/usecase" mockRepo "backend/pkg/permission/mock/repository" mockUC "backend/pkg/permission/mock/usecase" "context" "errors" "testing" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/v2/bson" "go.uber.org/mock/gomock" ) func stringPtr(s string) *string { return &s } func TestRoleUseCase_Create(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRolePermUC := mockUC.NewMockRolePermissionUseCase(mockCtrl) uc := NewRoleUseCase(RoleUseCaseParam{ RoleRepo: mockRoleRepo, UserRoleRepo: mockUserRoleRepo, RolePermUseCase: mockRolePermUC, }) ctx := context.Background() tests := []struct { name string req usecase.CreateRoleRequest mockSetup func() wantErr bool }{ { name: "成功創建角色", req: usecase.CreateRoleRequest{ ClientID: 1, Name: "管理員", }, mockSetup: func() { mockRoleRepo.EXPECT().NextID(ctx).Return(int64(1), nil) mockRoleRepo.EXPECT().Create(ctx, gomock.Any()).Return(nil) role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", ClientID: 1, Name: "管理員", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, gomock.Any()).Return(role, nil) mockRolePermUC.EXPECT().GetByRoleUID(ctx, gomock.Any()).Return(nil, nil) }, wantErr: false, }, { name: "NextID 失敗", req: usecase.CreateRoleRequest{ ClientID: 1, Name: "管理員", }, mockSetup: func() { mockRoleRepo.EXPECT().NextID(ctx).Return(int64(0), errors.New("db error")) }, wantErr: true, }, { name: "Create 失敗", req: usecase.CreateRoleRequest{ ClientID: 1, Name: "管理員", }, mockSetup: func() { mockRoleRepo.EXPECT().NextID(ctx).Return(int64(1), nil) mockRoleRepo.EXPECT().Create(ctx, gomock.Any()).Return(errors.New("db error")) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() result, err := uc.Create(ctx, tt.req) if tt.wantErr { assert.Error(t, err) assert.Nil(t, result) } else { assert.NoError(t, err) assert.NotNil(t, result) } }) } } func TestRoleUseCase_Update(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRolePermUC := mockUC.NewMockRolePermissionUseCase(mockCtrl) uc := NewRoleUseCase(RoleUseCaseParam{ RoleRepo: mockRoleRepo, UserRoleRepo: mockUserRoleRepo, RolePermUseCase: mockRolePermUC, }) ctx := context.Background() tests := []struct { name string uid string req usecase.UpdateRoleRequest mockSetup func() wantErr bool }{ { name: "成功更新角色", uid: "ROLE0000000001", req: usecase.UpdateRoleRequest{ Name: stringPtr("新管理員"), }, mockSetup: func() { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", ClientID: 1, Name: "管理員", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) mockRoleRepo.EXPECT().Update(ctx, gomock.Any()).Return(nil) mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) mockRolePermUC.EXPECT().GetByRoleUID(ctx, "ROLE0000000001").Return(nil, nil) }, wantErr: false, }, { name: "角色不存在", uid: "ROLE9999999999", req: usecase.UpdateRoleRequest{ Name: stringPtr("新管理員"), }, mockSetup: func() { mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE9999999999").Return(nil, errors.New("not found")) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.mockSetup() result, err := uc.Update(ctx, tt.uid, tt.req) if tt.wantErr { assert.Error(t, err) assert.Nil(t, result) } else { assert.NoError(t, err) assert.NotNil(t, result) } }) } } func TestRoleUseCase_Delete(t *testing.T) { ctx := context.Background() tests := []struct { name string uid string mockSetup func(*mockRepo.MockRoleRepository, *mockRepo.MockUserRoleRepository) wantErr bool }{ { name: "成功刪除角色", uid: "ROLE0000000001", mockSetup: func(mockRoleRepo *mockRepo.MockRoleRepository, mockUserRoleRepo *mockRepo.MockUserRoleRepository) { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", ClientID: 1, Name: "管理員", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) mockUserRoleRepo.EXPECT().GetByRoleID(ctx, "ROLE0000000001").Return([]*entity.UserRole{}, nil) mockRoleRepo.EXPECT().Delete(ctx, "ROLE0000000001").Return(nil) }, wantErr: false, }, { name: "角色不存在", uid: "ROLE9999999999", mockSetup: func(mockRoleRepo *mockRepo.MockRoleRepository, mockUserRoleRepo *mockRepo.MockUserRoleRepository) { mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE9999999999").Return(nil, errors.New("not found")) }, wantErr: true, }, { name: "角色正在使用中", uid: "ROLE0000000001", mockSetup: func(mockRoleRepo *mockRepo.MockRoleRepository, mockUserRoleRepo *mockRepo.MockUserRoleRepository) { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", ClientID: 1, Name: "管理員", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) mockUserRoleRepo.EXPECT().GetByRoleID(ctx, "ROLE0000000001").Return([]*entity.UserRole{ {UID: "user1"}, {UID: "user2"}, }, nil) }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // 為每個測試案例創建新的 mock controller 和 usecase 實例 mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRolePermUC := mockUC.NewMockRolePermissionUseCase(mockCtrl) tt.mockSetup(mockRoleRepo, mockUserRoleRepo) uc := NewRoleUseCase(RoleUseCaseParam{ RoleRepo: mockRoleRepo, UserRoleRepo: mockUserRoleRepo, RolePermUseCase: mockRolePermUC, }) err := uc.Delete(ctx, tt.uid) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestRoleUseCase_Get(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRolePermUC := mockUC.NewMockRolePermissionUseCase(mockCtrl) uc := NewRoleUseCase(RoleUseCaseParam{ RoleRepo: mockRoleRepo, UserRoleRepo: mockUserRoleRepo, RolePermUseCase: mockRolePermUC, }) ctx := context.Background() tests := []struct { name string uid string mockSetup func() wantNil bool wantErr bool }{ { name: "成功獲取角色", uid: "ROLE0000000001", mockSetup: func() { role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", ClientID: 1, Name: "管理員", Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) mockRolePermUC.EXPECT().GetByRoleUID(ctx, "ROLE0000000001").Return(nil, nil) }, wantNil: false, wantErr: false, }, { name: "角色不存在", uid: "ROLE9999999999", mockSetup: func() { mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE9999999999").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.uid) 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 TestRoleUseCase_List(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockRoleRepo := mockRepo.NewMockRoleRepository(mockCtrl) mockUserRoleRepo := mockRepo.NewMockUserRoleRepository(mockCtrl) mockRolePermUC := mockUC.NewMockRolePermissionUseCase(mockCtrl) uc := NewRoleUseCase(RoleUseCaseParam{ RoleRepo: mockRoleRepo, UserRoleRepo: mockUserRoleRepo, RolePermUseCase: mockRolePermUC, }) ctx := context.Background() tests := []struct { name string filter usecase.RoleFilterRequest mockSetup func() wantCount int wantErr bool }{ { name: "成功列出所有角色", filter: usecase.RoleFilterRequest{ ClientID: 1, }, mockSetup: func() { roles := []*entity.Role{ {ID: bson.NewObjectID(), UID: "ROLE0000000001", Name: "管理員", Status: domain.RecordActive}, {ID: bson.NewObjectID(), UID: "ROLE0000000002", Name: "用戶", Status: domain.RecordActive}, } mockRoleRepo.EXPECT().List(ctx, gomock.Any()).Return(roles, nil) mockRolePermUC.EXPECT().GetByRoleUID(ctx, gomock.Any()).Return(nil, nil).Times(2) }, wantCount: 2, wantErr: false, }, { name: "沒有角色", filter: usecase.RoleFilterRequest{ ClientID: 999, }, mockSetup: func() { mockRoleRepo.EXPECT().List(ctx, gomock.Any()).Return([]*entity.Role{}, nil) }, wantCount: 0, wantErr: false, }, { name: "Repository 錯誤", filter: usecase.RoleFilterRequest{ ClientID: 1, }, mockSetup: func() { mockRoleRepo.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) } }) } }