use std::collections::HashMap;
use std::path::Path;
use chrom_rs::cli::app::{ChromContext, RunHandler};
use dynamic_cli::{CommandHandler, ExecutionContext};
fn copy_files(files: &[&str], dest_dir: &Path) {
for src in files {
let name = Path::new(src).file_name().expect("file must have a name");
std::fs::copy(src, dest_dir.join(name))
.unwrap_or_else(|e| panic!("cannot copy {src}: {e}"));
}
}
fn make_args(entries: &[(&str, &str)]) -> HashMap<String, String> {
entries
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect()
}
fn run(dir: &Path, args: &HashMap<String, String>) {
let mut ctx = ChromContext::new();
RunHandler
.execute(&mut ctx as &mut dyn ExecutionContext, args)
.unwrap_or_else(|e| panic!("RunHandler::execute failed: {e}"));
let _ = dir;
}
#[test]
fn test_run_tfa_gaussian_rk4_csv() {
let dir = tempfile::tempdir().unwrap();
copy_files(
&[
"examples/config/tfa/model.yml",
"examples/config/tfa/scenario_gaussian.yml",
"examples/config/tfa/solver_rk4.yml",
],
dir.path(),
);
let project_dir = dir.path().to_str().unwrap();
let args = make_args(&[
("project-dir", project_dir),
("model", "model.yml"),
("scenario", "scenario_gaussian.yml"),
("solver", "solver_rk4.yml"),
("output-csv", "result.csv"),
]);
run(dir.path(), &args);
assert!(
dir.path().join("result.csv").exists(),
"CSV must be created"
);
}
#[test]
fn test_run_tfa_gaussian_euler_json() {
let dir = tempfile::tempdir().unwrap();
copy_files(
&[
"examples/config/tfa/model.yml",
"examples/config/tfa/scenario_gaussian.yml",
"examples/config/tfa/solver_euler.yml",
],
dir.path(),
);
let project_dir = dir.path().to_str().unwrap();
let args = make_args(&[
("project-dir", project_dir),
("model", "model.yml"),
("scenario", "scenario_gaussian.yml"),
("solver", "solver_euler.yml"),
("export-json", "result.json"),
]);
run(dir.path(), &args);
assert!(
dir.path().join("result.json").exists(),
"JSON must be created"
);
}
#[test]
fn test_run_tfa_gaussian_rk4_plot() {
let dir = tempfile::tempdir().unwrap();
copy_files(
&[
"examples/config/tfa/model.yml",
"examples/config/tfa/scenario_gaussian.yml",
"examples/config/tfa/solver_rk4.yml",
],
dir.path(),
);
let project_dir = dir.path().to_str().unwrap();
let args = make_args(&[
("project-dir", project_dir),
("model", "model.yml"),
("scenario", "scenario_gaussian.yml"),
("solver", "solver_rk4.yml"),
("output-plot", "result.png"),
]);
run(dir.path(), &args);
assert!(
dir.path().join("result.png").exists(),
"plot must be created"
);
}
#[test]
fn test_run_tfa_all_outputs() {
let dir = tempfile::tempdir().unwrap();
copy_files(
&[
"examples/config/tfa/model.yml",
"examples/config/tfa/scenario_gaussian.yml",
"examples/config/tfa/solver_rk4.yml",
],
dir.path(),
);
let project_dir = dir.path().to_str().unwrap();
let args = make_args(&[
("project-dir", project_dir),
("model", "model.yml"),
("scenario", "scenario_gaussian.yml"),
("solver", "solver_rk4.yml"),
("output-csv", "result.csv"),
("output-plot", "result.png"),
("export-json", "result.json"),
]);
run(dir.path(), &args);
assert!(
dir.path().join("result.csv").exists(),
"CSV must be created"
);
assert!(
dir.path().join("result.png").exists(),
"plot must be created"
);
assert!(
dir.path().join("result.json").exists(),
"JSON must be created"
);
}
#[test]
fn test_run_acids_multi_rk4_csv() {
let dir = tempfile::tempdir().unwrap();
copy_files(
&[
"examples/config/acids/model.yml",
"examples/config/acids/scenario_gaussian.yml",
"examples/config/acids/solver_rk4.yml",
],
dir.path(),
);
let project_dir = dir.path().to_str().unwrap();
let args = make_args(&[
("project-dir", project_dir),
("model", "model.yml"),
("scenario", "scenario_gaussian.yml"),
("solver", "solver_rk4.yml"),
("output-csv", "result.csv"),
]);
run(dir.path(), &args);
assert!(
dir.path().join("result.csv").exists(),
"multi-species CSV must be created"
);
}
#[test]
fn test_run_acids_multi_euler_all_outputs() {
let dir = tempfile::tempdir().unwrap();
copy_files(
&[
"examples/config/acids/model.yml",
"examples/config/acids/scenario_gaussian.yml",
"examples/config/acids/solver_euler.yml",
],
dir.path(),
);
let project_dir = dir.path().to_str().unwrap();
let args = make_args(&[
("project-dir", project_dir),
("model", "model.yml"),
("scenario", "scenario_gaussian.yml"),
("solver", "solver_euler.yml"),
("output-csv", "result.csv"),
("output-plot", "result.png"),
("export-json", "result.json"),
]);
run(dir.path(), &args);
assert!(
dir.path().join("result.csv").exists(),
"multi-species CSV must be created"
);
assert!(
dir.path().join("result.png").exists(),
"multi-species plot must be created"
);
assert!(
dir.path().join("result.json").exists(),
"multi-species JSON must be created"
);
}
#[test]
fn test_run_missing_model_arg_fails() {
let dir = tempfile::tempdir().unwrap();
let project_dir = dir.path().to_str().unwrap();
let args = make_args(&[
("project-dir", project_dir),
("scenario", "scenario.yml"),
("solver", "solver.yml"),
]);
let mut ctx = ChromContext::new();
let result = RunHandler.execute(&mut ctx as &mut dyn ExecutionContext, &args);
assert!(result.is_err(), "missing --model must return an error");
}
#[test]
fn test_run_project_dir_traversal_fails() {
let args = make_args(&[
("project-dir", "../etc"),
("model", "model.yml"),
("scenario", "scenario.yml"),
("solver", "solver.yml"),
]);
let mut ctx = ChromContext::new();
let result = RunHandler.execute(&mut ctx as &mut dyn ExecutionContext, &args);
assert!(result.is_err(), "path traversal must return an error");
}