package com.tourguide.modules.user.service; import com.tourguide.modules.operation.mapper.OperationCityMapper; import com.tourguide.modules.operation.mapper.OperationScenicSpotMapper; import com.tourguide.modules.user.dto.GuideUserDetailUpdateRequest; import com.tourguide.modules.user.dto.GuideUserDetailResponse; import com.tourguide.modules.user.entity.GuideApplication; import com.tourguide.modules.user.entity.GuideUser; import com.tourguide.modules.user.mapper.GuideAutoDisableConfigMapper; import com.tourguide.modules.user.mapper.GuideApplicationMapper; import com.tourguide.modules.user.mapper.GuideScenicConfigMapper; import com.tourguide.modules.user.mapper.GuideTeamMapper; import com.tourguide.modules.user.mapper.GuideUserMapper; import com.tourguide.common.exception.BusinessException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.security.crypto.password.PasswordEncoder; import java.time.LocalDate; import java.time.Period; import java.util.Collections; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.never; class GuideUserServiceProfileTest { private GuideUserMapper userMapper; private GuideApplicationMapper applicationMapper; private GuideScenicConfigMapper scenicConfigMapper; private GuideUserService service; @BeforeEach void setUp() { userMapper = mock(GuideUserMapper.class); applicationMapper = mock(GuideApplicationMapper.class); scenicConfigMapper = mock(GuideScenicConfigMapper.class); when(scenicConfigMapper.selectList(any())).thenReturn(Collections.emptyList()); when(userMapper.selectOne(any())).thenReturn(null); PasswordEncoder passwordEncoder = mock(PasswordEncoder.class); when(passwordEncoder.encode(any())).thenReturn("encoded-password"); service = new GuideUserService( userMapper, mock(GuideTeamMapper.class), applicationMapper, scenicConfigMapper, mock(GuideAutoDisableConfigMapper.class), mock(OperationScenicSpotMapper.class), mock(OperationCityMapper.class), passwordEncoder); } @Test void shouldDeriveBirthDateAndWorkYearsForPendingGuide() { GuideApplication application = new GuideApplication(); application.setMobile("13800138000"); application.setRealName("导游"); application.setGender(1); application.setIdCardNo("11010519491231002X"); application.setWorkYearRange("3-5年"); service.createPendingFromApplication(application); ArgumentCaptor captor = ArgumentCaptor.forClass(GuideUser.class); verify(userMapper).insert(captor.capture()); GuideUser guide = captor.getValue(); assertThat(guide.getBirthDate()).isEqualTo(LocalDate.of(1949, 12, 31)); assertThat(guide.getWorkYears()).isEqualTo(3); } @Test void shouldCopyRegistrationProfileWhenApprovingPendingGuide() { GuideUser pendingGuide = new GuideUser(); pendingGuide.setId(12L); pendingGuide.setStatus(GuideUserService.STATUS_PENDING); pendingGuide.setMobile("13800138000"); when(userMapper.selectOne(any())).thenReturn(pendingGuide); GuideApplication application = new GuideApplication(); application.setMobile("13800138000"); application.setIdCardNo("11010519491231002X"); application.setWorkYearRange("5年以上"); service.createFromApprovedApplication(application); ArgumentCaptor captor = ArgumentCaptor.forClass(GuideUser.class); verify(userMapper).updateById(captor.capture()); assertThat(captor.getValue().getBirthDate()).isEqualTo(LocalDate.of(1949, 12, 31)); assertThat(captor.getValue().getWorkYears()).isEqualTo(5); } @Test void shouldReuseCancelledGuideForNewRegistration() { GuideUser cancelledGuide = new GuideUser(); cancelledGuide.setId(12L); cancelledGuide.setStatus(GuideUserService.STATUS_CANCELLED); cancelledGuide.setMobile("13800138000"); cancelledGuide.setAutoDisableWhitelisted(1); cancelledGuide.setAutoDisabled(1); when(userMapper.selectOne(any())).thenReturn(cancelledGuide); GuideApplication application = new GuideApplication(); application.setMobile("13800138000"); application.setRealName("瀵兼父"); application.setIdCardNo("11010519491231002X"); service.createPendingFromApplication(application); ArgumentCaptor captor = ArgumentCaptor.forClass(GuideUser.class); verify(userMapper).updateById(captor.capture()); GuideUser reusedGuide = captor.getValue(); assertThat(reusedGuide.getStatus()).isEqualTo(GuideUserService.STATUS_PENDING); assertThat(reusedGuide.getAutoDisableWhitelisted()).isZero(); assertThat(reusedGuide.getAutoDisabled()).isZero(); } @Test void shouldTreatOneYearOrLessAsZeroWorkYears() { GuideApplication application = new GuideApplication(); application.setMobile("13800138000"); application.setIdCardNo("11010519491231002X"); application.setWorkYearRange("1年以内"); service.createPendingFromApplication(application); ArgumentCaptor captor = ArgumentCaptor.forClass(GuideUser.class); verify(userMapper).insert(captor.capture()); assertThat(captor.getValue().getWorkYears()).isZero(); } @Test void shouldUseRegistrationProfileAsDetailFallbackForExistingGuide() { GuideUser guide = new GuideUser(); guide.setId(12L); guide.setMobile("13800138000"); guide.setIdCardNo("11010519491231002X"); when(userMapper.selectById(12L)).thenReturn(guide); GuideApplication application = new GuideApplication(); application.setIdCardNo(guide.getIdCardNo()); application.setAgeRange("26-35岁"); application.setWorkYearRange("1-3年"); when(applicationMapper.selectOne(any())).thenReturn(application); GuideUserDetailResponse response = service.detail(12L); assertThat(response.getBirthDate()).isEqualTo(LocalDate.of(1949, 12, 31)); assertThat(response.getAge()).isEqualTo(Period.between(LocalDate.of(1949, 12, 31), LocalDate.now()).getYears()); assertThat(response.getWorkYears()).isEqualTo(1); assertThat(response.getAgeRange()).isEqualTo("26-35岁"); assertThat(response.getWorkYearRange()).isEqualTo("1-3年"); } @Test void adminPhoneChangeShouldUpdatePhoneLoginIdentity() { GuideUser guide = new GuideUser(); guide.setId(12L); guide.setStatus(GuideUserService.STATUS_ENABLED); guide.setUsername("13800138000"); guide.setMobile("13800138000"); when(userMapper.selectForUpdate(12L)).thenReturn(guide); when(userMapper.selectById(12L)).thenReturn(guide); GuideUserDetailUpdateRequest request = new GuideUserDetailUpdateRequest(); request.setRealName("导游"); request.setMobile("13900139000"); service.updateDetail(12L, request); assertThat(guide.getMobile()).isEqualTo("13900139000"); assertThat(guide.getUsername()).isEqualTo("13900139000"); verify(userMapper).updateById(guide); } @Test void shouldRequireWhitelistBeforeEnablingAutoDisabledGuide() { GuideUser guide = new GuideUser(); guide.setId(12L); guide.setStatus(GuideUserService.STATUS_DISABLED); guide.setAutoDisabled(1); guide.setAutoDisableWhitelisted(0); when(userMapper.selectForUpdate(12L)).thenReturn(guide); assertThatThrownBy(() -> service.updateStatus(12L, GuideUserService.STATUS_ENABLED)) .isInstanceOf(BusinessException.class) .hasMessage("该导游由自动禁用规则停用,请先在自动禁用设置中添加白名单后再启用"); verify(userMapper, never()).updateById(any()); } @Test void shouldEnableAutoDisabledGuideAfterWhitelistIsAdded() { GuideUser guide = new GuideUser(); guide.setId(12L); guide.setStatus(GuideUserService.STATUS_DISABLED); guide.setAutoDisabled(1); guide.setAutoDisableWhitelisted(1); when(userMapper.selectForUpdate(12L)).thenReturn(guide); service.updateStatus(12L, GuideUserService.STATUS_ENABLED); assertThat(guide.getStatus()).isEqualTo(GuideUserService.STATUS_ENABLED); assertThat(guide.getAutoDisabled()).isZero(); verify(userMapper).updateById(guide); } @Test void shouldAutomaticallyEnableGuideWhenAddedToWhitelist() { GuideUser guide = new GuideUser(); guide.setId(12L); guide.setStatus(GuideUserService.STATUS_DISABLED); guide.setAutoDisabled(1); guide.setAutoDisableWhitelisted(0); when(userMapper.selectById(12L)).thenReturn(guide); service.updateWhitelist(12L, true); assertThat(guide.getAutoDisableWhitelisted()).isEqualTo(1); assertThat(guide.getStatus()).isEqualTo(GuideUserService.STATUS_ENABLED); assertThat(guide.getAutoDisabled()).isZero(); verify(userMapper).updateById(guide); } @Test void shouldKeepManuallyDisabledGuideDisabledWhenAddedToWhitelist() { GuideUser guide = new GuideUser(); guide.setId(12L); guide.setStatus(GuideUserService.STATUS_DISABLED); guide.setAutoDisabled(0); guide.setAutoDisableWhitelisted(0); when(userMapper.selectById(12L)).thenReturn(guide); service.updateWhitelist(12L, true); assertThat(guide.getAutoDisableWhitelisted()).isEqualTo(1); assertThat(guide.getStatus()).isEqualTo(GuideUserService.STATUS_DISABLED); assertThat(guide.getAutoDisabled()).isZero(); verify(userMapper).updateById(guide); } }