use super::{
json, parse_bare_calls_in_body, parse_text_tool_calls_with_tools, sample_tool_registry,
};
fn json_call_args(json_body: &str) -> serde_json::Value {
let tools = sample_tool_registry();
let src = format!("<tool_call>{json_body}</tool_call>");
let result = parse_text_tool_calls_with_tools(&src, Some(&tools));
assert!(
result.errors.is_empty(),
"tool call must parse cleanly: {:?}",
result.errors
);
assert_eq!(result.calls.len(), 1, "exactly one call expected");
result.calls[0]["arguments"].clone()
}
#[test]
fn encoded_operators_in_json_content_decode() {
let args = json_call_args(
r#"{"name":"edit","arguments":{"action":"create","path":"a.ts","content":"xs.map(x => x)"}}"#,
);
assert_eq!(args["content"], json!("xs.map(x => x)"));
}
#[test]
fn all_operator_classes_decode() {
let args = json_call_args(
r#"{"name":"edit","arguments":{"action":"create","path":"a.ts","content":"if (a <= b && b >= 0) {}"}}"#,
);
assert_eq!(args["content"], json!("if (a <= b && b >= 0) {}"));
}
#[test]
fn double_escaped_reference_survives_as_literal() {
let args = json_call_args(
r#"{"name":"edit","arguments":{"action":"create","path":"page.html","content":"<p>a &lt; b &amp; c</p>"}}"#,
);
assert_eq!(args["content"], json!("<p>a < b & c</p>"));
}
#[test]
fn bare_ampersands_untouched() {
let args = json_call_args(
r#"{"name":"run","arguments":{"command":"echo R&D && sleep 1 & wait; printf '&'"}}"#,
);
assert_eq!(
args["command"],
json!("echo R&D && sleep 1 & wait; printf '&'")
);
}
#[test]
fn quote_references_decode() {
let args = json_call_args(
r#"{"name":"edit","arguments":{"action":"create","path":"a.py","content":"print("a", 'b', 'c')"}}"#,
);
assert_eq!(args["content"], json!("print(\"a\", 'b', 'c')"));
}
#[test]
fn nested_arguments_decode_recursively() {
let args = json_call_args(
r#"{"name":"edit","arguments":{"action":"patch","path":"a.ts","ops":[{"content":"x => x"},{"content":"a < b"}]}}"#,
);
assert_eq!(args["ops"][0]["content"], json!("x => x"));
assert_eq!(args["ops"][1]["content"], json!("a < b"));
}
#[test]
fn nested_xml_wrapper_content_decodes() {
let tools = sample_tool_registry();
let src = r#"<tool_call><edit>{"action":"create","path":"a.ts","content":"x => x"}</edit></tool_call>"#;
let result = parse_text_tool_calls_with_tools(src, Some(&tools));
assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
assert_eq!(result.calls.len(), 1);
assert_eq!(result.calls[0]["arguments"]["content"], json!("x => x"));
}
#[test]
fn heredoc_raw_body_is_not_decoded() {
let tools = sample_tool_registry();
let src =
"edit({ action: \"create\", path: \"page.html\", content: <<EOF\n<p>a < b</p>\nEOF\n })";
let result = parse_bare_calls_in_body(src, Some(&tools));
assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
assert_eq!(
result.calls[0]["arguments"]["content"],
json!("<p>a < b</p>"),
"heredoc content must reach the tool byte-for-byte"
);
}
#[test]
fn operator_corruption_class_is_repaired() {
let args = json_call_args(
r#"{"name":"edit","arguments":{"action":"replace_body","path":"a.ts","new_body":"const f = (xs) => xs.filter(x => x > 0)"}}"#,
);
assert_eq!(
args["new_body"],
json!("const f = (xs) => xs.filter(x => x > 0)")
);
}