package kr.co.vividnext.sodalive.member import com.fasterxml.jackson.databind.ObjectMapper import kr.co.vividnext.sodalive.common.CountryContext import kr.co.vividnext.sodalive.content.ContentType import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.i18n.LangContext import kr.co.vividnext.sodalive.i18n.SodaMessageSource import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService import kr.co.vividnext.sodalive.member.contentpreference.ViewerContentPreference import kr.co.vividnext.sodalive.member.social.google.GoogleUserInfo import kr.co.vividnext.sodalive.member.stipulation.Stipulation import kr.co.vividnext.sodalive.member.stipulation.StipulationAgreeRepository import kr.co.vividnext.sodalive.member.stipulation.StipulationIds import kr.co.vividnext.sodalive.member.stipulation.StipulationRepository import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.mockito.Mockito import org.springframework.cache.CacheManager import java.time.LocalDateTime import java.util.Optional class MemberServiceContentPreferenceTest { private lateinit var repository: MemberRepository private lateinit var stipulationRepository: StipulationRepository private lateinit var stipulationAgreeRepository: StipulationAgreeRepository private lateinit var nicknameGenerateService: kr.co.vividnext.sodalive.member.nickname.NicknameGenerateService private lateinit var memberContentPreferenceService: MemberContentPreferenceService private lateinit var chargeRepository: kr.co.vividnext.sodalive.can.charge.ChargeRepository private lateinit var memberPointRepository: kr.co.vividnext.sodalive.point.MemberPointRepository private lateinit var pushTokenService: kr.co.vividnext.sodalive.fcm.PushTokenService private lateinit var service: MemberService @BeforeEach fun setup() { repository = mock() stipulationRepository = mock() stipulationAgreeRepository = mock() nicknameGenerateService = mock() memberContentPreferenceService = mock() chargeRepository = mock() memberPointRepository = mock() pushTokenService = mock() service = MemberService( repository = repository, tokenRepository = mock(), stipulationRepository = stipulationRepository, stipulationAgreeRepository = stipulationAgreeRepository, creatorFollowingRepository = mock(), blockMemberRepository = mock(), signOutRepository = mock(), nicknameChangeLogRepository = mock(), memberTagRepository = mock(), liveReservationRepository = mock(), chargeRepository = chargeRepository, memberPointRepository = memberPointRepository, orderService = mock(), emailService = mock(), pushTokenService = pushTokenService, canPaymentService = mock(), nicknameGenerateService = nicknameGenerateService, memberNotificationService = mock(), s3Uploader = mock(), validator = mock(), tokenProvider = mock(), passwordEncoder = mock(), authenticationManagerBuilder = mock(), messageSource = SodaMessageSource(), langContext = LangContext(), countryContext = CountryContext(), memberContentPreferenceService = memberContentPreferenceService, objectMapper = ObjectMapper(), cacheManager = mock(), homeFollowingNewsInboxPort = mock(), s3Bucket = "test-bucket", cloudFrontHost = "https://cdn.test" ) } @Test @DisplayName("getMemberInfo는 저장된 콘텐츠 설정 필드를 그대로 반환한다") fun shouldReturnStoredPreferenceFieldsInMemberInfo() { val member = createMember(1L) member.createdAt = LocalDateTime.of(2026, 1, 1, 0, 0) val preference = ViewerContentPreference( countryCode = "JP", isAdultContentVisible = true, contentType = ContentType.MALE, isAdult = true ) Mockito.`when`(memberContentPreferenceService.getStoredPreference(member)).thenReturn(preference) Mockito.`when`(chargeRepository.getChargeCount(1L)).thenReturn(3) Mockito.`when`( memberPointRepository.findByMemberIdAndExpiresAtAfterOrderByExpiresAtAsc( memberId = Mockito.eq(1L), expiresAt = anyLocalDateTime() ) ).thenReturn(emptyList()) val response = service.getMemberInfo(member, "web") assertEquals("JP", response.countryCode) assertEquals(true, response.isAdultContentVisible) assertEquals(ContentType.MALE, response.contentType) } @Test @DisplayName("Google 소셜 회원 신규 생성 시 기본 콘텐츠 설정을 선저장한다") fun shouldInitializePreferenceWhenGoogleMemberIsRegistered() { var savedMember: Member? = null val terms = Stipulation(title = "terms", description = "desc") terms.id = StipulationIds.TERMS_OF_SERVICE_ID val privacy = Stipulation(title = "privacy", description = "desc") privacy.id = StipulationIds.PRIVACY_POLICY_ID Mockito.`when`(repository.findByGoogleId("sub-1")).thenReturn(null) Mockito.`when`(repository.findByEmail("google@test.com")).thenReturn(null) Mockito.`when`(stipulationRepository.findById(StipulationIds.TERMS_OF_SERVICE_ID)).thenReturn(Optional.of(terms)) Mockito.`when`(stipulationRepository.findById(StipulationIds.PRIVACY_POLICY_ID)).thenReturn(Optional.of(privacy)) Mockito.`when`(nicknameGenerateService.generateUniqueNickname(anyLang())).thenReturn("newbie") Mockito.`when`(repository.save(Mockito.any(Member::class.java))).thenAnswer { invocation -> val saved = invocation.getArgument(0) saved.id = 10L savedMember = saved saved } Mockito.`when`(stipulationAgreeRepository.save(Mockito.any())).thenAnswer { invocation -> invocation.getArgument(0) } val result = service.findOrRegister( googleUserInfo = GoogleUserInfo(sub = "sub-1", email = "google@test.com", name = "google-user"), container = "web", marketingPid = null, pushToken = null ) assertTrue(result.isNew) Mockito.verify(memberContentPreferenceService).initializeDefaultPreference(savedMember!!) assertEquals(10L, savedMember!!.id) } private fun createMember(id: Long): Member { val member = Member( email = "member$id@test.com", password = "password", nickname = "member$id" ) member.id = id return member } private inline fun mock(): T { return Mockito.mock(T::class.java) } private fun anyLocalDateTime(): LocalDateTime = Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now() private fun anyLang(): Lang = Mockito.any(Lang::class.java) ?: Lang.KO }