use super::*;
#[test]
fn test_parse_task_json_valid() {
let json = r#"[
{"id": "t1", "prompt": "Fix the bug", "role": "worker", "dependencies": [], "target_files": ["src/main.rs"]},
{"id": "t2", "prompt": "Add tests", "role": "worker", "dependencies": ["t1"], "target_files": ["tests/test.rs"]}
]"#;
let tasks = parse_task_json(json).unwrap();
assert_eq!(tasks.len(), 2);
assert_eq!(tasks[0].id, "t1");
assert_eq!(tasks[1].dependencies, vec!["t1"]);
}
#[test]
fn test_parse_task_json_wrapped() {
let text = "Here are the subtasks:\n```json\n[\n{\"id\": \"t1\", \"prompt\": \"Do work\", \"role\": \"worker\"}]\n```";
let tasks = parse_task_json(text).unwrap();
assert_eq!(tasks.len(), 1);
}
#[test]
fn test_parse_task_json_empty() {
let tasks = parse_task_json("No JSON here").unwrap();
assert!(tasks.is_empty());
}
#[test]
fn test_truncate() {
assert_eq!(truncate("hello", 10), "hello");
assert_eq!(truncate("hello world", 5), "hello...");
}
#[test]
fn test_is_trivially_sequential() {
assert!(is_trivially_sequential("fix the bug"));
assert!(is_trivially_sequential("what does this do?"));
assert!(is_trivially_sequential("버그 수정해줘"));
assert!(is_trivially_sequential("バグを直して"));
assert!(is_trivially_sequential(
"먼저 auth.rs를 고치고 그다음 config를 업데이트해"
));
assert!(is_trivially_sequential(
"step 1: read file, step 2: edit it"
));
assert!(is_trivially_sequential("do these one by one"));
assert!(is_trivially_sequential(
"まず認証を修正して、次にテストを追加して"
));
assert!(is_trivially_sequential("fix routes.rs"));
assert!(is_trivially_sequential(
"add a method to auth.rs that checks token expiry"
));
assert!(!is_trivially_sequential(
"현재 start가 foreground로 뜨게 되어 있는데, foreground는 serve로 변경. \
start,stop,restart는 background 프로세스로 처리 \
enable, disable은 로그인 아이템으로 등록하도록"
));
assert!(!is_trivially_sequential(
"refactor the authentication system: update auth middleware, update \
all API route handlers, update the user service, and add new tests"
));
assert!(!is_trivially_sequential(
"update auth.rs and api.rs and config.rs to use the new token format"
));
}
fn make_task(id: &str, deps: &[&str]) -> SwarmTask {
SwarmTask {
id: id.to_string(),
prompt: format!("task {id}"),
role: "worker".to_string(),
dependencies: deps.iter().map(|s| s.to_string()).collect(),
target_files: Vec::new(),
agent_name: None,
}
}
#[test]
fn test_enforce_file_disjoint() {
let mut tasks = vec![
SwarmTask {
id: "t1".to_string(),
prompt: "task 1".to_string(),
role: "worker".to_string(),
dependencies: vec![],
target_files: vec!["src/lib.rs".to_string()],
agent_name: None,
},
SwarmTask {
id: "t2".to_string(),
prompt: "task 2".to_string(),
role: "worker".to_string(),
dependencies: vec![],
target_files: vec!["src/lib.rs".to_string(), "src/main.rs".to_string()],
agent_name: None,
},
];
enforce_file_disjoint(&mut tasks);
assert!(tasks[1].dependencies.contains(&"t1".to_string()));
}
#[test]
fn test_enforce_file_disjoint_no_overlap() {
let mut tasks = vec![make_task("t1", &[]), make_task("t2", &[])];
tasks[0].target_files = vec!["a.rs".to_string()];
tasks[1].target_files = vec!["b.rs".to_string()];
enforce_file_disjoint(&mut tasks);
assert!(tasks[1].dependencies.is_empty());
}