use super::*;
#[test]
fn guard_runtime_state_default_is_empty() {
let state = crate::GuardRuntimeState::default();
assert!(state.heavy_since.is_empty());
assert!(state.notify_cooldowns.is_empty());
assert!(state.last_disk_state.is_empty());
}
#[test]
fn guard_runtime_state_insert_and_retrieve_heavy_process() {
let mut state = crate::GuardRuntimeState::default();
state.heavy_since.insert(1234, Instant::now());
assert!(state.heavy_since.contains_key(&1234));
state.heavy_since.remove(&1234);
assert!(!state.heavy_since.contains_key(&1234));
}
#[test]
fn guard_policy_disk_thresholds_are_public() {
let guard = GuardPolicy::default();
assert_eq!(guard.disk_warn_percent, 80);
assert_eq!(guard.disk_action_percent, 90);
assert_eq!(guard.disk_critical_percent, 95);
assert_eq!(guard.disk_early_warn_percent, 70);
}
#[test]
fn guard_report_can_be_created_with_alerts() {
use crate::GuardProcessAlert;
use crate::GuardReport;
let report = GuardReport {
enabled: true,
disk_use_percent: 72,
disk_state: "warn".to_string(),
sync_frozen: false,
alerts: vec![GuardProcessAlert {
pid: 12345,
ppid: 1,
command: "cargo".to_string(),
args: "build".to_string(),
cpu_percent: 250.0,
rss_mb: 1024,
sustained_secs: 35,
action: "reniced".to_string(),
nice_value: 5,
}],
};
assert!(report.enabled);
assert_eq!(report.disk_use_percent, 72);
assert_eq!(report.alerts.len(), 1);
assert_eq!(report.alerts[0].pid, 12345);
}
#[test]
fn graduated_nice_value_cpu_tier_180_percent() {
assert_eq!(crate::graduated_nice_value(180.0, 0, 5), 5);
assert_eq!(crate::graduated_nice_value(200.0, 0, 5), 5);
}
#[test]
fn graduated_nice_value_cpu_tier_300_percent() {
assert_eq!(crate::graduated_nice_value(300.0, 0, 5), 10);
assert_eq!(crate::graduated_nice_value(350.0, 0, 5), 10);
}
#[test]
fn graduated_nice_value_cpu_tier_500_percent() {
assert_eq!(crate::graduated_nice_value(500.0, 0, 5), 15);
assert_eq!(crate::graduated_nice_value(600.0, 0, 5), 15);
}
#[test]
fn graduated_nice_value_memory_4gb() {
assert_eq!(crate::graduated_nice_value(0.0, 4096, 5), 5);
}
#[test]
fn graduated_nice_value_memory_8gb() {
assert_eq!(crate::graduated_nice_value(0.0, 8192, 10), 10);
}
#[test]
fn graduated_nice_value_below_all_tiers_uses_base() {
assert_eq!(crate::graduated_nice_value(50.0, 100, 3), 3);
assert_eq!(crate::graduated_nice_value(100.0, 500, 7), 7);
}
#[test]
fn graduated_nice_value_negative_base_clamped_to_zero() {
assert_eq!(crate::graduated_nice_value(0.0, 0, -5), 0);
}
#[test]
fn graduated_nice_value_high_base_clamped_to_max() {
assert_eq!(crate::graduated_nice_value(0.0, 0, 20), 19);
}
#[test]
fn parse_ps_output_extracts_all_fields() {
let output = "12345 1 50.0 1024 cargo\n 23456 12345 25.0 2048 rustc";
let samples = crate::parse_ps_output(output);
assert_eq!(samples.len(), 2);
assert_eq!(samples[0].pid, 12345);
assert_eq!(samples[0].ppid, 1);
assert_eq!(samples[0].cpu_percent, 50.0);
assert_eq!(samples[0].rss_mb, 1024 / 1024); assert_eq!(samples[0].command, "cargo");
assert_eq!(samples[1].pid, 23456);
assert_eq!(samples[1].ppid, 12345);
assert_eq!(samples[1].cpu_percent, 25.0);
assert_eq!(samples[1].rss_mb, 2048 / 1024); assert_eq!(samples[1].command, "rustc");
}
#[test]
fn parse_ps_output_empty_input() {
let samples = crate::parse_ps_output("");
assert!(samples.is_empty());
}
#[test]
fn parse_ps_output_malformed_lines_skipped() {
let output = "not_valid\n12345 1 75.0 512 cargo";
let samples = crate::parse_ps_output(output);
assert_eq!(samples.len(), 1);
assert_eq!(samples[0].pid, 12345);
assert_eq!(samples[0].cpu_percent, 75.0);
}
#[test]
fn disk_state_ok_below_warn() {
let guard = GuardPolicy::default();
assert_eq!(crate::disk_state(50, &guard), "ok");
assert_eq!(crate::disk_state(79, &guard), "ok");
}
#[test]
fn disk_state_warn_between_warn_and_action() {
let guard = GuardPolicy::default();
assert_eq!(crate::disk_state(80, &guard), "warn");
assert_eq!(crate::disk_state(89, &guard), "warn");
}
#[test]
fn disk_state_action_between_action_and_critical() {
let guard = GuardPolicy::default();
assert_eq!(crate::disk_state(90, &guard), "action");
assert_eq!(crate::disk_state(94, &guard), "action");
}
#[test]
fn disk_state_critical_at_or_above_critical() {
let guard = GuardPolicy::default();
assert_eq!(crate::disk_state(95, &guard), "critical");
assert_eq!(crate::disk_state(100, &guard), "critical");
}
#[test]
fn parse_df_use_percent_works() {
let output = "Filesystem 1024-blocks Used Available Capacity Mounted on\n/dev/sda1 19512345 15678901 3823444 80% /";
assert_eq!(crate::parse_df_use_percent(output), Some(80));
}
#[test]
fn parse_df_use_percent_parses_without_percent_sign() {
let output = "Filesystem 1024-blocks Used Available Capacity Mounted on\n/dev/sda1 19512345 15678901 3823444 80 /";
assert_eq!(crate::parse_df_use_percent(output), Some(80));
}
#[test]
fn parse_df_use_percent_no_matching_line() {
assert_eq!(crate::parse_df_use_percent(""), None);
assert_eq!(crate::parse_df_use_percent("no df output here"), None);
}
#[test]
fn should_notify_first_time_allowed() {
let mut state = crate::GuardRuntimeState::default();
let result = crate::should_notify(&mut state, "test-key", 300);
assert!(result);
}
#[test]
fn should_notify_respects_cooldown() {
let mut state = crate::GuardRuntimeState::default();
let first = crate::should_notify(&mut state, "my-event", 300);
assert!(first);
let second = crate::should_notify(&mut state, "my-event", 300);
assert!(!second);
state.notify_cooldowns.remove("my-event");
let third = crate::should_notify(&mut state, "my-event", 300);
assert!(third);
}
#[test]
fn predict_fill_time_requires_minimum_samples() {
let history: Vec<(Instant, u8)> = vec![];
assert!(crate::predict_fill_time(&history).is_none());
let history = vec![(Instant::now(), 70)];
assert!(crate::predict_fill_time(&history).is_none());
}
#[test]
fn predict_fill_time_returns_none_for_stable_disk() {
let now = Instant::now();
let history: Vec<(Instant, u8)> = vec![
(now - std::time::Duration::from_secs(3600), 50u8),
(now - std::time::Duration::from_secs(1800), 50u8),
(now, 50u8),
];
assert!(crate::predict_fill_time(&history).is_none());
}
#[test]
fn predict_fill_time_estimates_for_filling_disk() {
let now = Instant::now();
let history: Vec<(Instant, u8)> = vec![
(now - std::time::Duration::from_secs(7200), 30u8), (now - std::time::Duration::from_secs(3600), 60u8), (now, 90u8), ];
let result = crate::predict_fill_time(&history);
assert!(result.is_some());
let hours = result.unwrap();
assert!(hours > 0.0 && hours < 5.0); }
#[test]
fn auto_cleanup_result_default() {
let result = crate::AutoCleanupResult::default();
assert_eq!(result.cleaned_count, 0);
assert_eq!(result.reclaimed_bytes, 0);
assert!(result.cleaned_paths.is_empty());
assert!(result.protected_paths.is_empty());
}