package cn.iocoder.yudao.module.mes.service.safety;
import cn.iocoder.yudao.module.hrm.api.employee.HrmEmployeeApi;
import cn.iocoder.yudao.module.hrm.api.employee.dto.HrmEmployeeSimpleDTO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* {@link SafetyRefResolver} 空集合场景回归测试
*
*
背景:{@code Map.of()} 是空且不可变的 Map,它的 {@code get(null)} 会抛 NPE,
* 而 {@code Map.of().get(非null)} 不会。安全生产模块里「组织 / 证件 / 隐患」等
* 记录在未关联员工(leaderId、employeeId 为 null)时,就会走到 {@code map.get(null)},
* 从而在列表页直接 500。
*
* 这里锁死约定:空集合必须返回可接受 null key 的空 Map。
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class SafetyRefResolverEmptyCollectionTest {
@InjectMocks
private SafetyRefResolver resolver;
@Mock
private HrmEmployeeApi hrmEmployeeApi;
@Mock
private cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkshopMapper workshopMapper;
/** 空集合:必须能 get(null) 而不抛 NPE(这就是线上 NPE 的根因) */
@Test
void employeeMap_emptyCollection_getNullShouldNotThrow() {
Map map = resolver.employeeMap(List.of());
assertTrue(map.isEmpty());
// Map.of() 在这里会抛 NullPointerException
assertNull(map.get(null), "空集合返回的 Map 必须允许用 null 作为 key 查询");
}
/** 集合里全是 null:过滤后为空,同样必须能 get(null) */
@Test
void employeeMap_allNullElements_getNullShouldNotThrow() {
Map map = resolver.employeeMap(java.util.Arrays.asList((Long) null, null));
assertTrue(map.isEmpty());
assertNull(map.get(null));
}
/** null 集合本身 */
@Test
void employeeMap_nullCollection_getNullShouldNotThrow() {
Map map = resolver.employeeMap(null);
assertTrue(map.isEmpty());
assertNull(map.get(null));
}
@Test
void workshopMap_emptyCollection_getNullShouldNotThrow() {
Map map = resolver.workshopMap(List.of());
assertTrue(map.isEmpty());
assertNull(map.get(null), "空集合返回的 Map 必须允许用 null 作为 key 查询");
}
@Test
void workshopMap_allNullElements_getNullShouldNotThrow() {
Map map = resolver.workshopMap(java.util.Arrays.asList((Long) null));
assertTrue(map.isEmpty());
assertNull(map.get(null));
}
@Test
void workshopMap_nullCollection_getNullShouldNotThrow() {
Map map = resolver.workshopMap(null);
assertTrue(map.isEmpty());
assertNull(map.get(null));
}
/** 返回的 Map 应该是可变的(避免后续 put 抛 UnsupportedOperationException) */
@Test
void employeeMap_emptyResultShouldBeMutable() {
Map map = resolver.employeeMap(List.of());
map.put(1L, new HrmEmployeeSimpleDTO());
assertEquals(1, map.size());
}
@Test
void workshopMap_emptyResultShouldBeMutable() {
Map map = resolver.workshopMap(List.of());
map.put(1L, new MesMdWorkshopDO());
assertEquals(1, map.size());
}
}