mod common;
use tempfile::TempDir;
fn stdout( out : &std::process::Output ) -> String
{
String::from_utf8_lossy( &out.stdout ).into_owned()
}
fn stderr( out : &std::process::Output ) -> String
{
String::from_utf8_lossy( &out.stderr ).into_owned()
}
fn assert_exit( out : &std::process::Output, code : i32 )
{
assert_eq!(
out.status.code().unwrap_or( -1 ),
code,
"expected exit {code}, got {:?}; stderr: {}",
out.status.code(),
stderr( out )
);
}
#[ test ]
fn ft_1_one_shot_command_executes_and_exits_cleanly()
{
let root = TempDir::new().unwrap();
let project = root.path().join( "proj" );
common::write_path_project_session( root.path(), &project, "session-ft1", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".status" )
.output()
.unwrap();
assert_exit( &out, 0 );
assert!(
!stdout( &out ).is_empty(),
"FT-1: .status must produce output; got silence; stderr: {}",
stderr( &out )
);
}
#[ test ]
fn ft_2_unknown_command_rejected_with_non_zero_exit()
{
let out = common::clg_cmd()
.env( "HOME", "/tmp" )
.arg( ".nonexistent_command" )
.output()
.unwrap();
assert_exit( &out, 1 );
let err = stderr( &out );
assert!(
!err.is_empty(),
"FT-2: unknown command must emit error on stderr; got silence"
);
assert!(
!err.contains( "panicked at" ),
"FT-2: unknown command must not panic; stderr:\n{err}"
);
}
#[ test ]
fn ft_3_path_encoded_project_returned_in_project_list()
{
let root = TempDir::new().unwrap();
let project = root.path().join( "myproject" );
common::write_path_project_session( root.path(), &project, "session-ft3", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".list" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
s.contains( "myproject" ),
"FT-3: path-encoded project must appear in .list output; got:\n{s}"
);
}
#[ test ]
fn ft_4_uuid_named_project_returned_in_project_list()
{
let root = TempDir::new().unwrap();
let project = root.path().join( "myproject" );
common::write_path_project_session( root.path(), &project, "session-ft4-path", 2 );
let uuid = "8d795a1c-c81d-4010-8d29-b4e678272419";
common::write_test_session( root.path(), uuid, "session-ft4-uuid", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".list" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
s.contains( uuid ) || s.contains( "8d795a1c" ),
"FT-4: UUID project must appear in .list output; got:\n{s}"
);
assert!(
s.contains( "myproject" ),
"FT-4: path-encoded project must appear alongside UUID project; got:\n{s}"
);
}
#[ test ]
fn ft_5_flat_layout_project_sessions_accessible()
{
let root = TempDir::new().unwrap();
let project = root.path().join( "flatproj" );
common::write_path_project_session( root.path(), &project, "session-ft5", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".list" )
.arg( "show_sessions::1" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
let err = stderr( &out );
assert!(
!s.is_empty(),
"FT-5: flat-layout sessions must appear in .list show_sessions::1; stderr: {err}"
);
assert!(
!err.contains( "unrecognized layout" ),
"FT-5: flat-layout must not produce layout error; stderr:\n{err}"
);
}
#[ test ]
fn ft_6_hierarchical_layout_project_sessions_accessible()
{
let root = TempDir::new().unwrap();
let flat_project = root.path().join( "flatproj" );
common::write_path_project_session( root.path(), &flat_project, "session-ft6-flat", 2 );
let hier_project = root.path().join( "hierproj" );
common::write_hierarchical_path_session(
root.path(),
&hier_project,
"session-ft6-hier",
&[ ( "agent-001", "task" ) ],
2,
);
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".list" )
.arg( "show_sessions::1" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
let err = stderr( &out );
assert!(
!s.is_empty(),
"FT-6: hierarchical-layout sessions must appear in .list show_sessions::1; stderr: {err}"
);
assert!(
!err.contains( "unrecognized layout" ),
"FT-6: hierarchical-layout must not produce layout error; stderr:\n{err}"
);
}