use crate::errors::Error;
type Fixture = Box<dyn Fn() -> Error>;
#[test]
fn a_database_error_renders_the_same_string_on_the_cli_and_the_mcp_surface() {
let busy_code = rusqlite::ffi::SQLITE_BUSY;
let busy_text = "database is locked".to_string();
let cases: Vec<(Fixture, &str)> = vec![
(
Box::new(|| {
Error::from(crate::sqlite::Error::Sqlite(
"no such table: memories".to_string(),
))
}),
"a plain database failure",
),
(
Box::new(|| {
Error::from(crate::sqlite::Error::Sqlite(
"attempt to write a readonly database".to_string(),
))
}),
"a permissions-shaped failure",
),
(
Box::new(move || {
Error::from(rusqlite::Error::SqliteFailure(
rusqlite::ffi::Error::new(busy_code),
Some(busy_text.clone()),
))
}),
"a lock classified from the raw result code",
),
(
Box::new(|| Error::from(crate::sqlite::Error::Locked)),
"the storage layer's own lock verdict",
),
];
for (produce, what) in cases {
let mcp_text = rmcp::ErrorData::from(produce()).message;
let cli_text = produce().to_string();
assert_eq!(
cli_text, mcp_text,
"{what} must render identically on the CLI and MCP surfaces, \
got CLI {cli_text:?} vs MCP {mcp_text:?}"
);
assert!(
!cli_text.is_empty(),
"{what} must render a message, got an empty string"
);
}
}