use crate::cli_runner::{ run_cs, stdout, assert_exit };
#[ test ]
fn dot01_dot_and_help_byte_identical()
{
let dot = run_cs( &[ "." ] );
let dot_help = run_cs( &[ ".help" ] );
assert_eq!(
dot.stdout,
dot_help.stdout,
"`.` and `.help` stdout must be byte-identical",
);
}
#[ test ]
fn dot02_dot_exits_0()
{
let out = run_cs( &[ "." ] );
assert_exit( &out, 0 );
}
#[ test ]
fn dot03_dot_hidden_from_listing()
{
let out = run_cs( &[ "." ] );
let text = stdout( &out );
assert!(
!text.contains( " . " ),
"`.` must not appear as a command row in the listing",
);
}
#[ test ]
fn dot04_all_visible_commands_present()
{
let out = run_cs( &[ "." ] );
let text = stdout( &out );
let visible = [
".accounts",
".account.save",
".account.use",
".account.delete",
".account.limits",
".account.relogin",
".account.rotate",
".account.renewal",
".account.inspect",
".credentials.status",
".token.status",
".paths",
".usage",
".model",
];
for name in &visible
{
assert!( text.contains( name ), "output must contain command {name:?}" );
}
assert!( !text.contains( ".account.list" ), ".account.list must not appear (removed)" );
assert!( !text.contains( ".account.status" ), ".account.status must not appear (removed)" );
assert!( !text.contains( ".account.assign" ), ".account.assign must not appear (removed)" );
assert!( !text.contains( ".account.unclaim" ), ".account.unclaim must not appear (removed)" );
}
#[ test ]
fn dot05_exactly_sixteen_command_rows()
{
let out = run_cs( &[ "." ] );
let text = stdout( &out );
let count = text.lines().filter( |l| l.starts_with( " ." ) ).count();
assert_eq!( count, 14, "expected 14 command rows starting with ' .', got {count}" );
}
#[ test ]
fn dot06_usage_line_present()
{
let out = run_cs( &[ "." ] );
let text = stdout( &out );
assert!(
text.contains( "Usage: clp <command>" ),
"output must contain usage line 'Usage: clp <command>'",
);
}
#[ test ]
fn dot07_unknown_param_ignored()
{
let bare = run_cs( &[ "." ] );
let extra = run_cs( &[ ".", "foo::bar" ] );
assert_eq!(
bare.stdout,
extra.stdout,
"trailing unknown param must not change help output",
);
}
#[ test ]
fn dot08_output_stable_across_invocations()
{
let out1 = run_cs( &[ "." ] );
let out2 = run_cs( &[ "." ] );
let out3 = run_cs( &[ "." ] );
assert_eq!( out1.stdout, out2.stdout, "first and second invocations must match" );
assert_eq!( out2.stdout, out3.stdout, "second and third invocations must match" );
}
#[ test ]
fn dot09_grouped_section_headers()
{
let out = run_cs( &[ "." ] );
let text = stdout( &out );
assert!( text.contains( "Account management" ), "output must contain 'Account management' header" );
assert!( text.contains( "Status & info" ), "output must contain 'Status & info' header" );
}
#[ test ]
fn dot10_no_per_command_param_syntax()
{
let out = run_cs( &[ "." ] );
let text = stdout( &out );
for line in text.lines()
{
if line.starts_with( " ." )
{
assert!( !line.contains( '[' ), "command row must not contain '[': {line:?}" );
assert!( !line.contains( ']' ), "command row must not contain ']': {line:?}" );
}
}
}
#[ test ]
fn dot11_options_section_hints()
{
let out = run_cs( &[ "." ] );
let text = stdout( &out );
assert!( text.contains( "format::text|json" ), "Options must include format hint" );
assert!( text.contains( "dry::bool" ), "Options must include dry hint" );
assert!( text.contains( "name::EMAIL" ), "Options must include name hint" );
}
#[ test ]
fn dot12_no_ansi_in_subprocess_output()
{
let out = run_cs( &[ "." ] );
assert!(
!out.stdout.contains( &0x1b_u8 ),
"subprocess stdout must not contain ESC bytes (ANSI suppressed in non-TTY)",
);
}