mod helpers;
use helpers::TestEnv;
use rustodo::cli::AddArgs;
use rustodo::commands::{purge, task};
use rustodo::models::Priority;
fn add_simple(env: &TestEnv, text: &str) {
task::add::execute(
env.storage(),
AddArgs {
text: text.to_string(),
priority: Priority::Medium,
tag: vec![],
project: None,
due: None,
recurrence: None,
depends_on: vec![],
},
)
.unwrap();
}
#[test]
fn test_purge_empty_storage_no_error() {
let env = TestEnv::new();
let result = purge::execute(env.storage(), 30, false, true);
assert!(result.is_ok());
}
#[test]
fn test_purge_no_deleted_tasks_no_error() {
let env = TestEnv::new();
add_simple(&env, "Active task");
let result = purge::execute(env.storage(), 30, false, true);
assert!(result.is_ok());
assert_eq!(env.task_count(), 1, "active task should be untouched");
}
#[test]
fn test_purge_dry_run_does_not_remove() {
let env = TestEnv::new();
add_simple(&env, "Task to delete");
task::remove::execute(env.storage(), 1, true).unwrap();
assert_eq!(env.task_count(), 0);
assert_eq!(env.raw_task_count(), 1, "tombstone should exist");
purge::execute(env.storage(), 0, true, true).unwrap();
assert_eq!(env.raw_task_count(), 1, "dry run must not remove tombstone");
}
#[test]
fn test_purge_days_zero_removes_all_tombstones() {
let env = TestEnv::new();
add_simple(&env, "Delete me");
task::remove::execute(env.storage(), 1, true).unwrap();
assert_eq!(env.raw_task_count(), 1);
purge::execute(env.storage(), 0, false, true).unwrap();
assert_eq!(
env.raw_task_count(),
0,
"tombstone should be permanently removed"
);
}
#[test]
fn test_purge_days_zero_removes_multiple_tombstones() {
let env = TestEnv::new();
add_simple(&env, "A");
add_simple(&env, "B");
add_simple(&env, "C");
task::remove::execute(env.storage(), 1, true).unwrap();
task::remove::execute(env.storage(), 1, true).unwrap();
task::remove::execute(env.storage(), 1, true).unwrap();
assert_eq!(env.raw_task_count(), 3);
assert_eq!(env.task_count(), 0);
purge::execute(env.storage(), 0, false, true).unwrap();
assert_eq!(env.raw_task_count(), 0);
}
#[test]
fn test_purge_high_days_threshold_keeps_recent_tombstones() {
let env = TestEnv::new();
add_simple(&env, "Recently deleted");
task::remove::execute(env.storage(), 1, true).unwrap();
purge::execute(env.storage(), 30, false, true).unwrap();
assert_eq!(
env.raw_task_count(),
1,
"recent tombstone should be kept with 30-day threshold"
);
}
#[test]
fn test_purge_days_zero_is_the_only_threshold_that_catches_new_tombstones() {
let env = TestEnv::new();
add_simple(&env, "Just deleted");
task::remove::execute(env.storage(), 1, true).unwrap();
purge::execute(env.storage(), 1, false, true).unwrap();
assert_eq!(
env.raw_task_count(),
1,
"1-day threshold should keep brand-new tombstone"
);
purge::execute(env.storage(), 0, false, true).unwrap();
assert_eq!(env.raw_task_count(), 0);
}
#[test]
fn test_purge_does_not_remove_active_tasks() {
let env = TestEnv::new();
add_simple(&env, "Keep me");
add_simple(&env, "Delete me");
task::remove::execute(env.storage(), 2, true).unwrap();
assert_eq!(env.task_count(), 1);
assert_eq!(env.raw_task_count(), 2);
purge::execute(env.storage(), 0, false, true).unwrap();
assert_eq!(env.task_count(), 1, "active task must survive purge");
assert_eq!(env.raw_task_count(), 1, "only tombstone should be removed");
let tasks = env.load_tasks();
assert_eq!(tasks[0].text, "Keep me");
}
#[test]
fn test_purge_mixed_active_and_tombstones() {
let env = TestEnv::new();
add_simple(&env, "Active A");
add_simple(&env, "Delete B");
add_simple(&env, "Active C");
add_simple(&env, "Delete D");
task::remove::execute(env.storage(), 2, true).unwrap(); task::remove::execute(env.storage(), 3, true).unwrap();
assert_eq!(env.task_count(), 2);
assert_eq!(env.raw_task_count(), 4);
purge::execute(env.storage(), 0, false, true).unwrap();
assert_eq!(env.task_count(), 2);
assert_eq!(env.raw_task_count(), 2);
let tasks = env.load_tasks();
assert!(tasks.iter().any(|t| t.text == "Active A"));
assert!(tasks.iter().any(|t| t.text == "Active C"));
}