Skip to content

Commit 3cc9726

Browse files
konardclaude
andcommitted
Move Rust tests to separate files for consistency with JavaScript
- Create rust/tests/ directory with separate test files: - claude_tests.rs (20 tests) - gemini_tests.rs (25 tests) - agent_tests.rs (18 tests) - codex_tests.rs (15 tests) - opencode_tests.rs (13 tests) - tools_tests.rs (12 tests) - streaming_tests.rs (17 tests) - lib_tests.rs (10 tests) - Remove embedded #[cfg(test)] mod tests from source files - All 173 Rust tests pass, matching JavaScript test structure - Follows the same pattern as js/test/*.test.mjs files Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 111714b commit 3cc9726

File tree

17 files changed

+1230
-678
lines changed

17 files changed

+1230
-678
lines changed

rust/src/lib.rs

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -331,75 +331,4 @@ pub fn agent(options: AgentOptions) -> Result<Agent, String> {
331331
Agent::new(options)
332332
}
333333

334-
#[cfg(test)]
335-
mod tests {
336-
use super::*;
337-
338-
#[test]
339-
fn test_agent_throws_without_tool() {
340-
let options = AgentOptions {
341-
working_directory: "/tmp/test".to_string(),
342-
..Default::default()
343-
};
344-
let result = agent(options);
345-
assert!(result.is_err());
346-
if let Err(e) = result {
347-
assert!(e.contains("tool is required"));
348-
}
349-
}
350-
351-
#[test]
352-
fn test_agent_throws_without_working_directory() {
353-
let options = AgentOptions {
354-
tool: "claude".to_string(),
355-
..Default::default()
356-
};
357-
let result = agent(options);
358-
assert!(result.is_err());
359-
if let Err(e) = result {
360-
assert!(e.contains("working_directory is required"));
361-
}
362-
}
363-
364-
#[test]
365-
fn test_agent_throws_for_screen_without_name() {
366-
let options = AgentOptions {
367-
tool: "claude".to_string(),
368-
working_directory: "/tmp/test".to_string(),
369-
isolation: "screen".to_string(),
370-
..Default::default()
371-
};
372-
let result = agent(options);
373-
assert!(result.is_err());
374-
if let Err(e) = result {
375-
assert!(e.contains("screen_name is required"));
376-
}
377-
}
378-
379-
#[test]
380-
fn test_agent_throws_for_docker_without_name() {
381-
let options = AgentOptions {
382-
tool: "claude".to_string(),
383-
working_directory: "/tmp/test".to_string(),
384-
isolation: "docker".to_string(),
385-
..Default::default()
386-
};
387-
let result = agent(options);
388-
assert!(result.is_err());
389-
if let Err(e) = result {
390-
assert!(e.contains("container_name is required"));
391-
}
392-
}
393-
394-
#[test]
395-
fn test_agent_creates_with_valid_options() {
396-
let options = AgentOptions {
397-
tool: "claude".to_string(),
398-
working_directory: "/tmp/test".to_string(),
399-
isolation: "none".to_string(),
400-
..Default::default()
401-
};
402-
let result = agent(options);
403-
assert!(result.is_ok());
404-
}
405-
}
334+
// Tests are in rust/tests/lib_tests.rs

rust/src/streaming/mod.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,4 @@ pub fn create_input_stream(compact: bool) -> JsonInputStream {
2222
JsonInputStream::new(compact)
2323
}
2424

25-
#[cfg(test)]
26-
mod tests {
27-
use super::*;
28-
29-
#[test]
30-
fn test_create_output_stream() {
31-
let stream = create_output_stream();
32-
assert_eq!(stream.get_messages().len(), 0);
33-
}
34-
35-
#[test]
36-
fn test_create_input_stream() {
37-
let stream = create_input_stream(true);
38-
assert_eq!(stream.size(), 0);
39-
}
40-
}
25+
// Tests are in rust/tests/streaming_tests.rs

