aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-test-harness/src/runner.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-01 19:24:28 +0900
committernsfisis <nsfisis@gmail.com>2026-05-01 19:24:28 +0900
commit7d36d8e5cf8c6f7c21a6b4c713217bc92c37d328 (patch)
treed8fdbdbc3abb6acf41095c013f281fdabc880372 /crates/mozart-test-harness/src/runner.rs
parent64ed53cf184fb05cbfe9f0336bc8695ff0e800f8 (diff)
downloadphp-mozart-7d36d8e5cf8c6f7c21a6b4c713217bc92c37d328.tar.gz
php-mozart-7d36d8e5cf8c6f7c21a6b4c713217bc92c37d328.tar.zst
php-mozart-7d36d8e5cf8c6f7c21a6b4c713217bc92c37d328.zip
feat(test-harness): add Composer .test fixture parser and runner
Foundation for porting Composer's installer integration fixtures. Parser covers the 13 sections of InstallerTest.php; runner sets up a tempdir from COMPOSER/LOCK/INSTALLED and invokes the mozart binary. No fixtures are migrated in this commit.
Diffstat (limited to 'crates/mozart-test-harness/src/runner.rs')
-rw-r--r--crates/mozart-test-harness/src/runner.rs62
1 files changed, 62 insertions, 0 deletions
diff --git a/crates/mozart-test-harness/src/runner.rs b/crates/mozart-test-harness/src/runner.rs
new file mode 100644
index 0000000..e041cd7
--- /dev/null
+++ b/crates/mozart-test-harness/src/runner.rs
@@ -0,0 +1,62 @@
+use anyhow::{Context, Result};
+use std::path::Path;
+use std::process::Command;
+use tempfile::TempDir;
+
+use crate::parser::ParsedTest;
+
+/// Outcome of running a parsed `.test` against the `mozart` binary.
+///
+/// The temp directory is kept alive in this struct so callers can inspect
+/// files written by the run; it is removed when `RunResult` is dropped.
+pub struct RunResult {
+ pub working_dir: TempDir,
+ pub stdout: String,
+ pub stderr: String,
+ pub exit_code: i32,
+ pub final_lock: Option<String>,
+ pub final_installed: Option<String>,
+}
+
+/// Set up a temp project from the parsed test, invoke `mozart` with the
+/// `--RUN--` command, and capture the result.
+pub fn run_test(test: &ParsedTest, mozart_bin: &Path) -> Result<RunResult> {
+ let working_dir = TempDir::new().context("failed to create tempdir")?;
+ let root = working_dir.path();
+
+ std::fs::write(root.join("composer.json"), &test.composer)
+ .context("failed to write composer.json")?;
+
+ if let Some(lock) = &test.lock {
+ std::fs::write(root.join("composer.lock"), lock)
+ .context("failed to write composer.lock")?;
+ }
+
+ if let Some(installed) = &test.installed {
+ let vendor_composer = root.join("vendor").join("composer");
+ std::fs::create_dir_all(&vendor_composer)
+ .context("failed to create vendor/composer dir")?;
+ std::fs::write(vendor_composer.join("installed.json"), installed)
+ .context("failed to write installed.json")?;
+ }
+
+ let args: Vec<&str> = test.run.split_whitespace().collect();
+ let output = Command::new(mozart_bin)
+ .args(&args)
+ .current_dir(root)
+ .output()
+ .with_context(|| format!("failed to invoke {}", mozart_bin.display()))?;
+
+ let final_lock = std::fs::read_to_string(root.join("composer.lock")).ok();
+ let final_installed =
+ std::fs::read_to_string(root.join("vendor").join("composer").join("installed.json")).ok();
+
+ Ok(RunResult {
+ working_dir,
+ stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
+ stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
+ exit_code: output.status.code().unwrap_or(-1),
+ final_lock,
+ final_installed,
+ })
+}