package com.vincent.rsf.server.system.controller; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.server.common.domain.BaseParam; import com.vincent.rsf.server.common.service.ListExportService; import com.vincent.rsf.server.system.entity.Role; import com.vincent.rsf.server.system.service.RoleMenuService; import com.vincent.rsf.server.system.service.RoleService; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletResponse; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.doReturn; @ExtendWith(MockitoExtension.class) class RoleControllerTest { @Mock private RoleService roleService; @Mock private RoleMenuService roleMenuService; @Mock private HttpServletResponse response; private RoleController roleController; private ListExportService listExportService; private ByteArrayOutputStream exportBuffer; @BeforeEach void setUp() throws Exception { roleController = new TestableRoleController(); ReflectionTestUtils.setField(roleController, "roleService", roleService); ReflectionTestUtils.setField(roleController, "roleMenuService", roleMenuService); listExportService = new ListExportService(); ReflectionTestUtils.setField(roleController, "listExportService", listExportService); exportBuffer = new ByteArrayOutputStream(); lenient().doReturn(new ServletOutputStream() { @Override public void write(int b) { exportBuffer.write(b); } @Override public boolean isReady() { return true; } @Override public void setWriteListener(jakarta.servlet.WriteListener writeListener) { } }).when(response).getOutputStream(); } @Test void exportPrefersSelectedIdsEvenWhenFiltersArePresent() throws Exception { Role role = role(1L, "管理员", "ADMIN", 1, "系统角色"); Map body = new HashMap<>(); body.put("ids", List.of(1L, 2L)); body.put("name", "管理员"); body.put("current", 1); body.put("pageSize", 20); body.put("meta", Map.of( "reportTitle", "角色管理报表", "columns", List.of( Map.of("source", "name", "label", "角色名称"), Map.of("source", "statusText", "label", "状态"), Map.of("source", "memo", "label", "备注") ) )); when(roleService.listByIds(List.of(1L, 2L))).thenReturn(List.of(role)); roleController.export(body, response); verify(roleService).listByIds(List.of(1L, 2L)); verify(roleService, never()).list(anyWrapper()); assertExportSheet( exportBuffer.toByteArray(), List.of("序号", "角色名称", "状态", "备注"), List.of("1", "管理员", "正常", "系统角色") ); } @Test void pageStillAcceptsFlatPrintQueryWithoutFilterFields() { Map body = new HashMap<>(); body.put("current", 1); body.put("pageSize", 200); when(roleService.page(any(), any())).thenReturn(new Page<>()); R result = roleController.page(body); assertNotNull(result); verify(roleService).page(any(), any()); } @Test void exportUsesFilteredRoleListWhenIdsMissing() throws Exception { Role role = role(1L, "管理员", "ADMIN", 1, "系统角色"); Map body = new HashMap<>(); body.put("name", "管理员"); body.put("current", 1); body.put("pageSize", 200); body.put("meta", Map.of( "reportTitle", "角色管理报表", "columns", List.of( Map.of("source", "name", "label", "角色名称"), Map.of("source", "statusText", "label", "状态") ) )); when(roleService.list(anyWrapper())).thenReturn(List.of(role)); roleController.export(body, response); verify(roleService).list(anyWrapper()); verify(roleService, never()).listByIds(any()); } @Test void exportInsertsSequenceHeaderFromReportStyleWhenSequenceColumnIsNotRequested() throws Exception { Role role = role(1L, "管理员", "ADMIN", 1, "系统角色"); List> requestedColumns = List.of( Map.of("source", "name", "label", "角色名称"), Map.of("source", "statusText", "label", "状态") ); Map body = new HashMap<>(); body.put("ids", List.of(1L)); body.put("meta", Map.of( "reportTitle", "角色管理报表", "reportDate", "2026-03-29", "columns", requestedColumns, "reportStyle", Map.of( "showSequence", true ) )); when(roleService.listByIds(List.of(1L))).thenReturn(List.of(role)); roleController.export(body, response); try (Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(exportBuffer.toByteArray()))) { Sheet sheet = workbook.getSheetAt(0); assertEquals("角色管理报表", sheet.getRow(0).getCell(0).getStringCellValue()); assertTrue(sheet.getRow(1).getCell(0).getStringCellValue().startsWith("报表日期:")); assertAll("showSequence generated column", () -> assertEquals("序号", sheet.getRow(3).getCell(0).getStringCellValue(), "showSequence=true should prepend a generated 序号 column even when request columns omit it."), () -> assertEquals("1", sheet.getRow(4).getCell(0).getStringCellValue(), "showSequence=true should generate the first sequence cell as 1 in the exported data row.") ); assertEquals("角色名称", sheet.getRow(3).getCell(1).getStringCellValue(), "Generated 序号 column should shift requested columns to the right."); } } private void assertExportSheet(byte[] workbookBytes, List expectedHeaders, List expectedFirstRow) throws Exception { try (Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(workbookBytes))) { Sheet sheet = workbook.getSheetAt(0); for (int index = 0; index < expectedHeaders.size(); index++) { assertEquals(expectedHeaders.get(index), sheet.getRow(3).getCell(index).getStringCellValue()); assertEquals(expectedFirstRow.get(index), sheet.getRow(4).getCell(index).getStringCellValue()); } } } private Role role(Long id, String name, String code, Integer status, String memo) { Role role = new Role(); role.setId(id); role.setName(name); role.setCode(code); role.setStatus(status); role.setMemo(memo); return role; } @SuppressWarnings("unchecked") private Wrapper anyWrapper() { return any(Wrapper.class); } private static final class TestableRoleController extends RoleController { @Override public T buildParam(Map map, Class clz) { try { T param = clz.getDeclaredConstructor().newInstance(); Map copy = new HashMap<>(map); Object metaObject = copy.remove("meta"); if (metaObject instanceof Map metaMap) { metaMap.forEach((key, value) -> copy.put(String.valueOf(key), value)); } BaseParam baseParam = param; baseParam.setCurrent(asInteger(copy.remove("current"))); baseParam.setPageSize(asInteger(copy.remove("pageSize"))); baseParam.setOrderBy(asString(copy.remove("orderBy"))); baseParam.setCondition(asString(copy.remove("condition"))); baseParam.setMap(copy); return param; } catch (Exception error) { throw new RuntimeException(error); } } private Integer asInteger(Object value) { return value == null ? null : Integer.valueOf(String.valueOf(value)); } private String asString(Object value) { return value == null ? null : String.valueOf(value); } } }