mod cli_binary_test_helpers;
use cli_binary_test_helpers::{ run_ask_dry, run_cli };
use std::process::Command;
fn run_run_dry( extra_args : &[ &str ] ) -> String
{
let bin = env!( "CARGO_BIN_EXE_clr" );
let mut args = vec![ "run", "--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 run --dry-run failed (exit {}): {}",
out.status.code().unwrap_or( -1 ),
String::from_utf8_lossy( &out.stderr )
);
String::from_utf8_lossy( &out.stdout ).into_owned()
}
#[ test ]
fn t01_ask_run_dry_run_equivalence()
{
let ask_out = run_ask_dry( &[ "What does X do?" ] );
let run_out = run_run_dry( &[ "What does X do?" ] );
assert_eq!(
ask_out, run_out,
"ask and run must produce identical dry-run output.\nask:\n{ask_out}\nrun:\n{run_out}"
);
}
#[ test ]
fn t02_ask_no_forced_new_session()
{
let output = run_ask_dry( &[ "What does X do?" ] );
let run_out = run_run_dry( &[ "What does X do?" ] );
assert_eq!(
output.contains( " -c" ),
run_out.contains( " -c" ),
"ask must produce same session-continuation state as run. ask:\n{output}\nrun:\n{run_out}"
);
}
#[ test ]
fn t03_ask_no_forced_no_chrome()
{
let ask_out = run_ask_dry( &[ "What does X do?" ] );
let run_out = run_run_dry( &[ "What does X do?" ] );
assert_eq!(
ask_out.contains( "--chrome" ),
run_out.contains( "--chrome" ),
"ask chrome flag must match run. ask:\n{ask_out}\nrun:\n{run_out}"
);
}
#[ test ]
fn t04_ask_no_forced_no_persist()
{
let ask_out = run_ask_dry( &[ "What does X do?" ] );
let run_out = run_run_dry( &[ "What does X do?" ] );
assert_eq!(
ask_out.contains( "--no-session-persistence" ),
run_out.contains( "--no-session-persistence" ),
"ask persistence flag must match run. ask:\n{ask_out}\nrun:\n{run_out}"
);
}
#[ test ]
fn t05_ask_ultrathink_suffix_injected()
{
let output = run_ask_dry( &[ "What does X do?" ] );
assert!(
output.contains( "ultrathink" ),
"ask must inject ultrathink suffix (same as run). Got:\n{output}"
);
}
#[ test ]
fn t06_ask_effort_defaults_to_max()
{
let output = run_ask_dry( &[ "What does X do?" ] );
assert!(
output.contains( "--effort max" ),
"ask must use --effort max (run default). Got:\n{output}"
);
assert!(
!output.contains( "--effort high" ),
"ask must NOT use --effort high (old ask default removed). Got:\n{output}"
);
}
#[ test ]
fn t07_ask_max_tokens_defaults_to_200000()
{
let output = run_ask_dry( &[ "What does X do?" ] );
assert!(
!output.contains( "CLAUDE_CODE_MAX_OUTPUT_TOKENS=16384" ),
"ask must NOT use max-tokens 16384 (old ask default removed). Got:\n{output}"
);
}
#[ test ]
fn t08_ask_explicit_new_session_respected()
{
let output = run_ask_dry( &[ "--new-session", "What does X do?" ] );
assert!(
!output.contains( " -c" ),
"explicit --new-session must suppress -c. Got:\n{output}"
);
}
#[ test ]
fn t09_ask_unknown_flag_rejected()
{
let out = run_cli( &[ "ask", "--unknown-flag-xyz", "X" ] );
assert!(
!out.status.success(),
"unknown flag must cause non-zero exit. Got exit: {:?}",
out.status.code()
);
let stderr = String::from_utf8_lossy( &out.stderr );
assert!(
stderr.contains( "unknown option" ) || stderr.contains( "Error:" ),
"error message must appear on stderr. Got:\n{stderr}"
);
}
#[ test ]
#[ cfg_attr( any(), doc = "bug_reproducer(BUG-249)" ) ]
fn t11_ask_positional_help_shows_help()
{
let bin = env!( "CARGO_BIN_EXE_clr" );
let out = Command::new( bin )
.args( [ "ask", "help" ] )
.output()
.expect( "failed to invoke clr binary" );
assert!(
out.status.success(),
"clr ask help must exit 0. Got exit {}: {}",
out.status.code().unwrap_or( -1 ),
String::from_utf8_lossy( &out.stderr )
);
let stdout = String::from_utf8_lossy( &out.stdout );
assert!(
stdout.contains( "Usage" ) || stdout.contains( "usage" ) || stdout.contains( "clr ask" ),
"clr ask help must print help text. Got stdout:\n{stdout}"
);
}
#[ test ]
fn t10_ask_subdir_effective_dir()
{
let output = run_ask_dry( &[ "--subdir", "feature", "What is X?" ] );
assert!(
output.contains( "/-feature" ),
"ask --subdir feature must produce path ending in /-feature. Got:\n{output}"
);
}
#[ test ]
fn t12_ask_edit_distance_typo_caught_by_guard()
{
let bin = env!( "CARGO_BIN_EXE_clr" );
let out = std::process::Command::new( bin )
.args( [ "assk", "--dry-run" ] )
.output()
.expect( "failed to invoke clr assk --dry-run" );
let stderr = String::from_utf8_lossy( &out.stderr );
assert_eq!(
out.status.code(),
Some( 1 ),
"'clr assk' must exit 1 (unknown subcommand guard); got {:?}\nstderr: {stderr}",
out.status.code(),
);
assert!(
stderr.contains( "unknown subcommand" ),
"stderr must contain 'unknown subcommand'; got: {stderr}"
);
assert!(
stderr.contains( "ask" ),
"stderr must suggest 'ask'; got: {stderr}"
);
}