use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use retiretui_engine::params::TaxTables;
use retiretui_engine::plan::Plan;
use retiretui_engine::project::project;
use crate::commands::tui::session::Projected;
pub const TEST_PLAN: &str = r#"
schema = 1
[plan]
name = "test-plan"
start_year = 2026
horizon_age = 70
inflation = 0.025
[household]
filing = "single"
[[household.people]]
id = "me"
birth = 1980-06-15
[[accounts]]
id = "cash"
kind = "cash"
owner = "me"
balance = 10000
[[accounts]]
id = "k"
kind = "401k"
owner = "me"
balance = 200000
expected_return = 0.05
[[income]]
id = "salary"
kind = "salary"
owner = "me"
amount = 100000
end = { age = 60, owner = "me" }
[[expenses]]
id = "living"
amount = 60000
"#;
pub const FEW_TRIALS: &str = "\n[market.monte_carlo]\ntrials = 20\n";
pub fn test_plan_briefly_run() -> String {
format!("{TEST_PLAN}{FEW_TRIALS}")
}
pub fn test_projected() -> Projected {
let projected = projected_from(TEST_PLAN);
let issues = projected.plan.validate();
assert!(issues.is_empty(), "invalid test plan: {issues:?}");
projected
}
pub fn projected_from(plan_text: &str) -> Projected {
let plan = Plan::from_toml_str(plan_text).unwrap();
let projection = project(&plan, &TaxTables::embedded());
Projected { plan, projection }
}
static NEXT_SCRATCH: AtomicUsize = AtomicUsize::new(0);
pub fn scratch_dir() -> PathBuf {
let ordinal = NEXT_SCRATCH.fetch_add(1, Ordering::Relaxed);
let dir = std::env::temp_dir().join(format!("retiretui-tui-{}-{ordinal}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
dir
}
pub fn scratch_plan() -> PathBuf {
let dir = scratch_dir();
let path = dir.join(dir.file_name().unwrap()).with_extension("toml");
std::fs::write(&path, TEST_PLAN).unwrap();
path
}
pub fn scratch_full_plan() -> PathBuf {
let fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../retiretui_engine/tests/fixtures/full.toml");
let scratch = scratch_plan();
std::fs::copy(fixture, &scratch).unwrap();
scratch
}
pub fn scenario_over(base: &str) -> String {
format!("schema = 1\nbase = \"{base}\"\n\n[plan]\nname = \"variant\"\n")
}
pub fn scratch_scenario() -> PathBuf {
let base = scratch_plan();
let scenario = base.with_extension("scenario.toml");
let overlay = scenario_over(&base.file_name().unwrap().to_string_lossy());
std::fs::write(&scenario, overlay).unwrap();
scenario
}
pub fn scratch_workspace(plan_text: &str) -> PathBuf {
let dir = scratch_dir();
std::fs::write(dir.join("plan.toml"), plan_text).unwrap();
std::fs::write(dir.join("variant.toml"), scenario_over("plan.toml")).unwrap();
std::fs::write(dir.join("broken.toml"), "schema = 1\n").unwrap();
std::fs::write(dir.join("notes.txt"), "not a plan").unwrap();
dir
}