mod common;
use std::fs;
use tempfile::TempDir;
#[ test ]
fn test_count_default_behavior_context_aware()
{
let storage = TempDir::new().unwrap();
let project_cwd = TempDir::new().unwrap();
common::write_path_project_session(
storage.path(),
project_cwd.path(),
"session-context-aware",
5,
);
let output = common::clg_cmd()
.args( [ ".count" ] )
.current_dir( project_cwd.path() )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "failed to execute .count" );
let stdout = String::from_utf8_lossy( &output.stdout );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".count must succeed. stderr: {stderr}"
);
let count_str = stdout.trim();
assert_eq!(
count_str, "5",
"Expected .count (no params) to return 5 entries in current project, got: {count_str}"
);
}
#[ test ]
fn test_count_with_path_project_parameter()
{
let storage = TempDir::new().unwrap();
let project_path = TempDir::new().unwrap();
common::write_path_project_session(
storage.path(),
project_path.path(),
"session-path-001",
1,
);
common::write_path_project_session(
storage.path(),
project_path.path(),
"session-path-002",
1,
);
common::write_path_project_session(
storage.path(),
project_path.path(),
"session-path-003",
1,
);
let output = common::clg_cmd()
.args( [
".count",
"target::sessions",
&format!( "project::{}", project_path.path().display() ),
] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "failed to execute .count" );
let stdout = String::from_utf8_lossy( &output.stdout );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".count should succeed with path parameter. stderr: {stderr}"
);
assert_eq!(
stdout.trim(), "3",
"Expected 3 sessions. stdout: {stdout}"
);
}
#[ test ]
#[ cfg( unix ) ]
fn test_count_skips_unreadable_sessions()
{
use std::os::unix::fs::PermissionsExt;
let storage = TempDir::new().unwrap();
let project_cwd = TempDir::new().unwrap();
let encoded = common::write_path_project_session(
storage.path(),
project_cwd.path(),
"aaaaaaaa-clean-ccccccccccc",
2,
);
let unreadable_session = storage.path()
.join( "projects" )
.join( &encoded )
.join( "bbbbbbbb-unreadable-dddddddddddd.jsonl" );
fs::write( &unreadable_session, "" ).unwrap();
fs::set_permissions(
&unreadable_session,
fs::Permissions::from_mode( 0o000 ),
).unwrap();
let output = common::clg_cmd()
.args( [ ".count" ] )
.current_dir( project_cwd.path() )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "failed to execute .count" );
fs::set_permissions(
&unreadable_session,
fs::Permissions::from_mode( 0o644 ),
).ok();
let stdout = String::from_utf8_lossy( &output.stdout );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".count must succeed even with unreadable sessions. stderr: {stderr}"
);
assert_eq!(
stdout.trim(), "2",
"Expected 2 entries from clean session only. stdout: {stdout}, stderr: {stderr}"
);
assert!(
stderr.contains( "Warning" ) && stderr.contains( "corrupted" ),
"Expected 'Warning: Skipping corrupted session ...' in stderr. stderr: {stderr}"
);
}
#[ test ]
fn test_count_explicit_target_projects()
{
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "proj-alpha", "s001", 1 );
common::write_test_session( storage.path(), "proj-beta", "s001", 1 );
let output = common::clg_cmd()
.args( [ ".count", "target::projects" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "failed to execute .count" );
let stdout = String::from_utf8_lossy( &output.stdout );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".count target::projects must succeed. stderr: {stderr}"
);
assert_eq!(
stdout.trim(), "2",
"Expected 2 projects. stdout: {stdout}"
);
}
#[ test ]
fn test_count_entries_with_session_filter()
{
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "count-sess-proj", "target-session-aaa", 3 );
common::write_test_session( storage.path(), "count-sess-proj", "other-session-bbb", 5 );
let output = common::clg_cmd()
.args( [
".count",
"target::entries",
"session::target-session-aaa",
"project::count-sess-proj",
] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "failed to execute .count" );
let stdout = String::from_utf8_lossy( &output.stdout );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".count with session filter should succeed. stderr: {stderr}"
);
assert_eq!(
stdout.trim(), "3",
"Expected 3 entries from target session only. stdout: {stdout}"
);
}
#[ test ]
fn test_count_entries_session_empty()
{
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".count", "target::entries", "session::", "project::some-proj" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "failed to execute .count" );
let stderr = String::from_utf8_lossy( &output.stderr );
let stdout = String::from_utf8_lossy( &output.stdout );
let combined = format!( "{stderr}{stdout}" );
assert!(
!output.status.success(),
"Should fail with empty session filter. Got: {combined}"
);
assert!(
combined.to_lowercase().contains( "error" ) ||
combined.contains( "session" ),
"Error should be a parse or validation error. Got: {combined}"
);
}
#[ test ]
fn test_count_entries_partial_uuid_match()
{
let storage = TempDir::new().unwrap();
let session_uuid = "79f86582-1435-442c-935a-13f8d874918a";
let session_prefix = "79f86582";
common::write_test_session( storage.path(), "count-partial-proj", session_uuid, 3 );
let output = common::clg_cmd()
.args( [
".count",
"target::entries",
"project::count-partial-proj",
&format!( "session::{session_prefix}" ),
] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "failed to execute .count" );
let stdout = String::from_utf8_lossy( &output.stdout );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".count target::entries with partial UUID must succeed. stderr: {stderr}"
);
assert_eq!(
stdout.trim(), "3",
"Expected 3 entries via partial UUID match. stdout: {stdout}"
);
}