From a7b4e08eb73ec72384fb42e3b7ca8ab44e924019 Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Sun, 31 May 2026 13:42:28 +1200 Subject: [PATCH] test(compat): add v0.132.0 regression test for entry parsing without formatted_output Codex v0.132.0 (PR #22706) removed the legacy `formatted_output` field from exec_command_end events. The parser fix was shipped in #71 (Fixes #64), but no version-specific regression test existed for v0.132.0 in entry.rs, unlike the pattern established for v0.128.0, v0.130.0, and v0.131.0. Add `v0132_all_standard_entry_types_parse_correctly` in entry.rs that: - Parses all four standard JSONL entry types from a v0.132.0 session - Includes an exec_command_end event with `aggregated_output` only (no `formatted_output`) and asserts the field is absent - Confirms `cli_version: "0.132.0"` is read correctly Fixes #78 --- src-tauri/src/parser/entry.rs | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src-tauri/src/parser/entry.rs b/src-tauri/src/parser/entry.rs index 5d29441..dd0533f 100644 --- a/src-tauri/src/parser/entry.rs +++ b/src-tauri/src/parser/entry.rs @@ -429,4 +429,42 @@ mod tests { assert_eq!(meta.payload["cli_version"], "0.131.0"); assert_eq!(meta.payload["profile"], "default"); } + + // Codex v0.132.0 (PR #22706): "Remove legacy shell output formatting paths". + // exec_command_end events no longer carry a `formatted_output` field — output is + // exclusively in `aggregated_output`. The JSONL entry types themselves are unchanged; + // this regression guard confirms all four standard types parse correctly under v0.132.0 + // and that exec_command_end events carrying only `aggregated_output` (no `formatted_output`) + // are valid JSONL that passes through RawEntry parsing without error. + #[test] + fn v0132_all_standard_entry_types_parse_correctly() { + let lines = [ + r#"{"timestamp":"2026-05-20T10:00:00Z","type":"session_meta","payload":{"id":"v0132-session","timestamp":"2026-05-20T10:00:00Z","cwd":"/tmp","cli_version":"0.132.0","model_provider":"openai"}}"#, + r#"{"timestamp":"2026-05-20T10:00:01Z","type":"event_msg","payload":{"type":"task_started","turn_id":"turn-1"}}"#, + r#"{"timestamp":"2026-05-20T10:00:02Z","type":"response_item","payload":{"type":"message","role":"assistant","content":"Hello"}}"#, + r#"{"timestamp":"2026-05-20T10:00:03Z","type":"turn_context","payload":{"model":"gpt-5","cwd":"/tmp"}}"#, + // exec_command_end with aggregated_output only — formatted_output field absent (removed in v0.132.0) + r#"{"timestamp":"2026-05-20T10:00:04Z","type":"event_msg","payload":{"type":"exec_command_end","call_id":"call_1","aggregated_output":"hello\n","exit_code":0,"status":"completed","duration":{"secs":0,"nanos":50000000}}}"#, + r#"{"timestamp":"2026-05-20T10:00:05Z","type":"event_msg","payload":{"type":"task_complete","turn_id":"turn-1","completed_at":1748606405.0}}"#, + ]; + let expected_types = [ + "session_meta", + "event_msg", + "response_item", + "turn_context", + "event_msg", + "event_msg", + ]; + for (line, expected) in lines.iter().zip(expected_types.iter()) { + let entry = RawEntry::parse(line).expect("parse failed"); + assert_eq!(entry.entry_type, *expected, "wrong type for: {line}"); + } + let meta = RawEntry::parse(lines[0]).unwrap(); + assert_eq!(meta.payload["cli_version"], "0.132.0"); + // exec_command_end payload must contain aggregated_output and no formatted_output + let exec_end = RawEntry::parse(lines[4]).unwrap(); + assert_eq!(exec_end.payload["type"], "exec_command_end"); + assert_eq!(exec_end.payload["aggregated_output"], "hello\n"); + assert!(exec_end.payload.get("formatted_output").is_none()); + } }