rust/src/streaming/ndjson.rs

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -76,73 +76,4 @@ pub fn stringify_ndjson(values: &[Value], compact: bool) -> String {
7676
.collect()
7777
}
7878

79-
#[cfg(test)]
80-
mod tests {
81-
use super::*;
82-
use serde_json::json;
83-
84-
#[test]
85-
fn test_parse_ndjson_line_valid_object() {
86-
let result = parse_ndjson_line(r#"{"type":"message"}"#);
87-
assert_eq!(result, Some(json!({"type": "message"})));
88-
}
89-
90-
#[test]
91-
fn test_parse_ndjson_line_valid_array() {
92-
let result = parse_ndjson_line("[1, 2, 3]");
93-
assert_eq!(result, Some(json!([1, 2, 3])));
94-
}
95-
96-
#[test]
97-
fn test_parse_ndjson_line_empty() {
98-
assert_eq!(parse_ndjson_line(""), None);
99-
assert_eq!(parse_ndjson_line(" "), None);
100-
}
101-
102-
#[test]
103-
fn test_parse_ndjson_line_non_json() {
104-
assert_eq!(parse_ndjson_line("hello world"), None);
105-
assert_eq!(parse_ndjson_line("123"), None);
106-
}
107-
108-
#[test]
109-
fn test_parse_ndjson_line_invalid_json() {
110-
assert_eq!(parse_ndjson_line("{invalid}"), None);
111-
}
112-
113-
#[test]
114-
fn test_parse_ndjson_line_trims_whitespace() {
115-
let result = parse_ndjson_line(r#" {"type":"message"} "#);
116-
assert_eq!(result, Some(json!({"type": "message"})));
117-
}
118-
119-
#[test]
120-
fn test_stringify_ndjson_line_object() {
121-
let value = json!({"type": "message"});
122-
let result = stringify_ndjson_line(&value, true);
123-
assert_eq!(result, "{\"type\":\"message\"}\n");
124-
}
125-
126-
#[test]
127-
fn test_stringify_ndjson_line_null() {
128-
let value = Value::Null;
129-
let result = stringify_ndjson_line(&value, true);
130-
assert_eq!(result, "");
131-
}
132-
133-
#[test]
134-
fn test_parse_ndjson() {
135-
let data = "{\"a\":1}\n{\"b\":2}\n";
136-
let result = parse_ndjson(data);
137-
assert_eq!(result.len(), 2);
138-
assert_eq!(result[0], json!({"a": 1}));
139-
assert_eq!(result[1], json!({"b": 2}));
140-
}
141-
142-
#[test]
143-
fn test_stringify_ndjson() {
144-
let values = vec![json!({"a": 1}), json!({"b": 2})];
145-
let result = stringify_ndjson(&values, true);
146-
assert_eq!(result, "{\"a\":1}\n{\"b\":2}\n");
147-
}
148-
}
79+
// Tests are in rust/tests/streaming_tests.rs

rust/src/tools/agent.rs

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -288,49 +288,4 @@ impl Default for AgentTool {
288288
}
289289
}
290290

291-
#[cfg(test)]
292-
mod tests {
293-
use super::*;
294-
295-
#[test]
296-
fn test_map_model_to_id_with_alias() {
297-
assert_eq!(map_model_to_id("grok"), "opencode/grok-code");
298-
assert_eq!(map_model_to_id("sonnet"), "anthropic/claude-3-5-sonnet");
299-
}
300-
301-
#[test]
302-
fn test_build_args_with_model() {
303-
let options = AgentBuildOptions {
304-
model: Some("grok".to_string()),
305-
..Default::default()
306-
};
307-
let args = build_args(&options);
308-
assert!(args.contains(&"--model".to_string()));
309-
assert!(args.contains(&"opencode/grok-code".to_string()));
310-
}
311-
312-
#[test]
313-
fn test_extract_usage_from_step_finish() {
314-
let output = r#"{"type":"step_finish","part":{"tokens":{"input":100,"output":50},"cost":0}}
315-
{"type":"step_finish","part":{"tokens":{"input":200,"output":75},"cost":0}}"#;
316-
let usage = extract_usage(output);
317-
assert_eq!(usage.input_tokens, 300);
318-
assert_eq!(usage.output_tokens, 125);
319-
assert_eq!(usage.step_count, 2);
320-
}
321-
322-
#[test]
323-
fn test_detect_errors_finds_error() {
324-
let output = r#"{"type":"error","message":"Something went wrong"}"#;
325-
let result = detect_errors(output);
326-
assert!(result.has_error);
327-
assert_eq!(result.error_type, Some("error".to_string()));
328-
}
329-
330-
#[test]
331-
fn test_detect_errors_normal_output() {
332-
let output = r#"{"type":"step_finish","part":{}}"#;
333-
let result = detect_errors(output);
334-
assert!(!result.has_error);
335-
}
336-
}
291+
// Tests are in rust/tests/agent_tests.rs

rust/src/tools/claude.rs

Lines changed: 1 addition & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -289,170 +289,4 @@ impl Default for ClaudeTool {
289289
}
290290
}
291291

