//! LastPass CSV importer — parser coverage. use relicario_core::import_lastpass::{parse_lastpass_csv, ImportWarning}; use relicario_core::ItemCore; const HEADER: &str = "url,username,password,totp,extra,name,grouping,fav"; #[test] fn single_login_row_round_trips() { let csv = format!( "{HEADER}\n\ https://github.com/login,alice,hunter2,,,GitHub,,", ); let (items, warnings) = parse_lastpass_csv(csv.as_bytes()).unwrap(); assert_eq!(items.len(), 1, "one item expected"); assert!(warnings.is_empty(), "no warnings expected"); let item = &items[0]; assert_eq!(item.title, "GitHub"); assert!(!item.favorite); assert!(item.group.is_none()); match &item.core { ItemCore::Login(l) => { assert_eq!(l.username.as_deref(), Some("alice")); assert_eq!(l.password.as_deref().map(String::as_str), Some("hunter2")); assert_eq!(l.url.as_ref().map(|u| u.as_str()), Some("https://github.com/login")); assert!(l.totp.is_none()); } other => panic!("expected Login, got {:?}", other), } } #[test] fn item_id_is_freshly_minted() { // Decision D12: title collisions don't dedupe; each row gets a fresh ID. let csv = format!("{HEADER}\nhttps://x,u,p,,,Same,,\nhttps://x,u,p,,,Same,,"); let (items, _) = parse_lastpass_csv(csv.as_bytes()).unwrap(); assert_eq!(items.len(), 2); assert_ne!(items[0].id, items[1].id, "IDs must be unique even for identical names"); } // Assertion helper used by later tests. #[allow(dead_code)] fn first_warning_message(warnings: &[ImportWarning]) -> String { warnings.first().expect("expected at least one warning").message.clone() }