use super::fixtures::*;
use crate::prompt::Error;
#[test]
fn run_surfaces_malformed_jsonl_line() {
let repo = scaffold_repo(VALID_PER_REPO_PROVIDERS_YAML, Some("body"));
let adapter = StubAdapter::happy(b"{ not json\n");
let err = run_with_stubs(repo.path(), "hi", &adapter, &StubGit::ok()).unwrap_err();
assert!(matches!(err, Error::AdapterJson(_)));
}
#[test]
fn run_surfaces_half_stream_as_adapter_half_stream() {
let repo = scaffold_repo(VALID_PER_REPO_PROVIDERS_YAML, Some("body"));
let adapter = StubAdapter::happy(b"");
let err = run_with_stubs(repo.path(), "hi", &adapter, &StubGit::ok()).unwrap_err();
assert!(matches!(err, Error::AdapterHalfStream { .. }));
}
#[test]
fn run_surfaces_the_adapter_stderr_when_it_never_reached_the_contract() {
let repo = scaffold_repo(VALID_PER_REPO_PROVIDERS_YAML, Some("body"));
let adapter = StubAdapter::happy_with_stderr(b"", b"bz: config.toml: expected `=`\n");
let err = run_with_stubs(repo.path(), "hi", &adapter, &StubGit::ok()).unwrap_err();
assert!(matches!(err, Error::AdapterHalfStream { .. }));
let text = err.to_string();
assert!(text.contains("bz: config.toml: expected `=`"), "{text}");
assert!(text.contains("stderr.log"), "{text}");
}
#[test]
fn run_surfaces_invalid_tool_input_json_delta() {
let repo = scaffold_repo(VALID_PER_REPO_PROVIDERS_YAML, Some("body"));
let body = concat!(
r#"{"type":"message_start","v":1,"role":"assistant"}"#,
"\n",
r#"{"type":"content_start","index":0,"kind":{"tool_use":{"id":"t1","name":"bash"}}}"#,
"\n",
r#"{"type":"content_delta","index":0,"delta":{"json_delta":"{ not json"}}"#,
"\n",
r#"{"type":"finish","reason":"tool_use"}"#,
"\n",
r#"{"type":"end"}"#,
"\n",
);
let adapter = StubAdapter::happy(body.as_bytes());
let err = run_with_stubs(repo.path(), "hi", &adapter, &StubGit::ok()).unwrap_err();
assert!(matches!(err, Error::AdapterJson(_)));
}
#[test]
fn run_surfaces_invalid_tool_input_json_delta_at_content_stop() {
let repo = scaffold_repo(VALID_PER_REPO_PROVIDERS_YAML, Some("body"));
let body = concat!(
r#"{"type":"message_start","v":1,"role":"assistant"}"#,
"\n",
r#"{"type":"content_start","index":0,"kind":{"tool_use":{"id":"t1","name":"bash"}}}"#,
"\n",
r#"{"type":"content_delta","index":0,"delta":{"json_delta":"{ not json"}}"#,
"\n",
r#"{"type":"content_stop","index":0}"#,
"\n",
r#"{"type":"finish","reason":"tool_use"}"#,
"\n",
r#"{"type":"end"}"#,
"\n",
);
let adapter = StubAdapter::happy(body.as_bytes());
let git = StubGit::ok();
let err = run_with_stubs(repo.path(), "hi", &adapter, &git).unwrap_err();
assert!(matches!(err, Error::AdapterJson(_)));
assert!(
!git.runs
.borrow()
.iter()
.any(|(_, args)| args.first().map(String::as_str) == Some("add")
&& args
.get(1)
.is_some_and(|a| a.ends_with("-claude-sonnet-5.json"))),
"no model-output transcript commit on a failed model call"
);
}
#[test]
fn run_short_circuits_after_first_parse_error() {
let repo = scaffold_repo(VALID_PER_REPO_PROVIDERS_YAML, Some("body"));
let body = concat!(
"{ not json\n",
r#"{"type":"finish","reason":"stop"}"#,
"\n",
r#"{"type":"end"}"#,
"\n",
);
let adapter = StubAdapter::happy(body.as_bytes());
let err = run_with_stubs(repo.path(), "hi", &adapter, &StubGit::ok()).unwrap_err();
assert!(matches!(err, Error::AdapterJson(_)));
}
#[test]
fn run_tolerates_post_terminal_stray_lines() {
let body = concat!(
r#"{"type":"message_start","v":1,"role":"assistant"}"#,
"\n",
r#"{"type":"content_start","index":0,"kind":{"text":{}}}"#,
"\n",
r#"{"type":"content_delta","index":0,"delta":{"text_delta":"hi"}}"#,
"\n",
r#"{"type":"finish","reason":"stop"}"#,
"\n",
r#"{"type":"end"}"#,
"\n",
r#"{"type":"content_delta","index":0,"delta":{"text_delta":"stray"}}"#,
"\n",
);
let repo = scaffold_repo(VALID_PER_REPO_PROVIDERS_YAML, Some("body"));
let adapter = StubAdapter::happy(body.as_bytes());
run_with_stubs(repo.path(), "hi", &adapter, &StubGit::ok())
.expect("post-terminal lines must not error the run");
}