package com.suno.android.common_data.repos import arrow.core.Either import arrow.retrofit.adapter.either.networkhandling.CallError import arrow.retrofit.adapter.either.networkhandling.HttpError import com.suno.android.common_core_utils.Id import com.suno.android.common_core_utils.SunoLogger import com.suno.android.common_core_utils.model.UserHandle import com.suno.android.common_data.metadata.MetadataType import com.suno.android.common_data.metadata.RecommendationMetadata import com.suno.android.common_networking.remote.entities.RemoteHideCreatorResponse import com.suno.android.common_networking.remote.recommendations.RecommendationsService import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Test class DefaultRecommendationsRepositoryTest { private val recommendationMetadata = RecommendationMetadata( hookId = Id("hookId"), recommendationItemId = Id("recommendationItemId"), metadataType = MetadataType.HooksFeed, ) private val loggerFactory = mockk(relaxed = true) private val recommendationsService = mockk() private val subject = DefaultRecommendationsRepository( loggerFactory = loggerFactory, recommendationsService = recommendationsService, ) @Test fun `given successful service response with success true when toggleHideCreator called then returns success`() = runTest { val creatorHandle = UserHandle("testuser") val contentType = HideCreatorContentType.Hook val hide = true mockSuccessfulServiceCall(success = true) val result = subject.toggleHideCreator( creatorHandle = creatorHandle, contentType = contentType, hide = hide, recommendationMetadata = recommendationMetadata, ) assertSuccessResult(result) verifyServiceCalledWithCorrectBody( creatorHandle = creatorHandle, contentType = contentType.value, unhide = false, recommendationMetadata = recommendationMetadata, ) } @Test fun `given successful service response with success false when toggleHideCreator called then returns error`() = runTest { val creatorHandle = UserHandle("testuser") val contentType = HideCreatorContentType.Hook val hide = true mockSuccessfulServiceCall(success = false) val result = subject.toggleHideCreator( creatorHandle = creatorHandle, contentType = contentType, hide = hide, recommendationMetadata = null, ) assertErrorResult(result) { throwable -> assertEquals("API returned success=false for hide creator request", throwable.message) } } @Test fun `given hide false when toggleHideCreator called then sends unhide true`() = runTest { val creatorHandle = UserHandle("testuser") val contentType = HideCreatorContentType.Hook val hide = false mockSuccessfulServiceCall(success = true) val result = subject.toggleHideCreator( creatorHandle = creatorHandle, contentType = contentType, hide = hide, recommendationMetadata = recommendationMetadata, ) assertSuccessResult(result) verifyServiceCalledWithCorrectBody( creatorHandle = creatorHandle, contentType = contentType.value, unhide = true, recommendationMetadata = recommendationMetadata, ) } @Test fun `given service error when toggleHideCreator called then returns error`() = runTest { val creatorHandle = UserHandle("testuser") val contentType = HideCreatorContentType.Hook val hide = true val httpError = HttpError(500, "Internal Server Error", "") mockServiceError(httpError) val result = subject.toggleHideCreator( creatorHandle = creatorHandle, contentType = contentType, hide = hide, recommendationMetadata = null, ) assertErrorResult(result) { throwable -> assertEquals("HTTP 500: Internal Server Error", throwable.message) } } private fun mockSuccessfulServiceCall( success: Boolean, ) { val response = RemoteHideCreatorResponse(success = success) coEvery { recommendationsService.hideCreator(any()) } returns Either.Right(response) } private fun mockServiceError( error: CallError, ) { coEvery { recommendationsService.hideCreator(any()) } returns Either.Left(error) } private fun verifyServiceCalledWithCorrectBody( creatorHandle: UserHandle, contentType: String, unhide: Boolean, recommendationMetadata: RecommendationMetadata?, ) { coVerify { recommendationsService.hideCreator( match { body -> val remoteMetadata = body.recommendationMetadata body.userHandle == creatorHandle.handle && body.contentType == contentType && body.unhide == unhide && remoteMetadata?.hookId == recommendationMetadata?.hookId?.value && remoteMetadata?.recommendationItemId == recommendationMetadata?.recommendationItemId?.value && remoteMetadata?.contextType == recommendationMetadata?.metadataType?.value }, ) } } private fun assertSuccessResult( result: Either, ) { when (result) { is Either.Right -> assertEquals(Unit, result.value) is Either.Left -> throw AssertionError("Expected success but got error: ${result.value}") } } private fun assertErrorResult( result: Either, assertion: (Throwable) -> Unit, ) { when (result) { is Either.Left -> assertion(result.value) is Either.Right -> throw AssertionError("Expected error but got success") } } }