feat(content): 추천 UI 모델 매핑을 추가한다

This commit is contained in:
2026-06-23 15:50:24 +09:00
parent 5746239873
commit c02437797c
4 changed files with 319 additions and 0 deletions

View File

@@ -0,0 +1,176 @@
package kr.co.vividnext.sodalive.v2.main.content
import kr.co.vividnext.sodalive.v2.main.content.data.AudioBannerResponse
import kr.co.vividnext.sodalive.v2.main.content.data.AudioCardResponse
import kr.co.vividnext.sodalive.v2.main.content.data.AudioRecommendationsResponse
import kr.co.vividnext.sodalive.v2.main.content.data.CommentedAudioResponse
import kr.co.vividnext.sodalive.v2.main.content.data.OriginalSeriesResponse
import kr.co.vividnext.sodalive.v2.main.content.model.toContent
import kr.co.vividnext.sodalive.v2.widget.AudioContentTag
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
class AudioRecommendationsMapperTest {
@Test
fun `price가 0이면 무료 tag가 포함된다`() {
val item = response(latestAudios = listOf(audio(price = 0))).toContent().latestAudios.items.single()
assertTrue(AudioContentTag.Free in item.tags)
}
@Test
fun `포인트 첫 콘텐츠 오리지널 시리즈 flag는 tag로 매핑된다`() {
val item = response(
latestAudios = listOf(
audio(
isPointAvailable = true,
isFirstContent = true,
isOriginalSeries = true
)
)
).toContent().latestAudios.items.single()
assertTrue(AudioContentTag.Point in item.tags)
assertTrue(AudioContentTag.First in item.tags)
assertTrue(AudioContentTag.Original in item.tags)
}
@Test
fun `성인 콘텐츠 flag는 showAdultBadge로 매핑된다`() {
val item = response(latestAudios = listOf(audio(isAdult = true))).toContent().latestAudios.items.single()
assertTrue(item.showAdultBadge)
}
@Test
fun `duration은 공통 오디오 UI model에 노출하지 않는다`() {
val fields = response(latestAudios = listOf(audio(duration = "10:00")))
.toContent()
.latestAudios
.items
.single()
.javaClass
.declaredFields
.map { it.name }
assertFalse(fields.contains("duration"))
}
@Test
fun `빈 리스트 섹션은 content의 empty 판단에 반영된다`() {
val content = response().toContent()
assertTrue(content.isEmpty)
assertEquals(emptyList<Any>(), content.latestAudios.items)
assertEquals(emptyList<Any>(), content.recommendedAudios.items)
}
@Test
fun `latestComment가 blank이면 댓글 영역 표시 flag가 false다`() {
val item = response(mostCommentedAudios = listOf(commentedAudio(latestComment = " ")))
.toContent()
.mostCommentedAudios
.items
.single()
assertFalse(item.showLatestComment)
}
@Test
fun `응답 리스트는 섹션별 UI model로 매핑된다`() {
val content = response(
banners = listOf(banner()),
originalSeries = listOf(originalSeries()),
latestAudios = listOf(audio(audioContentId = 1L)),
newAndHotAudios = listOf(audio(audioContentId = 2L)),
freeAudios = listOf(audio(audioContentId = 3L)),
pointAudios = listOf(audio(audioContentId = 4L)),
mostCommentedAudios = listOf(commentedAudio(audioContentId = 5L)),
recommendedAudios = listOf(audio(audioContentId = 6L))
).toContent()
assertFalse(content.isEmpty)
assertEquals(1, content.banners.items.size)
assertEquals(10L, content.originalSeries.items.single().seriesId)
assertEquals(1L, content.latestAudios.items.single().audioContentId)
assertEquals(2L, content.newAndHotAudios.items.single().audioContentId)
assertEquals(3L, content.freeAudios.items.single().audioContentId)
assertEquals(4L, content.pointAudios.items.single().audioContentId)
assertEquals(5L, content.mostCommentedAudios.items.single().audioContentId)
assertEquals(6L, content.recommendedAudios.items.single().audioContentId)
}
private fun response(
banners: List<AudioBannerResponse> = emptyList(),
originalSeries: List<OriginalSeriesResponse> = emptyList(),
latestAudios: List<AudioCardResponse> = emptyList(),
newAndHotAudios: List<AudioCardResponse> = emptyList(),
freeAudios: List<AudioCardResponse> = emptyList(),
pointAudios: List<AudioCardResponse> = emptyList(),
mostCommentedAudios: List<CommentedAudioResponse> = emptyList(),
recommendedAudios: List<AudioCardResponse> = emptyList()
) = AudioRecommendationsResponse(
banners = banners,
originalSeries = originalSeries,
latestAudios = latestAudios,
newAndHotAudios = newAndHotAudios,
freeAudios = freeAudios,
pointAudios = pointAudios,
mostCommentedAudios = mostCommentedAudios,
recommendedAudios = recommendedAudios
)
private fun banner() = AudioBannerResponse(
imageUrl = "https://example.com/banner.png",
eventItem = null,
creatorId = null,
seriesId = null,
link = null
)
private fun originalSeries() = OriginalSeriesResponse(
seriesId = 10L,
coverImageUrl = "https://example.com/series.png"
)
private fun audio(
audioContentId: Long = 1L,
title: String = "오디오",
duration: String? = "10:00",
imageUrl: String? = "https://example.com/audio.png",
price: Int = 100,
isAdult: Boolean = false,
isPointAvailable: Boolean = false,
isFirstContent: Boolean = false,
isOriginalSeries: Boolean = false,
creatorNickname: String = "크리에이터"
) = AudioCardResponse(
audioContentId = audioContentId,
title = title,
duration = duration,
imageUrl = imageUrl,
price = price,
isAdult = isAdult,
isPointAvailable = isPointAvailable,
isFirstContent = isFirstContent,
isOriginalSeries = isOriginalSeries,
creatorNickname = creatorNickname
)
private fun commentedAudio(
audioContentId: Long = 1L,
title: String = "댓글 오디오",
imageUrl: String? = "https://example.com/commented.png",
latestComment: String = "좋아요",
latestCommentWriterProfileImageUrl: String = "https://example.com/profile.png"
) = CommentedAudioResponse(
audioContentId = audioContentId,
title = title,
imageUrl = imageUrl,
latestComment = latestComment,
latestCommentWriterProfileImageUrl = latestCommentWriterProfileImageUrl
)
}