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_query_required_missing_exits_1()
{
let root = TempDir::new().unwrap();
common::write_test_session( root.path(), "proj-q", "sess", 2 );
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".search" )
.output()
.unwrap();
assert_exit( &out, 1 );
let combined = format!( "{}{}", stderr( &out ), stdout( &out ) );
assert!(
combined.contains( "query" ),
"EC-1: error must mention 'query'; got: {combined}"
);
}
#[ test ]
fn ec_2_query_empty_rejected()
{
let out = common::clg_cmd()
.arg( ".search" )
.arg( "query::" )
.output()
.unwrap();
assert_exit( &out, 1 );
let combined = format!( "{}{}", stderr( &out ), stdout( &out ) );
assert!(
combined.contains( "query" ) || combined.contains( "empty" ),
"EC-2: error must mention query or empty; got: {combined}"
);
}
#[ test ]
fn ec_3_query_single_word_accepted()
{
let root = TempDir::new().unwrap();
common::write_test_session_with_last_message(
root.path(),
"proj-q3",
"sess-q3",
0,
"error detected here",
);
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".search" )
.arg( "query::error" )
.arg( "project::proj-q3" )
.output()
.unwrap();
assert_exit( &out, 0 );
let output = stdout( &out );
assert!(
output.contains( "error" ),
"EC-3: single-word query must find matching entries; got: {output}"
);
}
#[ test ]
fn ec_4_query_multi_word_accepted()
{
let root = TempDir::new().unwrap();
common::write_test_session_with_last_message(
root.path(),
"proj-q4",
"sess-q4",
0,
"session management topic",
);
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".search" )
.arg( "query::management" )
.arg( "project::proj-q4" )
.output()
.unwrap();
assert_exit( &out, 0 );
}
#[ test ]
fn ec_5_query_alias_q_accepted()
{
let root = TempDir::new().unwrap();
common::write_test_session_with_last_message(
root.path(),
"proj-q5",
"sess-q5",
0,
"error in alias test",
);
let out_query = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".search" )
.arg( "query::error" )
.arg( "project::proj-q5" )
.output()
.unwrap();
let out_alias = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".search" )
.arg( "q::error" )
.arg( "project::proj-q5" )
.output()
.unwrap();
assert_exit( &out_query, 0 );
assert_exit( &out_alias, 0 );
assert_eq!(
stdout( &out_query ),
stdout( &out_alias ),
"EC-5: q:: alias must produce identical results to query::"
);
}
#[ test ]
fn ec_6_query_whitespace_only_rejected()
{
let root = TempDir::new().unwrap();
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".search" )
.arg( "query:: " )
.output()
.unwrap();
assert_exit( &out, 1 );
let combined = format!( "{}{}", stderr( &out ), stdout( &out ) );
assert!(
combined.contains( "query" ) || combined.contains( "empty" ),
"EC-6: error must mention query or empty; got: {combined}"
);
}
#[ test ]
fn ec_7_query_special_chars_accepted()
{
let root = TempDir::new().unwrap();
common::write_test_session_with_last_message(
root.path(),
"proj-q7",
"sess-q7",
0,
"param::value is the target",
);
let out = common::clg_cmd()
.env( "CLAUDE_STORAGE_ROOT", root.path() )
.arg( ".search" )
.arg( "query::param::value" )
.arg( "project::proj-q7" )
.output()
.unwrap();
assert_exit( &out, 0 );
let output = stdout( &out );
assert!(
output.contains( "param::value" ),
"EC-7: query with :: must search for literal param::value; got: {output}"
);
}