diff --git a/src/args.rs b/src/args.rs index f670bfd..d221048 100644 --- a/src/args.rs +++ b/src/args.rs @@ -41,6 +41,9 @@ pub struct AddPass { pub struct GetPass { /// The name of the password to get pub name: String, + /// Copy the password to the clipboard instead of printing it + #[arg(short, long)] + pub copy: bool, } #[derive(Args)] @@ -48,38 +51,3 @@ pub struct DeletePass { /// The name of the password to delete pub name: String, } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn parses_add_command() { - let cli = Cli::try_parse_from(["pm", "add", "github"]).expect("parse add"); - match cli.command { - Some(Commands::Add(add)) => assert_eq!(add.name, "github"), - _ => panic!("expected add command"), - } - } - - #[test] - fn parses_get_command() { - let cli = Cli::try_parse_from(["pm", "get", "email"]).expect("parse get"); - match cli.command { - Some(Commands::Get(get)) => assert_eq!(get.name, "email"), - _ => panic!("expected get command"), - } - } - - #[test] - fn rejects_removed_copy_flag() { - let cli = Cli::try_parse_from(["pm", "get", "email", "--copy"]); - assert!(cli.is_err()); - } - - #[test] - fn parses_list_command() { - let cli = Cli::try_parse_from(["pm", "list"]).expect("parse list"); - assert!(matches!(cli.command, Some(Commands::List))); - } -} diff --git a/src/storage.rs b/src/storage.rs index 5d42f96..f9879d6 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -118,74 +118,3 @@ pub fn verify_master_password(password: &str, recorded_hash: &str) -> bool { .verify_password(password.as_bytes(), &parsed_hash) .is_ok() } - -#[cfg(test)] -mod tests { - use super::*; - use std::time::{SystemTime, UNIX_EPOCH}; - - fn temp_file_path(prefix: &str) -> String { - let nanos = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("time went backwards") - .as_nanos(); - std::env::temp_dir() - .join(format!("pm_test_{}_{}_{}", prefix, std::process::id(), nanos)) - .to_string_lossy() - .to_string() - } - - #[test] - fn key_derivation_is_deterministic_for_same_input() { - let mut p1 = String::from("master-password"); - let mut p2 = String::from("master-password"); - let salt = "abc123fixedsalt"; - - let k1 = derive_key(&mut p1, salt); - let k2 = derive_key(&mut p2, salt); - - assert_eq!(k1, k2); - } - - #[test] - fn hash_and_verify_master_password_work() { - let password = "correct-horse-battery-staple"; - let hash = hash_master_password(password); - - assert!(verify_master_password(password, &hash)); - assert!(!verify_master_password("wrong-password", &hash)); - } - - #[test] - fn save_load_and_delete_roundtrip() { - let path = temp_file_path("vault"); - let key = [7u8; 32]; - let mut data = HashMap::new(); - data.insert("email".to_string(), "pw1".to_string()); - data.insert("bank".to_string(), "pw2".to_string()); - - save_passwords(&path, &data, &key); - let loaded = load_passwords(&path, &key); - assert_eq!(loaded, data); - - delete_password(&path, "email", &key); - let after_delete = load_passwords(&path, &key); - assert!(!after_delete.contains_key("email")); - assert_eq!(after_delete.get("bank"), Some(&"pw2".to_string())); - - let _ = std::fs::remove_file(path); - } - - #[test] - fn get_or_create_salt_reuses_existing_value() { - let path = temp_file_path("salt"); - - let first = get_or_create_salt(&path); - let second = get_or_create_salt(&path); - - assert_eq!(first, second); - assert_eq!(first.len(), 32); - - let _ = std::fs::remove_file(path); - } -}