aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/tests')
-rw-r--r--crates/shirabe/tests/command/run_script_command_test.rs8
-rw-r--r--crates/shirabe/tests/plugin/e2e_normalize_test.rs167
-rwxr-xr-xcrates/shirabe/tests/plugin/fixtures/e2e-normalize/fetch42
-rw-r--r--crates/shirabe/tests/plugin/fixtures/e2e-normalize/project/composer.json228
-rw-r--r--crates/shirabe/tests/plugin/main.rs1
5 files changed, 442 insertions, 4 deletions
diff --git a/crates/shirabe/tests/command/run_script_command_test.rs b/crates/shirabe/tests/command/run_script_command_test.rs
index 9e213cee..10e171ba 100644
--- a/crates/shirabe/tests/command/run_script_command_test.rs
+++ b/crates/shirabe/tests/command/run_script_command_test.rs
@@ -122,19 +122,19 @@ fn test_can_define_aliases() {
}
#[test]
-#[ignore = "the test invokes the script name as a top-level composer command, which requires Application::do_run to import the user's PHP Command class (MyCommand.php) as a live application command (todo!() in application.rs; needs a PHP-side Symfony Application, which does not exist yet). The EventDispatcher-side Command-class path alone cannot satisfy the direct invocation and its argument definitions"]
+#[ignore = "the test invokes the script name as a top-level composer command, which requires Application::do_run to import the user's PHP Command class (MyCommand.php) as a live application command (todo!() in application.rs: the worker-side console application exists, but the import arm is not wired to it), and the command's output would go to the worker's inherited stdio, which the in-process application tester cannot capture"]
fn test_execution_of_simple_symfony_command() {
// TODO(phase-d): the test invokes the script name as a top-level composer command, which
// requires Application::do_run to import the user's PHP Command class (MyCommand.php) as a
- // live application command (todo!() in application.rs; needs a PHP-side Symfony Application, which does not exist yet).
+ // live application command (todo!() in application.rs: the worker-side console application exists, but the import arm is not wired to it), and the worker writes to inherited stdio the tester cannot capture.
todo!()
}
#[test]
-#[ignore = "the test invokes the script name as a top-level composer command, which requires Application::do_run to import the user's PHP Command class (MyCommandWithDefinitions.php) as a live application command (todo!() in application.rs; needs a PHP-side Symfony Application, which does not exist yet). The EventDispatcher-side Command-class path alone cannot satisfy the direct invocation and its argument definitions"]
+#[ignore = "the test invokes the script name as a top-level composer command, which requires Application::do_run to import the user's PHP Command class (MyCommandWithDefinitions.php) as a live application command (todo!() in application.rs: the worker-side console application exists, but the import arm is not wired to it), and the command's output would go to the worker's inherited stdio, which the in-process application tester cannot capture"]
fn test_execution_of_symfony_command_with_configuration() {
// TODO(phase-d): the test invokes the script name as a top-level composer command, which
// requires Application::do_run to import the user's PHP Command class (MyCommandWithDefinitions.php)
- // as a live application command (todo!() in application.rs; needs a PHP-side Symfony Application, which does not exist yet).
+ // as a live application command (todo!() in application.rs: the worker-side console application exists, but the import arm is not wired to it), and the worker writes to inherited stdio the tester cannot capture.
todo!()
}
diff --git a/crates/shirabe/tests/plugin/e2e_normalize_test.rs b/crates/shirabe/tests/plugin/e2e_normalize_test.rs
new file mode 100644
index 00000000..ccfdb596
--- /dev/null
+++ b/crates/shirabe/tests/plugin/e2e_normalize_test.rs
@@ -0,0 +1,167 @@
+//! ergebnis/composer-normalize E2E compatibility check: upstream Composer and Shirabe each
+//! install the pinned plugin (with its real dependency tree) and the `list`/`help` renderings
+//! of its command are compared; the execution comparison is present but ignored until the
+//! worker can construct a second native Composer instance.
+//!
+//! Prerequisites: the PHP runtime, the Composer checkout, and the pinned packages in
+//! `fixtures/e2e-normalize/ext/` — run `fixtures/e2e-normalize/fetch` once to populate it.
+//! The test skips while any of these is missing; test runs themselves are offline.
+
+use crate::e2e_extension_installer_test::{copy_dir, upstream_composer_bin};
+use crate::plugin_installer_test::{lock_php_worker, php_runtime_available};
+use std::path::{Path, PathBuf};
+use tempfile::TempDir;
+
+fn fixture_dir() -> PathBuf {
+ Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/plugin/fixtures/e2e-normalize")
+}
+
+fn fixture_fetched() -> bool {
+ fixture_dir()
+ .join("ext/composer-normalize-2.52.0/src/NormalizePlugin.php")
+ .is_file()
+}
+
+struct CommandRun {
+ exit_code: i32,
+ stdout: String,
+}
+
+fn run_command(work: &Path, program: &str, prefix_args: &[&str], args: &[&str]) -> CommandRun {
+ let output = std::process::Command::new(program)
+ .args(prefix_args)
+ .args(args)
+ .current_dir(work.join("project"))
+ .env("COMPOSER_HOME", work.join("home"))
+ .env("COMPOSER_CACHE_DIR", work.join("cache"))
+ .env("COMPOSER_NO_INTERACTION", "1")
+ .env("COLUMNS", "120")
+ .env("LINES", "30")
+ .output()
+ .unwrap();
+ CommandRun {
+ exit_code: output.status.code().unwrap_or(-1),
+ stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
+ }
+}
+
+fn prepared_project(program: &str, prefix: &[&str]) -> TempDir {
+ let work = TempDir::new().unwrap();
+ copy_dir(&fixture_dir(), work.path());
+ let install = run_command(work.path(), program, prefix, &["install"]);
+ assert_eq!(0, install.exit_code, "{program}: install must succeed");
+ work
+}
+
+fn normalize_lines(stdout: &str) -> Vec<&str> {
+ stdout
+ .lines()
+ .filter(|line| line.contains("normalize"))
+ .collect()
+}
+
+#[test]
+fn test_normalize_listing_matches_upstream_composer() {
+ if !php_runtime_available() {
+ return;
+ }
+ let Some(composer_bin) = upstream_composer_bin() else {
+ return;
+ };
+ if !fixture_fetched() {
+ return;
+ }
+ let _worker = lock_php_worker();
+
+ let composer_bin = composer_bin.to_str().unwrap().to_string();
+ let upstream_prefix = [composer_bin.as_str()];
+ let u_work = prepared_project("php", &upstream_prefix);
+ let s_work = prepared_project(env!("CARGO_BIN_EXE_shirabe"), &[]);
+
+ let u_list = run_command(
+ u_work.path(),
+ "php",
+ &upstream_prefix,
+ &["list", "--no-ansi"],
+ );
+ let s_list = run_command(
+ s_work.path(),
+ env!("CARGO_BIN_EXE_shirabe"),
+ &[],
+ &["list", "--no-ansi"],
+ );
+ assert_eq!(0, u_list.exit_code);
+ assert_eq!(u_list.exit_code, s_list.exit_code);
+ assert_eq!(
+ normalize_lines(&u_list.stdout),
+ normalize_lines(&s_list.stdout)
+ );
+ assert!(
+ !normalize_lines(&s_list.stdout).is_empty(),
+ "list must mention the plugin-provided normalize command"
+ );
+
+ let u_help = run_command(
+ u_work.path(),
+ "php",
+ &upstream_prefix,
+ &["help", "normalize", "--no-ansi"],
+ );
+ let s_help = run_command(
+ s_work.path(),
+ env!("CARGO_BIN_EXE_shirabe"),
+ &[],
+ &["help", "normalize", "--no-ansi"],
+ );
+ assert_eq!(0, u_help.exit_code);
+ assert_eq!(u_help.exit_code, s_help.exit_code);
+ assert_eq!(
+ u_help.stdout, s_help.stdout,
+ "help normalize output differs"
+ );
+}
+
+// TODO(plugin): NormalizeCommand::execute builds a second, in-process Composer instance
+// (`(new Factory())->createComposer(...)`), and the worker's proxy stub classes reject native
+// construction of the FQCNs that path instantiates (Composer\Composer, the event dispatcher,
+// the package graph, ...); running the command therefore stops at that explicit error.
+#[ignore = "the worker cannot construct a second native Composer instance yet; see the TODO(plugin) above"]
+#[test]
+fn test_normalize_execution_matches_upstream_composer() {
+ if !php_runtime_available() {
+ return;
+ }
+ let Some(composer_bin) = upstream_composer_bin() else {
+ return;
+ };
+ if !fixture_fetched() {
+ return;
+ }
+ let _worker = lock_php_worker();
+
+ let composer_bin = composer_bin.to_str().unwrap().to_string();
+ let upstream_prefix = [composer_bin.as_str()];
+ let u_work = prepared_project("php", &upstream_prefix);
+ let s_work = prepared_project(env!("CARGO_BIN_EXE_shirabe"), &[]);
+
+ let dry = ["normalize", "--dry-run", "--no-ansi"];
+ let u_dry = run_command(u_work.path(), "php", &upstream_prefix, &dry);
+ let s_dry = run_command(s_work.path(), env!("CARGO_BIN_EXE_shirabe"), &[], &dry);
+ assert_eq!(1, u_dry.exit_code, "upstream dry-run must report a diff");
+ assert_eq!(u_dry.exit_code, s_dry.exit_code);
+ assert_eq!(
+ u_dry.stdout, s_dry.stdout,
+ "normalize --dry-run output differs"
+ );
+
+ let real = ["normalize", "--no-update-lock", "--no-ansi"];
+ let u_run = run_command(u_work.path(), "php", &upstream_prefix, &real);
+ let s_run = run_command(s_work.path(), env!("CARGO_BIN_EXE_shirabe"), &[], &real);
+ assert_eq!(0, u_run.exit_code, "upstream normalize must succeed");
+ assert_eq!(u_run.exit_code, s_run.exit_code);
+ assert_eq!(
+ std::fs::read(u_work.path().join("project/composer.json")).unwrap(),
+ std::fs::read(s_work.path().join("project/composer.json")).unwrap(),
+ "normalized composer.json differs"
+ );
+}
diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-normalize/fetch b/crates/shirabe/tests/plugin/fixtures/e2e-normalize/fetch
new file mode 100755
index 00000000..7fb7cd5a
--- /dev/null
+++ b/crates/shirabe/tests/plugin/fixtures/e2e-normalize/fetch
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Fetches the external packages the composer-normalize E2E test runs against, into the
+# git-ignored ext/ directory. Every package is pinned to an immutable upstream commit and the
+# extracted tree is verified by a content hash over all files, so the test stays deterministic
+# without any third-party source entering this repository. Requires network once; the E2E test
+# skips itself while ext/ is absent.
+set -eu
+
+base="$(dirname "$0")/ext"
+
+tree_hash() {
+ (cd "$1" && find . -type f | LC_ALL=C sort | xargs sha256sum | sha256sum | cut -d' ' -f1)
+}
+
+# <dir> <github repo> <commit> <tree hash>
+while read -r dir repo commit hash; do
+ target="$base/$dir"
+ if [ -d "$target" ]; then
+ echo "already fetched: $target"
+ continue
+ fi
+ mkdir -p "$target"
+ curl -fsSL "https://codeload.github.com/$repo/tar.gz/$commit" \
+ | tar -xz -C "$target" --strip-components=1
+ actual="$(tree_hash "$target")"
+ if [ "$actual" != "$hash" ]; then
+ rm -rf "$target"
+ echo "tree hash mismatch for $repo@$commit: got $actual; discarded the fetched tree" >&2
+ exit 1
+ fi
+ echo "fetched: $target"
+done <<'EOF'
+composer-normalize-2.52.0 ergebnis/composer-normalize 988f83f5e51a42cdd2337e5fcd935432f8dfa33c 5259a0371a2b571fab3018c8a6a5929883a669f516e1e8a3fb1cfb37e0803e2c
+json-1.6.0 ergebnis/json 7b56d2b5d9e897e75b43e2e753075a0904c921b1 faa07a09e62d6a47582f011744fae2d0f220ccdda157465d31b11b3c095c3605
+json-normalizer-4.10.1 ergebnis/json-normalizer 77961faf2c651c3f05977b53c6c68e8434febf62 edea5b84656b1ae172ca4e92ebe481ff3c22828d3637b36c76e65223c38e9dce
+json-pointer-3.8.0 ergebnis/json-pointer b58c3c468a7ff109fdf9a255f17de29ecbe5276c 5395f59f684babf62a33d721ef8ab49eaba3d1280786081b45c49c29fdea1562
+json-printer-3.8.1 ergebnis/json-printer 211d73fc7ec6daf98568ee6ed6e6d133dee8503e 72d8e6ca1a168229bb2a50524a00d0c0a3c69be5e65731d177b6b563503e6b9a
+json-schema-validator-4.5.1 ergebnis/json-schema-validator b739527a480a9e3651360ad351ea77e7e9019df2 a176d190b6517b0380edfe13e526289864849c8b1788dee19123560658fc0be4
+json-schema-6.10.0 jsonrainbow/json-schema 8b1308a9d7bdbdb20ce87ef920f82b4564bb2d33 8b6b7931f9072aabf599927cf92ecc171f37e6516c4075172b60a45baa276380
+php-enum-4.7.2 marc-mabe/php-enum bb426fcdd65c60fb3638ef741e8782508fda7eef 7bb6a4923625cd6353b95534b322f951acf0aef055054cffd99e97dcbf1778b5
+diff-1.3.0 localheinz/diff 33bd840935970cda6691c23fc7d94ae764c0734c 283c8104b38fc8428e0819d30ab5e94f4e8284293d79b994bba4fbf0e05ca86f
+EOF
diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-normalize/project/composer.json b/crates/shirabe/tests/plugin/fixtures/e2e-normalize/project/composer.json
new file mode 100644
index 00000000..9af30ddb
--- /dev/null
+++ b/crates/shirabe/tests/plugin/fixtures/e2e-normalize/project/composer.json
@@ -0,0 +1,228 @@
+{
+ "description": "E2E fixture project: install and run ergebnis/composer-normalize. The top-level keys are deliberately out of schema order so the normalize run has something to do.",
+ "require": {
+ "ergebnis/composer-normalize": "2.52.0"
+ },
+ "name": "shirabe/e2e-composer-normalize",
+ "config": {
+ "allow-plugins": {
+ "ergebnis/composer-normalize": true
+ }
+ },
+ "repositories": [
+ {
+ "type": "package",
+ "package": {
+ "name": "ergebnis/composer-normalize",
+ "version": "2.52.0",
+ "type": "composer-plugin",
+ "autoload": {
+ "psr-4": {
+ "Ergebnis\\Composer\\Normalize\\": "src/"
+ }
+ },
+ "require": {
+ "ext-json": "*",
+ "composer-plugin-api": "^2.0.0",
+ "ergebnis/json": "^1.4.0",
+ "ergebnis/json-normalizer": "^4.9.0",
+ "ergebnis/json-printer": "^3.7.0",
+ "justinrainbow/json-schema": "^5.2.12 || ^6.0.0",
+ "localheinz/diff": "^1.3.0"
+ },
+ "extra": {
+ "class": "Ergebnis\\Composer\\Normalize\\NormalizePlugin"
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/composer-normalize-2.52.0"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "type": "package",
+ "package": {
+ "name": "ergebnis/json",
+ "version": "1.6.0",
+ "autoload": {
+ "psr-4": {
+ "Ergebnis\\Json\\": "src/"
+ }
+ },
+ "require": {
+ "ext-json": "*"
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/json-1.6.0"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "type": "package",
+ "package": {
+ "name": "ergebnis/json-normalizer",
+ "version": "4.10.1",
+ "autoload": {
+ "psr-4": {
+ "Ergebnis\\Json\\Normalizer\\": "src/"
+ }
+ },
+ "require": {
+ "ext-json": "*",
+ "ergebnis/json": "^1.2.0",
+ "ergebnis/json-pointer": "^3.4.0",
+ "ergebnis/json-printer": "^3.5.0",
+ "ergebnis/json-schema-validator": "^4.2.0",
+ "justinrainbow/json-schema": "^5.2.12 || ^6.0.0"
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/json-normalizer-4.10.1"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "type": "package",
+ "package": {
+ "name": "ergebnis/json-pointer",
+ "version": "3.8.0",
+ "autoload": {
+ "psr-4": {
+ "Ergebnis\\Json\\Pointer\\": "src/"
+ }
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/json-pointer-3.8.0"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "type": "package",
+ "package": {
+ "name": "ergebnis/json-printer",
+ "version": "3.8.1",
+ "autoload": {
+ "psr-4": {
+ "Ergebnis\\Json\\Printer\\": "src/"
+ }
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-mbstring": "*"
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/json-printer-3.8.1"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "type": "package",
+ "package": {
+ "name": "ergebnis/json-schema-validator",
+ "version": "4.5.1",
+ "autoload": {
+ "psr-4": {
+ "Ergebnis\\Json\\SchemaValidator\\": "src/"
+ }
+ },
+ "require": {
+ "ext-json": "*",
+ "ergebnis/json": "^1.2.0",
+ "ergebnis/json-pointer": "^3.4.0",
+ "justinrainbow/json-schema": "^5.2.12 || ^6.0.0"
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/json-schema-validator-4.5.1"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "type": "package",
+ "package": {
+ "name": "justinrainbow/json-schema",
+ "version": "6.10.0",
+ "autoload": {
+ "psr-4": {
+ "JsonSchema\\": "src/JsonSchema/"
+ }
+ },
+ "require": {
+ "marc-mabe/php-enum": "^4.4"
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/json-schema-6.10.0"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "type": "package",
+ "package": {
+ "name": "marc-mabe/php-enum",
+ "version": "4.7.2",
+ "autoload": {
+ "psr-4": {
+ "MabeEnum\\": "src/"
+ },
+ "classmap": [
+ "stubs/Stringable.php"
+ ]
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/php-enum-4.7.2"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "type": "package",
+ "package": {
+ "name": "localheinz/diff",
+ "version": "1.3.0",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "dist": {
+ "type": "path",
+ "url": "../ext/diff-1.3.0"
+ },
+ "transport-options": {
+ "symlink": false
+ }
+ }
+ },
+ {
+ "packagist.org": false
+ }
+ ]
+}
diff --git a/crates/shirabe/tests/plugin/main.rs b/crates/shirabe/tests/plugin/main.rs
index 633ad790..a65594be 100644
--- a/crates/shirabe/tests/plugin/main.rs
+++ b/crates/shirabe/tests/plugin/main.rs
@@ -5,5 +5,6 @@ mod config_stub;
mod e2e_command_provider_test;
mod e2e_extension_installer_test;
+mod e2e_normalize_test;
mod plugin_installer_test;
mod subscriber_test;