1package com.peachpasswords.autofill23import com.peachpasswords.vault.VaultEntry4import org.junit.Assert.assertEquals5import org.junit.Assert.assertNull6import org.junit.Assert.assertTrue7import org.junit.Test89class AutofillSaveTest {1011 private fun entry(12 title: String,13 url: String,14 username: String? = "june",15 password: String = "old",16 ) = VaultEntry(17 id = title,18 type = "login",19 title = title,20 username = username,21 password = password,22 url = url,23 createdAt = 1,24 modifiedAt = 1,25 )2627 @Test28 fun autofillSaveDraft_requiresOriginAndPassword() {29 assertNull(autofillSaveDraft(ParsedStructure(webDomain = "example.com")))30 assertNull(autofillSaveDraft(ParsedStructure(passwordValue = "pw")))31 assertNull(32 autofillSaveDraft(33 ParsedStructure(34 webDomain = "example.com",35 passwordValue = "pw",36 credentialReleaseAllowed = false,37 ),38 ),39 )40 }4142 @Test43 fun planAutofillSave_addsNewWebLogin() {44 val draft = autofillSaveDraft(45 ParsedStructure(46 emailValue = "[email protected]",47 passwordValue = "new-secret",48 webDomain = "login.example.com",49 ),50 )!!5152 val plan = planAutofillSave(emptyList(), draft)5354 assertTrue(plan is AutofillSavePlan.Add)55 val entry = (plan as AutofillSavePlan.Add).entry56 assertEquals("login.example.com", entry.title)57 assertEquals("[email protected]", entry.email)58 assertEquals("new-secret", entry.password)59 assertEquals("https://login.example.com", entry.url)60 }6162 @Test63 fun planAutofillSave_updatesMatchingWebOriginAndIdentity() {64 val existing = entry("Example", "https://example.com/login", username = "june")65 val draft = AutofillSaveDraft(66 origin = "app.example.com",67 isWebOrigin = true,68 identity = "june",69 identityIsEmail = false,70 password = "new",71 )7273 val plan = planAutofillSave(listOf(existing), draft)7475 assertTrue(plan is AutofillSavePlan.Update)76 val updated = (plan as AutofillSavePlan.Update).entry77 assertEquals(existing.id, updated.id)78 assertEquals("new", updated.password)79 assertEquals("june", updated.username)80 }8182 @Test83 fun planAutofillSave_doesNotUpdateSubstringLookalikeOrigin() {84 val existing = entry("GitHub", "https://github.com/login", username = "june")85 val draft = AutofillSaveDraft(86 origin = "notgithub.com",87 isWebOrigin = true,88 identity = "june",89 identityIsEmail = false,90 password = "phished",91 )9293 val plan = planAutofillSave(listOf(existing), draft)9495 assertTrue(plan is AutofillSavePlan.Add)96 }9798 @Test99 fun planAutofillSave_updatesNativePackageOnlyOnExactOrigin() {100 val existing = entry("Native", "com.example.app", username = "june").copy(totp = "JBSWY3DPEHPK3PXP")101 val draft = AutofillSaveDraft(102 origin = "com.example.app",103 isWebOrigin = false,104 identity = "june",105 identityIsEmail = false,106 password = "new-native",107 )108109 val plan = planAutofillSave(listOf(existing), draft)110111 assertTrue(plan is AutofillSavePlan.Update)112 val updated = (plan as AutofillSavePlan.Update).entry113 assertEquals("new-native", updated.password)114 assertEquals("a save must never overwrite the stored seed", "JBSWY3DPEHPK3PXP", updated.totp)115 }116117 @Test118 fun autofillSaveDraft_ignores_a_live_otp_code_from_the_page() {119 120 121 122 val draft = autofillSaveDraft(123 ParsedStructure(124 webDomain = "example.com",125 passwordValue = "new",126 otpValue = "123456",127 ),128 )129130 assertTrue(draft != null)131 val existing = entry("Example", "https://example.com/login").copy(totp = "JBSWY3DPEHPK3PXP")132 val plan = planAutofillSave(listOf(existing), draft!!)133 assertEquals(134 "the stored seed is untouched by a save",135 "JBSWY3DPEHPK3PXP",136 (plan as AutofillSavePlan.Update).entry.totp,137 )138 }139}