1package com.peachpasswords.ui.vault23import com.peachpasswords.vault.VaultEntry4import org.junit.Assert.assertEquals5import org.junit.Assert.assertFalse6import org.junit.Assert.assertNull7import org.junit.Assert.assertTrue8import org.junit.Test910class ImportParsersTest {1112 @Test fun detect_blank_is_null() {13 assertNull(CsvImport.detectProvider(""))14 assertNull(CsvImport.detectProvider(" \n "))15 }1617 @Test fun chrome_csv_detects_and_parses() {18 val csv = "name,url,username,password\nGitHub,https://github.com,june,hunter2\n"19 assertEquals(CsvImport.CHROME_CSV, CsvImport.detectProvider(csv))20 val rows = CsvImport.parse(csv, CsvImport.CHROME_CSV)21 assertEquals(1, rows.size)22 assertEquals("GitHub", rows[0].title)23 assertEquals("https://github.com", rows[0].url)24 assertEquals("june", rows[0].username)25 assertEquals("hunter2", rows[0].password)26 }2728 @Test fun csv_quoted_fields_with_commas_are_preserved() {29 val rows = CsvImport.parseCsv("name,url,username,password\n\"Bank, NA\",https://b.com,j,\"p,w\"\n")30 31 assertEquals(2, rows.size)32 assertEquals(listOf("Bank, NA", "https://b.com", "j", "p,w"), rows[1])33 }3435 @Test fun csv_doubled_quotes_unescape() {36 assertEquals(listOf("a\"b", "c"), CsvImport.splitCsvLine("\"a\"\"b\",c"))37 }3839 @Test fun detect_and_parse_returns_success_for_chrome() {40 val csv = "name,url,username,password\nA,https://a.com,u,p\nB,https://b.com,u2,p2\n"41 val r = CsvImport.detectAndParse(csv)42 assertTrue(r is ImportParseResult.Success)43 r as ImportParseResult.Success44 assertEquals(2, r.entries.size)45 }4647 @Test fun proton_pass_json_detects_and_parses_login_items() {48 val json = """49 {50 "vaults": {51 "main": {52 "name": "Personal",53 "items": [54 {55 "data": {56 "type": "login",57 "metadata": { "name": "Proton Site", "note": "saved note" },58 "content": {59 "username": "june",60 "password": "hunter2",61 "urls": ["https://example.com"],62 "totpUri": "otpauth://totp/Example:june?secret=JBSWY3DPEHPK3PXP"63 }64 }65 }66 ]67 },68 "trash": {69 "name": "Recycle Bin",70 "items": [71 {72 "data": {73 "type": "login",74 "metadata": { "name": "Deleted" },75 "content": { "username": "x", "password": "y" }76 }77 }78 ]79 }80 }81 }82 """.trimIndent()8384 assertEquals(CsvImport.PROTONPASS_JSON, CsvImport.detectProvider(json))85 val rows = CsvImport.parse(json, CsvImport.PROTONPASS_JSON)8687 assertEquals(1, rows.size)88 assertEquals("Proton Site", rows[0].title)89 assertEquals("june", rows[0].username)90 assertEquals("hunter2", rows[0].password)91 assertEquals("https://example.com", rows[0].url)92 assertEquals("saved note", rows[0].notes)93 assertEquals("otpauth://totp/Example:june?secret=JBSWY3DPEHPK3PXP", rows[0].totp)94 }9596 @Test fun peachscript_export_is_recognised() {97 val out = PeachScriptExport.buildEncrypted(98 listOf(99 VaultEntry(100 id = "11111111-2222-3333-4444-555555555555", type = "login",101 title = "GH", username = "u", password = "p", createdAt = 0, modifiedAt = 0,102 ),103 ),104 "backup-pass-123",105 )106 assertTrue(PeachScriptImport.looksLikePeachScript(out))107 assertTrue(PeachScriptImport.isEncrypted(out))108 }109110 @Test fun non_peachscript_text_is_rejected() {111 assertFalse(PeachScriptImport.looksLikePeachScript("just text"))112 113 assertFalse(PeachScriptImport.looksLikePeachScript("""{"peachscript":1,"encrypted":true}"""))114 }115116 @Test fun file_picker_routes_peachscript_files_to_peachscript_restore() {117 val out = PeachScriptExport.buildEncrypted(118 listOf(119 VaultEntry(120 id = "11111111-2222-3333-4444-555555555555", type = "login",121 title = "GH", username = "u", password = "p", createdAt = 0, modifiedAt = 0,122 ),123 ),124 "backup-pass-123",125 )126127 assertTrue(shouldRouteFileToPeachScript("backup.txt", out))128 assertTrue(shouldRouteFileToPeachScript("backup.peach", "not yet decoded"))129 assertFalse(shouldRouteFileToPeachScript("export.csv", "name,url,username,password\nA,https://a.com,u,p\n"))130 }131132 @Test fun import_errors_match_browser_recovery_copy() {133 assertEquals(134 "Wrong backup password. This is the password you chose when you created the backup.",135 ImportErrors.WRONG_PASSWORD,136 )137 assertEquals(138 "This Peach backup file looks corrupted or incomplete.",139 ImportErrors.CORRUPTED,140 )141 assertEquals(142 "No importable password entries were found in that file.",143 ImportErrors.NO_ENTRIES,144 )145 }146}