diff --git a/blade-service/blade-system/src/test/java/org/springblade/system/service/impl/MpUserServiceImplTest.java b/blade-service/blade-system/src/test/java/org/springblade/system/service/impl/MpUserServiceImplTest.java index 53e22937..8ff82829 100644 --- a/blade-service/blade-system/src/test/java/org/springblade/system/service/impl/MpUserServiceImplTest.java +++ b/blade-service/blade-system/src/test/java/org/springblade/system/service/impl/MpUserServiceImplTest.java @@ -18,6 +18,7 @@ import org.springblade.system.mapper.MpUserDataScopeMapper; import org.springblade.system.mapper.MpUserMapper; import org.springblade.system.pojo.entity.MpUser; import org.springblade.system.pojo.entity.MpUserDataScope; +import org.springblade.system.pojo.vo.MpUserDataScopeVO; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -27,6 +28,7 @@ import java.util.function.Consumer; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -173,6 +175,30 @@ class MpUserServiceImplTest { verify(mpUserDataScopeMapper, never()).insert(any(MpUserDataScope.class)); } + @Test + @DisplayName("显式传 level=1:层级改写为仅本级,范围与自定义组织保持库值,关联表一行都不动") + void updateWithExplicitLevelRewritesLevelOnly() { + when(mpUserMapper.selectById(USER_ID)).thenReturn(customScopeDbUser()); + when(mpUserMapper.updateById(any(MpUser.class))).thenReturn(1); + when(mpUserDataScopeMapper.selectList(any())).thenReturn(scopes(SCOPE_DEPT_A, SCOPE_DEPT_B)); + + MpUser user = new MpUser(); + user.setId(USER_ID); + user.setTenantId(TENANT_ID); + user.setIdentities("admin"); + user.setDataLevelRange(1); + + assertTrue(updateUser(user)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(MpUser.class); + verify(mpUserMapper).updateById(captor.capture()); + assertEquals(1, captor.getValue().getDataLevelRange(), "显式传的层级要落库"); + assertEquals(3, captor.getValue().getDataScopeRange(), "未传范围时沿用库里的 3-自定义"); + assertEquals(List.of(SCOPE_DEPT_A, SCOPE_DEPT_B), captor.getValue().getDataScopeDeptIds()); + verify(mpUserDataScopeMapper, never()).delete(any()); + verify(mpUserDataScopeMapper, never()).insert(any(MpUserDataScope.class)); + } + @Test @DisplayName("只显式传自定义组织列表:关联按新列表重建,范围沿用库里的 3-自定义") void updateWithExplicitDeptIdsRebuildsScopes() { @@ -218,6 +244,79 @@ class MpUserServiceImplTest { verify(mpUserDataScopeMapper, times(2)).insert(any(MpUserDataScope.class)); } + // ------------------------------------------------------------ 注册路径不要求所属组织 + + @ParameterizedTest(name = "{1}") + @MethodSource("emptyDeptRegistrationCases") + @DisplayName("注册:司机 / 管理员 / 司机+管理员不选所属组织也能建号") + void submitAcceptsEmptyDeptForEveryIdentity(String identities, String label) { + when(mpUserMapper.selectOne(any(), anyBoolean())).thenReturn(null); + when(mpUserMapper.insert(any(MpUser.class))).thenAnswer(invocation -> { + invocation.getArgument(0, MpUser.class).setId(USER_ID); + return 1; + }); + + MpUser user = new MpUser(); + user.setTenantId(TENANT_ID); + user.setPhone(PHONE); + user.setIdentities(identities); + + try (MockedStatic ignored = mockStatic(MpUserCache.class)) { + assertTrue(service.submit(user), label + ":所属组织不是注册的准入门槛"); + } + + ArgumentCaptor captor = ArgumentCaptor.forClass(MpUser.class); + verify(mpUserMapper).insert(captor.capture()); + assertNull(captor.getValue().getDeptId(), "未选组织时组织列保持 null,不写空串"); + assertEquals(1, captor.getValue().getDataScopeRange(), "未选组织的账号按默认 1-仅所属组织落库"); + } + + static Stream emptyDeptRegistrationCases() { + return Stream.of( + Arguments.of("driver", "司机"), + Arguments.of("admin", "管理员"), + Arguments.of("driver,admin", "司机+管理员")); + } + + // ------------------------------------------------------------ 空组织的解析结果是空集 + + @ParameterizedTest(name = "{2}") + @MethodSource("emptyScopeCases") + @DisplayName("数据权限解析:基础组织为空时得到空集,不退化成全部组织") + void resolveDataScopeIsEmptyWhenBaseDeptsEmpty(Integer dataScopeRange, Integer dataLevelRange, String label) { + MpUser user = dbUser(); + user.setDeptId(null); + user.setDataScopeRange(dataScopeRange); + user.setDataLevelRange(dataLevelRange); + when(mpUserMapper.selectById(USER_ID)).thenReturn(user); + when(mpUserDataScopeMapper.selectList(any())).thenReturn(List.of()); + + MpUserDataScopeVO scope = service.resolveDataScope(USER_ID); + + assertFalse(scope.isAllDept(), label + ":空集不是全部组织,allDept=true 表示不按组织过滤"); + assertTrue(scope.getDeptIds().isEmpty()); + } + + static Stream emptyScopeCases() { + return Stream.of( + Arguments.of(null, null, "范围与层级都未设置"), + Arguments.of(1, 1, "1-仅所属组织 + 1-含下级,但没有组织"), + Arguments.of(3, 2, "3-自定义,但一条组织关联都没有")); + } + + @Test + @DisplayName("数据权限解析:只有范围是 2-全部组织时才返回全部") + void resolveDataScopeIsAllOnlyForAllScope() { + MpUser user = dbUser(); + user.setDeptId(null); + user.setDataScopeRange(2); + when(mpUserMapper.selectById(USER_ID)).thenReturn(user); + + MpUserDataScopeVO scope = service.resolveDataScope(USER_ID); + + assertTrue(scope.isAllDept()); + } + // ------------------------------------------------------------ 夹具 /**