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 int_1_default_output_with_real_storage()
{
let root = TempDir::new().unwrap();
let p1 = root.path().join( "proj-alpha" );
let p2 = root.path().join( "proj-beta" );
common::write_path_project_session( root.path(), &p1, "s001", 2 );
common::write_path_project_session( root.path(), &p2, "s002", 2 );
common::write_path_project_session( root.path(), &p2, "s003", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".status" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
!s.is_empty(),
"INT-1: .status must produce output on stdout; stderr: {}",
stderr( &out )
);
assert!(
s.contains( '2' ),
"INT-1: output must mention project count 2; got:\n{s}"
);
}
#[ test ]
fn int_3_show_tokens_adds_tokens_section()
{
let root = TempDir::new().unwrap();
let p1 = root.path().join( "int3-alpha" );
let p2 = root.path().join( "int3-beta" );
common::write_path_project_session( root.path(), &p1, "s001", 4 );
common::write_path_project_session( root.path(), &p2, "s002", 4 );
let base_out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".status" )
.output()
.unwrap();
let tokens_out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".status" )
.arg( "show_tokens::1" )
.output()
.unwrap();
assert_exit( &base_out, 0 );
assert_exit( &tokens_out, 0 );
let base = stdout( &base_out );
let tokens = stdout( &tokens_out );
assert!(
tokens.len() > base.len(),
"INT-3: show_tokens::1 must produce more output than bare .status;\n base ({} bytes):\n{base}\n tokens ({} bytes):\n{tokens}",
base.len(),
tokens.len()
);
assert!(
tokens.to_lowercase().contains( "token" ),
"INT-3: show_tokens::1 output must include Tokens section; got:\n{tokens}"
);
}
#[ test ]
fn int_4_custom_storage_path_via_path_param()
{
let alt_root = TempDir::new().unwrap();
let p = alt_root.path().join( "int4-only" );
common::write_path_project_session( alt_root.path(), &p, "s001", 2 );
let out = common::clg_cmd()
.arg( ".status" )
.arg( format!( "path::{}", alt_root.path().display() ) )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
s.contains( '1' ),
"INT-4: output must show 1 project from path:: fixture; got:\n{s}"
);
}
#[ test ]
fn int_5_custom_storage_path_via_env()
{
let root = TempDir::new().unwrap();
let p1 = root.path().join( "int5-x" );
let p2 = root.path().join( "int5-y" );
common::write_path_project_session( root.path(), &p1, "s001", 2 );
common::write_path_project_session( root.path(), &p2, "s002", 2 );
common::write_path_project_session( root.path(), &p2, "s003", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".status" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
!s.is_empty(),
"INT-5: CLAUDE_STORAGE_ROOT fixture must produce output; stderr: {}",
stderr( &out )
);
}
#[ test ]
fn int_6_exit_code_0_on_success()
{
let root = TempDir::new().unwrap();
let p = root.path().join( "int6-proj" );
common::write_path_project_session( root.path(), &p, "s001", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".status" )
.output()
.unwrap();
assert_exit( &out, 0 );
}
#[ test ]
fn int_7_exit_code_2_on_unreadable_storage_path()
{
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", "/tmp/nonexistent-storage-xyz-abc-int7" )
.arg( ".status" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
s.contains( '0' ),
"INT-7: nonexistent path gives empty stats; got:\n{s}"
);
}
#[ test ]
fn int_8_output_contains_project_and_session_count()
{
let root = TempDir::new().unwrap();
let p1 = root.path().join( "int8-a" );
let p2 = root.path().join( "int8-b" );
let p3 = root.path().join( "int8-c" );
common::write_path_project_session( root.path(), &p1, "s001", 2 );
common::write_path_project_session( root.path(), &p2, "s002", 2 );
common::write_path_project_session( root.path(), &p2, "s003", 2 );
common::write_path_project_session( root.path(), &p3, "s004", 2 );
common::write_path_project_session( root.path(), &p3, "s005", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".status" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
s.contains( '3' ),
"INT-8: output must reference project count 3; got:\n{s}"
);
assert!(
s.contains( '5' ),
"INT-8: output must reference session count 5; got:\n{s}"
);
}