use std::process::Command;
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn run_cli( args : &[ &str ] ) -> std::process::Output
{
let bin = env!( "CARGO_BIN_EXE_clr" );
Command::new( bin )
.args( args )
.output()
.expect( "Failed to invoke clr binary" )
}
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn run_cli_with_env
(
args : &[ &str ],
env : &[ ( &str, &str ) ],
) -> std::process::Output
{
let bin = env!( "CARGO_BIN_EXE_clr" );
Command::new( bin )
.args( args )
.envs( env.iter().copied() )
.output()
.expect( "failed to execute clr binary" )
}
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn make_session_dir() -> ( tempfile::TempDir, String )
{
let dir = tempfile::TempDir::new().expect( "failed to create temp session dir" );
std::fs::write( dir.path().join( "session.json" ), b"{}" )
.expect( "failed to write dummy session file" );
let path = dir.path().to_str().expect( "session dir path must be valid UTF-8" ).to_owned();
( dir, path )
}
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn exit_code( o : &std::process::Output ) -> i32 { o.status.code().unwrap_or( -1 ) }
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn stderr_str( o : &std::process::Output ) -> String
{
String::from_utf8_lossy( &o.stderr ).to_string()
}
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn stdout_str( o : &std::process::Output ) -> String
{
String::from_utf8_lossy( &o.stdout ).to_string()
}
#[inline]
#[must_use]
#[allow(dead_code)]
pub fn make_creds_file( content : &str ) -> tempfile::NamedTempFile
{
use std::io::Write as _;
let mut f = tempfile::NamedTempFile::new().expect( "failed to create temp creds file" );
f.write_all( content.as_bytes() ).expect( "failed to write creds content" );
f
}
#[cfg(unix)]
#[inline]
#[must_use]
#[allow(dead_code)]
pub fn fake_claude_dir( body : &str ) -> ( tempfile::TempDir, String )
{
use std::os::unix::fs::PermissionsExt as _;
let dir = tempfile::TempDir::new().expect( "tmpdir" );
let path = dir.path().join( "claude" );
let script = format!( "#!/bin/sh\n{body}\n" );
std::fs::write( &path, script.as_bytes() ).expect( "write fake-claude" );
std::fs::set_permissions( &path, std::fs::Permissions::from_mode( 0o755 ) )
.expect( "chmod fake-claude" );
let path_val = format!(
"{}:{}",
dir.path().display(),
std::env::var( "PATH" ).unwrap_or_default(),
);
( dir, path_val )
}
#[cfg(unix)]
#[inline]
#[must_use]
#[allow(dead_code)]
pub fn fake_claude_binary_dir() -> ( tempfile::TempDir, String )
{
use std::os::unix::fs::PermissionsExt as _;
let dir = tempfile::TempDir::new().expect( "tmpdir" );
let dest = dir.path().join( "claude" );
std::fs::copy( "/bin/sleep", &dest ).expect( "copy /bin/sleep as claude" );
std::fs::set_permissions( &dest, std::fs::Permissions::from_mode( 0o755 ) )
.expect( "chmod claude" );
let path_val = format!(
"{}:{}",
dir.path().display(),
std::env::var( "PATH" ).unwrap_or_default(),
);
( dir, path_val )
}
#[cfg(unix)]
#[inline]
#[must_use]
#[allow(dead_code)]
pub fn spawn_fake_claude( path_val : &str ) -> std::process::Child
{
let child = std::process::Command::new( "claude" )
.env( "PATH", path_val )
.arg( "30" )
.stdout( std::process::Stdio::null() )
.stderr( std::process::Stdio::null() )
.spawn()
.expect( "spawn fake claude" );
std::thread::sleep( core::time::Duration::from_millis( 200 ) );
child
}
#[cfg(unix)]
#[inline]
#[must_use]
#[allow(dead_code)]
pub fn run_clr_ps( path_val : &str ) -> std::process::Output
{
let bin = env!( "CARGO_BIN_EXE_clr" );
std::process::Command::new( bin )
.arg( "ps" )
.env( "PATH", path_val )
.output()
.expect( "run clr ps" )
}
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn run_ask_dry( extra_args : &[ &str ] ) -> String
{
let bin = env!( "CARGO_BIN_EXE_clr" );
let mut args = vec![ "ask", "--dry-run" ];
args.extend_from_slice( extra_args );
let out = Command::new( bin )
.args( &args )
.output()
.expect( "failed to invoke clr binary" );
assert!(
out.status.success(),
"clr ask --dry-run failed (exit {}): {}",
out.status.code().unwrap_or( -1 ),
String::from_utf8_lossy( &out.stderr )
);
String::from_utf8_lossy( &out.stdout ).into_owned()
}
#[cfg(unix)]
#[inline]
#[must_use]
#[allow(dead_code)]
pub fn fake_claude( script : &str ) -> ( tempfile::TempDir, String )
{
use std::os::unix::fs::PermissionsExt as _;
let tmp = tempfile::tempdir().expect( "Failed to create temp dir" );
let fake = tmp.path().join( "claude" );
std::fs::write( &fake, script ).expect( "Failed to write fake claude" );
std::fs::set_permissions( &fake, std::fs::Permissions::from_mode( 0o755 ) )
.expect( "Failed to chmod fake claude" );
let old_path = std::env::var( "PATH" ).unwrap_or_default();
let new_path = format!( "{}:{old_path}", tmp.path().display() );
( tmp, new_path )
}
#[ must_use ]
#[ inline ]
#[ allow( dead_code ) ]
pub fn run_dry( args : &[ &str ] ) -> String
{
let bin = env!( "CARGO_BIN_EXE_clr" );
let mut full = vec![ "--dry-run" ];
full.extend_from_slice( args );
let out = Command::new( bin )
.args( &full )
.output()
.expect( "Failed to invoke clr binary" );
assert!(
out.status.success(),
"dry-run failed (exit {}): {}",
out.status.code().unwrap_or( -1 ),
String::from_utf8_lossy( &out.stderr )
);
String::from_utf8_lossy( &out.stdout ).into_owned()
}
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn run_with_path( args : &[ &str ], path : &str ) -> std::process::Output
{
let bin = env!( "CARGO_BIN_EXE_clr" );
Command::new( bin )
.args( args )
.env( "PATH", path )
.output()
.expect( "Failed to invoke clr binary" )
}
#[cfg(unix)]
#[must_use]
#[inline]
#[allow(dead_code)]
pub fn run_clr_kill( pid : u32 ) -> std::process::Output
{
let bin = env!( "CARGO_BIN_EXE_clr" );
Command::new( bin )
.args( [ "kill", &pid.to_string() ] )
.output()
.expect( "run clr kill" )
}