package com.mydreamjob.talentinvitation; import com.mydreamjob.talentdiscovery.CandidateKeyGenerator; import com.mydreamjob.talentdiscovery.TalentDiscoveryCandidateSource; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.time.LocalDateTime; import java.util.List; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class TalentInvitationCandidateResolverTest { @Mock TalentDiscoveryCandidateSource source; @Mock CandidateKeyGenerator keyGenerator; @Test void resolvesOnlyCurrentKeyAndCandidateWithAtLeastOneSignal() { TalentInvitationCandidateResolver resolver = new TalentInvitationCandidateResolver(source, keyGenerator); LocalDateTime now = LocalDateTime.of(2026, 9, 7, 10, 0); var enabled = new TalentDiscoveryCandidateSource.CandidateSeed(101L, "北京", "本科", 2026, "[]", now); var noSignal = new TalentDiscoveryCandidateSource.CandidateSeed(102L, "上海", "本科", 2026, "[]", now); when(source.findEligibleCandidates(9L)).thenReturn(List.of(enabled, noSignal)); when(source.findPreferences(any())).thenReturn(Map.of(101L, new TalentDiscoveryCandidateSource.PreferenceSignal(null, null, List.of("北京"), List.of(), List.of(), List.of(), false))); when(source.findLatestRiasec(any())).thenReturn(Map.of()); when(source.findLatestAbility(any(), eq(now))).thenReturn(Map.of()); when(keyGenerator.generate(9L, 8L, 101L, now.toLocalDate())).thenReturn("key-101"); assertThat(resolver.resolve(9L, 8L, "key-101", now).matched()).isTrue(); assertThat(resolver.resolve(9L, 8L, "key-102", now).matched()).isFalse(); verify(keyGenerator, never()).generate(9L, 8L, 102L, now.toLocalDate()); } @Test void malformedOrCrossDayKeyDoesNotResolve() { TalentInvitationCandidateResolver resolver = new TalentInvitationCandidateResolver(source, keyGenerator); LocalDateTime now = LocalDateTime.of(2026, 9, 7, 10, 0); var candidate = new TalentDiscoveryCandidateSource.CandidateSeed(101L, "北京", "本科", 2026, "[]", now); when(source.findEligibleCandidates(9L)).thenReturn(List.of(candidate)); when(source.findPreferences(any())).thenReturn(Map.of(101L, new TalentDiscoveryCandidateSource.PreferenceSignal(null, null, List.of("北京"), List.of(), List.of(), List.of(), false))); when(source.findLatestRiasec(any())).thenReturn(Map.of()); when(source.findLatestAbility(any(), eq(now))).thenReturn(Map.of()); when(keyGenerator.generate(9L, 8L, 101L, now.toLocalDate())).thenReturn("key-101"); assertThat(resolver.resolve(9L, 8L, "tampered", now).matched()).isFalse(); verify(keyGenerator).generate(9L, 8L, 101L, now.toLocalDate()); } }