#[cfg(test)] mod tests { use std::fs; use std::io::Write; use std::path::Path; use std::process::Command; // Global test input values const INPUT_A: &str = "test content A"; const INPUT_B: &str = "test content B"; use tempfile::tempdir; // Helper function to run the keep binary with arguments fn run_keep(args: &[&str], stdin_data: Option<&str>, keep_dir: &Path) -> std::process::Output { let mut cmd = Command::new(env!("CARGO_BIN_EXE_keep")); cmd.args(args) .env("KEEP_DIR", keep_dir); if stdin_data.is_some() { cmd.stdin(std::process::Stdio::piped()); } else { cmd.stdin(std::process::Stdio::null()); } let mut child = cmd.spawn().expect("Failed to execute keep command"); if let Some(data) = stdin_data { if let Some(mut stdin) = child.stdin.take() { stdin.write_all(data.as_bytes()).expect("Failed to write to stdin"); } } child.wait_with_output().expect("Failed to wait for command") } // Helper function to create a temporary test environment fn with_temp_env(f: F) where F: FnOnce(&Path), { let dir = tempdir().expect("Failed to create temporary directory"); let data_path = dir.path(); // Create the data directory structure fs::create_dir_all(data_path).expect("Failed to create directory"); // Run the test f(data_path); // Clean up dir.close().expect("Failed to remove temporary directory"); } // Helper function to create test items with specific content and tags fn create_test_items(data_path: &Path) { // Create first item with tag_a and tag let output = run_keep(&["tag_a", "tag"], Some(INPUT_A), data_path); assert!( output.status.success(), "Failed to create first test item: {}", String::from_utf8_lossy(&output.stderr) ); // Create second item with tag_b and tag let output = run_keep(&["tag_b", "tag"], Some(INPUT_B), data_path); assert!( output.status.success(), "Failed to create second test item: {}", String::from_utf8_lossy(&output.stderr) ); } #[test] fn test_save_item() { with_temp_env(|data_path| { // Test content and tags let input = "test content"; let tag = "test_tag"; // Save an item let output = run_keep(&[tag], Some(input), data_path); assert!( output.status.success(), "Failed to save item: {}", String::from_utf8_lossy(&output.stderr) ); // Verify item was saved by listing let output = run_keep(&["--list"], None, data_path); assert!( output.status.success(), "Failed to list items: {}", String::from_utf8_lossy(&output.stderr) ); let output_str = String::from_utf8_lossy(&output.stdout); assert!( output_str.contains(tag), "List output does not contain expected tag. Output: {}", output_str ); }); } #[test] fn test_get_item() { with_temp_env(|data_path| { // Create test items create_test_items(data_path); // Get item by ID let output = run_keep(&["--get", "1"], None, data_path); assert!( output.status.success(), "Failed to get item by ID: {}", String::from_utf8_lossy(&output.stderr) ); let output_str = String::from_utf8_lossy(&output.stdout); assert!( output_str.contains(INPUT_A), "Get output does not contain expected content. Output: {}", output_str ); // Get item by tag let output = run_keep(&["--get", "tag_a"], None, data_path); assert!( output.status.success(), "Failed to get item by tag: {}", String::from_utf8_lossy(&output.stderr) ); let output_str = String::from_utf8_lossy(&output.stdout); assert!( output_str.contains(INPUT_A), "Get by tag output does not contain expected content. Output: {}", output_str ); }); } #[test] fn test_list_items() { with_temp_env(|data_path| { // Create test items create_test_items(data_path); // List all items let output = run_keep(&["--list"], None, data_path); assert!( output.status.success(), "Failed to list items: {}", String::from_utf8_lossy(&output.stderr) ); // List items with specific tag let output = run_keep(&["--list", "tag_a"], None, data_path); assert!( output.status.success(), "Failed to list items by tag: {}", String::from_utf8_lossy(&output.stderr) ); }); } #[test] fn test_delete_item() { with_temp_env(|data_path| { // Create test items create_test_items(data_path); // Try to delete with tag (should fail) let output = run_keep(&["--delete", "tag"], None, data_path); assert!( !output.status.success(), "Delete with tag should have failed but succeeded" ); // Delete item by ID let output = run_keep(&["--delete", "1"], None, data_path); assert!( output.status.success(), "Failed to delete item by ID: {}", String::from_utf8_lossy(&output.stderr) ); // Try to delete non-existent item (should succeed silently) let output = run_keep(&["--delete", "9999"], None, data_path); assert!( output.status.success(), "Delete non-existent item should succeed: {}", String::from_utf8_lossy(&output.stderr) ); }); } #[test] fn test_diff_items() { with_temp_env(|data_path| { // Create test items create_test_items(data_path); // Diff two items by ID let output = run_keep(&["--diff", "1", "2"], None, data_path); assert!( output.status.success(), "Failed to diff items: {}", String::from_utf8_lossy(&output.stderr) ); // Try to diff with tag (should fail) let output = run_keep(&["--diff", "tag_a", "tag_b"], None, data_path); assert!( !output.status.success(), "Diff with tags should have failed but succeeded" ); // Try to diff non-existent item (should fail) let output = run_keep(&["--diff", "9999", "1"], None, data_path); assert!( !output.status.success(), "Diff with non-existent item should have failed but succeeded" ); }); } #[test] fn test_info_item() { with_temp_env(|data_path| { // Create test items create_test_items(data_path); // Get info for item by ID let output = run_keep(&["--info", "1"], None, data_path); assert!( output.status.success(), "Failed to get item info: {}", String::from_utf8_lossy(&output.stderr) ); // Get info for last item let output = run_keep(&["--info"], None, data_path); assert!( output.status.success(), "Failed to get last item info: {}", String::from_utf8_lossy(&output.stderr) ); }); } #[test] fn test_update_item() { with_temp_env(|data_path| { // Create test items create_test_items(data_path); // Update item tags let output = run_keep(&["--update", "1", "new_tag"], None, data_path); assert!( output.status.success(), "Failed to update item: {}", String::from_utf8_lossy(&output.stderr) ); // Verify update by listing let output = run_keep(&["--list"], None, data_path); assert!( output.status.success(), "Failed to list items after update: {}", String::from_utf8_lossy(&output.stderr) ); }); } #[test] fn test_status() { with_temp_env(|data_path| { // Get status let output = run_keep(&["--status"], None, data_path); assert!( output.status.success(), "Failed to get status: {}", String::from_utf8_lossy(&output.stderr) ); }); } }