feat(content): 전체 탭 UI 매핑을 추가한다

This commit is contained in:
2026-06-25 01:55:05 +09:00
parent ee74519f6f
commit af895ed510
4 changed files with 277 additions and 0 deletions

View File

@@ -0,0 +1,154 @@
package kr.co.vividnext.sodalive.v2.main.content
import kr.co.vividnext.sodalive.home.SeriesPublishedDaysOfWeek
import kr.co.vividnext.sodalive.v2.common.data.ContentSort
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllTabResponse
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllType
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAudioResponse
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentSeriesResponse
import kr.co.vividnext.sodalive.v2.main.content.model.toContent
import kr.co.vividnext.sodalive.v2.main.content.model.usesDayOfWeekQuery
import kr.co.vividnext.sodalive.v2.main.content.model.usesSeriesItems
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 MainContentAllTabMapperTest {
@Test
fun `AUDIO FREE POINT는 audios 목록만 사용한다`() {
listOf(MainContentAllType.AUDIO, MainContentAllType.FREE, MainContentAllType.POINT).forEach { type ->
val content = response(type = type, audios = listOf(audio()), series = listOf(series())).toContent()
assertEquals(1, content.audioItems.size)
assertEquals(emptyList<Any>(), content.seriesItems)
}
}
@Test
fun `SERIES ORIGINAL은 series 목록만 사용한다`() {
listOf(MainContentAllType.SERIES, MainContentAllType.ORIGINAL).forEach { type ->
val content = response(type = type, audios = listOf(audio()), series = listOf(series())).toContent()
assertEquals(emptyList<Any>(), content.audioItems)
assertEquals(1, content.seriesItems.size)
}
}
@Test
fun `ORIGINAL은 시리즈 카드 타입으로 분류된다`() {
assertTrue(MainContentAllType.ORIGINAL.usesSeriesItems())
assertFalse(MainContentAllType.ORIGINAL.usesDayOfWeekQuery())
}
@Test
fun `성인 flag는 오디오와 시리즈 UI model의 adult badge로 매핑된다`() {
val audioContent = response(type = MainContentAllType.AUDIO, audios = listOf(audio(isAdult = true))).toContent()
val seriesContent = response(type = MainContentAllType.SERIES, series = listOf(series(isAdult = true))).toContent()
assertTrue(audioContent.audioItems.single().showAdultBadge)
assertTrue(seriesContent.seriesItems.single().showAdultBadge)
}
@Test
fun `오디오 flag와 가격은 tag로 매핑된다`() {
val item = response(
audios = listOf(
audio(
price = 0,
isPointAvailable = true,
isFirstContent = true,
isOriginalSeries = true
)
)
).toContent().audioItems.single()
assertTrue(AudioContentTag.Point in item.tags)
assertTrue(AudioContentTag.First in item.tags)
assertTrue(AudioContentTag.Original in item.tags)
assertTrue(AudioContentTag.Free in item.tags)
}
@Test
fun `paging과 선택 조건 metadata가 content state에 보존된다`() {
val content = response(
type = MainContentAllType.SERIES,
totalCount = 42,
sort = ContentSort.POPULAR,
dayOfWeek = SeriesPublishedDaysOfWeek.WED,
page = 2,
size = 30,
hasNext = true
).toContent()
assertEquals(MainContentAllType.SERIES, content.selectedType)
assertEquals(ContentSort.POPULAR, content.selectedSort)
assertEquals(SeriesPublishedDaysOfWeek.WED, content.selectedDayOfWeek)
assertEquals(42, content.totalCount)
assertEquals(2, content.page)
assertEquals(30, content.size)
assertTrue(content.hasNext)
}
private fun response(
type: MainContentAllType = MainContentAllType.AUDIO,
totalCount: Int = 1,
audios: List<MainContentAudioResponse> = emptyList(),
series: List<MainContentSeriesResponse> = emptyList(),
sort: ContentSort = ContentSort.LATEST,
dayOfWeek: SeriesPublishedDaysOfWeek? = null,
page: Int = 0,
size: Int = 20,
hasNext: Boolean = false
) = MainContentAllTabResponse(
type = type,
totalCount = totalCount,
audios = audios,
series = series,
sort = sort,
dayOfWeek = dayOfWeek,
page = page,
size = size,
hasNext = hasNext
)
private fun audio(
audioContentId: Long = 1L,
title: String = "오디오",
imageUrl: String? = "https://example.com/audio.png",
price: Int = 100,
isAdult: Boolean = false,
isPointAvailable: Boolean = false,
isFirstContent: Boolean = false,
isOriginalSeries: Boolean = false,
creatorNickname: String = "크리에이터"
) = MainContentAudioResponse(
audioContentId = audioContentId,
title = title,
imageUrl = imageUrl,
price = price,
isAdult = isAdult,
isPointAvailable = isPointAvailable,
isFirstContent = isFirstContent,
isOriginalSeries = isOriginalSeries,
creatorNickname = creatorNickname
)
private fun series(
seriesId: Long = 1L,
title: String = "시리즈",
coverImageUrl: String? = "https://example.com/series.png",
creatorNickname: String = "크리에이터",
isOriginal: Boolean = true,
isAdult: Boolean = false
) = MainContentSeriesResponse(
seriesId = seriesId,
title = title,
coverImageUrl = coverImageUrl,
creatorNickname = creatorNickname,
isOriginal = isOriginal,
isAdult = isAdult
)
}