#[cfg(test)]
mod tests {
use crate::protocol_impl::McpProtocolHandlerImpl;
use serde_json::{json, Value};
#[tokio::test]
async fn test_error_response_format() {
let mut handler = McpProtocolHandlerImpl::new();
let premature_call = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
});
let result = handler.handle_message(premature_call).await.unwrap();
assert_eq!(result["jsonrpc"], "2.0");
assert_eq!(result["id"], 1);
assert!(result.get("error").is_some());
let error = &result["error"];
assert!(error.get("code").is_some());
assert!(error.get("message").is_some());
assert!(error["code"].is_i64());
assert!(error["message"].is_string());
}
#[tokio::test]
async fn test_standard_error_codes() {
let mut handler = McpProtocolHandlerImpl::new();
let unknown_method = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "unknown/method",
"params": {}
});
let result = handler.handle_message(unknown_method).await.unwrap();
let error_code = result["error"]["code"].as_i64().unwrap();
assert_eq!(error_code, -32601);
let init = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18"
}
});
handler.handle_message(init).await.unwrap();
let invalid_params = json!({
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"arguments": {}
}
});
let result = handler.handle_message(invalid_params).await.unwrap();
if let Some(error) = result.get("error") {
let error_code = error["code"].as_i64().unwrap();
assert!(error_code == -32602 || error_code == -32603); }
}
#[tokio::test]
async fn test_tool_execution_errors() {
let mut handler = McpProtocolHandlerImpl::new();
let init = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18"
}
});
handler.handle_message(init).await.unwrap();
let call_unknown_tool = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "non_existent_tool",
"arguments": {}
}
});
let result = handler.handle_message(call_unknown_tool).await.unwrap();
assert!(result.get("error").is_some());
let error_message = result["error"]["message"].as_str().unwrap();
assert!(
error_message.to_lowercase().contains("unknown tool")
|| error_message.to_lowercase().contains("not found")
);
}
#[tokio::test]
async fn test_nested_error_propagation() {
let mut handler = McpProtocolHandlerImpl::new();
let init = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18"
}
});
handler.handle_message(init).await.unwrap();
let invalid_echo = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "echo",
"arguments": {
}
}
});
let result = handler.handle_message(invalid_echo).await.unwrap();
assert!(result.get("error").is_some());
}
#[tokio::test]
async fn test_initialization_errors() {
let mut handler = McpProtocolHandlerImpl::new();
let init = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18"
}
});
let result1 = handler.handle_message(init.clone()).await.unwrap();
assert!(result1.get("result").is_some());
let init2 = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18"
}
});
let result2 = handler.handle_message(init2).await.unwrap();
assert!(result2.get("result").is_some());
let init_invalid = json!({
"jsonrpc": "2.0",
"id": 3,
"method": "initialize",
"params": {
"protocolVersion": "invalid-version"
}
});
let result3 = handler.handle_message(init_invalid).await.unwrap();
assert!(result3.get("error").is_some());
let error_message = result3["error"]["message"].as_str().unwrap();
assert!(error_message.to_lowercase().contains("unsupported protocol"));
}
#[tokio::test]
async fn test_error_recovery() {
let mut handler = McpProtocolHandlerImpl::new();
let init = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18"
}
});
handler.handle_message(init).await.unwrap();
let error_request = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "unknown/method",
"params": {}
});
let error_result = handler.handle_message(error_request).await.unwrap();
assert!(error_result.get("error").is_some());
let valid_request = json!({
"jsonrpc": "2.0",
"id": 3,
"method": "tools/list",
"params": {}
});
let valid_result = handler.handle_message(valid_request).await.unwrap();
assert!(valid_result.get("result").is_some());
assert!(valid_result.get("error").is_none());
}
#[tokio::test]
async fn test_panic_handling() {
let mut handler = McpProtocolHandlerImpl::new();
let malformed = json!({
"jsonrpc": "2.0",
"id": 1,
"method": Value::Null, "params": "not an object"
});
let result = handler.handle_message(malformed).await;
assert!(result.is_err() || result.unwrap().get("error").is_some());
}
#[tokio::test]
async fn test_cancellation_handling() {
let mut handler = McpProtocolHandlerImpl::new();
let cancel = json!({
"jsonrpc": "2.0",
"method": "notifications/cancel",
"params": {
"requestId": "12345"
}
});
let result = handler.handle_message(cancel).await.unwrap();
assert!(result.as_object().unwrap().is_empty() || result == json!({}));
}
#[tokio::test]
async fn test_resource_errors() {
let mut handler = McpProtocolHandlerImpl::new();
let init = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18"
}
});
handler.handle_message(init).await.unwrap();
let read_missing = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "resources/read",
"params": {
"uri": "file:///non/existent/resource"
}
});
let result = handler.handle_message(read_missing).await.unwrap();
assert!(result.get("error").is_some());
}
#[tokio::test]
async fn test_deeply_nested_data() {
let mut handler = McpProtocolHandlerImpl::new();
let mut nested = json!({"level": 0});
for i in 1..100 {
nested = json!({"level": i, "nested": nested});
}
let deep_request = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": nested
}
});
let result = handler.handle_message(deep_request).await;
assert!(result.is_ok());
}
}