Use helpers instead of fixtures (#3888)

Move to using test helper method everywhere.
This commit is contained in:
pakrym-oai
2025-09-19 06:46:25 -07:00
committed by GitHub
parent 881c7978f1
commit 9b18875a42
8 changed files with 86 additions and 140 deletions

View File

@@ -74,6 +74,39 @@ pub fn ev_function_call(call_id: &str, name: &str, arguments: &str) -> Value {
}) })
} }
/// Convenience: SSE event for an `apply_patch` custom tool call with raw patch
/// text. This mirrors the payload produced by the Responses API when the model
/// invokes `apply_patch` directly (before we convert it to a function call).
pub fn ev_apply_patch_custom_tool_call(call_id: &str, patch: &str) -> Value {
serde_json::json!({
"type": "response.output_item.done",
"item": {
"type": "custom_tool_call",
"name": "apply_patch",
"input": patch,
"call_id": call_id
}
})
}
/// Convenience: SSE event for an `apply_patch` function call. The Responses API
/// wraps the patch content in a JSON string under the `input` key; we recreate
/// the same structure so downstream code exercises the full parsing path.
pub fn ev_apply_patch_function_call(call_id: &str, patch: &str) -> Value {
let arguments = serde_json::json!({ "input": patch });
let arguments = serde_json::to_string(&arguments).expect("serialize apply_patch arguments");
serde_json::json!({
"type": "response.output_item.done",
"item": {
"type": "function_call",
"name": "apply_patch",
"arguments": arguments,
"call_id": call_id
}
})
}
pub fn sse_response(body: String) -> ResponseTemplate { pub fn sse_response(body: String) -> ResponseTemplate {
ResponseTemplate::new(200) ResponseTemplate::new(200)
.insert_header("content-type", "text/event-stream") .insert_header("content-type", "text/event-stream")

View File

@@ -1,25 +0,0 @@
[
{
"type": "response.output_item.done",
"item": {
"type": "custom_tool_call",
"name": "apply_patch",
"input": "*** Begin Patch\n*** Add File: test.md\n+Hello world\n*** End Patch",
"call_id": "__ID__"
}
},
{
"type": "response.completed",
"response": {
"id": "__ID__",
"usage": {
"input_tokens": 0,
"input_tokens_details": null,
"output_tokens": 0,
"output_tokens_details": null,
"total_tokens": 0
},
"output": []
}
}
]

View File

@@ -1,25 +0,0 @@
[
{
"type": "response.output_item.done",
"item": {
"type": "custom_tool_call",
"name": "apply_patch",
"input": "*** Begin Patch\n*** Add File: app.py\n+class BaseClass:\n+ def method():\n+ return False\n*** End Patch",
"call_id": "__ID__"
}
},
{
"type": "response.completed",
"response": {
"id": "__ID__",
"usage": {
"input_tokens": 0,
"input_tokens_details": null,
"output_tokens": 0,
"output_tokens_details": null,
"total_tokens": 0
},
"output": []
}
}
]

View File

@@ -1,25 +0,0 @@
[
{
"type": "response.output_item.done",
"item": {
"type": "custom_tool_call",
"name": "apply_patch",
"input": "*** Begin Patch\n*** Update File: app.py\n@@ def method():\n- return False\n+\n+ return True\n*** End Patch",
"call_id": "__ID__"
}
},
{
"type": "response.completed",
"response": {
"id": "__ID__",
"usage": {
"input_tokens": 0,
"input_tokens_details": null,
"output_tokens": 0,
"output_tokens_details": null,
"total_tokens": 0
},
"output": []
}
}
]

View File

@@ -1,25 +0,0 @@
[
{
"type": "response.output_item.done",
"item": {
"type": "function_call",
"name": "apply_patch",
"arguments": "{\n \"input\": \"*** Begin Patch\\n*** Update File: test.md\\n@@\\n-Hello world\\n+Final text\\n*** End Patch\"\n}",
"call_id": "__ID__"
}
},
{
"type": "response.completed",
"response": {
"id": "__ID__",
"usage": {
"input_tokens": 0,
"input_tokens_details": null,
"output_tokens": 0,
"output_tokens_details": null,
"total_tokens": 0
},
"output": []
}
}
]

View File

@@ -1,16 +0,0 @@
[
{
"type": "response.completed",
"response": {
"id": "__ID__",
"usage": {
"input_tokens": 0,
"input_tokens_details": null,
"output_tokens": 0,
"output_tokens_details": null,
"total_tokens": 0
},
"output": []
}
}
]

View File

@@ -1,8 +1,12 @@
#![allow(clippy::expect_used, clippy::unwrap_used)] #![allow(clippy::expect_used, clippy::unwrap_used, unused_imports)]
use anyhow::Context; use anyhow::Context;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use codex_core::CODEX_APPLY_PATCH_ARG1; use codex_core::CODEX_APPLY_PATCH_ARG1;
use core_test_support::responses::ev_apply_patch_custom_tool_call;
use core_test_support::responses::ev_apply_patch_function_call;
use core_test_support::responses::ev_completed;
use core_test_support::responses::sse;
use std::fs; use std::fs;
use std::process::Command; use std::process::Command;
use tempfile::tempdir; use tempfile::tempdir;
@@ -55,15 +59,28 @@ async fn test_apply_patch_tool() -> anyhow::Result<()> {
let tmp_cwd = tempdir().expect("failed to create temp dir"); let tmp_cwd = tempdir().expect("failed to create temp dir");
let tmp_path = tmp_cwd.path().to_path_buf(); let tmp_path = tmp_cwd.path().to_path_buf();
run_e2e_exec_test( let add_patch = r#"*** Begin Patch
tmp_cwd.path(), *** Add File: test.md
vec![ +Hello world
include_str!("../fixtures/sse_apply_patch_add.json").to_string(), *** End Patch"#;
include_str!("../fixtures/sse_apply_patch_update.json").to_string(), let update_patch = r#"*** Begin Patch
include_str!("../fixtures/sse_response_completed.json").to_string(), *** Update File: test.md
], @@
) -Hello world
.await; +Final text
*** End Patch"#;
let response_streams = vec![
sse(vec![
ev_apply_patch_custom_tool_call("request_0", add_patch),
ev_completed("request_0"),
]),
sse(vec![
ev_apply_patch_function_call("request_1", update_patch),
ev_completed("request_1"),
]),
sse(vec![ev_completed("request_2")]),
];
run_e2e_exec_test(tmp_cwd.path(), response_streams).await;
let final_path = tmp_path.join("test.md"); let final_path = tmp_path.join("test.md");
let contents = std::fs::read_to_string(&final_path) let contents = std::fs::read_to_string(&final_path)
@@ -86,15 +103,31 @@ async fn test_apply_patch_freeform_tool() -> anyhow::Result<()> {
} }
let tmp_cwd = tempdir().expect("failed to create temp dir"); let tmp_cwd = tempdir().expect("failed to create temp dir");
run_e2e_exec_test( let freeform_add_patch = r#"*** Begin Patch
tmp_cwd.path(), *** Add File: app.py
vec![ +class BaseClass:
include_str!("../fixtures/sse_apply_patch_freeform_add.json").to_string(), + def method():
include_str!("../fixtures/sse_apply_patch_freeform_update.json").to_string(), + return False
include_str!("../fixtures/sse_response_completed.json").to_string(), *** End Patch"#;
], let freeform_update_patch = r#"*** Begin Patch
) *** Update File: app.py
.await; @@ def method():
- return False
+
+ return True
*** End Patch"#;
let response_streams = vec![
sse(vec![
ev_apply_patch_custom_tool_call("request_0", freeform_add_patch),
ev_completed("request_0"),
]),
sse(vec![
ev_apply_patch_custom_tool_call("request_1", freeform_update_patch),
ev_completed("request_1"),
]),
sse(vec![ev_completed("request_2")]),
];
run_e2e_exec_test(tmp_cwd.path(), response_streams).await;
// Verify final file contents // Verify final file contents
let final_path = tmp_cwd.path().join("app.py"); let final_path = tmp_cwd.path().join("app.py");

View File

@@ -4,7 +4,6 @@
use anyhow::Context; use anyhow::Context;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use core_test_support::load_sse_fixture_with_id_from_str;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use std::sync::atomic::AtomicUsize; use std::sync::atomic::AtomicUsize;
@@ -27,10 +26,7 @@ impl Respond for SeqResponder {
match self.responses.get(call_num) { match self.responses.get(call_num) {
Some(body) => wiremock::ResponseTemplate::new(200) Some(body) => wiremock::ResponseTemplate::new(200)
.insert_header("content-type", "text/event-stream") .insert_header("content-type", "text/event-stream")
.set_body_raw( .set_body_string(body.clone()),
load_sse_fixture_with_id_from_str(body, &format!("request_{call_num}")),
"text/event-stream",
),
None => panic!("no response for {call_num}"), None => panic!("no response for {call_num}"),
} }
} }