mod common;
#[ test ]
fn test_list_verbosity_negative()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "verbosity::-1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
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 verbosity::-1. Got: {combined}"
);
assert!(
combined.to_lowercase().contains( "verbosity" ) ||
combined.to_lowercase().contains( "invalid" ),
"Error should mention verbosity or invalid. Got: {combined}"
);
}
#[ test ]
fn test_list_verbosity_out_of_range()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "verbosity::6" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
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 verbosity::6. Got: {combined}"
);
assert!(
combined.to_lowercase().contains( "verbosity" ) ||
combined.to_lowercase().contains( "invalid" ),
"Error should mention verbosity or invalid. Got: {combined}"
);
}
#[ test ]
fn test_list_verbosity_zero()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-proj-v0", "sess-v0-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "verbosity::0" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list verbosity::0 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_verbosity_mid_range()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-proj-v3", "sess-v3-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "verbosity::3" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list verbosity::3 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_verbosity_max()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-proj-v5", "sess-v5-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "verbosity::5" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list verbosity::5 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_agent_invalid()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "agent::2" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
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 invalid Boolean agent::2. Got: {combined}"
);
}
#[ test ]
fn test_list_agent_zero()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "agent::0" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list agent::0 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_agent_one()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-proj-ag", "sess-ag-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "agent::1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list agent::1 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_session_filter()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-proj-sf", "sess-sf-abc", 2 );
let output = common::clg_cmd()
.args( [ ".list", "session::abc" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list session::abc should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_session_filter_empty()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "session::" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
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.contains( "session" ),
"Error should mention session parameter. Got: {combined}"
);
}
#[ test ]
fn test_list_sessions_invalid()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "sessions::2" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
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 invalid Boolean sessions::2. Got: {combined}"
);
}
#[ test ]
fn test_list_type_uuid_with_sessions()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-pair-uuid", "sess-uuid-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "type::uuid", "sessions::1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list type::uuid sessions::1 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_type_path_with_verbosity()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-pair-path", "sess-path-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "type::path", "verbosity::2" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list type::path verbosity::2 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_sessions_with_invalid_verbosity()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "sessions::0", "verbosity::-1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
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 verbosity::-1 even alongside valid sessions::0. Got: {combined}"
);
}
#[ test ]
fn test_list_no_params()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-base-proj", "sess-base-001", 2 );
let output = common::clg_cmd()
.args( [ ".list" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list with no params should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_sessions_zero()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-s0-proj", "sess-s0-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "sessions::0" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list sessions::0 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_sessions_one()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-s1-proj", "sess-s1-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "sessions::1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list sessions::1 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_min_entries_zero()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-me-proj", "sess-me-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "min_entries::0" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list min_entries::0 should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_path_filter()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "path::/tmp" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list path::/tmp should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_type_all()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-tall-proj", "sess-tall-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "type::all" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list type::all should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_type_invalid()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
let output = common::clg_cmd()
.args( [ ".list", "type::notvalid" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
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 invalid type. Got: {combined}"
);
assert!(
combined.to_lowercase().contains( "type" ) ||
combined.to_lowercase().contains( "invalid" ),
"Error should mention type or invalid. Got: {combined}"
);
}
#[ test ]
fn test_list_verbosity_default_explicit()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "list-vdef-proj", "sess-vdef-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "verbosity::1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stderr = String::from_utf8_lossy( &output.stderr );
assert!(
output.status.success(),
".list verbosity::1 (default) should succeed. stderr: {stderr}"
);
}
#[ test ]
fn test_list_singular_noun_one_project()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "only-proj", "sess-sing-001", 2 );
let output = common::clg_cmd()
.args( [ ".list", "verbosity::1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stdout = String::from_utf8_lossy( &output.stdout );
assert!(
output.status.success(),
".list with 1 project should succeed; stderr: {}",
String::from_utf8_lossy( &output.stderr )
);
assert!(
stdout.contains( "Found 1 project:" ),
"with 1 project, header must use singular 'project'; got:\n{stdout}"
);
assert!(
!stdout.contains( "Found 1 projects:" ),
"with 1 project, header must NOT use plural 'projects'; got:\n{stdout}"
);
}
#[ test ]
fn test_list_plural_noun_multiple_projects()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "proj-a", "sess-plur-a", 2 );
common::write_test_session( storage.path(), "proj-b", "sess-plur-b", 2 );
let output = common::clg_cmd()
.args( [ ".list", "verbosity::1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stdout = String::from_utf8_lossy( &output.stdout );
assert!(
output.status.success(),
".list with 2 projects should succeed; stderr: {}",
String::from_utf8_lossy( &output.stderr )
);
assert!(
stdout.contains( "Found 2 projects:" ),
"with 2 projects, header must use plural 'projects'; got:\n{stdout}"
);
}
#[ test ]
fn test_list_session_count_singular_when_one_session()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "sing-proj", "sess-sing-only", 2 );
let output = common::clg_cmd()
.args( [ ".list", "sessions::1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stdout = String::from_utf8_lossy( &output.stdout );
assert!(
output.status.success(),
".list sessions::1 should succeed; stderr: {}",
String::from_utf8_lossy( &output.stderr )
);
assert!(
stdout.contains( "(1 session)" ),
"with 1 session, project label must use singular '(1 session)'; got:\n{stdout}"
);
assert!(
!stdout.contains( "(1 sessions)" ),
"with 1 session, project label must NOT use plural '(1 sessions)'; got:\n{stdout}"
);
}
#[ test ]
fn test_list_session_count_plural_when_multiple_sessions()
{
use tempfile::TempDir;
let storage = TempDir::new().unwrap();
common::write_test_session( storage.path(), "plur-proj", "sess-plur-x", 2 );
common::write_test_session( storage.path(), "plur-proj", "sess-plur-y", 2 );
let output = common::clg_cmd()
.args( [ ".list", "sessions::1" ] )
.env( "CLAUDE_STORAGE_ROOT", storage.path() )
.output()
.expect( "Failed to execute .list" );
let stdout = String::from_utf8_lossy( &output.stdout );
assert!(
output.status.success(),
".list sessions::1 should succeed; stderr: {}",
String::from_utf8_lossy( &output.stderr )
);
assert!(
stdout.contains( "(2 sessions)" ),
"with 2 sessions, project label must use plural '(2 sessions)'; got:\n{stdout}"
);
}