feat(content): 콘텐츠 이동 가드를 보강한다

This commit is contained in:
2026-06-27 03:54:45 +09:00
parent a0cfa70551
commit a91ec763e1
2 changed files with 117 additions and 16 deletions

View File

@@ -0,0 +1,76 @@
package kr.co.vividnext.sodalive.v2.main.content
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import java.io.File
class ContentMainFragmentLoginGuardSourceTest {
@Test
fun `ContentMainFragment 실제 이동은 MainV2 로그인 가드를 통과한다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt"
).readText()
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.ensureMainV2NavigationAllowed"))
assertGuardedStartActivity(source, "private fun onBannerClick(item: ContentBannerUiModel)")
assertGuardedStartActivity(source, "audioContentId: Long,\n requiresAdultContentAccess: Boolean = false")
assertGuardedStartActivity(source, "seriesId: Long,\n requiresAdultContentAccess: Boolean = false")
assertFalse(source.contains("kr.co.vividnext.sodalive.main.MainActivity"))
}
@Test
fun `ContentMainFragment invalid id return은 로그인 가드보다 먼저 유지된다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt"
).readText()
assertBeforeGuard(source, "val route = item.toContentBannerRoute() ?: return")
assertBeforeGuard(source, "if (audioContentId <= 0L) return")
assertBeforeGuard(source, "if (seriesId <= 0L) return")
}
@Test
fun `ContentMainFragment는 판단 가능한 성인 콘텐츠 여부를 guard에 전달한다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt"
).readText()
assertTrue(source.contains("openAudioContentDetail(item.audioContentId, item.showAdultBadge)"))
assertTrue(source.contains("openAudioContentDetail(audioContentId, findAllTabAudioAdultAccess(audioContentId))"))
assertTrue(source.contains("openSeriesDetail(seriesId, findAllTabSeriesAdultAccess(seriesId))"))
assertTrue(source.contains("requiresAdultContentAccess = requiresAdultContentAccess"))
assertFalse(source.contains("ContentCommentedAudioUiModel.showAdultBadge"))
assertFalse(source.contains("ContentOriginalSeriesUiModel.showAdultBadge"))
}
private fun assertGuardedStartActivity(source: String, functionSignature: String) {
val functionSource = source.substringFrom(functionSignature)
assertTrue(
"$functionSignature must call ensureMainV2NavigationAllowed before startActivity.",
functionSource.indexOf("ensureMainV2NavigationAllowed") in 0 until functionSource.indexOf("startActivity")
)
}
private fun assertBeforeGuard(source: String, expectedReturn: String) {
val returnIndex = source.indexOf(expectedReturn)
val guardIndex = source.indexOf("ensureMainV2NavigationAllowed", returnIndex)
assertTrue("Missing source: $expectedReturn", returnIndex >= 0)
assertTrue("$expectedReturn must stay before guard.", guardIndex > returnIndex)
}
private fun String.substringFrom(marker: String): String {
val startIndex = indexOf(marker)
assertTrue("Missing function: $marker", startIndex >= 0)
val nextFunctionIndex = indexOf("\n private fun ", startIndex + marker.length).takeIf { it >= 0 } ?: length
return substring(startIndex, nextFunctionIndex)
}
private fun projectFile(relativePath: String): File {
val candidates = listOf(File(relativePath), File("../$relativePath"))
return candidates.firstOrNull { it.exists() }
?: error("Project file not found: $relativePath")
}
}