aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe')
-rw-r--r--crates/shirabe/tests/completion_functional_test.rs499
1 files changed, 487 insertions, 12 deletions
diff --git a/crates/shirabe/tests/completion_functional_test.rs b/crates/shirabe/tests/completion_functional_test.rs
index 860df546..89478d9d 100644
--- a/crates/shirabe/tests/completion_functional_test.rs
+++ b/crates/shirabe/tests/completion_functional_test.rs
@@ -1,16 +1,491 @@
//! ref: composer/tests/Composer/Test/CompletionFunctionalTest.php
+//!
+//! Validate autocompletion for all commands.
+//!
+//! The PHP test runs inside the Composer dev checkout and takes its expectations from that
+//! environment: the checkout's own composer.json/composer.lock (installed packages, scripts,
+//! package properties) and live Packagist queries for available-package suggestions. Each
+//! data-provider entry is ported as its own test so the entries that cannot run here can be
+//! ignored individually (currently only `exec `, whose expectations require a fully
+//! installed vendor/bin).
+#[path = "common/bootstrap.rs"]
+mod bootstrap;
+
+use serial_test::serial;
+use shirabe::console::application::{Application, ApplicationHandle};
+use shirabe_external_packages::symfony::console::tester::command_completion_tester::CommandCompletionTester;
+
+struct RestoreCwd(std::path::PathBuf);
+
+impl Drop for RestoreCwd {
+ fn drop(&mut self) {
+ let _ = std::env::set_current_dir(&self.0);
+ }
+}
+
+/// PHP runs from the Composer dev checkout; chdir into the vendored checkout to reproduce
+/// that environment (restored on drop, so the tests are `#[serial]`).
+fn chdir_composer_checkout() -> RestoreCwd {
+ let prev = std::env::current_dir().unwrap();
+ let checkout = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../composer");
+ std::env::set_current_dir(checkout).unwrap();
+ RestoreCwd(prev)
+}
+
+/// ref: CompletionFunctionalTest::testComplete
+///
+/// `expected_suggestions` are sample expected suggestions (a subset). None if nothing is
+/// expected.
+fn assert_complete(input: &str, expected_suggestions: Option<&[&str]>) {
+ bootstrap::bootstrap();
+ let _guard = chdir_composer_checkout();
+
+ let mut input: Vec<&str> = input.split(' ').collect();
+ let command_name = input.remove(0);
+ // PHP: $this->getApplication()->get($commandName)
+ let application = ApplicationHandle::new("Composer".to_string(), "".to_string()).unwrap();
+ let base = application.__base_application();
+ let command = {
+ let mut app_ref = base.borrow_mut();
+ let app_dyn: &mut dyn shirabe_external_packages::symfony::console::application::Application =
+ &mut *app_ref;
+ let app = app_dyn
+ .as_any_mut()
+ .downcast_mut::<Application>()
+ .expect("ApplicationHandle wraps the shirabe Application");
+ app.get(command_name).unwrap()
+ };
+
+ let tester = CommandCompletionTester::new(command);
+ let suggestions = tester.complete(&input).unwrap();
+
+ let Some(expected_suggestions) = expected_suggestions else {
+ assert!(
+ suggestions.is_empty(),
+ "Expected no suggestions. Got \"{}\".",
+ suggestions.join("\", \"")
+ );
+ return;
+ };
+
+ let diff: Vec<&str> = expected_suggestions
+ .iter()
+ .copied()
+ .filter(|expected| !suggestions.iter().any(|s| s == expected))
+ .collect();
+ assert!(
+ diff.is_empty(),
+ "Suggestions must contain \"{}\". Got \"{}\".",
+ diff.join("\", \""),
+ suggestions.join("\", \"")
+ );
+}
+
+// PHP: $randomVendor = 'a/'; $installedPackages = [...]; $preferInstall = [...]
+const RANDOM_VENDOR: &str = "a/";
+const INSTALLED_PACKAGES: &[&str] = &["composer/semver", "psr/log"];
+const PREFER_INSTALL: &[&str] = &["dist", "source", "auto"];
+
+#[test]
+#[serial]
+fn test_complete_archive() {
+ assert_complete("archive ", Some(&[RANDOM_VENDOR]));
+}
+
+#[test]
+#[serial]
+fn test_complete_archive_package_prefix() {
+ assert_complete(
+ "archive symfony/http-",
+ Some(&["symfony/http-kernel", "symfony/http-foundation"]),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_archive_format() {
+ assert_complete("archive --format ", Some(&["tar", "zip"]));
+}
+
+#[test]
+#[serial]
+fn test_complete_create_project() {
+ assert_complete("create-project ", Some(&[RANDOM_VENDOR]));
+}
+
+#[test]
+#[serial]
+fn test_complete_create_project_prefer_install() {
+ assert_complete(
+ "create-project symfony/skeleton --prefer-install ",
+ Some(PREFER_INSTALL),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_depends() {
+ assert_complete("depends ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_why() {
+ assert_complete("why ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+#[ignore = "expects the Composer dev checkout's fully installed vendor/bin (phpstan, simple-phpunit, ...); the vendored checkout ships only jsonlint and validate-json"]
+fn test_complete_exec() {
+ assert_complete(
+ "exec ",
+ Some(&[
+ "composer",
+ "jsonlint",
+ "phpstan",
+ "phpstan.phar",
+ "simple-phpunit",
+ "validate-json",
+ ]),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_browse() {
+ assert_complete("browse ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_home_h() {
+ assert_complete("home -H ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_init_require() {
+ assert_complete("init --require ", Some(&[RANDOM_VENDOR]));
+}
+
+#[test]
+#[serial]
+fn test_complete_init_require_dev() {
+ assert_complete(
+ "init --require-dev foo/bar --require-dev ",
+ Some(&[RANDOM_VENDOR]),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_install_prefer_install() {
+ assert_complete("install --prefer-install ", Some(PREFER_INSTALL));
+}
+
+#[test]
+#[serial]
+fn test_complete_install() {
+ assert_complete("install ", None);
+}
+
+#[test]
+#[serial]
+fn test_complete_outdated() {
+ assert_complete("outdated ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_prohibits() {
+ assert_complete("prohibits ", Some(&[RANDOM_VENDOR]));
+}
+
+#[test]
+#[serial]
+fn test_complete_why_not() {
+ assert_complete("why-not symfony/http-ker", Some(&["symfony/http-kernel"]));
+}
+
+#[test]
+#[serial]
+fn test_complete_reinstall_prefer_install() {
+ assert_complete("reinstall --prefer-install ", Some(PREFER_INSTALL));
+}
+
+#[test]
+#[serial]
+fn test_complete_reinstall() {
+ assert_complete("reinstall ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_remove() {
+ assert_complete("remove ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_require_prefer_install() {
+ assert_complete("require --prefer-install ", Some(PREFER_INSTALL));
+}
+
+#[test]
+#[serial]
+fn test_complete_require() {
+ assert_complete("require ", Some(&[RANDOM_VENDOR]));
+}
+
+#[test]
+#[serial]
+fn test_complete_require_dev_package_prefix() {
+ assert_complete(
+ "require --dev symfony/http-",
+ Some(&["symfony/http-kernel", "symfony/http-foundation"]),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_run_script() {
+ assert_complete("run-script ", Some(&["compile", "test", "phpstan"]));
+}
+
+#[test]
+#[serial]
+fn test_complete_run_script_args() {
+ assert_complete("run-script test ", None);
+}
+
+#[test]
+#[serial]
+fn test_complete_search_format() {
+ assert_complete("search --format ", Some(&["text", "json"]));
+}
+
+#[test]
+#[serial]
+fn test_complete_show_format() {
+ assert_complete("show --format ", Some(&["text", "json"]));
+}
+
+#[test]
+#[serial]
+fn test_complete_info() {
+ assert_complete("info ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_suggests() {
+ assert_complete("suggests ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_update_prefer_install() {
+ assert_complete("update --prefer-install ", Some(PREFER_INSTALL));
+}
+
+#[test]
+#[serial]
+fn test_complete_update() {
+ assert_complete("update ", Some(INSTALLED_PACKAGES));
+}
+
+#[test]
+#[serial]
+fn test_complete_config_list() {
+ assert_complete("config --list ", None);
+}
+
+#[test]
+#[serial]
+fn test_complete_config_editor() {
+ assert_complete("config --editor ", None);
+}
+
+#[test]
+#[serial]
+fn test_complete_config_auth() {
+ assert_complete("config --auth ", None);
+}
+
+#[test]
+#[serial]
+fn test_complete_config() {
+ assert_complete(
+ "config ",
+ Some(&[
+ "bin-compat",
+ "extra",
+ "extra.branch-alias",
+ "home",
+ "name",
+ "repositories",
+ "repositories.packagist.org",
+ "suggest",
+ "suggest.ext-zip",
+ "type",
+ "version",
+ ]),
+ );
+}
+
+// global setting
+#[test]
+#[serial]
+fn test_complete_config_bin() {
+ assert_complete("config bin", Some(&["bin-dir"]));
+}
+
+// existing package-property
+#[test]
+#[serial]
+fn test_complete_config_nam() {
+ assert_complete("config nam", Some(&["name"]));
+}
+
+// non-existing package-property
+#[test]
+#[serial]
+fn test_complete_config_ver() {
+ assert_complete("config ver", Some(&["version"]));
+}
+
+#[test]
+#[serial]
+fn test_complete_config_repo() {
+ assert_complete(
+ "config repo",
+ Some(&["repositories", "repositories.packagist.org"]),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_config_repositories_dot() {
+ assert_complete(
+ "config repositories.",
+ Some(&["repositories.packagist.org"]),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_config_sug() {
+ assert_complete("config sug", Some(&["suggest", "suggest.ext-zip"]));
+}
+
+#[test]
+#[serial]
+fn test_complete_config_suggest_ext() {
+ assert_complete("config suggest.ext-", Some(&["suggest.ext-zip"]));
+}
+
+#[test]
+#[serial]
+fn test_complete_config_ext() {
+ assert_complete(
+ "config ext",
+ Some(&["extra", "extra.branch-alias", "extra.branch-alias.dev-main"]),
+ );
+}
+
+// as this test does not use a fixture (yet?), the completion
+// of setting authentication settings can have varying results
+// yield ['config http-basic.', […]];
+
+#[test]
+#[serial]
+fn test_complete_config_unset() {
+ assert_complete(
+ "config --unset ",
+ Some(&[
+ "extra",
+ "extra.branch-alias",
+ "extra.branch-alias.dev-main",
+ "name",
+ "suggest",
+ "suggest.ext-zip",
+ "type",
+ ]),
+ );
+}
+
+// global setting
#[test]
-#[ignore = "CommandCompletionTester (Symfony Console test helper) is not ported, and the test only works inside the Composer dev checkout (its own composer.json/lock + installed vendor dir, plus live Packagist queries for package-name suggestions)"]
-fn test_complete() {
- // TODO(phase-d): two blockers. (1) CommandCompletionTester (Symfony Console test helper
- // driving the `|_complete` command) is not implemented in the shirabe-external-packages
- // console port, so the data-provider-driven completion test has no harness to run against.
- // (2) The PHP test's expected suggestions come from the environment it runs in: the Composer
- // dev checkout's own composer.json/composer.lock and installed vendor packages (e.g.
- // `depends ` -> composer/semver, psr/log; `run-script ` -> compile/test/phpstan) and live
- // Packagist API queries for package-name completion (e.g. `archive symfony/http-`). The port
- // has no equivalent fixture environment, so even with a tester the data sets could not be
- // reproduced without altering expected values.
- todo!()
+#[serial]
+fn test_complete_config_unset_bin_dir() {
+ assert_complete("config --unset bin-dir", None);
}
+
+// existing package-property
+#[test]
+#[serial]
+fn test_complete_config_unset_nam() {
+ assert_complete("config --unset nam", Some(&["name"]));
+}
+
+// non-existing package-property
+#[test]
+#[serial]
+fn test_complete_config_unset_version() {
+ assert_complete("config --unset version", None);
+}
+
+#[test]
+#[serial]
+fn test_complete_config_unset_extra_dot() {
+ assert_complete(
+ "config --unset extra.",
+ Some(&["extra.branch-alias", "extra.branch-alias.dev-main"]),
+ );
+}
+
+// as this test does not use a fixture (yet?), the completion
+// of unsetting authentication settings can have varying results
+// yield ['config --unset http-basic.', […]];
+
+#[test]
+#[serial]
+fn test_complete_config_global() {
+ assert_complete(
+ "config --global ",
+ Some(&[
+ "bin-compat",
+ "home",
+ "repositories",
+ "repositories.packagist.org",
+ ]),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_config_global_repo() {
+ assert_complete(
+ "config --global repo",
+ Some(&["repositories", "repositories.packagist.org"]),
+ );
+}
+
+#[test]
+#[serial]
+fn test_complete_config_global_repositories_dot() {
+ assert_complete(
+ "config --global repositories.",
+ Some(&["repositories.packagist.org"]),
+ );
+}
+
+// as this test does not use a fixture (yet?), the completion
+// of unsetting global settings can have varying results
+// yield ['config --global --unset ', null];
+
+// as this test does not use a fixture (yet?), the completion of
+// unsetting global authentication settings can have varying results
+// yield ['config --global --unset http-basic.', […]];