292-
#[cfg(test)]
293-
mod tests {
294-
use super::*;
295-
296-
#[test]
297-
fn test_map_model_to_id_with_alias() {
298-
assert_eq!(map_model_to_id("sonnet"), "claude-sonnet-4-5-20250929");
299-
assert_eq!(map_model_to_id("opus"), "claude-opus-4-5-20251101");
300-
assert_eq!(map_model_to_id("haiku"), "claude-haiku-4-5-20251001");
301-
}
302-
303-
#[test]
304-
fn test_map_model_to_id_with_full_id() {
305-
assert_eq!(
306-
map_model_to_id("claude-3-opus-20240229"),
307-
"claude-3-opus-20240229"
308-
);
309-
}
310-
311-
#[test]
312-
fn test_build_args_with_prompt() {
313-
let options = ClaudeBuildOptions {
314-
prompt: Some("Hello".to_string()),
315-
..Default::default()
316-
};
317-
let args = build_args(&options);
318-
assert!(args.contains(&"--prompt".to_string()));
319-
assert!(args.contains(&"Hello".to_string()));
320-
}
321-
322-
#[test]
323-
fn test_build_args_with_model() {
324-
let options = ClaudeBuildOptions {
325-
model: Some("sonnet".to_string()),
326-
..Default::default()
327-
};
328-
let args = build_args(&options);
329-
assert!(args.contains(&"--model".to_string()));
330-
assert!(args.contains(&"claude-sonnet-4-5-20250929".to_string()));
331-
}
332-
333-
#[test]
334-
fn test_parse_output_ndjson() {
335-
let output = "{\"type\":\"message\",\"content\":\"Hello\"}\n{\"type\":\"done\"}";
336-
let messages = parse_output(output);
337-
assert_eq!(messages.len(), 2);
338-
assert_eq!(messages[0]["type"], "message");
339-
assert_eq!(messages[1]["type"], "done");
340-
}
341-
342-
#[test]
343-
fn test_extract_session_id() {
344-
let output = "{\"session_id\":\"abc123\"}\n{\"type\":\"done\"}";
345-
let session_id = extract_session_id(output);
346-
assert_eq!(session_id, Some("abc123".to_string()));
347-
}
348-
349-
// New capability tests (issue #3)
350-
#[test]
351-
fn test_build_args_always_includes_dangerously_skip_permissions() {
352-
// dangerously_skip_permissions is always enabled and not configurable
353-
let options = ClaudeBuildOptions::new();
354-
let args = build_args(&options);
355-
assert!(args.contains(&"--dangerously-skip-permissions".to_string()));
356-
357-
// Even with default options, it should still be included
358-
let default_options = ClaudeBuildOptions::default();
359-
let default_args = build_args(&default_options);
360-
assert!(default_args.contains(&"--dangerously-skip-permissions".to_string()));
361-
}
362-
363-
#[test]
364-
fn test_build_args_uses_stream_json_format() {
365-
let options = ClaudeBuildOptions {
366-
json: true,
367-
..Default::default()
368-
};
369-
let args = build_args(&options);
370-
assert!(args.contains(&"--output-format".to_string()));
371-
assert!(args.contains(&"stream-json".to_string()));
372-
assert!(!args.contains(&"json".to_string())); // Should not contain plain 'json'
373-
}
374-
375-
#[test]
376-
fn test_build_args_with_fallback_model() {
377-
let options = ClaudeBuildOptions {
378-
model: Some("opus".to_string()),
379-
fallback_model: Some("sonnet".to_string()),
380-
..Default::default()
381-
};
382-
let args = build_args(&options);
383-
assert!(args.contains(&"--model".to_string()));
384-
assert!(args.contains(&"claude-opus-4-5-20251101".to_string()));
385-
assert!(args.contains(&"--fallback-model".to_string()));
386-
assert!(args.contains(&"claude-sonnet-4-5-20250929".to_string()));
387-
}
388-
389-
#[test]
390-
fn test_build_args_with_append_system_prompt() {
391-
let options = ClaudeBuildOptions {
392-
append_system_prompt: Some("Extra instructions".to_string()),
393-
..Default::default()
394-
};
395-
let args = build_args(&options);
396-
assert!(args.contains(&"--append-system-prompt".to_string()));
397-
assert!(args.contains(&"Extra instructions".to_string()));
398-
}
399-
400-
#[test]
401-
fn test_build_args_with_session_management() {
402-
let options = ClaudeBuildOptions {
403-
session_id: Some("123e4567-e89b-12d3-a456-426614174000".to_string()),
404-
resume: Some("abc123".to_string()),
405-
fork_session: true,
406-
..Default::default()
407-
};
408-
let args = build_args(&options);
409-
assert!(args.contains(&"--session-id".to_string()));
410-
assert!(args.contains(&"123e4567-e89b-12d3-a456-426614174000".to_string()));
411-
assert!(args.contains(&"--resume".to_string()));
412-
assert!(args.contains(&"abc123".to_string()));
413-
assert!(args.contains(&"--fork-session".to_string()));
414-
}
415-
416-
#[test]
417-
fn test_build_args_with_verbose() {
418-
let options = ClaudeBuildOptions {
419-
verbose: true,
420-
..Default::default()
421-
};
422-
let args = build_args(&options);
423-
assert!(args.contains(&"--verbose".to_string()));
424-
}
425-
426-
#[test]
427-
fn test_build_args_with_json_input() {
428-
let options = ClaudeBuildOptions {
429-
json_input: true,
430-
..Default::default()
431-
};
432-
let args = build_args(&options);
433-
assert!(args.contains(&"--input-format".to_string()));
434-
assert!(args.contains(&"stream-json".to_string()));
435-
}
436-
437-
#[test]
438-
fn test_build_args_with_replay_user_messages() {
439-
let options = ClaudeBuildOptions {
440-
replay_user_messages: true,
441-
..Default::default()
442-
};
443-
let args = build_args(&options);
444-
assert!(args.contains(&"--replay-user-messages".to_string()));
445-
}
446-
447-
#[test]
448-
fn test_claude_tool_supports_new_capabilities() {
449-
let tool = ClaudeTool::default();
450-
assert!(tool.supports_json_input);
451-
assert!(tool.supports_append_system_prompt);
452-
assert!(tool.supports_fork_session);
453-
assert!(tool.supports_session_id);
454-
assert!(tool.supports_fallback_model);
455-
assert!(tool.supports_verbose);
456-
assert!(tool.supports_replay_user_messages);
457-
}
458-
}
292+
// Tests are in rust/tests/claude_tests.rs

0 commit comments

Comments
 (0)