use super::{
json, parse_bare_calls_in_body, parse_text_tool_calls_with_tools, sample_tool_registry,
};
#[test]
fn implicit_call_paren_close_recovers_plain_object_arg() {
let tools = sample_tool_registry();
let text = "run({ command: \"go build ./...\" }"; let result = parse_bare_calls_in_body(text, Some(&tools));
assert_eq!(
result.calls.len(),
1,
"omitted `)` should be recovered, errors: {:?}",
result.errors
);
assert_eq!(result.calls[0]["name"], json!("run"));
assert_eq!(
result.calls[0]["arguments"]["command"],
json!("go build ./...")
);
}
#[test]
fn implicit_call_paren_close_recovers_heredoc_edit() {
let tools = sample_tool_registry();
let text = "edit({\n \"action\": \"create\",\n \"path\": \"a.scala\",\n \"content\": <<EOF\npackage x\nfinal case class Y()\nEOF\n}";
let result = parse_bare_calls_in_body(text, Some(&tools));
assert_eq!(
result.calls.len(),
1,
"heredoc edit with omitted `)` should be recovered, errors: {:?}",
result.errors
);
let content = result.calls[0]["arguments"]["content"].as_str().unwrap();
assert!(
content.contains("package x"),
"content should carry the heredoc body: {content}"
);
assert!(content.contains("final case class Y()"));
}
#[test]
fn multiblock_turn_lands_every_call_when_paren_omitted() {
let text = include_str!("tool_call_multiblock_real_payload.txt");
let tools = sample_tool_registry(); let result = parse_text_tool_calls_with_tools(text, Some(&tools));
let names: Vec<&str> = result
.calls
.iter()
.map(|c| c["name"].as_str().unwrap_or(""))
.collect();
assert_eq!(
names,
vec!["edit", "edit", "edit", "run"],
"all four authored calls should land, errors: {:?}",
result.errors
);
}
#[test]
fn omitted_paren_recovery_still_rejects_trailing_garbage() {
let tools = sample_tool_registry();
let text = "edit({ action: \"create\", path: \"a.rs\" } and then some stray words";
let result = parse_bare_calls_in_body(text, Some(&tools));
assert!(
result.calls.is_empty(),
"trailing garbage after `}}` must not be recovered as a call, calls: {:?}",
result.calls
);
}