use std::path::{Path, PathBuf};
use std::process::{Command, Output};
pub type TestError = Box<dyn std::error::Error>;
pub fn run_cli(current_dir: &Path, args: &[&str]) -> Result<Output, TestError> {
Ok(Command::new(env!("CARGO_BIN_EXE_aion"))
.args(args)
.current_dir(current_dir)
.output()?)
}
pub fn success_json(output: &Output) -> Result<serde_json::Value, TestError> {
if output.status.code() != Some(0) {
return Err(format!(
"expected success, got {:?}; stdout: {} stderr: {}",
output.status.code(),
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
)
.into());
}
Ok(serde_json::from_slice(&output.stdout)?)
}
pub fn scaffold_project(
parent: &Path,
name: &str,
extra: &[&str],
) -> Result<(PathBuf, serde_json::Value), TestError> {
let mut args = vec!["new", name];
args.extend_from_slice(extra);
let output = run_cli(parent, &args)?;
let report = success_json(&output)?;
Ok((parent.join(name), report))
}
pub fn patch_aion_flow_to_workspace(project: &Path) -> Result<(), TestError> {
let manifest_path = project.join("gleam.toml");
let manifest = std::fs::read_to_string(&manifest_path)?;
let ranges = [
"aion_flow = \">= 0.5.0 and < 0.6.0\"",
"aion_flow = \">= 0.4.0 and < 0.5.0\"",
];
let Some(published) = ranges.iter().find(|range| manifest.contains(**range)) else {
return Err(format!(
"emitted gleam.toml must require a published aion_flow range; got:\n{manifest}"
)
.into());
};
let sdk = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../gleam/aion_flow")
.canonicalize()?;
let patched = manifest.replace(
published,
&format!("aion_flow = {{ path = \"{}\" }}", sdk.display()),
);
std::fs::write(manifest_path, patched)?;
Ok(())
}
pub fn gleam_build(project: &Path) -> Result<(), TestError> {
crate::gleam_test_support::compile_whole_project(project)?;
Ok(())
}
pub fn package_project(project: &Path, name: &str) -> Result<PathBuf, TestError> {
let output = run_cli(project, &["package", "."])?;
let report = success_json(&output)?;
let packaged = report["packages"]
.as_array()
.and_then(|packages| packages.first())
.ok_or("aion package must report one packaged workflow")?;
if packaged["workflow_type"] != name {
return Err(format!("packaged workflow type must be {name}; report: {report}").into());
}
let archive = project.join(format!("{name}.aion"));
if !archive.is_file() {
return Err(format!(
"aion package did not produce the declared archive {}",
archive.display()
)
.into());
}
Ok(archive)
}