use serde_json::json;
#[cfg(test)]
mod schema_tests {
use super::*;
#[test]
fn test_current_schema_compliance() {
}
#[test]
fn test_current_protocol_version() {
let test_data = json!({
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
});
assert!(test_data.is_object());
assert_eq!(test_data["protocolVersion"], "2025-06-18");
}
#[test]
fn test_current_protocol_messages() {
let initialize_message = json!({
"jsonrpc": "2.0",
"id": "init-1",
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
});
assert_eq!(initialize_message["jsonrpc"], "2.0");
assert_eq!(initialize_message["method"], "initialize");
assert!(initialize_message["params"].is_object());
}
#[test]
fn test_audio_content_schema() {
let audio_content = json!({
"type": "audio",
"data": "base64encodedaudiodata",
"mimeType": "audio/wav"
});
assert_eq!(audio_content["type"], "audio");
assert_eq!(audio_content["mimeType"], "audio/wav");
assert!(audio_content["data"].is_string());
}
#[test]
fn test_annotation_schema() {
let annotation = json!({
"type": "user",
"text": "This is an important note",
"audience": ["user"],
"priority": "high"
});
assert_eq!(annotation["type"], "user");
assert_eq!(annotation["priority"], "high");
assert!(annotation["audience"].is_array());
}
#[test]
fn test_tool_annotation_schema() {
let tool_annotation = json!({
"type": "danger",
"level": "high",
"audience": ["user", "assistant"],
"text": "This tool performs destructive operations"
});
assert_eq!(tool_annotation["type"], "danger");
assert_eq!(tool_annotation["level"], "high");
assert!(tool_annotation["text"].is_string());
}
#[test]
fn test_completion_capabilities_schema() {
let completion_caps = json!({
"argument": {
"available": true
}
});
assert_eq!(completion_caps["argument"]["available"], true);
}
#[test]
fn test_roots_capabilities_schema() {
let roots_caps = json!({
"listChanged": true
});
assert_eq!(roots_caps["listChanged"], true);
}
#[test]
fn test_server_capabilities_2025() {
let capabilities = json!({
"experimental": {
"newFeature": true
},
"tools": {
"listChanged": true
},
"resources": {
"subscribe": true,
"listChanged": true
},
"prompts": {
"listChanged": true
},
"logging": {},
"completion": {
"argument": {
"available": true
}
},
"roots": {
"listChanged": true
}
});
assert!(capabilities["experimental"].is_object());
assert!(capabilities["completion"].is_object());
assert!(capabilities["roots"].is_object());
assert_eq!(capabilities["tools"]["listChanged"], true);
assert_eq!(capabilities["resources"]["subscribe"], true);
}
#[test]
fn test_embedded_resource_schema() {
let embedded_resource = json!({
"type": "resource",
"resource": {
"uri": "file://example.txt",
"text": "File content here",
"mimeType": "text/plain"
}
});
assert_eq!(embedded_resource["type"], "resource");
assert_eq!(embedded_resource["resource"]["uri"], "file://example.txt");
assert_eq!(embedded_resource["resource"]["mimeType"], "text/plain");
}
#[test]
fn test_resource_link_schema() {
let resource_link = json!({
"type": "resource_link",
"uri": "file://example.txt",
"name": "Example File",
"description": "An example text file",
"mimeType": "text/plain",
"size": 1024
});
assert_eq!(resource_link["type"], "resource_link");
assert_eq!(resource_link["uri"], "file://example.txt");
assert_eq!(resource_link["name"], "Example File");
assert_eq!(resource_link["mimeType"], "text/plain");
assert_eq!(resource_link["size"], 1024);
}
#[test]
fn test_sampling_message_schema() {
let sampling_message = json!({
"role": "user",
"content": {
"type": "text",
"text": "Hello, how are you?"
}
});
assert_eq!(sampling_message["role"], "user");
assert_eq!(sampling_message["content"]["type"], "text");
assert!(sampling_message["content"]["text"].is_string());
}
#[test]
fn test_model_preferences_schema() {
let model_prefs = json!({
"hints": [
{
"name": "claude-3-5-sonnet"
}
],
"costPriority": 0.3,
"speedPriority": 0.7,
"intelligencePriority": 0.9
});
assert!(model_prefs["hints"].is_array());
assert_eq!(model_prefs["costPriority"], 0.3);
assert_eq!(model_prefs["speedPriority"], 0.7);
assert_eq!(model_prefs["intelligencePriority"], 0.9);
}
#[test]
fn test_progress_notification_schema() {
let progress = json!({
"progressToken": "upload-123",
"progress": 75,
"total": 100
});
assert_eq!(progress["progressToken"], "upload-123");
assert_eq!(progress["progress"], 75);
assert_eq!(progress["total"], 100);
}
#[test]
fn test_complete_request_schema() {
let complete_request = json!({
"ref": {
"type": "tool",
"name": "file_search"
},
"argument": {
"name": "pattern",
"value": "*.rs"
}
});
assert_eq!(complete_request["ref"]["type"], "tool");
assert_eq!(complete_request["ref"]["name"], "file_search");
assert_eq!(complete_request["argument"]["name"], "pattern");
assert_eq!(complete_request["argument"]["value"], "*.rs");
}
#[test]
fn test_complete_response_schema() {
let complete_response = json!({
"completion": {
"values": ["documents/", "downloads/"],
"total": 2,
"hasMore": false
}
});
assert!(complete_response["completion"]["values"].is_array());
assert_eq!(complete_response["completion"]["total"], 2);
assert_eq!(complete_response["completion"]["hasMore"], false);
}
#[test]
fn test_root_schema() {
let root = json!({
"uri": "file:///project",
"name": "Main Project"
});
assert_eq!(root["uri"], "file:///project");
assert_eq!(root["name"], "Main Project");
}
#[test]
fn test_logging_level_schema() {
let logging_levels = vec![
"debug",
"info",
"notice",
"warning",
"error",
"critical",
"alert",
"emergency",
];
for level in logging_levels {
let log_message = json!({
"level": level,
"data": format!("Test message at {} level", level),
"logger": "test"
});
assert_eq!(log_message["level"], level);
assert!(log_message["data"].is_string());
}
}
#[test]
fn test_method_constants() {
let methods = vec![
"initialize",
"initialized",
"ping",
"tools/list",
"tools/call",
"resources/list",
"resources/read",
"resources/subscribe",
"resources/unsubscribe",
"prompts/list",
"prompts/get",
"logging/set_level",
"completion/complete",
"roots/list",
];
for method in methods {
assert!(!method.is_empty());
assert!(
method
.chars()
.all(|c| c.is_ascii_lowercase() || c == '/' || c == '_')
);
}
}
#[test]
fn test_error_codes() {
let error_codes = vec![
(-32700, "Parse error"),
(-32600, "Invalid Request"),
(-32601, "Method not found"),
(-32602, "Invalid params"),
(-32603, "Internal error"),
];
for (code, message) in error_codes {
let error = json!({
"code": code,
"message": message
});
assert_eq!(error["code"], code);
assert_eq!(error["message"], message);
}
}
#[test]
fn test_jsonrpc_request_schema() {
let requests = vec![
json!({
"jsonrpc": "2.0",
"id": "1",
"method": "tools/list"
}),
json!({
"jsonrpc": "2.0",
"id": "2",
"method": "tools/call",
"params": {
"name": "echo",
"arguments": {
"message": "Hello"
}
}
}),
json!({
"jsonrpc": "2.0",
"method": "notifications/cancelled",
"params": {
"requestId": "req-123"
}
}),
];
for request in requests {
assert_eq!(request["jsonrpc"], "2.0");
assert!(request["method"].is_string());
if request["id"].is_null() {
assert!(request["params"].is_object());
} else {
assert!(request["id"].is_string() || request["id"].is_number());
}
}
}
#[test]
fn test_jsonrpc_response_schema() {
let responses = vec![
json!({
"jsonrpc": "2.0",
"id": "1",
"result": {
"tools": []
}
}),
json!({
"jsonrpc": "2.0",
"id": "2",
"error": {
"code": -32601,
"message": "Method not found"
}
}),
];
for response in responses {
assert_eq!(response["jsonrpc"], "2.0");
assert!(response["id"].is_string() || response["id"].is_number());
assert!(response["result"].is_object() || response["error"].is_object());
}
}
#[test]
fn test_content_types_comprehensive() {
let content_types = vec![
json!({
"type": "text",
"text": "Sample text content"
}),
json!({
"type": "image",
"data": "base64imagedata",
"mimeType": "image/png"
}),
json!({
"type": "audio",
"data": "base64audiodata",
"mimeType": "audio/wav"
}),
json!({
"type": "resource",
"resource": {
"type": "text",
"uri": "file://example.txt",
"text": "File content"
}
}),
];
for content in content_types {
assert!(content["type"].is_string());
match content["type"].as_str().unwrap() {
"text" => assert!(content["text"].is_string()),
"image" | "audio" => {
assert!(content["data"].is_string());
assert!(content["mimeType"].is_string());
}
"resource" => assert!(content["resource"].is_object()),
_ => panic!("Unknown content type"),
}
}
}
#[test]
fn test_tool_schema_validation() {
let tool = json!({
"name": "calculator",
"description": "Perform mathematical calculations",
"inputSchema": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Mathematical expression to evaluate"
}
},
"required": ["expression"]
}
});
assert_eq!(tool["name"], "calculator");
assert!(tool["description"].is_string());
assert!(tool["inputSchema"].is_object());
assert_eq!(tool["inputSchema"]["type"], "object");
assert!(tool["inputSchema"]["properties"].is_object());
assert!(tool["inputSchema"]["required"].is_array());
}
#[test]
fn test_resource_schema_validation() {
let resource = json!({
"uri": "file:///project/data.json",
"name": "Project Data",
"description": "Main project data file",
"mimeType": "application/json"
});
assert_eq!(resource["uri"], "file:///project/data.json");
assert_eq!(resource["name"], "Project Data");
assert!(resource["description"].is_string());
assert_eq!(resource["mimeType"], "application/json");
}
#[test]
fn test_prompt_schema_validation() {
let prompt = json!({
"name": "code_review",
"description": "Code review prompt",
"arguments": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"language": {
"type": "string"
}
}
}
});
assert_eq!(prompt["name"], "code_review");
assert!(prompt["description"].is_string());
assert!(prompt["arguments"].is_object());
assert_eq!(prompt["arguments"]["type"], "object");
}
#[test]
fn test_schema_extensibility() {
let extended_tool = json!({
"name": "extended_tool",
"description": "Tool with extensions",
"inputSchema": {
"type": "object"
},
"customProperty": "custom_value",
"metadata": {
"author": "test",
"version": "1.0.0"
}
});
assert_eq!(extended_tool["name"], "extended_tool");
assert_eq!(extended_tool["customProperty"], "custom_value");
assert!(extended_tool["metadata"].is_object());
}
#[test]
fn test_schema_version_compatibility() {
let version_info = json!({
"protocolVersion": "2025-03-26",
"implementationVersion": "1.0.0",
"supportedFeatures": [
"audio_content",
"annotations",
"completion",
"roots"
]
});
assert_eq!(version_info["protocolVersion"], "2025-03-26");
assert!(version_info["supportedFeatures"].is_array());
assert!(
!version_info["supportedFeatures"]
.as_array()
.unwrap()
.is_empty()
);
}
#[test]
fn test_complex_nested_schemas() {
let complex_message = json!({
"jsonrpc": "2.0",
"id": "complex-1",
"method": "sampling/createMessage",
"params": {
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Hello"
}
},
{
"role": "assistant",
"content": {
"type": "audio",
"data": "audiodata",
"mimeType": "audio/wav",
"annotations": [
{
"type": "generated",
"text": "AI-generated audio",
"audience": ["user"],
"priority": "normal"
}
]
}
}
],
"modelPreferences": {
"hints": [
{
"name": "claude-3-5-sonnet"
}
],
"costPriority": 0.3,
"speedPriority": 0.7,
"intelligencePriority": 0.9
},
"systemPrompt": "You are a helpful assistant",
"includeContext": "allServers",
"temperature": 0.7,
"maxTokens": 1000
}
});
assert_eq!(complex_message["jsonrpc"], "2.0");
assert_eq!(complex_message["method"], "sampling/createMessage");
assert!(complex_message["params"]["messages"].is_array());
assert!(complex_message["params"]["modelPreferences"].is_object());
assert_eq!(complex_message["params"]["temperature"], 0.7);
let messages = complex_message["params"]["messages"].as_array().unwrap();
assert_eq!(messages.len(), 2);
assert_eq!(messages[0]["role"], "user");
assert_eq!(messages[1]["role"], "assistant");
assert_eq!(messages[1]["content"]["type"], "audio");
}
#[test]
fn test_schema_error_handling() {
let invalid_schemas = vec![
json!({
"id": "1",
"method": "test"
}),
json!({
"jsonrpc": "1.0", "id": "1",
"method": "test"
}),
json!({
"jsonrpc": "2.0",
"id": "1",
}),
];
for invalid_schema in invalid_schemas {
assert!(invalid_schema.is_object());
}
}
#[test]
fn test_all_2025_features() {
let features_2025 = json!({
"audioContent": {
"type": "audio",
"data": "base64audiodata",
"mimeType": "audio/wav"
},
"annotations": [
{
"type": "user",
"text": "Important note",
"audience": ["user"],
"priority": "high"
}
],
"toolAnnotations": [
{
"type": "danger",
"level": "high",
"audience": ["user", "assistant"],
"text": "Destructive operation"
}
],
"completion": {
"argument": {
"available": true
}
},
"roots": {
"listChanged": true
},
"enhancedProgress": {
"progressToken": "token-123",
"progress": 50,
"total": 100,
"message": "Processing files..."
}
});
assert!(features_2025["audioContent"].is_object());
assert!(features_2025["annotations"].is_array());
assert!(features_2025["toolAnnotations"].is_array());
assert!(features_2025["completion"].is_object());
assert!(features_2025["roots"].is_object());
assert!(features_2025["enhancedProgress"].is_object());
assert_eq!(features_2025["audioContent"]["type"], "audio");
assert_eq!(features_2025["annotations"][0]["type"], "user");
assert_eq!(features_2025["toolAnnotations"][0]["level"], "high");
assert_eq!(features_2025["completion"]["argument"]["available"], true);
assert_eq!(features_2025["roots"]["listChanged"], true);
}
}