package com.peachpasswords.ui import com.peachpasswords.ui.lock.postUnlockDestination import com.peachpasswords.ui.onboarding.onboardingStartDestination import com.peachpasswords.ui.vault.entryTapDestination import com.peachpasswords.vault.VaultEntry import org.junit.Assert.assertEquals import org.junit.Test /** * Navigation suite (brief Suite 9): route construction and the flow-decision * functions that route the app — onboarding gate, list-tap, and post-unlock. */ class NavigationFlowTest { private fun login(id: String) = VaultEntry(id = id, title = id, type = "login", createdAt = 0, modifiedAt = 0) private fun note(id: String) = VaultEntry(id = id, title = id, type = "note", createdAt = 0, modifiedAt = 0) // ── Route construction ──────────────────────────────────────────────────── @Test fun entry_detail_route_embeds_id() { assertEquals("entry/abc", PeachNav.EntryDetail("abc").route) assertEquals("entry/abc", PeachNav.EntryDetail.of("abc")) assertEquals("entry/{id}", PeachNav.EntryDetail.ROUTE) } @Test fun notes_mode_route_embeds_id() { assertEquals("notes/n1", PeachNav.NotesMode("n1").route) assertEquals("notes/n1", PeachNav.NotesMode.of("n1")) assertEquals("notes/{id}", PeachNav.NotesMode.ROUTE) } @Test fun entry_edit_route_handles_null_and_value() { assertEquals("edit?id=&prefillUrl=&prefillUsername=&prefillEmail=", PeachNav.EntryEdit(null).route) assertEquals("edit?id=x&prefillUrl=&prefillUsername=&prefillEmail=", PeachNav.EntryEdit("x").route) assertEquals("edit?id=&prefillUrl=&prefillUsername=&prefillEmail=", PeachNav.EntryEdit.of(null)) assertEquals("edit?id=x&prefillUrl=&prefillUsername=&prefillEmail=", PeachNav.EntryEdit.of("x")) } @Test fun entry_edit_route_carries_prefill_payload() { val route = PeachNav.EntryEdit.of( id = null, prefillUrl = "github.com", prefillUsername = "june", prefillEmail = "june@github.com", ) assertEquals( "edit?id=&prefillUrl=github.com&prefillUsername=june&prefillEmail=june@github.com", route, ) } @Test fun static_routes_are_stable() { assertEquals("onboarding", PeachNav.Onboarding.route) assertEquals("lock", PeachNav.Lock.route) assertEquals("vault", PeachNav.VaultList.route) assertEquals("settings", PeachNav.Settings.route) } @Test fun locked_navigation_allows_only_pre_vault_surfaces() { listOf( PeachNav.Onboarding.route, PeachNav.Lock.route, PeachNav.AdoptVault.route, PeachNav.Import.route, PeachNav.CodexRestore.route, PeachNav.RecoveryEntry.route, PeachNav.Update.route, ).forEach { route -> assertEquals("$route should stay available while locked", false, requiresUnlockedVault(route)) } listOf( PeachNav.Settings.route, PeachNav.VaultList.route, PeachNav.EntryDetail.ROUTE, PeachNav.Export.route, ).forEach { route -> assertEquals("$route should redirect to Lock", true, requiresUnlockedVault(route)) } } // ── First-launch gate ───────────────────────────────────────────────────── @Test fun first_launch_shows_onboarding() { assertEquals(PeachNav.Onboarding, onboardingStartDestination(hasVault = false, onboarded = false)) } @Test fun subsequent_launch_skips_onboarding() { assertEquals(PeachNav.Lock, onboardingStartDestination(hasVault = true, onboarded = true)) } // ── List tap ────────────────────────────────────────────────────────────── @Test fun list_tap_login_opens_detail() { assertEquals(PeachNav.EntryDetail("l"), entryTapDestination(login("l"))) } @Test fun list_tap_note_opens_notes_mode() { assertEquals(PeachNav.NotesMode("n"), entryTapDestination(note("n"))) } // ── Post-unlock landing ─────────────────────────────────────────────────── @Test fun post_unlock_opens_last_viewed() { val entries = mapOf("a" to login("a"), "b" to login("b")) assertEquals(PeachNav.EntryDetail("b"), postUnlockDestination("b", entries::get, entries["a"])) } @Test fun post_unlock_empty_vault_falls_to_list() { assertEquals(PeachNav.VaultList, postUnlockDestination(null, { null }, null)) } @Test fun vault_from_entry_uses_sheet_transition() { assertEquals(true, isVaultSheetTransition("entry/a", PeachNav.VaultList.route)) assertEquals(true, isVaultSheetTransition("notes/n", PeachNav.VaultList.route)) assertEquals(false, isVaultSheetTransition(PeachNav.Lock.route, PeachNav.VaultList.route)) } @Test fun vault_to_entry_uses_reverse_sheet_transition() { assertEquals(true, isVaultSheetTransition(PeachNav.VaultList.route, "entry/a", reverse = true)) assertEquals(true, isVaultSheetTransition(PeachNav.VaultList.route, "notes/n", reverse = true)) assertEquals(false, isVaultSheetTransition(PeachNav.VaultList.route, PeachNav.Settings.route, reverse = true)) } }