mod common;
use std::fs;
use tempfile::TempDir;
fn stdout( out : &std::process::Output ) -> String
{
String::from_utf8_lossy( &out.stdout ).into_owned()
}
fn assert_exit( out : &std::process::Output, code : i32 )
{
let stderr = String::from_utf8_lossy( &out.stderr );
assert_eq!(
out.status.code().unwrap_or( -1 ),
code,
"expected exit {code}, got {:?}; stderr: {}",
out.status.code(),
stderr
);
}
fn write_zero_byte_session(
root : &std::path::Path,
project_id : &str,
session_id : &str,
)
{
let dir = root.join( "projects" ).join( project_id );
fs::create_dir_all( &dir ).expect( "create project dir" );
let path = dir.join( format!( "{session_id}.jsonl" ) );
fs::File::create( &path ).expect( "create zero-byte session file" );
}
fn write_zero_byte_path_session(
root : &std::path::Path,
project_path : &std::path::Path,
session_id : &str,
) -> String
{
let encoded = claude_storage_core::encode_path( project_path )
.expect( "encode project path" );
write_zero_byte_session( root, &encoded, session_id );
encoded
}
#[test]
fn it54_use_families_zero_byte_excluded_from_header_count()
{
let root = TempDir::new().unwrap();
let storage_root = root.path().join( ".claude" );
let project_path = root.path().join( "proj54" );
std::fs::create_dir_all( &project_path ).expect( "create project dir" );
common::write_path_project_session( &storage_root, &project_path, "session-it54-real", 4 );
write_zero_byte_path_session( &storage_root, &project_path, "session-it54-zero" );
let out = common::clg_cmd()
.env( "HOME", root.path().to_str().unwrap() )
.env( "CLAUDE_STORAGE_ROOT", storage_root.to_str().unwrap() )
.current_dir( &project_path )
.arg( ".projects" )
.arg( "scope::local" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
s.contains( "(1 session)" ),
"header must say '(1 session)' — zero-byte must not be counted; got:\n{s}"
);
assert!(
!s.contains( "(2 session" ),
"header must NOT say '(2 session...)' — that would include zero-byte; got:\n{s}"
);
assert!(
s.contains( "session-it54-real" ),
"real session must appear in output; got:\n{s}"
);
}
#[test]
fn it55_flat_branch_zero_byte_excluded_from_header_count()
{
let root = TempDir::new().unwrap();
let storage_root = root.path().join( ".claude" );
let project_path = root.path().join( "proj55" );
std::fs::create_dir_all( &project_path ).expect( "create project dir" );
common::write_path_project_session( &storage_root, &project_path, "session-it55-real", 4 );
write_zero_byte_path_session( &storage_root, &project_path, "session-it55-zero" );
let out = common::clg_cmd()
.env( "HOME", root.path().to_str().unwrap() )
.env( "CLAUDE_STORAGE_ROOT", storage_root.to_str().unwrap() )
.current_dir( &project_path )
.arg( ".projects" )
.arg( "scope::local" )
.arg( "agent::0" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
s.contains( "(1 session)" ),
"flat-branch header must say '(1 session)' — zero-byte must not be counted; got:\n{s}"
);
assert!(
!s.contains( "(2 session" ),
"flat-branch header must NOT say '(2 session...)'; got:\n{s}"
);
assert!(
s.contains( "session-it55-real" ),
"real session must appear in flat output; got:\n{s}"
);
}
#[test]
fn it56_zero_byte_only_project_excluded_from_list_output()
{
let root = TempDir::new().unwrap();
let storage_root = root.path().join( ".claude" );
let proj_zero = root.path().join( "proj56_zero" );
std::fs::create_dir_all( &proj_zero ).expect( "create proj56_zero dir" );
write_zero_byte_path_session( &storage_root, &proj_zero, "session-it56-z1" );
write_zero_byte_path_session( &storage_root, &proj_zero, "session-it56-z2" );
let proj_real = root.path().join( "proj56_real" );
std::fs::create_dir_all( &proj_real ).expect( "create proj56_real dir" );
common::write_path_project_session( &storage_root, &proj_real, "session-it56-real", 4 );
let out = common::clg_cmd()
.env( "HOME", root.path().to_str().unwrap() )
.env( "CLAUDE_STORAGE_ROOT", storage_root.to_str().unwrap() )
.arg( ".projects" )
.arg( "scope::global" )
.output()
.unwrap();
assert_exit( &out, 0 );
let s = stdout( &out );
assert!(
s.contains( "Found 1 project" ),
"only the real project must be listed; got:\n{s}"
);
assert!(
s.contains( "session-it56-real" ),
"real session must appear in output; got:\n{s}"
);
assert!(
!s.contains( "proj56_zero" ),
"zero-byte-only project must NOT appear in list output; got:\n{s}"
);
}