Files
codex/prs/bolinfest/study/PR-1545-study.md
2025-09-02 15:17:45 -07:00

118 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
**DOs**
- Put tests first: Keep helper fns after tests to foreground intent.
```rust
// Tests first
/// Sends a prompt and asserts the streamed message.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn full_conversation_turn_integration() { /* ... */ }
// Helpers after tests
fn write_config(codex_home: &Path, server: &MockServer) { /* ... */ }
```
- Use readable multi-line config strings: Start with a leading newline; inline variables with format!.
```rust
fs::write(
codex_home.join("config.toml"),
format!(r#"
model_provider = "mock"
model = "test-model"
[model_providers.mock]
name = "mock"
base_url = "{}/v1"
env_key = "PATH"
wire_api = "responses"
"#, server.uri()),
)?;
```
- Consider indoc for long blocks: Keep indentation tidy without left margin loss.
```rust
use indoc::formatdoc;
fs::write(
codex_home.join("config.toml"),
formatdoc!(r#"
model_provider = "mock"
model = "test-model"
[model_providers.mock]
name = "mock"
base_url = "{base}/v1"
env_key = "PATH"
wire_api = "responses"
"#, base = server.uri()),
)?;
```
- Prefer template + replace for SSE: Avoid brace-escaping hell in format! strings.
```rust
fn sse_message(text: &str) -> String {
const TEMPLATE: &str = r#"event: response.output_item.done
data: {"type":"response.output_item.done","item":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"TEXT_PLACEHOLDER"}]}}
event: response.completed
data: {"type":"response.completed","response":{"id":"resp1","output":[]}}
"#;
TEMPLATE.replace("TEXT_PLACEHOLDER", text)
}
```
- Name things precisely: Use codex_home for the temp config directory.
```rust
fn write_config(codex_home: &Path, server: &MockServer) {
// ...
}
```
- Assert on the final message via file: Use --output-last-message and compare file contents.
```rust
let codex_home = TempDir::new().unwrap();
let sandbox = TempDir::new().unwrap();
write_config(codex_home.path(), &server);
let last = sandbox.path().join("last_message.txt");
let mut cmd = assert_cmd::Command::cargo_bin("codex").unwrap();
cmd.env("CODEX_HOME", codex_home.path())
.current_dir(sandbox.path())
.arg("exec")
.arg("--skip-git-repo-check")
.arg("--output-last-message")
.arg(&last)
.arg("Hello");
cmd.assert().success().stdout(predicates::str::contains("Hello, world."));
assert_eq!(fs::read_to_string(&last).unwrap().trim(), "Hello, world.");
```
- Document each test: Add a one-liner docstring explaining the behavior under test.
```rust
/// Simulates a shell tool call then verifies the assistant's follow-up.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn tool_invocation_flow() { /* ... */ }
```
**DON'Ts**
- Dont put helpers above tests: It hides the tests purpose and increases scrolling.
```rust
// Anti-pattern: helpers first
fn write_config(...) { /* ... */ }
#[tokio::test] async fn test_case() { /* ... */ }
```
- Dont hand-escape JSON braces inside format!: Hard to read and easy to break.
```rust
// Anti-pattern: unreadable escaping
format!("data: {{\"text\":\"{text}\"}}");
```
- Dont use vague names like dir or home: Be explicit about the directorys role.
```rust
// Anti-pattern: vague
fn write_config(dir: &Path, server: &MockServer) { /* ... */ }
```
- Dont assert only via stdout: Stream formatting can change; assert the canonical last message file.
```rust
// Anti-pattern: only stdout check
cmd.assert().stdout(predicates::str::contains("done"));
```
- Dont omit test docstrings: Future readers shouldnt have to infer the intent.
```rust
// Anti-pattern: no docstring
#[tokio::test] async fn full_conversation_turn_integration() { /* ... */ }
```