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 ec_1_scope_local_accepted()
{
let root = TempDir::new().unwrap();
let project_dir = TempDir::new().unwrap();
common::write_path_project_session( root.path(), project_dir.path(), "sess-local", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.current_dir( project_dir.path() )
.arg( ".projects" )
.arg( "scope::local" )
.output()
.unwrap();
assert_exit( &out, 0 );
}
#[ test ]
fn ec_2_scope_relevant_accepted()
{
let root = TempDir::new().unwrap();
let project_dir = TempDir::new().unwrap();
common::write_path_project_session( root.path(), project_dir.path(), "sess-rel", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.current_dir( project_dir.path() )
.arg( ".projects" )
.arg( "scope::relevant" )
.output()
.unwrap();
assert_exit( &out, 0 );
}
#[ test ]
fn ec_3_scope_under_accepted()
{
let root = TempDir::new().unwrap();
common::write_test_session( root.path(), "proj-under", "sess-under", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".projects" )
.arg( "scope::under" )
.arg( format!( "path::{}", root.path().display() ) )
.output()
.unwrap();
assert_exit( &out, 0 );
}
#[ test ]
fn ec_4_scope_global_accepted()
{
let root = TempDir::new().unwrap();
common::write_test_session( root.path(), "proj-a", "sess-a", 2 );
common::write_test_session( root.path(), "proj-b", "sess-b", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".projects" )
.arg( "scope::global" )
.output()
.unwrap();
assert_exit( &out, 0 );
}
#[ test ]
fn ec_5_scope_uppercase_accepted()
{
let root = TempDir::new().unwrap();
let project_dir = TempDir::new().unwrap();
common::write_path_project_session( root.path(), project_dir.path(), "sess-rel", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.current_dir( project_dir.path() )
.arg( ".projects" )
.arg( "scope::RELEVANT" )
.output()
.unwrap();
assert_exit( &out, 0 );
}
#[ test ]
fn ec_6_scope_all_rejected()
{
let out = common::clg_cmd()
.arg( ".projects" )
.arg( "scope::all" )
.output()
.unwrap();
assert_exit( &out, 1 );
let err = stderr( &out );
assert!(
err.contains( "scope" ) && err.contains( "all" ),
"EC-6: expected 'scope' and 'all' in stderr; got: {err}"
);
}
#[ test ]
fn ec_7_scope_omitted_defaults_to_under()
{
let root = TempDir::new().unwrap();
let parent_dir = TempDir::new().unwrap();
let child_dir_path = parent_dir.path().join( "child" );
std::fs::create_dir_all( &child_dir_path ).unwrap();
common::write_path_project_session(
root.path(),
&child_dir_path,
"sess-child",
2,
);
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.current_dir( parent_dir.path() )
.arg( ".projects" )
.output()
.unwrap();
assert_exit( &out, 0 );
let output = stdout( &out );
assert!(
output.contains( "child" ),
"EC-7: default .projects from parent dir must show child project; got: {output}"
);
}
#[ test ]
fn ec_8_scope_global_ignores_path()
{
let root = TempDir::new().unwrap();
common::write_test_session( root.path(), "proj-global", "sess-g", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".projects" )
.arg( "scope::global" )
.arg( "path::/tmp/nonexistent-subpath-clg-test" )
.output()
.unwrap();
assert_exit( &out, 0 );
}