use super::*;
fn whole(bytes: &[u8]) -> bool {
settled(bytes).whole()
}
fn framing_of(bytes: &[u8]) -> Framing {
settled(bytes).framing
}
const FINISH_END: &[u8] = br#"{"type":"message_start","v":1,"role":"assistant"}
{"type":"finish","reason":"stop"}
{"type":"end"}
"#;
const ERROR_END: &[u8] = br#"{"type":"message_start","v":1,"role":"assistant"}
{"type":"error","kind":"transport","message":"reset"}
{"type":"end"}
"#;
#[test]
fn finish_then_end_is_complete() {
assert!(whole(FINISH_END));
}
#[test]
fn error_then_end_is_not_complete() {
assert!(!whole(ERROR_END));
}
#[test]
fn no_trailing_end_is_not_complete() {
let jsonl = br#"{"type":"content_delta","index":0,"delta":{"text_delta":"hi"}}
"#;
assert!(!whole(jsonl));
}
#[test]
fn empty_or_newline_only_is_not_complete() {
assert!(!whole(b""));
assert!(!whole(b"\n\n"));
}
#[test]
fn trailing_partial_line_after_end_is_ignored() {
let jsonl = b"{\"type\":\"finish\",\"reason\":\"stop\"}\n{\"type\":\"end\"}\n{partial";
assert!(whole(jsonl));
}
#[test]
fn only_latest_segment_decides_complete() {
let jsonl = br#"{"type":"error","kind":"x"}
{"type":"end"}
{"type":"message_start","v":1}
{"type":"finish","reason":"stop"}
{"type":"end"}
"#;
assert!(whole(jsonl));
}
#[test]
fn latest_segment_error_after_earlier_finish_is_not_complete() {
let jsonl = br#"{"type":"finish","reason":"stop"}
{"type":"end"}
{"type":"error","kind":"x"}
{"type":"end"}
"#;
assert!(!whole(jsonl));
}
#[test]
fn end_without_finish_or_error_is_not_complete() {
assert!(!whole(
b"{\"type\":\"message_start\"}\n{\"type\":\"end\"}\n"
));
}
#[test]
fn malformed_last_line_is_not_complete() {
assert!(!whole(b"{\"type\":\"finish\"}\nnot json\n"));
}
#[test]
fn framing_classifies_the_three_outcomes() {
assert_eq!(framing_of(FINISH_END), Framing::Complete);
assert_eq!(framing_of(ERROR_END), Framing::Failed);
assert_eq!(
framing_of(b"{\"type\":\"content_delta\",\"index\":0}\n"),
Framing::Killed
);
assert_eq!(
framing_of(b"{\"type\":\"message_start\"}\n{\"type\":\"end\"}\n"),
Framing::Killed
);
}
#[test]
fn error_text_returns_the_error_line_iff_framing_is_failed() {
let failed = br#"{"type":"error","kind":"http","status":401}
{"type":"end"}
"#;
assert_eq!(
error_text(failed).as_deref(),
Some(r#"{"type":"error","kind":"http","status":401}"#)
);
assert_eq!(framing_of(failed), Framing::Failed);
assert_eq!(error_text(FINISH_END), None); assert_eq!(error_text(b"{\"type\":\"content_delta\"}\n"), None); assert_eq!(error_text(b""), None); assert_eq!(error_text(b"\n\n"), None); assert_eq!(error_text(b"no trailing newline"), None); }
#[test]
fn error_text_reads_only_the_latest_segment() {
let retried = br#"{"type":"error","kind":"x"}
{"type":"end"}
{"type":"finish","reason":"stop"}
{"type":"end"}
"#;
assert_eq!(error_text(retried), None);
assert_eq!(framing_of(retried), Framing::Complete);
}
#[test]
fn segment_count_counts_end_events() {
let jsonl = br#"{"type":"error","kind":"x"}
{"type":"end"}
{"type":"finish","reason":"stop"}
{"type":"end"}
"#;
assert_eq!(segment_count(jsonl), 2);
assert_eq!(
segment_count(b"{\"type\":\"content_delta\",\"index\":0}\n"),
0
);
assert_eq!(segment_count(b""), 0);
}
#[test]
fn the_ending_reads_the_canonical_finish_reason_and_nothing_else() {
let of = |reason: &str| {
let jsonl =
format!("{{\"type\":\"finish\",\"reason\":\"{reason}\"}}\n{{\"type\":\"end\"}}\n");
settled(jsonl.as_bytes())
};
assert_eq!(of("length").ending, Ending::OutputLimit);
for reason in [
"stop",
"tool_use",
"stop_sequence",
"pause",
"refusal",
"eos",
] {
assert_eq!(of(reason).ending, Ending::OwnTerms, "{reason}");
}
assert_eq!(
settled(b"{\"type\":\"finish\"}\n{\"type\":\"end\"}\n").ending,
Ending::OwnTerms
);
assert_eq!(
settled(b"{\"type\":\"finish\",\"reason\":7}\n{\"type\":\"end\"}\n").ending,
Ending::OwnTerms
);
}
#[test]
fn an_output_limited_tail_is_complete_transport_and_an_unfinished_turn() {
let jsonl = br#"{"type":"message_start","v":1,"role":"assistant"}
{"type":"content_delta","index":0,"delta":{"thinking_delta":"hmm"}}
{"type":"finish","reason":"length"}
{"type":"end"}
"#;
let read = settled(jsonl);
assert_eq!(read.framing, Framing::Complete);
assert_eq!(read.ending, Ending::OutputLimit);
assert!(!read.whole(), "complete on the wire, unfinished as a turn");
assert!(settled(FINISH_END).whole());
}
#[test]
fn a_partial_text_length_turn_is_truncated_without_losing_what_it_said() {
let jsonl = br#"{"type":"content_delta","index":0,"delta":{"text_delta":"as I was say"}}
{"type":"finish","reason":"length"}
{"type":"end"}
"#;
assert_eq!(settled(jsonl).ending, Ending::OutputLimit);
assert_eq!(
super::super::fold_stream(jsonl).text.as_deref(),
Some("as I was say"),
"the §5.1 #10 fold still hands the fragment to the transcript"
);
}
#[test]
fn a_tail_with_no_finish_reads_no_ending_at_all() {
for bytes in [
ERROR_END, b"{\"type\":\"content_delta\",\"index\":0}\n", b"{\"type\":\"message_start\"}\n{\"type\":\"end\"}\n", b"",
] {
assert_eq!(settled(bytes).ending, Ending::Unread);
assert!(!settled(bytes).whole());
}
}
#[test]
fn only_the_latest_segment_decides_the_ending() {
let truncated_retry = br#"{"type":"finish","reason":"stop"}
{"type":"end"}
{"type":"finish","reason":"length"}
{"type":"end"}
"#;
assert_eq!(settled(truncated_retry).ending, Ending::OutputLimit);
let clean_retry = br#"{"type":"finish","reason":"length"}
{"type":"end"}
{"type":"finish","reason":"stop"}
{"type":"end"}
"#;
assert_eq!(settled(clean_retry).ending, Ending::OwnTerms);
let doubled = br#"{"type":"finish","reason":"length"}
{"type":"finish","reason":"stop"}
{"type":"end"}
"#;
assert_eq!(settled(doubled).ending, Ending::OwnTerms);
}
#[test]
fn an_error_in_the_settled_segment_outranks_its_finish() {
let jsonl = br#"{"type":"error","kind":"x"}
{"type":"finish","reason":"length"}
{"type":"end"}
"#;
let read = settled(jsonl);
assert_eq!(read.framing, Framing::Failed);
assert_eq!(read.ending, Ending::Unread);
assert_eq!(Ending::default(), Ending::Unread);
}