diff --git a/src-rust/crates/commands/tests/common/goal.rs b/src-rust/crates/commands/tests/common/goal.rs new file mode 100644 index 00000000..5b811e16 --- /dev/null +++ b/src-rust/crates/commands/tests/common/goal.rs @@ -0,0 +1,50 @@ +use std::process::{Command, Stdio}; +use std::time::{Duration, Instant}; + +pub fn run_cases(worker: &str, cases: &[&str]) { + let mut failures = Vec::new(); + for case in cases { + let temp = tempfile::tempdir().unwrap(); + let home = temp.path().join("home"); + let project = temp.path().join("project"); + std::fs::create_dir(&home).unwrap(); + std::fs::create_dir(&project).unwrap(); + let log = temp.path().join("stderr"); + let mut child = Command::new(std::env::current_exe().unwrap()) + .args(["--exact", worker, "--ignored", "--nocapture"]) + .env_clear() + .env("HOME", &home) + .env("USERPROFILE", &home) + .env("COVEN_CODE_HOME", &home) + .env("COVEN_HOME", temp.path().join("coven")) + .env("COVEN_CAVE_HOME", temp.path().join("cave")) + .env("GOAL_FIXTURE_PROJECT", &project) + .env("GOAL_FIXTURE_CASE", case) + .env("GOAL_FIXTURE_DONE", temp.path().join("done")) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(std::fs::File::create(&log).unwrap()) + .spawn() + .unwrap(); + let deadline = Instant::now() + Duration::from_secs(10); + let outcome = loop { + match child.try_wait() { + Ok(Some(status)) => break status, + Ok(None) if Instant::now() < deadline => { + std::thread::sleep(Duration::from_millis(10)) + } + result => { + let _ = child.kill(); + let _ = child.wait(); + panic!("{case}: child wait failed: {result:?}"); + } + } + }; + if outcome.success() { + assert_eq!(std::fs::read(temp.path().join("done")).unwrap(), b"checked"); + } else { + failures.push(format!("{case}: {}", std::fs::read_to_string(log).unwrap())); + } + } + assert!(failures.is_empty(), "{}", failures.join("\n")); +} diff --git a/src-rust/crates/commands/tests/goal_budget.rs b/src-rust/crates/commands/tests/goal_budget.rs index b5dc94c0..5e9f118d 100644 --- a/src-rust/crates/commands/tests/goal_budget.rs +++ b/src-rust/crates/commands/tests/goal_budget.rs @@ -1,66 +1,30 @@ +#[path = "common/goal.rs"] +mod goal_fixture; + use claurst_commands::{CommandContext, CommandResult, GoalCommand, SlashCommand}; use claurst_core::{config::Config, cost::CostTracker, GoalStore}; -use std::process::{Command, Stdio}; -use std::time::{Duration, Instant}; +use goal_fixture::run_cases; #[test] fn invalid_explicit_goal_budgets_preserve_existing_goal() { - run_cases(&[ - "overflow_k", - "overflow_m", - "overflow_integer", - "invalid", - "negative", - "over_storage", - ]); + run_cases( + "goal_budget_worker", + &[ + "overflow_k", + "overflow_m", + "overflow_integer", + "invalid", + "negative", + "over_storage", + ], + ); } #[test] fn valid_goal_budgets_preserve_existing_semantics() { - run_cases(&["zero", "plain", "k", "m", "none", "max_storage"]); -} - -fn run_cases(cases: &[&str]) { - let mut failures = Vec::new(); - for case in cases { - let temp = tempfile::tempdir().unwrap(); - let home = temp.path().join("home"); - let project = temp.path().join("project"); - std::fs::create_dir(&home).unwrap(); - std::fs::create_dir(&project).unwrap(); - let log = temp.path().join("stderr"); - let mut child = Command::new(std::env::current_exe().unwrap()) - .args(["--exact", "goal_budget_worker", "--ignored", "--nocapture"]) - .env_clear() - .env("COVEN_CODE_HOME", &home) - .env("GOAL_FIXTURE_PROJECT", &project) - .env("GOAL_FIXTURE_CASE", case) - .env("GOAL_FIXTURE_DONE", temp.path().join("done")) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(std::fs::File::create(&log).unwrap()) - .spawn() - .unwrap(); - let deadline = Instant::now() + Duration::from_secs(10); - let outcome = loop { - match child.try_wait() { - Ok(Some(status)) => break status, - Ok(None) if Instant::now() < deadline => { - std::thread::sleep(Duration::from_millis(10)) - } - result => { - let _ = child.kill(); - let _ = child.wait(); - panic!("{case}: child wait failed: {result:?}"); - } - } - }; - if outcome.success() { - assert_eq!(std::fs::read(temp.path().join("done")).unwrap(), b"checked"); - } else { - failures.push(format!("{case}: {}", std::fs::read_to_string(log).unwrap())); - } - } - assert!(failures.is_empty(), "{}", failures.join("\n")); + run_cases( + "goal_budget_worker", + &["zero", "plain", "k", "m", "none", "max_storage"], + ); } #[test] diff --git a/src-rust/crates/commands/tests/goal_clear.rs b/src-rust/crates/commands/tests/goal_clear.rs index 96a46cdd..a58d34ee 100644 --- a/src-rust/crates/commands/tests/goal_clear.rs +++ b/src-rust/crates/commands/tests/goal_clear.rs @@ -1,64 +1,18 @@ +#[path = "common/goal.rs"] +mod goal_fixture; + use claurst_commands::{CommandContext, CommandResult, CovenCommand, GoalCommand, SlashCommand}; use claurst_core::{config::Config, cost::CostTracker, Goal, GoalStore}; -use std::process::{Command, Stdio}; -use std::time::{Duration, Instant}; +use goal_fixture::run_cases; #[test] fn failed_goal_deletion_is_reported_without_mutating_goals() { - run_cases(&["direct_failure", "coven_failure"]); + run_cases("goal_clear_worker", &["direct_failure", "coven_failure"]); } #[test] fn successful_and_absent_goal_deletion_keep_existing_behavior() { - run_cases(&["direct_success", "coven_success"]); -} - -fn run_cases(cases: &[&str]) { - let mut failures = Vec::new(); - for case in cases { - let temp = tempfile::tempdir().unwrap(); - let home = temp.path().join("home"); - let project = temp.path().join("project"); - std::fs::create_dir(&home).unwrap(); - std::fs::create_dir(&project).unwrap(); - let log = temp.path().join("stderr"); - let mut child = Command::new(std::env::current_exe().unwrap()) - .args(["--exact", "goal_clear_worker", "--ignored", "--nocapture"]) - .env_clear() - .env("HOME", &home) - .env("USERPROFILE", &home) - .env("COVEN_CODE_HOME", &home) - .env("COVEN_HOME", temp.path().join("coven")) - .env("COVEN_CAVE_HOME", temp.path().join("cave")) - .env("GOAL_FIXTURE_PROJECT", &project) - .env("GOAL_FIXTURE_CASE", case) - .env("GOAL_FIXTURE_DONE", temp.path().join("done")) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(std::fs::File::create(&log).unwrap()) - .spawn() - .unwrap(); - let deadline = Instant::now() + Duration::from_secs(10); - let outcome = loop { - match child.try_wait() { - Ok(Some(status)) => break status, - Ok(None) if Instant::now() < deadline => { - std::thread::sleep(Duration::from_millis(10)) - } - result => { - let _ = child.kill(); - let _ = child.wait(); - panic!("{case}: child wait failed: {result:?}"); - } - } - }; - if outcome.success() { - assert_eq!(std::fs::read(temp.path().join("done")).unwrap(), b"checked"); - } else { - failures.push(format!("{case}: {}", std::fs::read_to_string(log).unwrap())); - } - } - assert!(failures.is_empty(), "{}", failures.join("\n")); + run_cases("goal_clear_worker", &["direct_success", "coven_success"]); } fn assert_goal_unchanged(before: &Goal, after: &Goal) { diff --git a/src-rust/crates/commands/tests/goal_reads.rs b/src-rust/crates/commands/tests/goal_reads.rs index a90e0e50..94766687 100644 --- a/src-rust/crates/commands/tests/goal_reads.rs +++ b/src-rust/crates/commands/tests/goal_reads.rs @@ -1,64 +1,18 @@ +#[path = "common/goal.rs"] +mod goal_fixture; + use claurst_commands::{CommandContext, CommandResult, CovenCommand, GoalCommand, SlashCommand}; use claurst_core::{config::Config, cost::CostTracker, GoalError, GoalStatus, GoalStore}; -use std::process::{Command, Stdio}; -use std::time::{Duration, Instant}; +use goal_fixture::run_cases; #[test] fn corrupt_goal_reads_are_errors_without_mutation() { - run_cases(&["status", "counter"]); + run_cases("goal_read_worker", &["status", "counter"]); } #[test] fn missing_and_valid_goal_reads_keep_existing_behavior() { - run_cases(&["missing", "valid"]); -} - -fn run_cases(cases: &[&str]) { - let mut failures = Vec::new(); - for case in cases { - let temp = tempfile::tempdir().unwrap(); - let home = temp.path().join("home"); - let project = temp.path().join("project"); - std::fs::create_dir(&home).unwrap(); - std::fs::create_dir(&project).unwrap(); - let log = temp.path().join("stderr"); - let mut child = Command::new(std::env::current_exe().unwrap()) - .args(["--exact", "goal_read_worker", "--ignored", "--nocapture"]) - .env_clear() - .env("HOME", &home) - .env("USERPROFILE", &home) - .env("COVEN_CODE_HOME", &home) - .env("COVEN_HOME", temp.path().join("coven")) - .env("COVEN_CAVE_HOME", temp.path().join("cave")) - .env("GOAL_FIXTURE_PROJECT", &project) - .env("GOAL_FIXTURE_CASE", case) - .env("GOAL_FIXTURE_DONE", temp.path().join("done")) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(std::fs::File::create(&log).unwrap()) - .spawn() - .unwrap(); - let deadline = Instant::now() + Duration::from_secs(10); - let outcome = loop { - match child.try_wait() { - Ok(Some(status)) => break status, - Ok(None) if Instant::now() < deadline => { - std::thread::sleep(Duration::from_millis(10)) - } - result => { - let _ = child.kill(); - let _ = child.wait(); - panic!("{case}: child wait failed: {result:?}"); - } - } - }; - if outcome.success() { - assert_eq!(std::fs::read(temp.path().join("done")).unwrap(), b"checked"); - } else { - failures.push(format!("{case}: {}", std::fs::read_to_string(log).unwrap())); - } - } - assert!(failures.is_empty(), "{}", failures.join("\n")); + run_cases("goal_read_worker", &["missing", "valid"]); } #[derive(Debug, Clone, PartialEq, Eq)]