diff options
Diffstat (limited to 'crates/mozart/tests/installer_in_process.rs')
| -rw-r--r-- | crates/mozart/tests/installer_in_process.rs | 162 |
1 files changed, 0 insertions, 162 deletions
diff --git a/crates/mozart/tests/installer_in_process.rs b/crates/mozart/tests/installer_in_process.rs deleted file mode 100644 index f3e8ce2..0000000 --- a/crates/mozart/tests/installer_in_process.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! In-process installer fixture runner. -//! -//! Mirrors Composer's PHPUnit-driven `InstallerTest`: parses the same -//! `.test` fixture files, sets up a tempdir with `composer.json` / -//! `composer.lock` / `vendor/composer/installed.json`, then invokes -//! `mozart::commands::{install,update}::run` directly with an empty -//! `RepositorySet` (Composer's `'packagist' => false` test config) and a -//! `TraceRecorderExecutor` (Composer's `InstallationManagerMock`). -//! -//! Step F will move every fixture in `installer.rs` over to this harness; -//! for now this file just demonstrates the path on a single fixture -//! (`suggest_replaced` — the original CI failure that motivated the whole -//! DI refactor). - -use std::path::{Path, PathBuf}; -use std::sync::Arc; - -use clap::Parser; -use mozart::commands::{Cli, Commands, install, update}; -use mozart_core::console::Console; -use mozart_core::exit_code::MozartError; -use mozart_registry::installer_executor::TraceRecorderExecutor; -use mozart_registry::repository::RepositorySet; -use mozart_test_harness::{ParsedTest, parse_test_file}; -use tempfile::TempDir; - -fn fixtures_dir() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("../../composer/tests/Composer/Test/Fixtures/installer") -} - -/// Outcome of a single in-process fixture run. -struct InProcessRunResult { - /// Kept alive so the caller can inspect on-disk artifacts; dropped - /// (and removed) when this struct goes out of scope. - _working_dir: TempDir, - /// Composer-shape operation trace from `TraceRecorderExecutor`. - /// Compare against the fixture's `--EXPECT--` section. - trace: Vec<String>, - /// Final `composer.lock` JSON, as written to disk by the runner. - final_lock: Option<String>, - /// Final `vendor/composer/installed.json`, as written to disk. - final_installed: Option<String>, - /// Mapped exit code: 0 for success, otherwise the carried - /// [`MozartError::exit_code`] (or 1 for unclassified errors). - exit_code: i32, -} - -async fn run_fixture_in_process(test: &ParsedTest) -> anyhow::Result<InProcessRunResult> { - let working_dir = TempDir::new()?; - let root = working_dir.path(); - - std::fs::write(root.join("composer.json"), &test.composer)?; - if let Some(lock) = &test.lock { - std::fs::write(root.join("composer.lock"), lock)?; - } - if let Some(installed) = &test.installed { - let vendor_composer = root.join("vendor").join("composer"); - std::fs::create_dir_all(&vendor_composer)?; - std::fs::write(vendor_composer.join("installed.json"), installed)?; - } - - // Parse the `--RUN--` line through clap so we get the same arg semantics - // the real CLI does — including default flags, validators, etc. - let argv: Vec<String> = std::iter::once("mozart".to_string()) - .chain(test.run.split_whitespace().map(String::from)) - .collect(); - let cli = Cli::try_parse_from(&argv)?; - - // Quiet console: tests assert on `trace` / lock / installed, not on - // captured stdout/stderr (Console doesn't yet support buffered sinks). - let console = Console::new(0, true, false, true, true); - let repositories = Arc::new(RepositorySet::empty()); - let mut executor = TraceRecorderExecutor::new(); - - let outcome: anyhow::Result<()> = match &cli.command { - Some(Commands::Install(args)) => { - install::run(root, args, &console, repositories, &mut executor).await - } - Some(Commands::Update(args)) => { - update::run(root, args, &console, repositories, &mut executor).await - } - other => anyhow::bail!( - "unsupported run command in fixture: {:?}", - other.is_some() - ), - }; - - let exit_code = match &outcome { - Ok(()) => 0, - Err(e) => e - .downcast_ref::<MozartError>() - .map(|m| m.exit_code) - .unwrap_or(1), - }; - - 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(InProcessRunResult { - _working_dir: working_dir, - trace: executor.into_trace(), - final_lock, - final_installed, - exit_code, - }) -} - -fn run_fixture(ident: &str) { - let filename = format!("{}.test", ident.replace('_', "-")); - let path = fixtures_dir().join(&filename); - let parsed = parse_test_file(&path) - .unwrap_or_else(|e| panic!("failed to parse {}: {:#}", path.display(), e)); - - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("failed to build tokio runtime"); - let result = runtime - .block_on(run_fixture_in_process(&parsed)) - .unwrap_or_else(|e| panic!("failed to run {}: {:#}", path.display(), e)); - - let expected_exit = parsed.expect_exit_code.unwrap_or(0); - assert_eq!( - result.exit_code, - expected_exit, - "exit code mismatch for {}\n--- trace ---\n{}", - path.display(), - result.trace.join("\n"), - ); - - // EXPECT (the trace) is the load-bearing assertion in Composer's - // PHPUnit harness — every line of the operation log must match - // byte-for-byte against `(string) $operation` after `strip_tags`. - let expected_trace = parsed.expect.trim(); - let actual_trace = result.trace.join("\n"); - assert_eq!( - actual_trace.trim(), - expected_trace, - "EXPECT trace mismatch for {}\n--- expected ---\n{}\n--- actual ---\n{}\n--- final lock ---\n{}\n--- final installed ---\n{}", - path.display(), - expected_trace, - actual_trace, - result.final_lock.as_deref().unwrap_or("(absent)"), - result.final_installed.as_deref().unwrap_or("(absent)"), - ); -} - -// ──────────────────────────────────────────────────────────────────────────── -// In-process fixtures -// -// Step F will migrate every fixture from `installer.rs` to this harness. -// For now this file holds just the proof-of-concept: `suggest_replaced`, -// the original CI failure (the spawn runner can't reach Packagist for -// `b/b`, even though `c/c` replaces it). -// ──────────────────────────────────────────────────────────────────────────── - -#[test] -fn suggest_replaced_in_process() { - run_fixture("suggest_replaced"); -} |
