use kimi_wire::protocol::*;
use serde_json::json;
#[test]
fn test_jsonrpc_request_roundtrip() {
let req = JsonRpcRequest {
jsonrpc: JsonRpcVersion::V2,
method: "initialize".to_string(),
id: "init-1".to_string(),
params: InitializeParams {
protocol_version: "1.10".to_string(),
client: Some(ClientInfo {
name: "test-client".to_string(),
version: Some("1.0.0".to_string()),
}),
external_tools: None,
capabilities: Some(ClientCapabilities {
supports_question: Some(true),
supports_plan_mode: Some(false),
}),
hooks: None,
},
};
let json = serde_json::to_string(&req).unwrap();
assert!(json.contains("\"jsonrpc\":\"2.0\""));
assert!(json.contains("\"method\":\"initialize\""));
assert!(json.contains("\"protocol_version\":\"1.10\""));
let de: JsonRpcRequest<InitializeParams> = serde_json::from_str(&json).unwrap();
assert_eq!(de, req);
}
#[test]
fn test_prompt_result_roundtrip() {
let result = PromptResult {
status: PromptStatus::Finished,
steps: None,
};
let json = serde_json::to_string(&result).unwrap();
assert!(json.contains("\"status\":\"finished\""));
let de: PromptResult = serde_json::from_str(&json).unwrap();
assert_eq!(de, result);
let result_steps = PromptResult {
status: PromptStatus::MaxStepsReached,
steps: Some(42),
};
let json = serde_json::to_string(&result_steps).unwrap();
assert!(json.contains("\"steps\":42"));
let de: PromptResult = serde_json::from_str(&json).unwrap();
assert_eq!(de, result_steps);
}
#[test]
fn test_replay_result_roundtrip() {
let result = ReplayResult {
status: ReplayStatus::Finished,
events: 42,
requests: 3,
};
let json = serde_json::to_string(&result).unwrap();
assert!(json.contains("\"events\":42"));
assert!(json.contains("\"requests\":3"));
let de: ReplayResult = serde_json::from_str(&json).unwrap();
assert_eq!(de, result);
}
#[test]
fn test_event_turn_begin_roundtrip() {
let event = Event::TurnBegin {
user_input: "hello".into(),
};
let json = serde_json::to_string(&event).unwrap();
assert!(json.contains("\"type\":\"TurnBegin\""));
let val: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(val["type"], "TurnBegin");
assert!(val["payload"].is_object());
assert_eq!(val["payload"]["user_input"], "hello");
let de: Event = serde_json::from_str(&json).unwrap();
assert_eq!(de, event);
}
#[test]
fn test_content_part_media_url_roundtrip() {
let part = ContentPart::ImageUrl(ImageUrlPart {
image_url: MediaUrl {
url: "https://example.com/img.png".to_string(),
id: Some("img-1".to_string()),
},
});
let json = serde_json::to_value(&part).unwrap();
assert_eq!(json["type"], "image_url");
assert_eq!(json["image_url"]["url"], "https://example.com/img.png");
assert_eq!(json["image_url"]["id"], "img-1");
let de: ContentPart = serde_json::from_value(json).unwrap();
assert_eq!(de, part);
}
#[test]
fn test_request_approval_roundtrip() {
let request = Request::ApprovalRequest(ApprovalRequest {
id: "approval_1".to_string(),
tool_call_id: "call_1".to_string(),
sender: "Shell".to_string(),
action: "run shell command".to_string(),
description: "Run command `ls`".to_string(),
display: Some(vec![DisplayBlock {
block_type: DisplayBlockType::Brief,
text: Some("writing file".to_string()),
path: None,
old_text: None,
new_text: None,
is_summary: None,
items: None,
language: None,
command: None,
data: None,
}]),
source_kind: Some(SourceKind::ForegroundTurn),
source_id: None,
agent_id: None,
subagent_type: None,
source_description: None,
});
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("\"type\":\"ApprovalRequest\""));
let val: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(val["type"], "ApprovalRequest");
assert!(val["payload"].is_object());
assert_eq!(val["payload"]["id"], "approval_1");
let de: Request = serde_json::from_str(&json).unwrap();
assert_eq!(de, request);
}
#[test]
fn test_display_block_unknown_roundtrip() {
let block = DisplayBlock {
block_type: DisplayBlockType::Unknown,
text: None,
path: None,
old_text: None,
new_text: None,
is_summary: None,
items: None,
language: None,
command: None,
data: Some(json!({"foo": "bar"})),
};
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains("\"type\":\"unknown\""));
let de: DisplayBlock = serde_json::from_str(&json).unwrap();
assert_eq!(de, block);
}
#[test]
fn test_toolcall_wire_envelope_format() {
let json = r#"{"type":"ToolCall","payload":{"type":"function","id":"tc-1","function":{"name":"tool","arguments":"{}"}}}"#;
let event: Event = serde_json::from_str(json).unwrap();
assert!(
matches!(event, Event::ToolCall { ref id, function: ToolCallFunction { ref name, arguments: Some(ref args) }, .. } if id == "tc-1" && name == "tool" && args == "{}")
);
let back = serde_json::to_string(&event).unwrap();
let val: serde_json::Value = serde_json::from_str(&back).unwrap();
assert_eq!(val["type"], "ToolCall");
assert_eq!(val["payload"]["type"], "function");
assert_eq!(val["payload"]["id"], "tc-1");
assert_eq!(val["payload"]["function"]["name"], "tool");
}
#[test]
fn test_tool_output_parts_roundtrip() {
let output = ToolOutput::Parts(vec![ContentPart::Text(TextPart {
text: "hello".to_string(),
})]);
let json = serde_json::to_string(&output).unwrap();
let de: ToolOutput = serde_json::from_str(&json).unwrap();
assert_eq!(de, output);
}
#[test]
fn test_jsonrpc_version_serializes_as_string_2_0() {
let json = serde_json::to_string(&JsonRpcVersion::V2).unwrap();
assert_eq!(json, "\"2.0\"");
}
#[test]
fn test_jsonrpc_version_deserializes_2_0() {
let de: JsonRpcVersion = serde_json::from_str("\"2.0\"").unwrap();
assert_eq!(de, JsonRpcVersion);
}
#[test]
fn test_jsonrpc_version_rejects_1_0() {
let err = serde_json::from_str::<JsonRpcVersion>("\"1.0\"").unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("2.0"),
"error message should mention expected version '2.0', got: {msg}"
);
}
#[test]
fn test_jsonrpc_version_rejects_empty_string() {
let err = serde_json::from_str::<JsonRpcVersion>("\"\"").unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("2.0"),
"error message should mention expected version '2.0', got: {msg}"
);
}
#[test]
fn test_jsonrpc_version_rejects_non_string() {
assert!(serde_json::from_str::<JsonRpcVersion>("42").is_err());
}
#[test]
fn test_jsonrpc_request_with_v2_constant() {
let req = JsonRpcRequest {
jsonrpc: JsonRpcVersion::V2,
method: "initialize".to_string(),
id: "init-1".to_string(),
params: InitializeParams {
protocol_version: "1.10".to_string(),
client: Some(ClientInfo {
name: "test-client".to_string(),
version: Some("1.0.0".to_string()),
}),
external_tools: None,
capabilities: Some(ClientCapabilities {
supports_question: Some(true),
supports_plan_mode: Some(false),
}),
hooks: None,
},
};
let json = serde_json::to_string(&req).unwrap();
assert!(json.contains("\"jsonrpc\":\"2.0\""));
}