feat(home): 팔로잉 탭 로그인 가드를 보강한다

This commit is contained in:
2026-06-27 03:54:21 +09:00
parent 39dd003b4e
commit a0cfa70551
2 changed files with 173 additions and 23 deletions

View File

@@ -0,0 +1,117 @@
package kr.co.vividnext.sodalive.v2.main.home
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import java.io.File
class HomeMainFragmentLoginGuardSourceTest {
@Test
fun `HomeMainFragment 실제 이동은 MainV2 로그인 가드를 통과한다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt"
).readText()
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.ensureMainV2NavigationAllowed"))
assertGuardedStartActivity(source, "private fun openHomeOnAirLive()")
assertGuardedStartActivity(source, "private fun openFollowingChat(item: ChatRoomListUiItem)")
assertGuardedStartActivity(source, "private fun onBannerClick(item: HomeRecommendationBannerUiModel)")
assertGuardedStartActivity(
source,
"private fun onRecentActivityClick(item: HomeRecommendationRecentlyActiveCreatorUiModel)"
)
assertGuardedStartActivity(source, "private fun onAiCharacterClick(item: HomeRecommendationAiCharacterUiModel)")
assertGuardedStartActivity(source, "private fun openCreatorProfile(creatorId: Long)")
assertGuardedStartActivity(source, "private fun openAudioContentDetail(item: HomeRecommendationFirstAudioContentUiModel)")
assertGuardedStartActivity(source, "private fun openPopularCommunityPost(item: FeedItem.Community)")
}
@Test
fun `HomeMainFragment invalid route와 id return은 로그인 가드보다 먼저 유지된다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt"
).readText()
assertBeforeGuard(source, "val route = item.toHomeRecommendationBannerRoute() ?: return")
assertBeforeGuard(source, "val route = item.toHomeRecommendationRecentlyActiveCreatorRoute() ?: return")
assertBeforeGuard(source, "val route = item.toHomeRecommendationAiCharacterRoute() ?: return")
assertBeforeGuard(source, "val creatorId = item.creatorId.toLongOrNull() ?: return")
assertBeforeGuard(source, "val postId = item.postId.toLongOrNull() ?: return")
assertFalse(source.contains("requiresAdultContentAccess = true"))
}
@Test
fun `HomeMainFragment 팔로잉 탭 선택은 로그인 가드 통과 후 탭을 전환한다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt"
).readText()
val listenerSource = source.substringFrom("binding.textTabBarHome.root.setOnTabSelectedListener { index ->")
assertTrue(listenerSource.contains("HOME_TAB_FOLLOWING -> openFollowingTab()"))
assertTrue(listenerSource.contains("else -> showHomeTab(index)"))
assertFalse(listenerSource.contains("showHomeTab(index)\n }"))
val followingTabSource = source.substringFrom("HOME_TAB_FOLLOWING -> {")
assertTrue(followingTabSource.contains("homeFollowingViewModel.loadFollowing()"))
}
@Test
fun `HomeMainFragment 팔로잉 탭 미로그인 차단은 이전 탭 선택 상태로 복구한다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt"
).readText()
assertTrue(source.contains("import kr.co.vividnext.sodalive.common.SharedPreferenceManager"))
assertTrue(source.contains("private var currentHomeTabIndex = HOME_TAB_RECOMMENDATION"))
val followingTabSource = source.substringFrom("private fun openFollowingTab()")
assertTrue(followingTabSource.contains("if (SharedPreferenceManager.token.isBlank())"))
assertBefore(
followingTabSource,
"binding.textTabBarHome.root.selectTab(currentHomeTabIndex)",
"ensureMainV2NavigationAllowed"
)
assertTrue(followingTabSource.contains("showHomeTab(HOME_TAB_FOLLOWING)"))
val showHomeTabSource = source.substringFrom("private fun showHomeTab(index: Int)")
assertTrue(showHomeTabSource.contains("currentHomeTabIndex = index"))
}
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 assertBefore(source: String, expectedBefore: String, expectedAfter: String) {
val beforeIndex = source.indexOf(expectedBefore)
val afterIndex = source.indexOf(expectedAfter, beforeIndex)
assertTrue("Missing source: $expectedBefore", beforeIndex >= 0)
assertTrue("Missing source after $expectedBefore: $expectedAfter", afterIndex > beforeIndex)
}
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")
}
}