package com.ruoyi.projectManagement.service; import com.fasterxml.jackson.databind.ObjectMapper; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.projectManagement.controller.InfoController; import com.ruoyi.projectManagement.dto.ProjectWorkflowDtos; 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.security.access.prepost.PreAuthorize; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class ProjectWorkflowServiceTest { @Mock private NamedParameterJdbcTemplate jdbc; private final ObjectMapper objectMapper = new ObjectMapper(); @Test void completedProjectCannotBeStartedAgain() { when(jdbc.queryForObject(anyString(), anyMap(), eq(Integer.class))).thenReturn(1); when(jdbc.queryForObject(anyString(), anyMap(), eq(String.class))).thenReturn("已完成"); ProjectWorkflowService service = new ProjectWorkflowService(jdbc, objectMapper); assertThatThrownBy(() -> service.startProject(10L)) .isInstanceOf(ServiceException.class) .hasMessageContaining("只有未开始的项目可以开始"); } @Test void transitionCannotSkipStages() { when(jdbc.queryForObject(anyString(), anyMap(), eq(Integer.class))).thenReturn(1); when(jdbc.queryForObject(anyString(), anyMap(), eq(String.class))).thenReturn("开发"); ProjectWorkflowService service = new ProjectWorkflowService(jdbc, objectMapper); ProjectWorkflowDtos.StageTransitionRequest request = new ProjectWorkflowDtos.StageTransitionRequest(); request.setProjectId(10L); request.setTargetStage("验收"); assertThatThrownBy(() -> service.transitionStage(request)) .isInstanceOf(ServiceException.class) .hasMessageContaining("只能按开发、申报、申报结果、验收、已完成的顺序推进"); } @Test void legacyEstablishedProjectCannotBypassExplicitStart() { when(jdbc.queryForObject(anyString(), anyMap(), eq(Integer.class))).thenReturn(1); when(jdbc.queryForObject(anyString(), anyMap(), eq(String.class))).thenReturn("立项"); ProjectWorkflowService service = new ProjectWorkflowService(jdbc, objectMapper); ProjectWorkflowDtos.StageTransitionRequest request = new ProjectWorkflowDtos.StageTransitionRequest(); request.setProjectId(10L); request.setTargetStage("申报"); assertThatThrownBy(() -> service.transitionStage(request)) .isInstanceOf(ServiceException.class) .hasMessageContaining("只能按开发、申报、申报结果、验收、已完成的顺序推进"); } @Test void transitionRequiresCurrentStageBusinessFields() { when(jdbc.queryForObject(anyString(), anyMap(), eq(Integer.class))).thenReturn(1); when(jdbc.queryForObject(anyString(), anyMap(), eq(String.class))).thenReturn("开发"); ProjectWorkflowService service = new ProjectWorkflowService(jdbc, objectMapper); ProjectWorkflowDtos.StageTransitionRequest request = new ProjectWorkflowDtos.StageTransitionRequest(); request.setProjectId(10L); request.setTargetStage("申报"); request.setFormData(Map.of()); assertThatThrownBy(() -> service.transitionStage(request)) .isInstanceOf(ServiceException.class) .hasMessageContaining("请填写申报日期"); } @Test void supplementalPhaseCannotModifyEarlierStage() { when(jdbc.queryForObject(anyString(), anyMap(), eq(Integer.class))).thenReturn(1); when(jdbc.queryForObject(anyString(), anyMap(), eq(String.class))).thenReturn("验收"); ProjectWorkflowService service = new ProjectWorkflowService(jdbc, objectMapper); ProjectWorkflowDtos.PhaseRequest request = new ProjectWorkflowDtos.PhaseRequest(); request.setProjectId(10L); request.setPhaseCode("APPLICATION"); request.setStatus("IN_PROGRESS"); assertThatThrownBy(() -> service.savePhase(request)) .isInstanceOf(ServiceException.class) .hasMessageContaining("不能跳转或倒退阶段"); } @Test void legacyStageWriteAndReadEndpointsAreRetired() throws Exception { assertThat(InfoController.class.getMethod("saveStage", com.ruoyi.projectManagement.vo.SaveInfoStageVo.class) .getAnnotation(PreAuthorize.class).value()).isEqualTo("denyAll()"); assertThat(InfoController.class.getMethod("listStage", Long.class) .getAnnotation(PreAuthorize.class).value()).isEqualTo("denyAll()"); assertThat(InfoController.class.getMethod("deleteStage", Long.class) .getAnnotation(PreAuthorize.class).value()).isEqualTo("denyAll()"); } }