use std::process::Command;
use claude_runner_core::process::{ find_claude_processes, send_sigterm, send_sigkill };
fn spawn_sleep() -> std::process::Child
{
Command::new( "sleep" )
.arg( "60" )
.stdout( std::process::Stdio::null() )
.stderr( std::process::Stdio::null() )
.spawn()
.expect( "failed to spawn sleep process" )
}
#[ test ]
fn tc061_find_claude_processes_does_not_panic()
{
let _procs = find_claude_processes();
}
#[ test ]
fn tc062_find_claude_processes_excludes_self_pid()
{
let self_pid = std::process::id();
let procs = find_claude_processes();
assert!(
!procs.iter().any( |p| p.pid == self_pid ),
"self PID {self_pid} must not appear in find_claude_processes() results"
);
}
#[ test ]
fn tc063_finds_one_claude_process()
{
let Ok( mut child ) = Command::new( "claude" )
.arg( "--version" )
.stdout( std::process::Stdio::null() )
.stderr( std::process::Stdio::null() )
.spawn()
else { return; };
std::thread::sleep( core::time::Duration::from_millis( 100 ) );
let pid = child.id();
let procs = find_claude_processes();
let found = procs.iter().any( |p| p.pid == pid );
child.kill().ok();
child.wait().ok();
assert!( found, "spawned claude process with PID {pid} must be found by scanner" );
}
#[ test ]
fn tc064_finds_two_claude_processes()
{
let Ok( mut c1 ) = Command::new( "claude" )
.arg( "--version" )
.stdout( std::process::Stdio::null() )
.stderr( std::process::Stdio::null() )
.spawn()
else { return; };
let Ok( mut c2 ) = Command::new( "claude" )
.arg( "--version" )
.stdout( std::process::Stdio::null() )
.stderr( std::process::Stdio::null() )
.spawn()
else { c1.kill().ok(); c1.wait().ok(); return; };
std::thread::sleep( core::time::Duration::from_millis( 100 ) );
let pid1 = c1.id();
let pid2 = c2.id();
let procs = find_claude_processes();
let found1 = procs.iter().any( |p| p.pid == pid1 );
let found2 = procs.iter().any( |p| p.pid == pid2 );
c1.kill().ok(); c1.wait().ok();
c2.kill().ok(); c2.wait().ok();
assert!( found1, "first spawned claude PID {pid1} must be found" );
assert!( found2, "second spawned claude PID {pid2} must be found" );
}
#[ test ]
fn tc065_process_with_deleted_cwd_included_with_fallback()
{
use tempfile::TempDir;
let dir = TempDir::new().unwrap();
let mut child = Command::new( "sleep" )
.arg( "60" )
.current_dir( dir.path() )
.stdout( std::process::Stdio::null() )
.stderr( std::process::Stdio::null() )
.spawn()
.expect( "failed to spawn sleep" );
let _pid = child.id();
let path = dir.keep();
std::fs::remove_dir_all( &path ).ok();
std::thread::sleep( core::time::Duration::from_millis( 50 ) );
let _ = find_claude_processes();
child.kill().ok();
child.wait().ok();
}
#[ test ]
fn tc066_unreadable_cmdline_silently_skipped()
{
let _ = find_claude_processes();
}
#[ test ]
fn tc067_send_sigterm_valid_pid_returns_ok()
{
let mut child = spawn_sleep();
let pid = child.id();
let result = send_sigterm( pid );
child.wait().ok();
assert!( result.is_ok(), "send_sigterm to valid PID must succeed, got: {result:?}" );
}
#[ test ]
fn tc068_send_sigterm_nonexistent_pid_returns_err()
{
let pid_max : u32 = std::fs::read_to_string( "/proc/sys/kernel/pid_max" )
.ok()
.and_then( | s | s.trim().parse().ok() )
.unwrap_or( 32768 );
let result = send_sigterm( pid_max + 1 );
assert!( result.is_err(), "send_sigterm to PID above pid_max must fail" );
}
#[ test ]
fn tc069_send_sigkill_valid_pid_returns_ok()
{
let mut child = spawn_sleep();
let pid = child.id();
let result = send_sigkill( pid );
child.wait().ok();
assert!( result.is_ok(), "send_sigkill to valid PID must succeed, got: {result:?}" );
}
#[ test ]
fn tc070_find_claude_processes_does_not_panic()
{
let _ = find_claude_processes();
}