use crosswin::prelude::*;
use crosswin::processes::{list_processes, find_process_by_pid, find_processes_by_name, ProcessFilter};
#[tokio::test]
async fn test_list_processes_not_empty() -> Result<()> {
let processes = list_processes().await?;
assert!(!processes.is_empty(), "Should have at least one process");
Ok(())
}
#[tokio::test]
async fn test_process_info_has_basic_fields() -> Result<()> {
let processes = list_processes().await?;
let proc = processes.first().expect("Should have at least one process");
assert!(proc.pid > 0, "PID should be positive");
assert!(!proc.name.is_empty(), "Name should not be empty");
Ok(())
}
#[tokio::test]
async fn test_find_current_process_by_pid() -> Result<()> {
let current_pid = std::process::id();
let proc = find_process_by_pid(current_pid).await?;
assert!(proc.is_some(), "Should find current process");
let proc = proc.unwrap();
assert_eq!(proc.pid, current_pid);
Ok(())
}
#[tokio::test]
async fn test_find_nonexistent_process() -> Result<()> {
let proc = find_process_by_pid(9999999).await?;
assert!(proc.is_none(), "Should not find process with impossible PID");
Ok(())
}
#[tokio::test]
async fn test_find_processes_by_name() -> Result<()> {
let processes = find_processes_by_name("").await?;
assert!(!processes.is_empty(), "Empty search should return all processes");
Ok(())
}
#[tokio::test]
async fn test_process_filter_builder() -> Result<()> {
let processes = ProcessFilter::new()
.min_memory(0) .list()
.await?;
assert!(!processes.is_empty());
for proc in &processes {
assert!(proc.memory_usage.is_some(), "Filtered processes should have memory info");
}
Ok(())
}
#[tokio::test]
async fn test_process_has_extended_info() -> Result<()> {
let processes = list_processes().await?;
let proc_with_info = processes.iter().find(|p| {
p.parent_pid.is_some()
&& p.memory_usage.is_some()
&& p.thread_count.is_some()
});
assert!(proc_with_info.is_some(), "Should have at least one process with extended info");
if let Some(proc) = proc_with_info {
assert!(proc.parent_pid.is_some(), "parent_pid should be populated");
assert!(proc.memory_usage.unwrap() > 0);
assert!(proc.thread_count.unwrap() > 0);
}
Ok(())
}
#[tokio::test]
async fn test_process_memory_mb_conversion() -> Result<()> {
let mut proc = ProcessInfo::basic(123, "test.exe".to_string());
proc.memory_usage = Some(10_485_760);
let mb = proc.memory_usage_mb().unwrap();
assert!((mb - 10.0).abs() < 0.1, "Should be approximately 10 MB");
Ok(())
}
#[tokio::test]
async fn test_process_total_cpu_time() -> Result<()> {
use std::time::Duration;
let mut proc = ProcessInfo::basic(123, "test.exe".to_string());
proc.user_cpu_time = Some(Duration::from_secs(5));
proc.kernel_cpu_time = Some(Duration::from_secs(3));
let total = proc.total_cpu_time().unwrap();
assert_eq!(total, Duration::from_secs(8));
Ok(())
}
#[tokio::test]
async fn test_process_filter_sort_by_pid() -> Result<()> {
use crosswin::processes::ProcessFilter;
let processes = ProcessFilter::new().sort_by_pid().list().await?;
let pids: Vec<u32> = processes.iter().map(|p| p.pid).collect();
let mut sorted = pids.clone();
sorted.sort_unstable();
assert_eq!(pids, sorted, "sort_by_pid should produce ascending PID order");
Ok(())
}
#[tokio::test]
async fn test_process_filter_sort_by_memory() -> Result<()> {
use crosswin::processes::ProcessFilter;
let processes = ProcessFilter::new()
.min_memory(0) .sort_by_memory()
.list()
.await?;
for window in processes.windows(2) {
let a = window[0].memory_usage.unwrap_or(0);
let b = window[1].memory_usage.unwrap_or(0);
assert!(a >= b, "sort_by_memory must be descending: {} < {}", a, b);
}
Ok(())
}
#[tokio::test]
async fn test_process_filter_sort_by_cpu() -> Result<()> {
use crosswin::processes::ProcessFilter;
let processes = ProcessFilter::new().sort_by_cpu().list().await?;
for window in processes.windows(2) {
let a = window[0].total_cpu_time().map(|d| d.as_nanos()).unwrap_or(0);
let b = window[1].total_cpu_time().map(|d| d.as_nanos()).unwrap_or(0);
assert!(a >= b, "sort_by_cpu must be descending");
}
Ok(())
}
#[tokio::test]
async fn test_find_process_by_name_returns_first() -> Result<()> {
use crosswin::processes::{find_process_by_name, find_processes_by_name};
let all = find_processes_by_name("").await?;
if all.is_empty() {
return Ok(());
}
let first_all = all.into_iter().next().unwrap();
let found = find_process_by_name(&first_all.name).await?;
assert!(found.is_some(), "find_process_by_name must find a known process");
Ok(())
}
#[cfg(feature = "win32")]
#[tokio::test]
async fn test_process_info_is_alive() -> Result<()> {
let current_pid = std::process::id();
let procs = list_processes().await?;
let me = procs.iter().find(|p| p.pid == current_pid);
if let Some(proc) = me {
assert!(proc.is_alive(), "current process must be alive");
}
Ok(())
}
#[test]
fn test_process_priority_display() {
use crosswin::processes::ProcessPriority;
assert_eq!(format!("{}", ProcessPriority::Normal), "Normal");
assert_eq!(format!("{}", ProcessPriority::High), "High");
assert_eq!(format!("{}", ProcessPriority::Idle), "Idle");
assert_eq!(format!("{}", ProcessPriority::Realtime), "Realtime");
}
#[tokio::test]
async fn test_process_info_display() -> Result<()> {
let mut proc = ProcessInfo::basic(1234, "example.exe".to_string());
proc.memory_usage = Some(10 * 1024 * 1024); proc.thread_count = Some(8);
proc.priority_class = Some(crosswin::processes::ProcessPriority::Normal);
let s = format!("{}", proc);
assert!(s.contains("1234"), "Display must include PID");
assert!(s.contains("example.exe"), "Display must include name");
assert!(s.contains("10.0 MB"), "Display must include memory");
assert!(s.contains("threads=8"), "Display must include thread count");
assert!(s.contains("Normal"), "Display must include priority");
Ok(())
}