fn run_ast( args : &[ &str ] ) -> ( i32, String, String )
{
let home = tempfile::TempDir::new().unwrap();
let out = std::process::Command::new(
assert_cmd::cargo::cargo_bin!( "ast" )
)
.env( "HOME", home.path() )
.args( args )
.output()
.unwrap();
(
out.status.code().unwrap_or( -1 ),
String::from_utf8_lossy( &out.stdout ).into_owned(),
String::from_utf8_lossy( &out.stderr ).into_owned(),
)
}
#[test]
fn ft1_all_five_l2_crates_contribute_commands()
{
let cases : &[ ( &str, &str ) ] = &[
( ".kinds", "claude_assets" ),
( ".version.show", "claude_version" ),
( ".paths", "claude_profile" ),
( ".claude", "claude_runner" ),
( ".show", "claude_storage" ),
];
for ( cmd, crate_name ) in cases
{
let ( code, _, stderr ) = run_ast( &[ cmd ] );
assert!(
code == 0 || code == 2,
"FT-1: {cmd} ({crate_name}) should exit 0 or 2, not {code}; stderr: {stderr}",
);
}
}
#[test]
fn ft2_first_wins_precedence_status()
{
let ( code, _, stderr ) = run_ast( &[ ".status" ] );
assert_eq!(
code, 0,
"FT-2: .status must exit 0 (version implementation); stderr: {stderr}",
);
}
#[test]
fn ft3_yaml_backed_commands_reachable()
{
let export_dir = tempfile::TempDir::new().unwrap();
let export_path = export_dir.path().join( "export_out" );
let export_arg = format!( "output::{}", export_path.display() );
let yaml_commands : Vec< Vec< &str > > = vec![
vec![ ".show" ],
vec![ ".count" ],
vec![ ".search", "query::test" ],
vec![ ".export", "session_id::test", &export_arg ],
];
for args in &yaml_commands
{
let ( code, _, stderr ) = run_ast( args );
let label = args[ 0 ];
assert!(
code == 0 || code == 2,
"FT-3: {label} (YAML-backed) should exit 0 or 2, not {code}; stderr: {stderr}",
);
}
}
#[test]
fn ft4_claude_stub_prints_redirect()
{
let ( code, stdout, stderr ) = run_ast( &[ ".claude" ] );
assert_eq!(
code, 0,
"FT-4: .claude should exit 0; stderr: {stderr}",
);
assert!(
stdout.contains( "For Claude Code execution, use clr directly." ),
"FT-4: .claude stdout must contain redirect message; got: {stdout}",
);
}
#[test]
fn ic1_register_commands_contract()
{
let crate_commands : &[ ( &str, &str ) ] = &[
( ".kinds", "claude_assets" ),
( ".processes","claude_version" ),
( ".accounts", "claude_profile" ),
( ".claude", "claude_runner" ),
( ".projects", "claude_storage" ),
];
for ( cmd, crate_name ) in crate_commands
{
let ( code, _, stderr ) = run_ast( &[ cmd ] );
assert_ne!(
code, 1,
"IC-1: {cmd} ({crate_name}) must not exit 1 (unknown command); stderr: {stderr}",
);
}
}
#[test]
fn ic2_no_orphan_yaml_commands()
{
let export_dir = tempfile::TempDir::new().unwrap();
let export_path = export_dir.path().join( "export_out" );
let export_arg = format!( "output::{}", export_path.display() );
let phf_commands : Vec< Vec< &str > > = vec![
vec![ ".claude" ], vec![ ".claude.help" ],
vec![ ".status" ], vec![ ".list" ], vec![ ".show" ], vec![ ".projects" ],
vec![ ".count" ], vec![ ".search", "query::test" ], vec![ ".export", "session_id::test", &export_arg ],
vec![ ".session.dir" ], vec![ ".session.ensure" ],
];
for args in &phf_commands
{
let ( code, _, stderr ) = run_ast( args );
let label = args[ 0 ];
assert_ne!(
code, 1,
"IC-2: {label} must not exit 1 (orphan command); stderr: {stderr}",
);
}
}
#[test]
fn unknown_command_exits_1()
{
let ( code, _, _ ) = run_ast( &[ ".nonexistent_command_xyz" ] );
assert_eq!(
code, 1,
"Unknown command must exit 1; got {code}",
);
}