aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-22 02:09:59 +0900
committernsfisis <nsfisis@gmail.com>2026-06-22 02:09:59 +0900
commit822d9a872807a92a5337ee8b7bab96dc9845cdbb (patch)
tree4931365df5978caffade69cad2154718a9076f66 /crates/shirabe/tests
parentf691b864b687f251c3b266e8cff2774d730567ba (diff)
downloadphp-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.tar.gz
php-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.tar.zst
php-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.zip
test: port more test cases
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests')
-rw-r--r--crates/shirabe/tests/advisory/auditor_test.rs150
-rw-r--r--crates/shirabe/tests/all_functional_test.rs4
-rw-r--r--crates/shirabe/tests/application_test.rs91
-rw-r--r--crates/shirabe/tests/autoload/autoload_generator_test.rs80
-rw-r--r--crates/shirabe/tests/autoload/class_loader_test.rs4
-rw-r--r--crates/shirabe/tests/cache_test.rs4
-rw-r--r--crates/shirabe/tests/command/about_command_test.rs2
-rw-r--r--crates/shirabe/tests/command/archive_command_test.rs6
-rw-r--r--crates/shirabe/tests/command/audit_command_test.rs8
-rw-r--r--crates/shirabe/tests/command/base_dependency_command_test.rs14
-rw-r--r--crates/shirabe/tests/command/bump_command_test.rs6
-rw-r--r--crates/shirabe/tests/command/check_platform_reqs_command_test.rs6
-rw-r--r--crates/shirabe/tests/command/clear_cache_command_test.rs6
-rw-r--r--crates/shirabe/tests/command/config_command_test.rs10
-rw-r--r--crates/shirabe/tests/command/diagnose_command_test.rs4
-rw-r--r--crates/shirabe/tests/command/dump_autoload_command_test.rs24
-rw-r--r--crates/shirabe/tests/command/exec_command_test.rs4
-rw-r--r--crates/shirabe/tests/command/fund_command_test.rs2
-rw-r--r--crates/shirabe/tests/command/global_command_test.rs16
-rw-r--r--crates/shirabe/tests/command/home_command_test.rs2
-rw-r--r--crates/shirabe/tests/command/init_command_test.rs44
-rw-r--r--crates/shirabe/tests/command/install_command_test.rs8
-rw-r--r--crates/shirabe/tests/command/licenses_command_test.rs16
-rw-r--r--crates/shirabe/tests/command/reinstall_command_test.rs2
-rw-r--r--crates/shirabe/tests/command/remove_command_test.rs32
-rw-r--r--crates/shirabe/tests/command/repository_command_test.rs32
-rw-r--r--crates/shirabe/tests/command/require_command_test.rs8
-rw-r--r--crates/shirabe/tests/command/run_script_command_test.rs10
-rw-r--r--crates/shirabe/tests/command/search_command_test.rs6
-rw-r--r--crates/shirabe/tests/command/self_update_command_test.rs8
-rw-r--r--crates/shirabe/tests/command/show_command_test.rs46
-rw-r--r--crates/shirabe/tests/command/status_command_test.rs4
-rw-r--r--crates/shirabe/tests/command/suggests_command_test.rs4
-rw-r--r--crates/shirabe/tests/command/update_command_test.rs14
-rw-r--r--crates/shirabe/tests/command/validate_command_test.rs8
-rw-r--r--crates/shirabe/tests/completion_functional_test.rs2
-rw-r--r--crates/shirabe/tests/config/json_config_source_test.rs452
-rw-r--r--crates/shirabe/tests/config_test.rs557
-rw-r--r--crates/shirabe/tests/dependency_resolver/default_policy_test.rs523
-rw-r--r--crates/shirabe/tests/dependency_resolver/pool_builder_test.rs2
-rw-r--r--crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs263
-rw-r--r--crates/shirabe/tests/dependency_resolver/rule_set_test.rs60
-rw-r--r--crates/shirabe/tests/dependency_resolver/rule_test.rs81
-rw-r--r--crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs89
-rw-r--r--crates/shirabe/tests/dependency_resolver/solver_test.rs521
-rw-r--r--crates/shirabe/tests/dependency_resolver/transaction_test.rs5
-rw-r--r--crates/shirabe/tests/documentation_test.rs2
-rw-r--r--crates/shirabe/tests/downloader/archive_downloader_test.rs12
-rw-r--r--crates/shirabe/tests/downloader/download_manager_test.rs62
-rw-r--r--crates/shirabe/tests/downloader/file_downloader_test.rs18
-rw-r--r--crates/shirabe/tests/downloader/fossil_downloader_test.rs12
-rw-r--r--crates/shirabe/tests/downloader/git_downloader_test.rs30
-rw-r--r--crates/shirabe/tests/downloader/hg_downloader_test.rs12
-rw-r--r--crates/shirabe/tests/downloader/perforce_downloader_test.rs8
-rw-r--r--crates/shirabe/tests/downloader/xz_downloader_test.rs90
-rw-r--r--crates/shirabe/tests/downloader/zip_downloader_test.rs16
-rw-r--r--crates/shirabe/tests/event_dispatcher/event_dispatcher_test.rs30
-rw-r--r--crates/shirabe/tests/factory_test.rs2
-rw-r--r--crates/shirabe/tests/installed_versions_test.rs431
-rw-r--r--crates/shirabe/tests/installer/binary_installer_test.rs2
-rw-r--r--crates/shirabe/tests/installer/installation_manager_test.rs16
-rw-r--r--crates/shirabe/tests/installer/library_installer_test.rs167
-rw-r--r--crates/shirabe/tests/installer/suggested_packages_reporter_test.rs76
-rw-r--r--crates/shirabe/tests/installer_test.rs8
-rw-r--r--crates/shirabe/tests/io/console_io_test.rs80
-rw-r--r--crates/shirabe/tests/json/composer_schema_test.rs10
-rw-r--r--crates/shirabe/tests/json/json_file_test.rs462
-rw-r--r--crates/shirabe/tests/json/json_formatter_test.rs4
-rw-r--r--crates/shirabe/tests/json/json_manipulator_test.rs5514
-rw-r--r--crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs6
-rw-r--r--crates/shirabe/tests/package/archiver/archive_manager_test.rs10
-rw-r--r--crates/shirabe/tests/package/archiver/phar_archiver_test.rs4
-rw-r--r--crates/shirabe/tests/package/archiver/zip_archiver_test.rs6
-rw-r--r--crates/shirabe/tests/package/base_package_test.rs2
-rw-r--r--crates/shirabe/tests/package/dumper/array_dumper_test.rs2
-rw-r--r--crates/shirabe/tests/package/loader/array_loader_test.rs621
-rw-r--r--crates/shirabe/tests/package/loader/root_package_loader_test.rs137
-rw-r--r--crates/shirabe/tests/package/loader/validating_array_loader_test.rs1022
-rw-r--r--crates/shirabe/tests/package/locker_test.rs20
-rw-r--r--crates/shirabe/tests/package/version/version_guesser_test.rs59
-rw-r--r--crates/shirabe/tests/package/version/version_selector_test.rs26
-rw-r--r--crates/shirabe/tests/platform/hhvm_detector_test.rs53
-rw-r--r--crates/shirabe/tests/plugin/plugin_installer_test.rs32
-rw-r--r--crates/shirabe/tests/question/strict_confirmation_question_test.rs6
-rw-r--r--crates/shirabe/tests/repository/artifact_repository_test.rs6
-rw-r--r--crates/shirabe/tests/repository/composer_repository_test.rs18
-rw-r--r--crates/shirabe/tests/repository/filesystem_repository_test.rs144
-rw-r--r--crates/shirabe/tests/repository/path_repository_test.rs16
-rw-r--r--crates/shirabe/tests/repository/platform_repository_test.rs45
-rw-r--r--crates/shirabe/tests/repository/repository_factory_test.rs2
-rw-r--r--crates/shirabe/tests/repository/repository_manager_test.rs163
-rw-r--r--crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs8
-rw-r--r--crates/shirabe/tests/repository/vcs/git_bitbucket_driver_test.rs10
-rw-r--r--crates/shirabe/tests/repository/vcs/git_driver_test.rs12
-rw-r--r--crates/shirabe/tests/repository/vcs/github_driver_test.rs18
-rw-r--r--crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs112
-rw-r--r--crates/shirabe/tests/repository/vcs/hg_driver_test.rs6
-rw-r--r--crates/shirabe/tests/repository/vcs/perforce_driver_test.rs39
-rw-r--r--crates/shirabe/tests/repository/vcs/svn_driver_test.rs2
-rw-r--r--crates/shirabe/tests/repository/vcs_repository_test.rs23
-rw-r--r--crates/shirabe/tests/script/event_test.rs2
-rw-r--r--crates/shirabe/tests/util/auth_helper_test.rs40
-rw-r--r--crates/shirabe/tests/util/bitbucket_test.rs30
-rw-r--r--crates/shirabe/tests/util/error_handler_test.rs6
-rw-r--r--crates/shirabe/tests/util/filesystem_test.rs752
-rw-r--r--crates/shirabe/tests/util/forgejo_test.rs4
-rw-r--r--crates/shirabe/tests/util/git_test.rs14
-rw-r--r--crates/shirabe/tests/util/github_test.rs4
-rw-r--r--crates/shirabe/tests/util/gitlab_test.rs4
-rw-r--r--crates/shirabe/tests/util/http/proxy_manager_test.rs202
-rw-r--r--crates/shirabe/tests/util/http_downloader_test.rs100
-rw-r--r--crates/shirabe/tests/util/metadata_minifier_test.rs2
-rw-r--r--crates/shirabe/tests/util/perforce_test.rs211
-rw-r--r--crates/shirabe/tests/util/process_executor_test.rs174
-rw-r--r--crates/shirabe/tests/util/remote_filesystem_test.rs26
-rw-r--r--crates/shirabe/tests/util/stream_context_factory_test.rs66
-rw-r--r--crates/shirabe/tests/util/svn_test.rs12
-rw-r--r--crates/shirabe/tests/util/tls_helper_test.rs4
118 files changed, 13263 insertions, 1324 deletions
diff --git a/crates/shirabe/tests/advisory/auditor_test.rs b/crates/shirabe/tests/advisory/auditor_test.rs
index ea0b3c8..038c675 100644
--- a/crates/shirabe/tests/advisory/auditor_test.rs
+++ b/crates/shirabe/tests/advisory/auditor_test.rs
@@ -1,33 +1,171 @@
//! ref: composer/tests/Composer/Test/Advisory/AuditorTest.php
+use chrono::Utc;
+use indexmap::IndexMap;
+use shirabe::advisory::AnySecurityAdvisory;
+use shirabe::advisory::Auditor;
+use shirabe::advisory::PartialSecurityAdvisory;
+use shirabe::advisory::SecurityAdvisory;
+use shirabe_semver::constraint::SimpleConstraint;
+
+fn constraint(operator: &str, version: &str) -> shirabe_semver::constraint::AnyConstraint {
+ SimpleConstraint::new(operator.to_string(), version.to_string(), None).into()
+}
+
+fn full_advisory() -> AnySecurityAdvisory {
+ let mut source: IndexMap<String, String> = IndexMap::new();
+ source.insert("name".to_string(), "foo".to_string());
+ source.insert("remoteId".to_string(), "remoteID".to_string());
+ AnySecurityAdvisory::Full(SecurityAdvisory::new(
+ "foo/bar".to_string(),
+ "123".to_string(),
+ constraint("=", "1.0.0.0"),
+ "test".to_string(),
+ vec![source],
+ Utc::now(),
+ None,
+ None,
+ None,
+ ))
+}
+
+fn full_advisory_with_id(advisory_id: &str) -> AnySecurityAdvisory {
+ let mut source: IndexMap<String, String> = IndexMap::new();
+ source.insert("name".to_string(), "foo".to_string());
+ source.insert("remoteId".to_string(), "remoteID".to_string());
+ AnySecurityAdvisory::Full(SecurityAdvisory::new(
+ "foo/bar".to_string(),
+ advisory_id.to_string(),
+ constraint("=", "1.0.0.0"),
+ "test".to_string(),
+ vec![source],
+ Utc::now(),
+ None,
+ None,
+ None,
+ ))
+}
+
+fn partial_advisory(advisory_id: &str) -> AnySecurityAdvisory {
+ AnySecurityAdvisory::Partial(PartialSecurityAdvisory::new(
+ "foo/bar".to_string(),
+ advisory_id.to_string(),
+ constraint("=", "1.0.0.0"),
+ ))
+}
+
+fn ignore_list(pairs: Vec<(&str, Option<&str>)>) -> IndexMap<String, Option<String>> {
+ pairs
+ .into_iter()
+ .map(|(k, v)| (k.to_string(), v.map(String::from)))
+ .collect()
+}
+
// These run the Auditor against a mocked HttpDownloader/IO and packages built from version
// constraints (parsed via a look-around regex the regex crate cannot compile).
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore = "requires PHPUnit getMockBuilder partial mock of ComposerRepository (hasSecurityAdvisories/getSecurityAdvisories) and BufferIO; no mocking infrastructure exists"]
fn test_audit() {
todo!()
}
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore = "requires getIOMock with expects() output expectations and getMockBuilder mock of ComposerRepository; no mocking infrastructure exists"]
fn test_audit_with_ignore() {
todo!()
}
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore = "requires getMockBuilder partial mock of RepositorySet (getMatchingSecurityAdvisories willReturnCallback); no mocking infrastructure exists"]
fn test_audit_with_ignore_unreachable() {
todo!()
}
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore = "requires getIOMock with expects() output expectations and getMockBuilder mock of ComposerRepository; no mocking infrastructure exists"]
fn test_audit_with_ignore_severity() {
todo!()
}
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore]
fn test_needs_complete_advisory_load() {
- todo!()
+ let cases: Vec<(
+ IndexMap<String, Vec<AnySecurityAdvisory>>,
+ IndexMap<String, Option<String>>,
+ bool,
+ )> = vec![
+ // no filter or advisories
+ (IndexMap::new(), ignore_list(vec![]), false),
+ // packagist filters are IDs so work fine with partial advisories
+ (
+ IndexMap::new(),
+ ignore_list(vec![("PKSA-foo-bar", None)]),
+ false,
+ ),
+ // packagist filters are IDs so work fine with partial advisories/2
+ (
+ {
+ let mut m: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ m.insert(
+ "vendor1/package1".to_string(),
+ vec![full_advisory(), partial_advisory("1234")],
+ );
+ m
+ },
+ ignore_list(vec![("PKSA-foo-bar", Some("this is fine 🔥"))]),
+ false,
+ ),
+ // no advisories no need to load any further
+ (
+ IndexMap::new(),
+ ignore_list(vec![("CVE-2025-1234", None)]),
+ false,
+ ),
+ // no advisories no need to load any further/2
+ (
+ {
+ let mut m: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ m.insert("vendor1/package1".to_string(), vec![]);
+ m
+ },
+ ignore_list(vec![("CVE-2025-1234", None)]),
+ false,
+ ),
+ // CVE filter or other non-packagist ones might need to fully load for safety if partial advisories are present
+ (
+ {
+ let mut m: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ m.insert(
+ "vendor1/package1".to_string(),
+ vec![full_advisory(), partial_advisory("1234")],
+ );
+ m
+ },
+ ignore_list(vec![("CVE-2025-1234", None)]),
+ true,
+ ),
+ // filter does not trigger load if all advisories are fully loaded
+ (
+ {
+ let mut m: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ m.insert("vendor1/package1".to_string(), vec![full_advisory()]);
+ m.insert(
+ "vendor1/package2".to_string(),
+ vec![full_advisory_with_id("1234")],
+ );
+ m
+ },
+ ignore_list(vec![("CVE-2025-1234", None)]),
+ false,
+ ),
+ ];
+
+ let auditor = Auditor;
+ for (advisories, ignore_list, expected) in cases {
+ assert_eq!(
+ expected,
+ auditor.needs_complete_advisory_load(&advisories, &ignore_list)
+ );
+ }
}
diff --git a/crates/shirabe/tests/all_functional_test.rs b/crates/shirabe/tests/all_functional_test.rs
index 22e495a..98b800b 100644
--- a/crates/shirabe/tests/all_functional_test.rs
+++ b/crates/shirabe/tests/all_functional_test.rs
@@ -22,14 +22,14 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "not yet ported (builds composer.phar and runs the functional .test fixtures via the binary)"]
+#[ignore = "depends on unported bin/compile phar build (./bin/compile) and running composer.phar as a subprocess"]
fn test_build_phar() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "not yet ported (builds composer.phar and runs the functional .test fixtures via the binary)"]
+#[ignore = "depends on unported functional-test harness (parseTestFile/cleanOutput) running the built composer.phar as a subprocess"]
fn test_integration() {
let _tear_down = TearDown;
todo!()
diff --git a/crates/shirabe/tests/application_test.rs b/crates/shirabe/tests/application_test.rs
index 856c1b7..dddf8de 100644
--- a/crates/shirabe/tests/application_test.rs
+++ b/crates/shirabe/tests/application_test.rs
@@ -1,9 +1,22 @@
//! ref: composer/tests/Composer/Test/ApplicationTest.php
-// These drive the console Application (doRun, getDisplay, plugin disabling, command
-// resolution) via ApplicationTester, none of which are ported.
+// These drive the console Application (doRun, command resolution, plugin disabling).
+// The tests needing Application::setAutoExit/setCatchErrors or the initTempComposer
+// helper, or a runtime define() of COMPOSER_DEV_WARNING_TIME, remain unportable.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use shirabe::command::about_command::AboutCommand;
+use shirabe::command::self_update_command::SelfUpdateCommand;
+use shirabe::console::application::Application;
use shirabe::util::platform::Platform;
+use shirabe_external_packages::symfony::console::command::Command;
+use shirabe_external_packages::symfony::console::input::array_input::ArrayInput;
+use shirabe_external_packages::symfony::console::input::input_interface::InputInterface;
+use shirabe_external_packages::symfony::console::output::buffered_output::BufferedOutput;
+use shirabe_external_packages::symfony::console::output::output_interface::OutputInterface;
+use shirabe_php_shim::PhpMixed;
fn set_up() {
Platform::put_env("COMPOSER_DISABLE_XDEBUG_WARN", "1");
@@ -21,8 +34,8 @@ impl Drop for TearDown {
}
}
+#[ignore = "no define() setter exists for the COMPOSER_DEV_WARNING_TIME constant (shim defined() is a fixed matches!)"]
#[test]
-#[ignore = "requires the console Application/ApplicationTester harness, which is not yet ported"]
fn test_dev_warning() {
let _tear_down = TearDown;
set_up();
@@ -30,26 +43,86 @@ fn test_dev_warning() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "requires the console Application/ApplicationTester harness, which is not yet ported"]
fn test_dev_warning_suppressed_for_self_update() {
let _tear_down = TearDown;
set_up();
- todo!()
+ if Platform::is_windows() {
+ // markTestSkipped('Does not run on windows')
+ return;
+ }
+
+ let application = Rc::new(RefCell::new(Application::new(
+ "Composer".to_string(),
+ "".to_string(),
+ )));
+ let command: Rc<RefCell<dyn Command>> = Rc::new(RefCell::new(SelfUpdateCommand::new()));
+ application.borrow_mut().add(command).unwrap();
+
+ let output = Rc::new(RefCell::new(BufferedOutput::new(None, false, None)));
+ let input: Rc<RefCell<dyn InputInterface>> = Rc::new(RefCell::new(
+ ArrayInput::new(
+ vec![(PhpMixed::from("command"), PhpMixed::from("self-update"))],
+ None,
+ )
+ .unwrap(),
+ ));
+ let output_trait: Rc<RefCell<dyn OutputInterface>> = output.clone();
+ Application::do_run(&application, input, output_trait).unwrap();
+
+ assert_eq!(
+ "This instance of Composer does not have the self-update command.\n\
+ This could be due to a number of reasons, such as Composer being installed as a system package on your OS, or Composer being installed as a package in the current project.\n",
+ output.borrow().fetch().as_str()
+ );
}
+#[ignore]
#[test]
-#[ignore = "requires the console Application/ApplicationTester harness, which is not yet ported"]
fn test_process_isolation_works_multiple_times() {
let _tear_down = TearDown;
set_up();
- todo!()
+ let application = Rc::new(RefCell::new(Application::new(
+ "Composer".to_string(),
+ "".to_string(),
+ )));
+ let command: Rc<RefCell<dyn Command>> = Rc::new(RefCell::new(AboutCommand::new()));
+ application.borrow_mut().add(command).unwrap();
+
+ let input1: Rc<RefCell<dyn InputInterface>> = Rc::new(RefCell::new(
+ ArrayInput::new(
+ vec![(PhpMixed::from("command"), PhpMixed::from("about"))],
+ None,
+ )
+ .unwrap(),
+ ));
+ let output1: Rc<RefCell<dyn OutputInterface>> =
+ Rc::new(RefCell::new(BufferedOutput::new(None, false, None)));
+ assert_eq!(
+ 0,
+ Application::do_run(&application, input1, output1).unwrap()
+ );
+
+ let input2: Rc<RefCell<dyn InputInterface>> = Rc::new(RefCell::new(
+ ArrayInput::new(
+ vec![(PhpMixed::from("command"), PhpMixed::from("about"))],
+ None,
+ )
+ .unwrap(),
+ ));
+ let output2: Rc<RefCell<dyn OutputInterface>> =
+ Rc::new(RefCell::new(BufferedOutput::new(None, false, None)));
+ assert_eq!(
+ 0,
+ Application::do_run(&application, input2, output2).unwrap()
+ );
}
+#[ignore = "Application::set_auto_exit / set_catch_errors and the initTempComposer test helper do not exist"]
#[test]
-#[ignore = "requires the console Application/ApplicationTester harness, which is not yet ported"]
fn test_no_plugins_disables_plugins_when_script_commands_exist() {
let _tear_down = TearDown;
set_up();
@@ -57,8 +130,8 @@ fn test_no_plugins_disables_plugins_when_script_commands_exist() {
todo!()
}
+#[ignore = "Application::set_auto_exit / set_catch_errors and the initTempComposer test helper do not exist"]
#[test]
-#[ignore = "requires the console Application/ApplicationTester harness, which is not yet ported"]
fn test_script_command_takes_priority_over_abbreviated_builtin_command() {
let _tear_down = TearDown;
set_up();
diff --git a/crates/shirabe/tests/autoload/autoload_generator_test.rs b/crates/shirabe/tests/autoload/autoload_generator_test.rs
index 0729497..72ac999 100644
--- a/crates/shirabe/tests/autoload/autoload_generator_test.rs
+++ b/crates/shirabe/tests/autoload/autoload_generator_test.rs
@@ -27,241 +27,241 @@ impl Drop for TearDown {
// the generated autoload files. The integration setup (fixtures, mocks, filesystem) is not
// ported yet.
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config::get, InstallationManager::getInstallPath, InstalledRepositoryInterface::getCanonicalPackages and TestCase::getUniqueTmpDirectory/ensureDirectoryExistsAndClear; no mock infra exists"]
fn test_root_package_autoloading() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_root_package_dev_autoloading() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_root_package_dev_autoloading_disabled_by_default() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_vendor_dir_same_as_working_dir() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_root_package_autoloading_alternative_vendor_dir() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_root_package_autoloading_with_target_dir() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_duplicate_files_warning() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_vendors_autoloading() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_vendors_autoloading_with_metapackages() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_non_dev_autoload_exclusion_with_recursion() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_non_dev_autoload_should_include_replaced_packages() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_non_dev_autoload_exclusion_with_recursion_replace() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_non_dev_autoload_replaces_nested_requirements() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_phar_autoload() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_psr_to_class_map_ignores_non_existing_dir() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_psr_to_class_map_ignores_non_psr_classes() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_vendors_class_map_autoloading() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_vendors_class_map_autoloading_with_target_dir() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_class_map_autoloading_empty_dir_and_exact_file() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_class_map_autoloading_authoritative_and_apcu() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_class_map_autoloading_authoritative_and_apcu_prefix() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_files_autoload_generation() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_files_autoload_generation_remove_extra_entities_from_autoload_files() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_files_autoload_order_by_dependencies() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_override_vendors_autoloading() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_include_path_file_generation() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_include_paths_are_prepended_in_autoload_file() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_include_paths_in_root_package() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_include_path_file_without_paths_is_skipped() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface plus EventDispatcher::dispatch expectations; no mock infra exists"]
fn test_pre_and_post_events_are_dispatched_during_autoload_dump() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_use_global_include_path() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_vendor_dir_excluded_from_working_dir() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_up_level_relative_paths() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_autoload_rules_in_package_that_does_not_exist_on_disk() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_empty_paths() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_vendor_substring_path() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_exclude_from_classmap() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_generates_platform_check() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_absolute_symlink_with_psr4_does_not_generate_warnings() {
todo!()
}
#[test]
-#[ignore = "not yet ported (AutoloadGenerator integration: fixtures, mocked installers and generated-file comparison)"]
+#[ignore = "setUp needs mocked Config/InstallationManager/InstalledRepositoryInterface and TestCase tmp-dir helpers; no mock infra exists"]
fn test_absolute_symlink_with_classmap_exclude_from_classmap() {
todo!()
}
diff --git a/crates/shirabe/tests/autoload/class_loader_test.rs b/crates/shirabe/tests/autoload/class_loader_test.rs
index 68a0ba4..66cc3e8 100644
--- a/crates/shirabe/tests/autoload/class_loader_test.rs
+++ b/crates/shirabe/tests/autoload/class_loader_test.rs
@@ -6,7 +6,7 @@ use shirabe::autoload::class_loader::ClassLoader;
// class_exists(). There is no equivalent runtime notion of loading and defining a
// class in Rust, so this case cannot be ported faithfully.
#[test]
-#[ignore = "relies on PHP loadClass()/class_exists() runtime class loading, which has no Rust equivalent"]
+#[ignore = "depends on PHP runtime class_exists() to verify loadClass defined a class; no Rust equivalent"]
fn test_load_class() {
todo!()
}
@@ -20,7 +20,7 @@ fn test_get_prefixes_with_no_psr0_configuration() {
// In PHP this serializes the loader and unserializes it, then compares every getter.
// PHP serialize()/unserialize() has no Rust equivalent here.
#[test]
-#[ignore = "relies on PHP serialize()/unserialize() round-tripping of the ClassLoader, which is not ported"]
+#[ignore = "depends on PHP serialize()/unserialize() round-trip of ClassLoader; no Rust equivalent"]
fn test_serializability() {
todo!()
}
diff --git a/crates/shirabe/tests/cache_test.rs b/crates/shirabe/tests/cache_test.rs
index 1e346cf..2e18856 100644
--- a/crates/shirabe/tests/cache_test.rs
+++ b/crates/shirabe/tests/cache_test.rs
@@ -59,8 +59,8 @@ impl Drop for TearDown {
// In PHP these mock Cache::getFinder() to feed the gc() routine a controlled set of
// files. getFinder is pub(crate) and cannot be overridden from a test, so the
// finder-driven removal paths cannot be exercised faithfully here.
+#[ignore = "requires mocking Cache::get_finder (pub(crate), PHPUnit MockObject) to feed gc() a controlled Finder iterator; not overridable from a test"]
#[test]
-#[ignore = "mocks Cache::getFinder to drive gc(); getFinder cannot be overridden from a test"]
fn test_remove_outdated_files() {
let SetUp { root, files, cache } = set_up();
let _tear_down = TearDown::new(root.path().to_path_buf());
@@ -68,8 +68,8 @@ fn test_remove_outdated_files() {
todo!()
}
+#[ignore = "requires mocking Cache::get_finder (pub(crate), PHPUnit MockObject) to feed gc() a controlled Finder iterator; not overridable from a test"]
#[test]
-#[ignore = "mocks Cache::getFinder to drive gc(); getFinder cannot be overridden from a test"]
fn test_remove_files_when_cache_is_too_large() {
let SetUp { root, files, cache } = set_up();
let _tear_down = TearDown::new(root.path().to_path_buf());
diff --git a/crates/shirabe/tests/command/about_command_test.rs b/crates/shirabe/tests/command/about_command_test.rs
index 3f19885..591fbfa 100644
--- a/crates/shirabe/tests/command/about_command_test.rs
+++ b/crates/shirabe/tests/command/about_command_test.rs
@@ -1,7 +1,7 @@
//! ref: composer/tests/Composer/Test/Command/AboutCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester harness (TestCase::getApplicationTester), which is not yet ported"]
+#[ignore = "missing get_application_tester (ApplicationTester) infrastructure and Application::get_display/set_auto_exit"]
fn test_about() {
todo!()
}
diff --git a/crates/shirabe/tests/command/archive_command_test.rs b/crates/shirabe/tests/command/archive_command_test.rs
index b716a3c..b381129 100644
--- a/crates/shirabe/tests/command/archive_command_test.rs
+++ b/crates/shirabe/tests/command/archive_command_test.rs
@@ -1,19 +1,19 @@
//! ref: composer/tests/Composer/Test/Command/ArchiveCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires PHPUnit getMockBuilder/onlyMethods partial mock of ArchiveCommand (override tryComposer/requireComposer) plus expects()/willReturn() mocks for OutputInterface/EventDispatcher/ArchiveManager/RootPackageInterface; no mocking infrastructure exists"]
fn test_uses_config_from_composer_object() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires PHPUnit getMockBuilder/onlyMethods partial mock of ArchiveCommand (override tryComposer/archive) with expects()/with()/willReturn() expectation verification and Factory::createConfig mock OutputInterface; no mocking infrastructure exists"]
fn test_uses_config_from_factory_when_composer_is_not_defined() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires PHPUnit getMockBuilder/onlyMethods partial mock of ArchiveCommand plus expects()/willReturn() mocks for OutputInterface/EventDispatcher/ArchiveManager/InstalledRepositoryInterface/RepositoryManager; no mocking infrastructure exists"]
fn test_uses_config_from_composer_object_with_package_name() {
todo!()
}
diff --git a/crates/shirabe/tests/command/audit_command_test.rs b/crates/shirabe/tests/command/audit_command_test.rs
index 4972793..7d585d9 100644
--- a/crates/shirabe/tests/command/audit_command_test.rs
+++ b/crates/shirabe/tests/command/audit_command_test.rs
@@ -1,25 +1,25 @@
//! ref: composer/tests/Composer/Test/Command/AuditCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
fn test_successful_response_code_when_no_packages_are_required() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
fn test_error_auditing_lock_file_when_it_is_missing() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
fn test_audit_package_with_no_security_vulnerabilities() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
fn test_audit_package_with_no_dev_option_passed() {
todo!()
}
diff --git a/crates/shirabe/tests/command/base_dependency_command_test.rs b/crates/shirabe/tests/command/base_dependency_command_test.rs
index 74a8adf..a112933 100644
--- a/crates/shirabe/tests/command/base_dependency_command_test.rs
+++ b/crates/shirabe/tests/command/base_dependency_command_test.rs
@@ -1,43 +1,43 @@
//! ref: composer/tests/Composer/Test/Command/BaseDependencyCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_exception_when_no_required_parameters() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / get_application_tester helper not implemented"]
fn test_exception_when_running_locked_without_lock_file() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / get_application_tester helper not implemented"]
fn test_exception_when_it_could_not_found_the_package() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / create_installed_json / create_composer_lock / get_application_tester helpers not implemented"]
fn test_exception_when_package_was_not_found_in_project() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / create_composer_lock / get_application_tester helpers not implemented"]
fn test_warning_when_dependencies_are_not_installed() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / create_composer_lock / create_installed_json / get_application_tester helpers not implemented"]
fn test_why_command_outputs() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / create_composer_lock / create_installed_json / get_application_tester helpers not implemented"]
fn test_why_not_command_outputs() {
todo!()
}
diff --git a/crates/shirabe/tests/command/bump_command_test.rs b/crates/shirabe/tests/command/bump_command_test.rs
index a96dcc7..4e9a49c 100644
--- a/crates/shirabe/tests/command/bump_command_test.rs
+++ b/crates/shirabe/tests/command/bump_command_test.rs
@@ -1,19 +1,19 @@
//! ref: composer/tests/Composer/Test/Command/BumpCommandTest.php
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_bump() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_bump_fails_on_non_existing_composer_file() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_bump_fails_on_write_error_to_composer_file() {
todo!()
}
diff --git a/crates/shirabe/tests/command/check_platform_reqs_command_test.rs b/crates/shirabe/tests/command/check_platform_reqs_command_test.rs
index a3a6ae5..9cbba58 100644
--- a/crates/shirabe/tests/command/check_platform_reqs_command_test.rs
+++ b/crates/shirabe/tests/command/check_platform_reqs_command_test.rs
@@ -1,19 +1,19 @@
//! ref: composer/tests/Composer/Test/Command/CheckPlatformReqsCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_platform_reqs_are_satisfied() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
fn test_exception_thrown_if_no_lockfile_found() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_failed_platform_requirement() {
todo!()
}
diff --git a/crates/shirabe/tests/command/clear_cache_command_test.rs b/crates/shirabe/tests/command/clear_cache_command_test.rs
index 29a745b..4ad04dd 100644
--- a/crates/shirabe/tests/command/clear_cache_command_test.rs
+++ b/crates/shirabe/tests/command/clear_cache_command_test.rs
@@ -16,7 +16,7 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_clear_cache_command_success() {
let _tear_down = TearDown;
@@ -24,7 +24,7 @@ fn test_clear_cache_command_success() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_clear_cache_command_with_option_garbage_collection() {
let _tear_down = TearDown;
@@ -32,7 +32,7 @@ fn test_clear_cache_command_with_option_garbage_collection() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_clear_cache_command_with_option_no_cache() {
let _tear_down = TearDown;
diff --git a/crates/shirabe/tests/command/config_command_test.rs b/crates/shirabe/tests/command/config_command_test.rs
index 63bcac7..70e6a97 100644
--- a/crates/shirabe/tests/command/config_command_test.rs
+++ b/crates/shirabe/tests/command/config_command_test.rs
@@ -1,31 +1,31 @@
//! ref: composer/tests/Composer/Test/Command/ConfigCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_config_updates() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_config_reads() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester (getApplicationTester) harness (not implemented)"]
fn test_config_throws_for_invalid_arg_combination() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_config_throws_for_invalid_severity() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_config_throws_when_merging_array_with_object() {
todo!()
}
diff --git a/crates/shirabe/tests/command/diagnose_command_test.rs b/crates/shirabe/tests/command/diagnose_command_test.rs
index 4b5dc9a..a5a6c8b 100644
--- a/crates/shirabe/tests/command/diagnose_command_test.rs
+++ b/crates/shirabe/tests/command/diagnose_command_test.rs
@@ -1,13 +1,13 @@
//! ref: composer/tests/Composer/Test/Command/DiagnoseCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
fn test_cmd_fail() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
fn test_cmd_success() {
todo!()
}
diff --git a/crates/shirabe/tests/command/dump_autoload_command_test.rs b/crates/shirabe/tests/command/dump_autoload_command_test.rs
index db27ebb..b3e79b3 100644
--- a/crates/shirabe/tests/command/dump_autoload_command_test.rs
+++ b/crates/shirabe/tests/command/dump_autoload_command_test.rs
@@ -1,73 +1,73 @@
//! ref: composer/tests/Composer/Test/Command/DumpAutoloadCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_dump_autoload() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_dump_dev_autoload() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_dump_no_dev_autoload() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_using_optimize_and_strict_psr() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / get_application_tester helpers not implemented"]
fn test_fails_using_strict_psr_if_class_map_violations_are_found() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_using_classmap_authoritative() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_using_classmap_authoritative_and_strict_psr() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_strict_psr_does_not_work_without_optimized_autoloader() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "ApplicationTester / get_application_tester helper not implemented"]
fn test_dev_and_no_dev_cannot_be_combined() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / get_application_tester helpers not implemented"]
fn test_with_custom_autoloader_suffix() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / get_application_tester helpers not implemented"]
fn test_with_existing_composer_lock_and_autoloader_suffix() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / get_application_tester helpers not implemented"]
fn test_with_existing_composer_lock_without_autoloader_suffix() {
todo!()
}
diff --git a/crates/shirabe/tests/command/exec_command_test.rs b/crates/shirabe/tests/command/exec_command_test.rs
index 89963db..d182754 100644
--- a/crates/shirabe/tests/command/exec_command_test.rs
+++ b/crates/shirabe/tests/command/exec_command_test.rs
@@ -1,13 +1,13 @@
//! ref: composer/tests/Composer/Test/Command/ExecCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester with run/get_display) infrastructure"]
fn test_list_throws_if_no_binaries_exist() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester with run/get_display) infrastructure"]
fn test_list() {
todo!()
}
diff --git a/crates/shirabe/tests/command/fund_command_test.rs b/crates/shirabe/tests/command/fund_command_test.rs
index d66795f..f75090c 100644
--- a/crates/shirabe/tests/command/fund_command_test.rs
+++ b/crates/shirabe/tests/command/fund_command_test.rs
@@ -1,7 +1,7 @@
//! ref: composer/tests/Composer/Test/Command/FundCommandTest.php
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_fund_command() {
todo!()
}
diff --git a/crates/shirabe/tests/command/global_command_test.rs b/crates/shirabe/tests/command/global_command_test.rs
index 10ddf6c..0b62150 100644
--- a/crates/shirabe/tests/command/global_command_test.rs
+++ b/crates/shirabe/tests/command/global_command_test.rs
@@ -16,7 +16,7 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/getUniqueTmpDirectory harness (not implemented)"]
fn test_global() {
let _tear_down = TearDown;
@@ -24,7 +24,7 @@ fn test_global() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::getUniqueTmpDirectory harness (not implemented)"]
fn test_cannot_create_home() {
let _tear_down = TearDown;
@@ -32,7 +32,7 @@ fn test_cannot_create_home() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createInstalledJson harness (not implemented)"]
fn test_global_show() {
let _tear_down = TearDown;
@@ -40,7 +40,7 @@ fn test_global_show() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createInstalledJson harness (not implemented)"]
fn test_global_show_without_packages() {
let _tear_down = TearDown;
@@ -48,7 +48,7 @@ fn test_global_show_without_packages() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_global_require() {
let _tear_down = TearDown;
@@ -56,7 +56,7 @@ fn test_global_require() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createInstalledJson/createComposerLock harness (not implemented)"]
fn test_global_update() {
let _tear_down = TearDown;
@@ -64,7 +64,7 @@ fn test_global_update() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_global_changes_directory() {
let _tear_down = TearDown;
@@ -72,7 +72,7 @@ fn test_global_changes_directory() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_global_missing_command_name() {
let _tear_down = TearDown;
diff --git a/crates/shirabe/tests/command/home_command_test.rs b/crates/shirabe/tests/command/home_command_test.rs
index 0bb4357..b8b67d7 100644
--- a/crates/shirabe/tests/command/home_command_test.rs
+++ b/crates/shirabe/tests/command/home_command_test.rs
@@ -1,7 +1,7 @@
//! ref: composer/tests/Composer/Test/Command/HomeCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "init_temp_composer / create_installed_json / get_application_tester (ApplicationTester) helpers not implemented"]
fn test_home_command_with_show_flag() {
todo!()
}
diff --git a/crates/shirabe/tests/command/init_command_test.rs b/crates/shirabe/tests/command/init_command_test.rs
index 043011d..7c296a0 100644
--- a/crates/shirabe/tests/command/init_command_test.rs
+++ b/crates/shirabe/tests/command/init_command_test.rs
@@ -3,6 +3,7 @@
// The author/namespace/git-config helpers are protected methods exercised via reflection
// in PHP; the run cases need the ApplicationTester. Neither is available here.
+use shirabe::command::init_command::InitCommand;
use shirabe_php_shim::server_set;
fn set_up() {
@@ -10,112 +11,121 @@ fn set_up() {
server_set("COMPOSER_DEFAULT_EMAIL", "john@example.com".to_string());
}
+#[ignore = "InitCommand::parse_author_string is private; integration tests cannot reach it (PHP uses reflection)"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_parse_valid_author_string() {
set_up();
todo!()
}
+#[ignore = "InitCommand::parse_author_string is private; integration tests cannot reach it (PHP uses reflection)"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_parse_empty_author_string() {
set_up();
todo!()
}
+#[ignore = "InitCommand::parse_author_string is private; integration tests cannot reach it (PHP uses reflection)"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_parse_author_string_with_invalid_email() {
set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_namespace_from_valid_package_name() {
set_up();
- todo!()
+ let command = InitCommand::new();
+ let namespace = command.namespace_from_package_name("new_projects.acme-extra/package-name");
+ assert_eq!(
+ Some("NewProjectsAcmeExtra\\PackageName".to_string()),
+ namespace
+ );
}
+#[ignore]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_namespace_from_invalid_package_name() {
set_up();
- todo!()
+ let command = InitCommand::new();
+ let namespace = command.namespace_from_package_name("invalid-package-name");
+ assert_eq!(None, namespace);
}
+#[ignore]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_namespace_from_missing_package_name() {
set_up();
- todo!()
+ let command = InitCommand::new();
+ let namespace = command.namespace_from_package_name("");
+ assert_eq!(None, namespace);
}
+#[ignore = "needs TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure, not implemented"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_run_command() {
set_up();
todo!()
}
+#[ignore = "needs TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure, not implemented"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_run_command_invalid() {
set_up();
todo!()
}
+#[ignore = "needs TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure, not implemented"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_run_guess_name_from_dir_sanitizes_dir() {
set_up();
todo!()
}
+#[ignore = "needs TestCase::init_temp_composer and get_application_tester (ApplicationTester with set_inputs) infrastructure, not implemented"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_interactive_run() {
set_up();
todo!()
}
+#[ignore = "InitCommand::format_authors is pub(crate); integration tests cannot reach it (PHP subclasses via DummyInitCommand)"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_format_authors() {
set_up();
todo!()
}
+#[ignore = "InitCommand::get_git_config is pub(crate); integration tests cannot reach it (PHP subclasses via DummyInitCommand)"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_get_git_config() {
set_up();
todo!()
}
+#[ignore = "InitCommand::add_vendor_ignore is pub(crate) and test needs TestCase::get_unique_tmp_directory; neither reachable from integration tests"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_add_vendor_ignore() {
set_up();
todo!()
}
+#[ignore = "InitCommand::has_vendor_ignore/add_vendor_ignore are pub(crate) and test needs TestCase::get_unique_tmp_directory; neither reachable from integration tests"]
#[test]
-#[ignore = "needs the ApplicationTester harness or reflection into protected InitCommand helpers"]
fn test_has_vendor_ignore() {
set_up();
diff --git a/crates/shirabe/tests/command/install_command_test.rs b/crates/shirabe/tests/command/install_command_test.rs
index 1774721..a0586ab 100644
--- a/crates/shirabe/tests/command/install_command_test.rs
+++ b/crates/shirabe/tests/command/install_command_test.rs
@@ -1,25 +1,25 @@
//! ref: composer/tests/Composer/Test/Command/InstallCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock/createInstalledJson harness (not implemented)"]
fn test_install_command_errors() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock harness (not implemented)"]
fn test_install_from_empty_vendor() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock harness (not implemented)"]
fn test_install_from_empty_vendor_no_dev() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock/createInstalledJson harness (not implemented)"]
fn test_install_new_packages_with_existing_partial_vendor() {
todo!()
}
diff --git a/crates/shirabe/tests/command/licenses_command_test.rs b/crates/shirabe/tests/command/licenses_command_test.rs
index 113a77e..6bfe832 100644
--- a/crates/shirabe/tests/command/licenses_command_test.rs
+++ b/crates/shirabe/tests/command/licenses_command_test.rs
@@ -7,7 +7,7 @@ fn set_up() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_installed_json / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_basic_run() {
set_up();
@@ -15,7 +15,7 @@ fn test_basic_run() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_installed_json / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_no_dev() {
set_up();
@@ -23,7 +23,7 @@ fn test_no_dev() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_installed_json / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_format_json() {
set_up();
@@ -31,7 +31,7 @@ fn test_format_json() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_installed_json / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_format_summary() {
set_up();
@@ -39,7 +39,7 @@ fn test_format_summary() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_installed_json / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_format_unknown() {
set_up();
@@ -47,7 +47,7 @@ fn test_format_unknown() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_installed_json / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_locked() {
set_up();
@@ -55,7 +55,7 @@ fn test_locked() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_installed_json / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_locked_no_dev() {
set_up();
@@ -63,7 +63,7 @@ fn test_locked_no_dev() {
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_installed_json / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_locked_without_lock_file() {
set_up();
diff --git a/crates/shirabe/tests/command/reinstall_command_test.rs b/crates/shirabe/tests/command/reinstall_command_test.rs
index df0b618..b420fd5 100644
--- a/crates/shirabe/tests/command/reinstall_command_test.rs
+++ b/crates/shirabe/tests/command/reinstall_command_test.rs
@@ -1,7 +1,7 @@
//! ref: composer/tests/Composer/Test/Command/ReinstallCommandTest.php
+#[ignore = "missing TestCase::init_temp_composer, create_composer_lock, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_reinstall_command() {
todo!()
}
diff --git a/crates/shirabe/tests/command/remove_command_test.rs b/crates/shirabe/tests/command/remove_command_test.rs
index 297d136..2ea8c88 100644
--- a/crates/shirabe/tests/command/remove_command_test.rs
+++ b/crates/shirabe/tests/command/remove_command_test.rs
@@ -1,97 +1,97 @@
//! ref: composer/tests/Composer/Test/Command/RemoveCommandTest.php
+#[ignore = "missing TestCase::get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_exception_running_with_no_remove_packages() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_exception_when_running_unused_without_lock_file() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_warning_when_removing_non_existent_package() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_warning_when_removing_package_from_wrong_type() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_warning_when_removing_package_with_deprecated_dependencies_flag() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_message_output_when_no_unused_packages_to_remove() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_remove_unused_package() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_remove_package_by_name() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_remove_package_by_name_with_dry_run() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_remove_allowed_plugin_package_with_no_other_allowed_plugins() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_remove_allowed_plugin_package_with_other_allowed_plugins() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_remove_packages_by_vendor() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_remove_packages_by_vendor_with_dry_run() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_warning_when_removing_packages_by_vendor_from_wrong_type() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_package_still_present_error_when_no_install_flag_used() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_update_inherited_dependencies_flag_is_passed_to_post_remove_installer() {
todo!()
}
diff --git a/crates/shirabe/tests/command/repository_command_test.rs b/crates/shirabe/tests/command/repository_command_test.rs
index 33a4451..dd7a4bf 100644
--- a/crates/shirabe/tests/command/repository_command_test.rs
+++ b/crates/shirabe/tests/command/repository_command_test.rs
@@ -1,97 +1,97 @@
//! ref: composer/tests/Composer/Test/Command/RepositoryCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_list_with_no_repositories() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_list_with_repositories_as_list() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_list_with_repositories_as_assoc() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_add_repository_with_type_and_url() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_add_repository_with_json() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_remove_repository() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_set_and_get_url_in_repository_assoc() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_set_and_get_url_in_repository_list() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_disable_and_enable_packagist() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_invalid_arg_combination_throws() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_prepend_repository_by_name_list_to_assoc() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_append_repository_by_name_list_to_assoc() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_prepend_repository_assoc_with_packagist_disabled() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_append_repository_assoc_with_packagist_disabled() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_add_before_and_after_by_name() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"]
fn test_add_same_name_replaces_existing() {
todo!()
}
diff --git a/crates/shirabe/tests/command/require_command_test.rs b/crates/shirabe/tests/command/require_command_test.rs
index 470bbe2..0f43342 100644
--- a/crates/shirabe/tests/command/require_command_test.rs
+++ b/crates/shirabe/tests/command/require_command_test.rs
@@ -1,25 +1,25 @@
//! ref: composer/tests/Composer/Test/Command/RequireCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/getApplicationTester harness (not implemented)"]
fn test_require_throws_if_none_matches() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/getApplicationTester/setInputs harness (not implemented)"]
fn test_require_warns_if_resolved_to_feature_branch() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/getApplicationTester harness (not implemented)"]
fn test_require() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock/createInstalledJson/getApplicationTester harness (not implemented)"]
fn test_inconsistent_require_keys() {
todo!()
}
diff --git a/crates/shirabe/tests/command/run_script_command_test.rs b/crates/shirabe/tests/command/run_script_command_test.rs
index 14766d4..366ee96 100644
--- a/crates/shirabe/tests/command/run_script_command_test.rs
+++ b/crates/shirabe/tests/command/run_script_command_test.rs
@@ -1,31 +1,31 @@
//! ref: composer/tests/Composer/Test/Command/RunScriptCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires PHPUnit getMockBuilder/onlyMethods partial mock of RunScriptCommand (override requireComposer/initialize/etc) plus expects()/with()/willReturn()/returnValueMap mocks of InputInterface/OutputInterface/EventDispatcher with a callback constraint on ScriptEvent; no mocking infrastructure exists"]
fn test_detect_and_pass_dev_mode_to_event_and_to_dispatching() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires init_temp_composer and get_application_tester (ApplicationTester) infrastructure; neither exists"]
fn test_can_list_scripts() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires init_temp_composer and get_application_tester (ApplicationTester) infrastructure; neither exists"]
fn test_can_define_aliases() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires init_temp_composer/get_application_tester (ApplicationTester) plus writing and executing a PHP-generated Symfony Command class (file_put_contents MyCommand.php); fundamentally unportable, no infrastructure exists"]
fn test_execution_of_simple_symfony_command() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires init_temp_composer/get_application_tester (ApplicationTester) plus writing and executing a PHP-generated Symfony Command class (file_put_contents MyCommandWithDefinitions.php); fundamentally unportable, no infrastructure exists"]
fn test_execution_of_symfony_command_with_configuration() {
todo!()
}
diff --git a/crates/shirabe/tests/command/search_command_test.rs b/crates/shirabe/tests/command/search_command_test.rs
index d5b6a76..5cad1eb 100644
--- a/crates/shirabe/tests/command/search_command_test.rs
+++ b/crates/shirabe/tests/command/search_command_test.rs
@@ -1,19 +1,19 @@
//! ref: composer/tests/Composer/Test/Command/SearchCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
fn test_search() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
fn test_invalid_format() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
fn test_invalid_flags() {
todo!()
}
diff --git a/crates/shirabe/tests/command/self_update_command_test.rs b/crates/shirabe/tests/command/self_update_command_test.rs
index d741302..8e51580 100644
--- a/crates/shirabe/tests/command/self_update_command_test.rs
+++ b/crates/shirabe/tests/command/self_update_command_test.rs
@@ -7,7 +7,7 @@ fn set_up() -> String {
}
#[test]
-#[ignore = "requires the ApplicationTester harness, which is not yet ported"]
+#[ignore = "depends on initTempComposer, composer-test.phar fixture, and Symfony Process to spawn the phar; none ported"]
fn test_successful_update() {
let _phar = set_up();
@@ -15,7 +15,7 @@ fn test_successful_update() {
}
#[test]
-#[ignore = "requires the ApplicationTester harness, which is not yet ported"]
+#[ignore = "depends on initTempComposer, composer-test.phar fixture, and Symfony Process to spawn the phar; none ported"]
fn test_update_to_specific_version() {
let _phar = set_up();
@@ -23,7 +23,7 @@ fn test_update_to_specific_version() {
}
#[test]
-#[ignore = "requires the ApplicationTester harness, which is not yet ported"]
+#[ignore = "depends on getApplicationTester (ApplicationTester) which is not ported"]
fn test_update_with_invalid_option_throws_exception() {
let _phar = set_up();
@@ -31,7 +31,7 @@ fn test_update_with_invalid_option_throws_exception() {
}
#[test]
-#[ignore = "requires the ApplicationTester harness, which is not yet ported"]
+#[ignore = "depends on initTempComposer, composer-test.phar fixture, and Symfony Process to spawn the phar; none ported"]
fn test_update_to_different_channel() {
let _phar = set_up();
diff --git a/crates/shirabe/tests/command/show_command_test.rs b/crates/shirabe/tests/command/show_command_test.rs
index b17ce22..56e8106 100644
--- a/crates/shirabe/tests/command/show_command_test.rs
+++ b/crates/shirabe/tests/command/show_command_test.rs
@@ -1,139 +1,139 @@
//! ref: composer/tests/Composer/Test/Command/ShowCommandTest.php
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_show() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_outdated_filters_according_to_platform_reqs_and_warns() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_outdated_filters_according_to_platform_reqs_without_warning_for_higher_versions() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, configure_links, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_show_direct_with_name_does_not_show_transient_dependencies() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_show_direct_with_name_only_shows_direct_dependents() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_show_platform_only_shows_platform_packages() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_show_platform_works_without_composer_json() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_outdated_with_zero_major() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_show_all_shows_all_sections() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_locked_requires_valid_lock_file() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_locked_shows_all_locked() {
todo!()
}
+#[ignore = "missing TestCase::get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_invalid_option_combinations() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_ignored_option_combinations() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_self_and_name_only() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_self_and_package_combination() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_self() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_not_installed_error() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_no_dev_option() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_package_filter() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_not_existing_package() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_not_existing_package_with_working_dir() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_specific_package_and_tree() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_name_only_prints_no_trailing_whitespace() {
todo!()
}
diff --git a/crates/shirabe/tests/command/status_command_test.rs b/crates/shirabe/tests/command/status_command_test.rs
index 6b8dcf6..6154ea0 100644
--- a/crates/shirabe/tests/command/status_command_test.rs
+++ b/crates/shirabe/tests/command/status_command_test.rs
@@ -1,13 +1,13 @@
//! ref: composer/tests/Composer/Test/Command/StatusCommandTest.php
+#[ignore = "missing TestCase::init_temp_composer, create_composer_lock, create_installed_json, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_no_local_changes() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_locally_modified_packages() {
todo!()
}
diff --git a/crates/shirabe/tests/command/suggests_command_test.rs b/crates/shirabe/tests/command/suggests_command_test.rs
index ca4d9a2..c23691b 100644
--- a/crates/shirabe/tests/command/suggests_command_test.rs
+++ b/crates/shirabe/tests/command/suggests_command_test.rs
@@ -1,13 +1,13 @@
//! ref: composer/tests/Composer/Test/Command/SuggestsCommandTest.php
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, and get_application_tester (ApplicationTester) infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_installed_packages_with_no_suggestions() {
todo!()
}
+#[ignore = "missing TestCase::init_temp_composer, create_installed_json, create_composer_lock, get_application_tester (ApplicationTester), and get_version_parser infrastructure"]
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
fn test_suggest() {
todo!()
}
diff --git a/crates/shirabe/tests/command/update_command_test.rs b/crates/shirabe/tests/command/update_command_test.rs
index ceae0eb..95b6962 100644
--- a/crates/shirabe/tests/command/update_command_test.rs
+++ b/crates/shirabe/tests/command/update_command_test.rs
@@ -1,43 +1,43 @@
//! ref: composer/tests/Composer/Test/Command/UpdateCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock harness (not implemented)"]
fn test_update() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock harness (not implemented)"]
fn test_update_with_patch_only() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock harness (not implemented)"]
fn test_interactive_mode_throws_if_no_package_to_update() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock harness (not implemented)"]
fn test_interactive_mode_throws_if_no_package_entered() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer/createComposerLock/createInstalledJson harness (not implemented)"]
fn test_interactive_tmp() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_no_security_blocking_allows_insecure_packages() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "requires ApplicationTester and TestCase::initTempComposer harness (not implemented)"]
fn test_bump_after_update_without_lockfile() {
todo!()
}
diff --git a/crates/shirabe/tests/command/validate_command_test.rs b/crates/shirabe/tests/command/validate_command_test.rs
index 26af2ae..b306100 100644
--- a/crates/shirabe/tests/command/validate_command_test.rs
+++ b/crates/shirabe/tests/command/validate_command_test.rs
@@ -1,25 +1,25 @@
//! ref: composer/tests/Composer/Test/Command/ValidateCommandTest.php
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester with run/get_display) infrastructure"]
fn test_validate() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester with run/get_display) infrastructure"]
fn test_validate_on_file_issues() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer / create_composer_lock and get_application_tester (ApplicationTester) infrastructure"]
fn test_with_composer_lock() {
todo!()
}
#[test]
-#[ignore = "requires the ApplicationTester/initTempComposer harness, which is not yet ported"]
+#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester with run/get_display/get_status_code) infrastructure"]
fn test_unaccessible_file() {
todo!()
}
diff --git a/crates/shirabe/tests/completion_functional_test.rs b/crates/shirabe/tests/completion_functional_test.rs
index 9dc0482..06f8dd8 100644
--- a/crates/shirabe/tests/completion_functional_test.rs
+++ b/crates/shirabe/tests/completion_functional_test.rs
@@ -1,7 +1,7 @@
//! ref: composer/tests/Composer/Test/CompletionFunctionalTest.php
#[test]
-#[ignore = "requires the console completion harness (Application + CompletionInput), which is not yet ported"]
+#[ignore = "CommandCompletionTester (Symfony Console test helper) is not implemented in the port"]
fn test_complete() {
todo!()
}
diff --git a/crates/shirabe/tests/config/json_config_source_test.rs b/crates/shirabe/tests/config/json_config_source_test.rs
index b8abf57..974c5da 100644
--- a/crates/shirabe/tests/config/json_config_source_test.rs
+++ b/crates/shirabe/tests/config/json_config_source_test.rs
@@ -1,7 +1,14 @@
//! ref: composer/tests/Composer/Test/Config/JsonConfigSourceTest.php
+use indexmap::IndexMap;
+use shirabe::config::ConfigSourceInterface;
+use shirabe::config::JsonConfigSource;
+use shirabe::json::JsonFile;
use shirabe::util::filesystem::Filesystem;
+use shirabe_php_shim::PhpMixed;
+use std::cell::RefCell;
use std::path::PathBuf;
+use std::rc::Rc;
use tempfile::TempDir;
fn set_up() -> TearDown {
@@ -31,58 +38,455 @@ impl Drop for TearDown {
}
}
+fn fixture_path(name: &str) -> PathBuf {
+ PathBuf::from(format!(
+ "{}/../../composer/tests/Composer/Test/Config/Fixtures/{}",
+ env!("CARGO_MANIFEST_DIR"),
+ name
+ ))
+}
+
+fn assert_file_equals(expected: &std::path::Path, actual: &std::path::Path) {
+ let expected_contents = std::fs::read(expected).unwrap();
+ let actual_contents = std::fs::read(actual).unwrap();
+ assert_eq!(
+ expected_contents, actual_contents,
+ "Failed asserting that file {:?} matches {:?}",
+ actual, expected
+ );
+}
+
+fn json_config_source(config: &std::path::Path) -> JsonConfigSource {
+ let json_file = JsonFile::new(config.to_string_lossy().to_string(), None, None).unwrap();
+ JsonConfigSource::new(Rc::new(RefCell::new(json_file)), false)
+}
+
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_add_repository() {
- let _tear_down = set_up();
- todo!()
+ let tear_down = set_up();
+ let config = tear_down.working_dir().join("composer.json");
+ std::fs::copy(fixture_path("composer-repositories.json"), &config).unwrap();
+ let mut json_config_source = json_config_source(&config);
+
+ let mut repo = IndexMap::new();
+ repo.insert("type".to_string(), PhpMixed::String("git".to_string()));
+ repo.insert(
+ "url".to_string(),
+ PhpMixed::String("example.tld".to_string()),
+ );
+ json_config_source
+ .add_repository("example_tld", PhpMixed::Array(repo), true)
+ .unwrap();
+
+ assert_file_equals(
+ &fixture_path("config/config-with-exampletld-repository.json"),
+ &config,
+ );
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_add_repository_as_list() {
- let _tear_down = set_up();
- todo!()
+ let tear_down = set_up();
+ let config = tear_down.working_dir().join("composer.json");
+ std::fs::copy(fixture_path("composer-repositories.json"), &config).unwrap();
+ let mut json_config_source = json_config_source(&config);
+
+ let mut repo = IndexMap::new();
+ repo.insert("type".to_string(), PhpMixed::String("git".to_string()));
+ repo.insert(
+ "url".to_string(),
+ PhpMixed::String("example.tld".to_string()),
+ );
+ json_config_source
+ .add_repository("", PhpMixed::Array(repo), true)
+ .unwrap();
+
+ assert_file_equals(
+ &fixture_path("config/config-with-exampletld-repository-as-list.json"),
+ &config,
+ );
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_add_repository_with_options() {
- let _tear_down = set_up();
- todo!()
+ let tear_down = set_up();
+ let config = tear_down.working_dir().join("composer.json");
+ std::fs::copy(fixture_path("composer-repositories.json"), &config).unwrap();
+ let mut json_config_source = json_config_source(&config);
+
+ let mut repo = IndexMap::new();
+ repo.insert("type".to_string(), PhpMixed::String("composer".to_string()));
+ repo.insert(
+ "url".to_string(),
+ PhpMixed::String("https://example.tld".to_string()),
+ );
+ {
+ let mut local_cert = IndexMap::new();
+ local_cert.insert(
+ "local_cert".to_string(),
+ PhpMixed::String("/home/composer/.ssl/composer.pem".to_string()),
+ );
+ let mut ssl = IndexMap::new();
+ ssl.insert("ssl".to_string(), PhpMixed::Array(local_cert));
+ repo.insert("options".to_string(), PhpMixed::Array(ssl));
+ }
+
+ json_config_source
+ .add_repository("example_tld", PhpMixed::Array(repo), true)
+ .unwrap();
+
+ assert_file_equals(
+ &fixture_path("config/config-with-exampletld-repository-and-options.json"),
+ &config,
+ );
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_remove_repository() {
- let _tear_down = set_up();
- todo!()
+ let tear_down = set_up();
+ let config = tear_down.working_dir().join("composer.json");
+ std::fs::copy(
+ fixture_path("config/config-with-exampletld-repository.json"),
+ &config,
+ )
+ .unwrap();
+ let mut json_config_source = json_config_source(&config);
+ json_config_source.remove_repository("example_tld").unwrap();
+
+ assert_file_equals(&fixture_path("composer-empty.json"), &config);
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_add_packagist_repository_with_false_value() {
- let _tear_down = set_up();
- todo!()
+ let tear_down = set_up();
+ let config = tear_down.working_dir().join("composer.json");
+ std::fs::copy(fixture_path("composer-repositories.json"), &config).unwrap();
+ let mut json_config_source = json_config_source(&config);
+ json_config_source
+ .add_repository("packagist", PhpMixed::Bool(false), true)
+ .unwrap();
+
+ assert_file_equals(
+ &fixture_path("config/config-with-packagist-false.json"),
+ &config,
+ );
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_remove_packagist() {
- let _tear_down = set_up();
- todo!()
+ let tear_down = set_up();
+ let config = tear_down.working_dir().join("composer.json");
+ std::fs::copy(
+ fixture_path("config/config-with-packagist-false.json"),
+ &config,
+ )
+ .unwrap();
+ let mut json_config_source = json_config_source(&config);
+ json_config_source.remove_repository("packagist").unwrap();
+
+ assert_file_equals(&fixture_path("composer-empty.json"), &config);
+}
+
+/// Mirror of provideAddLinkData(): (sourceFile, type, name, value, compareAgainst).
+fn provide_add_link_data() -> Vec<(PathBuf, &'static str, &'static str, &'static str, PathBuf)> {
+ let empty = fixture_path("composer-empty.json");
+ let one_of_everything = fixture_path("composer-one-of-everything.json");
+ let two_of_everything = fixture_path("composer-two-of-everything.json");
+
+ let add_link_data_arguments = |r#type: &'static str,
+ name: &'static str,
+ value: &'static str,
+ fixture_basename: &str,
+ before: &PathBuf| {
+ (
+ before.clone(),
+ r#type,
+ name,
+ value,
+ fixture_path(&format!("addLink/{}.json", fixture_basename)),
+ )
+ };
+
+ vec![
+ add_link_data_arguments(
+ "require",
+ "my-vend/my-lib",
+ "1.*",
+ "require-from-empty",
+ &empty,
+ ),
+ add_link_data_arguments(
+ "require",
+ "my-vend/my-lib",
+ "1.*",
+ "require-from-oneOfEverything",
+ &one_of_everything,
+ ),
+ add_link_data_arguments(
+ "require",
+ "my-vend/my-lib",
+ "1.*",
+ "require-from-twoOfEverything",
+ &two_of_everything,
+ ),
+ add_link_data_arguments(
+ "require-dev",
+ "my-vend/my-lib-tests",
+ "1.*",
+ "require-dev-from-empty",
+ &empty,
+ ),
+ add_link_data_arguments(
+ "require-dev",
+ "my-vend/my-lib-tests",
+ "1.*",
+ "require-dev-from-oneOfEverything",
+ &one_of_everything,
+ ),
+ add_link_data_arguments(
+ "require-dev",
+ "my-vend/my-lib-tests",
+ "1.*",
+ "require-dev-from-twoOfEverything",
+ &two_of_everything,
+ ),
+ add_link_data_arguments(
+ "provide",
+ "my-vend/my-lib-interface",
+ "1.*",
+ "provide-from-empty",
+ &empty,
+ ),
+ add_link_data_arguments(
+ "provide",
+ "my-vend/my-lib-interface",
+ "1.*",
+ "provide-from-oneOfEverything",
+ &one_of_everything,
+ ),
+ add_link_data_arguments(
+ "provide",
+ "my-vend/my-lib-interface",
+ "1.*",
+ "provide-from-twoOfEverything",
+ &two_of_everything,
+ ),
+ add_link_data_arguments(
+ "suggest",
+ "my-vend/my-optional-extension",
+ "1.*",
+ "suggest-from-empty",
+ &empty,
+ ),
+ add_link_data_arguments(
+ "suggest",
+ "my-vend/my-optional-extension",
+ "1.*",
+ "suggest-from-oneOfEverything",
+ &one_of_everything,
+ ),
+ add_link_data_arguments(
+ "suggest",
+ "my-vend/my-optional-extension",
+ "1.*",
+ "suggest-from-twoOfEverything",
+ &two_of_everything,
+ ),
+ add_link_data_arguments(
+ "replace",
+ "my-vend/other-app",
+ "1.*",
+ "replace-from-empty",
+ &empty,
+ ),
+ add_link_data_arguments(
+ "replace",
+ "my-vend/other-app",
+ "1.*",
+ "replace-from-oneOfEverything",
+ &one_of_everything,
+ ),
+ add_link_data_arguments(
+ "replace",
+ "my-vend/other-app",
+ "1.*",
+ "replace-from-twoOfEverything",
+ &two_of_everything,
+ ),
+ add_link_data_arguments(
+ "conflict",
+ "my-vend/my-old-app",
+ "1.*",
+ "conflict-from-empty",
+ &empty,
+ ),
+ add_link_data_arguments(
+ "conflict",
+ "my-vend/my-old-app",
+ "1.*",
+ "conflict-from-oneOfEverything",
+ &one_of_everything,
+ ),
+ add_link_data_arguments(
+ "conflict",
+ "my-vend/my-old-app",
+ "1.*",
+ "conflict-from-twoOfEverything",
+ &two_of_everything,
+ ),
+ ]
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_add_link() {
- let _tear_down = set_up();
- todo!()
+ for (source_file, r#type, name, value, compare_against) in provide_add_link_data() {
+ let tear_down = set_up();
+ let composer_json = tear_down.working_dir().join("composer.json");
+ std::fs::copy(&source_file, &composer_json).unwrap();
+ let mut json_config_source = json_config_source(&composer_json);
+
+ json_config_source.add_link(r#type, name, value).unwrap();
+
+ assert_file_equals(&compare_against, &composer_json);
+ }
}
+/// Mirror of provideRemoveLinkData(): (sourceFile, type, name, compareAgainst).
+fn provide_remove_link_data() -> Vec<(PathBuf, &'static str, &'static str, PathBuf)> {
+ let one_of_everything = fixture_path("composer-one-of-everything.json");
+ let two_of_everything = fixture_path("composer-two-of-everything.json");
+
+ let remove_link_data_arguments =
+ |r#type: &'static str,
+ name: &'static str,
+ fixture_basename: &str,
+ after: Option<&PathBuf>| {
+ let after = after.cloned().unwrap_or_else(|| {
+ fixture_path(&format!("removeLink/{}-after.json", fixture_basename))
+ });
+ (
+ fixture_path(&format!("removeLink/{}.json", fixture_basename)),
+ r#type,
+ name,
+ after,
+ )
+ };
+
+ vec![
+ remove_link_data_arguments("require", "my-vend/my-lib", "require-to-empty", None),
+ remove_link_data_arguments(
+ "require",
+ "my-vend/my-lib",
+ "require-to-oneOfEverything",
+ Some(&one_of_everything),
+ ),
+ remove_link_data_arguments(
+ "require",
+ "my-vend/my-lib",
+ "require-to-twoOfEverything",
+ Some(&two_of_everything),
+ ),
+ remove_link_data_arguments(
+ "require-dev",
+ "my-vend/my-lib-tests",
+ "require-dev-to-empty",
+ None,
+ ),
+ remove_link_data_arguments(
+ "require-dev",
+ "my-vend/my-lib-tests",
+ "require-dev-to-oneOfEverything",
+ Some(&one_of_everything),
+ ),
+ remove_link_data_arguments(
+ "require-dev",
+ "my-vend/my-lib-tests",
+ "require-dev-to-twoOfEverything",
+ Some(&two_of_everything),
+ ),
+ remove_link_data_arguments(
+ "provide",
+ "my-vend/my-lib-interface",
+ "provide-to-empty",
+ None,
+ ),
+ remove_link_data_arguments(
+ "provide",
+ "my-vend/my-lib-interface",
+ "provide-to-oneOfEverything",
+ Some(&one_of_everything),
+ ),
+ remove_link_data_arguments(
+ "provide",
+ "my-vend/my-lib-interface",
+ "provide-to-twoOfEverything",
+ Some(&two_of_everything),
+ ),
+ remove_link_data_arguments(
+ "suggest",
+ "my-vend/my-optional-extension",
+ "suggest-to-empty",
+ None,
+ ),
+ remove_link_data_arguments(
+ "suggest",
+ "my-vend/my-optional-extension",
+ "suggest-to-oneOfEverything",
+ Some(&one_of_everything),
+ ),
+ remove_link_data_arguments(
+ "suggest",
+ "my-vend/my-optional-extension",
+ "suggest-to-twoOfEverything",
+ Some(&two_of_everything),
+ ),
+ remove_link_data_arguments("replace", "my-vend/other-app", "replace-to-empty", None),
+ remove_link_data_arguments(
+ "replace",
+ "my-vend/other-app",
+ "replace-to-oneOfEverything",
+ Some(&one_of_everything),
+ ),
+ remove_link_data_arguments(
+ "replace",
+ "my-vend/other-app",
+ "replace-to-twoOfEverything",
+ Some(&two_of_everything),
+ ),
+ remove_link_data_arguments("conflict", "my-vend/my-old-app", "conflict-to-empty", None),
+ remove_link_data_arguments(
+ "conflict",
+ "my-vend/my-old-app",
+ "conflict-to-oneOfEverything",
+ Some(&one_of_everything),
+ ),
+ remove_link_data_arguments(
+ "conflict",
+ "my-vend/my-old-app",
+ "conflict-to-twoOfEverything",
+ Some(&two_of_everything),
+ ),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_remove_link() {
- let _tear_down = set_up();
- todo!()
+ for (source_file, r#type, name, compare_against) in provide_remove_link_data() {
+ let tear_down = set_up();
+ let composer_json = tear_down.working_dir().join("composer.json");
+ std::fs::copy(&source_file, &composer_json).unwrap();
+ let mut json_config_source = json_config_source(&composer_json);
+
+ json_config_source.remove_link(r#type, name).unwrap();
+
+ assert_file_equals(&compare_against, &composer_json);
+ }
}
diff --git a/crates/shirabe/tests/config_test.rs b/crates/shirabe/tests/config_test.rs
index b91237e..956e76b 100644
--- a/crates/shirabe/tests/config_test.rs
+++ b/crates/shirabe/tests/config_test.rs
@@ -1,9 +1,26 @@
//! ref: composer/tests/Composer/Test/ConfigTest.php
use indexmap::IndexMap;
+use shirabe::advisory::Auditor;
use shirabe::config::Config;
+use shirabe::util::Platform;
use shirabe_php_shim::PhpMixed;
+/// Builds a `['config' => {...}]` map for `Config::merge`.
+fn config_section(pairs: Vec<(&str, PhpMixed)>) -> IndexMap<String, PhpMixed> {
+ let mut m: IndexMap<String, PhpMixed> = IndexMap::new();
+ m.insert("config".to_string(), PhpMixed::Array(map(pairs)));
+ m
+}
+
+/// PHP assertEquals on associative arrays compares pairs irrespective of order.
+fn assert_map_equals(expected: &IndexMap<String, PhpMixed>, actual: &IndexMap<String, PhpMixed>) {
+ assert_eq!(expected.len(), actual.len());
+ for (key, value) in expected {
+ assert_eq!(Some(value), actual.get(key), "key {key:?}");
+ }
+}
+
fn repo(r#type: &str, url: &str) -> PhpMixed {
let mut m: IndexMap<String, PhpMixed> = IndexMap::new();
m.insert("type".to_string(), PhpMixed::String(r#type.to_string()));
@@ -166,134 +183,588 @@ fn test_add_packagist_repository() {
// htaccess-protect, var/realpath replacement, oauth, audit, ...) without the env isolation
// their setUp/tearDown provides, or exercise plugin-config merge details. They are not
// ported yet.
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_preferred_install_as_string() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![(
+ "preferred-install",
+ PhpMixed::String("source".to_string()),
+ )]),
+ "test",
+ );
+ config.merge(
+ &config_section(vec![(
+ "preferred-install",
+ PhpMixed::String("dist".to_string()),
+ )]),
+ "test",
+ );
+
+ assert_eq!(
+ PhpMixed::String("dist".to_string()),
+ config.get("preferred-install")
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_merge_preferred_install() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![(
+ "preferred-install",
+ PhpMixed::String("dist".to_string()),
+ )]),
+ "test",
+ );
+ config.merge(
+ &config_section(vec![(
+ "preferred-install",
+ PhpMixed::Array(map(vec![("foo/*", PhpMixed::String("source".to_string()))])),
+ )]),
+ "test",
+ );
+
+ // This assertion needs to make sure full wildcard preferences are placed last
+ // Handled by composer because we convert string preferences for BC, all other
+ // care for ordering and collision prevention is up to the user
+ let expected = map(vec![
+ ("foo/*", PhpMixed::String("source".to_string())),
+ ("*", PhpMixed::String("dist".to_string())),
+ ]);
+ match config.get("preferred-install") {
+ PhpMixed::Array(actual) => assert_map_equals(&expected, &actual),
+ other => panic!("expected array, got {other:?}"),
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_merge_github_oauth() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![(
+ "github-oauth",
+ PhpMixed::Array(map(vec![("foo", PhpMixed::String("bar".to_string()))])),
+ )]),
+ "test",
+ );
+ config.merge(
+ &config_section(vec![(
+ "github-oauth",
+ PhpMixed::Array(map(vec![("bar", PhpMixed::String("baz".to_string()))])),
+ )]),
+ "test",
+ );
+
+ let expected = map(vec![
+ ("foo", PhpMixed::String("bar".to_string())),
+ ("bar", PhpMixed::String("baz".to_string())),
+ ]);
+ match config.get("github-oauth") {
+ PhpMixed::Array(actual) => assert_map_equals(&expected, &actual),
+ other => panic!("expected array, got {other:?}"),
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_var_replacement() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![
+ ("a", PhpMixed::String("b".to_string())),
+ ("c", PhpMixed::String("{$a}".to_string())),
+ ]),
+ "test",
+ );
+ config.merge(
+ &config_section(vec![
+ ("bin-dir", PhpMixed::String("$HOME".to_string())),
+ ("cache-dir", PhpMixed::String("~/foo/".to_string())),
+ ]),
+ "test",
+ );
+
+ let home_raw = Platform::get_env("HOME")
+ .filter(|s| !s.is_empty())
+ .or_else(|| Platform::get_env("USERPROFILE"))
+ .unwrap_or_default();
+ let home = home_raw.trim_end_matches(['\\', '/']).to_string();
+ assert_eq!(PhpMixed::String("b".to_string()), config.get("c"));
+ assert_eq!(PhpMixed::String(home.clone()), config.get("bin-dir"));
+ assert_eq!(
+ PhpMixed::String(format!("{}/foo", home)),
+ config.get("cache-dir")
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_realpath_replacement() {
- todo!()
+ let mut config = Config::new(false, Some("/foo/bar".to_string()));
+ config.merge(
+ &config_section(vec![
+ ("bin-dir", PhpMixed::String("$HOME/foo".to_string())),
+ ("cache-dir", PhpMixed::String("/baz/".to_string())),
+ ("vendor-dir", PhpMixed::String("vendor".to_string())),
+ ]),
+ "test",
+ );
+
+ let home_raw = Platform::get_env("HOME")
+ .filter(|s| !s.is_empty())
+ .or_else(|| Platform::get_env("USERPROFILE"))
+ .unwrap_or_default();
+ let home = home_raw.trim_end_matches(['\\', '/']).to_string();
+ assert_eq!(
+ PhpMixed::String("/foo/bar/vendor".to_string()),
+ config.get("vendor-dir")
+ );
+ assert_eq!(
+ PhpMixed::String(format!("{}/foo", home)),
+ config.get("bin-dir")
+ );
+ assert_eq!(
+ PhpMixed::String("/baz".to_string()),
+ config.get("cache-dir")
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_stream_wrapper_dirs() {
- todo!()
+ let mut config = Config::new(false, Some("/foo/bar".to_string()));
+ config.merge(
+ &config_section(vec![(
+ "cache-dir",
+ PhpMixed::String("s3://baz/".to_string()),
+ )]),
+ "test",
+ );
+
+ assert_eq!(
+ PhpMixed::String("s3://baz".to_string()),
+ config.get("cache-dir")
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_fetching_relative_paths() {
- todo!()
+ let mut config = Config::new(false, Some("/foo/bar".to_string()));
+ config.merge(
+ &config_section(vec![
+ ("bin-dir", PhpMixed::String("{$vendor-dir}/foo".to_string())),
+ ("vendor-dir", PhpMixed::String("vendor".to_string())),
+ ]),
+ "test",
+ );
+
+ assert_eq!(
+ PhpMixed::String("/foo/bar/vendor".to_string()),
+ config.get("vendor-dir")
+ );
+ assert_eq!(
+ PhpMixed::String("/foo/bar/vendor/foo".to_string()),
+ config.get("bin-dir")
+ );
+ assert_eq!(
+ PhpMixed::String("vendor".to_string()),
+ config
+ .get_with_flags("vendor-dir", Config::RELATIVE_PATHS)
+ .unwrap()
+ );
+ assert_eq!(
+ PhpMixed::String("vendor/foo".to_string()),
+ config
+ .get_with_flags("bin-dir", Config::RELATIVE_PATHS)
+ .unwrap()
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_override_github_protocols() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![(
+ "github-protocols",
+ PhpMixed::List(vec![
+ PhpMixed::String("https".to_string()),
+ PhpMixed::String("ssh".to_string()),
+ ]),
+ )]),
+ "test",
+ );
+ config.merge(
+ &config_section(vec![(
+ "github-protocols",
+ PhpMixed::List(vec![PhpMixed::String("https".to_string())]),
+ )]),
+ "test",
+ );
+
+ assert_eq!(
+ PhpMixed::List(vec![PhpMixed::String("https".to_string())]),
+ config.get("github-protocols")
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_git_disabled_by_default_in_github_protocols() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![(
+ "github-protocols",
+ PhpMixed::List(vec![
+ PhpMixed::String("https".to_string()),
+ PhpMixed::String("git".to_string()),
+ ]),
+ )]),
+ "test",
+ );
+ assert_eq!(
+ PhpMixed::List(vec![PhpMixed::String("https".to_string())]),
+ config.get("github-protocols")
+ );
+
+ config.merge(
+ &config_section(vec![("secure-http", PhpMixed::Bool(false))]),
+ "test",
+ );
+ assert_eq!(
+ PhpMixed::List(vec![
+ PhpMixed::String("https".to_string()),
+ PhpMixed::String("git".to_string()),
+ ]),
+ config.get("github-protocols")
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_allowed_urls_pass() {
- todo!()
+ let urls = vec![
+ "https://packagist.org",
+ "git@github.com:composer/composer.git",
+ "hg://user:pass@my.satis/satis",
+ "\\\\myserver\\myplace.git",
+ "file://myserver.localhost/mygit.git",
+ "file://example.org/mygit.git",
+ "git:Department/Repo.git",
+ "ssh://[user@]host.xz[:port]/path/to/repo.git/",
+ ];
+ for url in urls {
+ let mut config = Config::new(false, None);
+ config
+ .prohibit_url_by_config(url, None, &IndexMap::new())
+ .unwrap();
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_prohibited_urls_throw_exception() {
- todo!()
+ let urls = vec![
+ "http://packagist.org",
+ "http://10.1.0.1/satis",
+ "http://127.0.0.1/satis",
+ "http://\u{1F49B}@example.org",
+ "svn://localhost/trunk",
+ "svn://will.not.resolve/trunk",
+ "svn://192.168.0.1/trunk",
+ "svn://1.2.3.4/trunk",
+ "git://5.6.7.8/git.git",
+ ];
+ for url in urls {
+ let mut config = Config::new(false, None);
+ let err = config
+ .prohibit_url_by_config(url, None, &IndexMap::new())
+ .unwrap_err();
+ assert!(
+ err.to_string().contains(&format!(
+ "Your configuration does not allow connections to {url}"
+ )),
+ "url {url:?}: {err}"
+ );
+ }
}
+#[ignore = "requires getIOMock with expects() output expectations; no IO mocking infrastructure exists"]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_prohibited_urls_warning_verify_peer() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_disable_tls_can_be_overridden() {
- todo!()
+ let mut config = Config::new(true, None);
+ config.merge(
+ &config_section(vec![("disable-tls", PhpMixed::String("false".to_string()))]),
+ "test",
+ );
+ assert_eq!(PhpMixed::Bool(false), config.get("disable-tls"));
+ config.merge(
+ &config_section(vec![("disable-tls", PhpMixed::String("true".to_string()))]),
+ "test",
+ );
+ assert_eq!(PhpMixed::Bool(true), config.get("disable-tls"));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_process_timeout() {
- todo!()
+ Platform::put_env("COMPOSER_PROCESS_TIMEOUT", "0");
+ let config = Config::new(true, None);
+ let result = config.get("process-timeout");
+ Platform::clear_env("COMPOSER_PROCESS_TIMEOUT");
+
+ assert_eq!(PhpMixed::Int(0), result);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_htaccess_protect() {
- todo!()
+ Platform::put_env("COMPOSER_HTACCESS_PROTECT", "0");
+ let config = Config::new(true, None);
+ let result = config.get("htaccess-protect");
+ Platform::clear_env("COMPOSER_HTACCESS_PROTECT");
+
+ assert_eq!(PhpMixed::Bool(false), result);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_get_source_of_value() {
- todo!()
+ Platform::clear_env("COMPOSER_PROCESS_TIMEOUT");
+
+ let mut config = Config::new(true, None);
+
+ assert_eq!(
+ Config::SOURCE_DEFAULT,
+ config.get_source_of_value("process-timeout").as_str()
+ );
+
+ config.merge(
+ &config_section(vec![("process-timeout", PhpMixed::Int(1))]),
+ "phpunit-test",
+ );
+
+ assert_eq!(
+ "phpunit-test",
+ config.get_source_of_value("process-timeout").as_str()
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_get_source_of_value_env_variables() {
- todo!()
+ Platform::put_env("COMPOSER_HTACCESS_PROTECT", "0");
+ let mut config = Config::new(true, None);
+ let result = config.get_source_of_value("htaccess-protect");
+ Platform::clear_env("COMPOSER_HTACCESS_PROTECT");
+
+ assert_eq!("COMPOSER_HTACCESS_PROTECT", result.as_str());
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_audit() {
- todo!()
+ let mut config = Config::new(true, None);
+ let result = config.get("audit");
+ let result = result.as_array().unwrap();
+ assert!(result.contains_key("abandoned"));
+ assert!(result.contains_key("ignore"));
+ assert_eq!(
+ Some(&PhpMixed::String(Auditor::ABANDONED_FAIL.to_string())),
+ result.get("abandoned")
+ );
+ assert_eq!(
+ Some(&PhpMixed::Array(IndexMap::new())),
+ result.get("ignore")
+ );
+
+ Platform::put_env("COMPOSER_AUDIT_ABANDONED", Auditor::ABANDONED_IGNORE);
+ let result = config.get("audit");
+ Platform::clear_env("COMPOSER_AUDIT_ABANDONED");
+ let result = result.as_array().unwrap();
+ assert!(result.contains_key("abandoned"));
+ assert!(result.contains_key("ignore"));
+ assert_eq!(
+ Some(&PhpMixed::String(Auditor::ABANDONED_IGNORE.to_string())),
+ result.get("abandoned")
+ );
+ assert_eq!(
+ Some(&PhpMixed::Array(IndexMap::new())),
+ result.get("ignore")
+ );
+
+ config.merge(
+ &config_section(vec![(
+ "audit",
+ PhpMixed::Array(map(vec![(
+ "ignore",
+ PhpMixed::List(vec![
+ PhpMixed::String("A".to_string()),
+ PhpMixed::String("B".to_string()),
+ ]),
+ )])),
+ )]),
+ "test",
+ );
+ config.merge(
+ &config_section(vec![(
+ "audit",
+ PhpMixed::Array(map(vec![(
+ "ignore",
+ PhpMixed::List(vec![
+ PhpMixed::String("A".to_string()),
+ PhpMixed::String("C".to_string()),
+ ]),
+ )])),
+ )]),
+ "test",
+ );
+ let result = config.get("audit");
+ let result = result.as_array().unwrap();
+ assert!(result.contains_key("ignore"));
+ assert_eq!(
+ Some(&PhpMixed::List(vec![
+ PhpMixed::String("A".to_string()),
+ PhpMixed::String("B".to_string()),
+ PhpMixed::String("A".to_string()),
+ PhpMixed::String("C".to_string()),
+ ])),
+ result.get("ignore")
+ );
+
+ // Test COMPOSER_SECURITY_BLOCKING_ABANDONED env var
+ Platform::put_env("COMPOSER_SECURITY_BLOCKING_ABANDONED", "1");
+ let result = config.get("audit");
+ Platform::clear_env("COMPOSER_SECURITY_BLOCKING_ABANDONED");
+ let result = result.as_array().unwrap();
+ assert!(result.contains_key("block-abandoned"));
+ assert_eq!(Some(&PhpMixed::Bool(true)), result.get("block-abandoned"));
+
+ Platform::put_env("COMPOSER_SECURITY_BLOCKING_ABANDONED", "0");
+ let result = config.get("audit");
+ Platform::clear_env("COMPOSER_SECURITY_BLOCKING_ABANDONED");
+ let result = result.as_array().unwrap();
+ assert!(result.contains_key("block-abandoned"));
+ assert_eq!(Some(&PhpMixed::Bool(false)), result.get("block-abandoned"));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_get_defaults_to_an_empty_array() {
- todo!()
+ let config = Config::new(true, None);
+ let keys = [
+ "bitbucket-oauth",
+ "github-oauth",
+ "gitlab-oauth",
+ "gitlab-token",
+ "forgejo-token",
+ "http-basic",
+ "bearer",
+ ];
+ for key in keys {
+ let value = config.get(key);
+ match value {
+ PhpMixed::Array(m) => assert_eq!(0, m.len(), "key {key:?}"),
+ other => panic!("key {key:?}: expected array, got {other:?}"),
+ }
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_merges_plugin_config() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![(
+ "allow-plugins",
+ PhpMixed::Array(map(vec![("some/plugin", PhpMixed::Bool(true))])),
+ )]),
+ "test",
+ );
+ match config.get("allow-plugins") {
+ PhpMixed::Array(actual) => {
+ assert_map_equals(&map(vec![("some/plugin", PhpMixed::Bool(true))]), &actual)
+ }
+ other => panic!("expected array, got {other:?}"),
+ }
+
+ config.merge(
+ &config_section(vec![(
+ "allow-plugins",
+ PhpMixed::Array(map(vec![("another/plugin", PhpMixed::Bool(true))])),
+ )]),
+ "test",
+ );
+ match config.get("allow-plugins") {
+ PhpMixed::Array(actual) => assert_map_equals(
+ &map(vec![
+ ("some/plugin", PhpMixed::Bool(true)),
+ ("another/plugin", PhpMixed::Bool(true)),
+ ]),
+ &actual,
+ ),
+ other => panic!("expected array, got {other:?}"),
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_overrides_global_boolean_plugins_config() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![("allow-plugins", PhpMixed::Bool(true))]),
+ "test",
+ );
+ assert_eq!(PhpMixed::Bool(true), config.get("allow-plugins"));
+
+ config.merge(
+ &config_section(vec![(
+ "allow-plugins",
+ PhpMixed::Array(map(vec![("another/plugin", PhpMixed::Bool(true))])),
+ )]),
+ "test",
+ );
+ match config.get("allow-plugins") {
+ PhpMixed::Array(actual) => assert_map_equals(
+ &map(vec![("another/plugin", PhpMixed::Bool(true))]),
+ &actual,
+ ),
+ other => panic!("expected array, got {other:?}"),
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (env-dependent without the setUp/tearDown isolation, or plugin-config merge details)"]
fn test_allows_all_plugins_from_local_boolean() {
- todo!()
+ let mut config = Config::new(false, None);
+ config.merge(
+ &config_section(vec![(
+ "allow-plugins",
+ PhpMixed::Array(map(vec![("some/plugin", PhpMixed::Bool(true))])),
+ )]),
+ "test",
+ );
+ match config.get("allow-plugins") {
+ PhpMixed::Array(actual) => {
+ assert_map_equals(&map(vec![("some/plugin", PhpMixed::Bool(true))]), &actual)
+ }
+ other => panic!("expected array, got {other:?}"),
+ }
+
+ config.merge(
+ &config_section(vec![("allow-plugins", PhpMixed::Bool(true))]),
+ "test",
+ );
+ assert_eq!(PhpMixed::Bool(true), config.get("allow-plugins"));
}
diff --git a/crates/shirabe/tests/dependency_resolver/default_policy_test.rs b/crates/shirabe/tests/dependency_resolver/default_policy_test.rs
index 077dd71..776de6c 100644
--- a/crates/shirabe/tests/dependency_resolver/default_policy_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/default_policy_test.rs
@@ -1,17 +1,23 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php
use indexmap::IndexMap;
+use shirabe::dependency_resolver::PolicyInterface;
use shirabe::dependency_resolver::default_policy::DefaultPolicy;
+use shirabe::package::handle::{CompleteAliasPackageHandle, CompletePackageHandle};
use shirabe::repository::array_repository::ArrayRepository;
+use shirabe::repository::handle::{LockArrayRepositoryHandle, RepositoryInterfaceHandle};
use shirabe::repository::lock_array_repository::LockArrayRepository;
use shirabe::repository::repository_set::RepositorySet;
use shirabe::util::platform::Platform;
+use shirabe_semver::constraint::{AnyConstraint, SimpleConstraint};
+
+use crate::test_case::get_package;
#[allow(dead_code)]
struct Fixtures {
repository_set: RepositorySet,
repo: ArrayRepository,
- repo_locked: LockArrayRepository,
+ repo_locked: LockArrayRepositoryHandle,
policy: DefaultPolicy,
}
@@ -25,7 +31,7 @@ fn set_up() -> Fixtures {
IndexMap::new(),
);
let repo = ArrayRepository::new(vec![]).unwrap();
- let repo_locked = LockArrayRepository::new(vec![]).unwrap();
+ let repo_locked = LockArrayRepositoryHandle::new(LockArrayRepository::new(vec![]).unwrap());
let policy = DefaultPolicy::new(false, false, None);
@@ -48,141 +54,558 @@ impl Drop for TearDown {
}
}
-// These build a Pool from packages and exercise DefaultPolicy::selectPreferredPackages.
-// Constructing the packages/constraints parses versions through a look-around regex the
-// regex crate cannot compile, and the setup mirrors the solver fixtures.
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_single() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a = get_package("A", "1.0");
+ fixtures.repo.add_package(package_a.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a.get_id()];
+ let expected = vec![package_a.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0");
+ let package_a2 = get_package("A", "2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a2.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_picks_latest() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.0.1-alpha");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a2.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_picks_latest_stable_with_prefer_stable() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.0.1-alpha");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a1.get_id()];
+
+ let policy = DefaultPolicy::new(true, false, None);
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_lowest_with_prefer_dev_over_prerelease() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+
+ for stability in ["alpha1", "beta1", "RC1"] {
+ let mut fixtures = set_up();
+
+ Platform::put_env("COMPOSER_PREFER_DEV_OVER_PRERELEASE", "1");
+ let dev_package = get_package("A", "dev-master");
+ let prerelease_package = get_package("A", &format!("1.0.0-{}", stability));
+ fixtures.repo.add_package(dev_package.clone()).unwrap();
+ fixtures
+ .repo
+ .add_package(prerelease_package.clone())
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![dev_package.get_id(), prerelease_package.get_id()];
+ let expected = vec![dev_package.get_id()];
+
+ let policy = DefaultPolicy::new(true, true, None);
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_lowest_prefers_prerelease_over_dev() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+
+ for stability in ["alpha1", "beta1", "RC1"] {
+ let mut fixtures = set_up();
+
+ let dev_package = get_package("A", "dev-master");
+ let prerelease_package = get_package("A", &format!("1.0.0-{}", stability));
+ fixtures.repo.add_package(dev_package.clone()).unwrap();
+ fixtures
+ .repo
+ .add_package(prerelease_package.clone())
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![prerelease_package.get_id(), dev_package.get_id()];
+ let expected = vec![prerelease_package.get_id()];
+
+ let policy = DefaultPolicy::new(true, true, None);
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_lowest_with_prefer_stable_still_prefers_stable() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ Platform::put_env("COMPOSER_PREFER_DEV_OVER_PRERELEASE", "1");
+ let stable_package = get_package("A", "1.0.0");
+ let dev_package = get_package("A", "dev-master");
+ fixtures.repo.add_package(stable_package.clone()).unwrap();
+ fixtures.repo.add_package(dev_package.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![stable_package.get_id(), dev_package.get_id()];
+ let expected = vec![stable_package.get_id()];
+
+ let policy = DefaultPolicy::new(true, true, None);
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_with_dev_picks_non_dev() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "dev-foo");
+ let package_a2 = get_package("A", "1.0.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a2.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_with_preferred_version_picks_preferred_version_if_available() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.1.0");
+ let package_a2b = get_package("A", "1.1.0");
+ let package_a3 = get_package("A", "1.2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures.repo.add_package(package_a2b.clone()).unwrap();
+ fixtures.repo.add_package(package_a3.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![
+ package_a1.get_id(),
+ package_a2.get_id(),
+ package_a2b.get_id(),
+ package_a3.get_id(),
+ ];
+ let expected = vec![package_a2.get_id(), package_a2b.get_id()];
+
+ let mut preferred = IndexMap::new();
+ preferred.insert("a".to_string(), "1.1.0.0".to_string());
+ let policy = DefaultPolicy::new(false, false, Some(preferred));
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_with_preferred_version_picks_newest_otherwise() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a2.get_id()];
+
+ let mut preferred = IndexMap::new();
+ preferred.insert("a".to_string(), "1.1.0.0".to_string());
+ let policy = DefaultPolicy::new(false, false, Some(preferred));
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_with_preferred_version_picks_lowest_if_prefer_lowest() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a1.get_id()];
+
+ let mut preferred = IndexMap::new();
+ preferred.insert("a".to_string(), "1.1.0.0".to_string());
+ let policy = DefaultPolicy::new(false, true, Some(preferred));
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_repository_ordering_affects_priority() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let repo1 = ArrayRepository::new(vec![]).unwrap();
+ let repo2 = ArrayRepository::new(vec![]).unwrap();
+
+ let package1 = get_package("A", "1.0");
+ let package2 = get_package("A", "1.1");
+ let package3 = get_package("A", "1.1");
+ let package4 = get_package("A", "1.2");
+ repo1.add_package(package1.clone()).unwrap();
+ repo1.add_package(package2.clone()).unwrap();
+ repo2.add_package(package3.clone()).unwrap();
+ repo2.add_package(package4.clone()).unwrap();
+
+ let repo1_handle = RepositoryInterfaceHandle::new(repo1);
+ let repo2_handle = RepositoryInterfaceHandle::new(repo2);
+
+ fixtures
+ .repository_set
+ .add_repository(repo1_handle.clone())
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(repo2_handle.clone())
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![
+ package1.get_id(),
+ package2.get_id(),
+ package3.get_id(),
+ package4.get_id(),
+ ];
+ let expected = vec![package2.get_id()];
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals.clone(), None);
+
+ assert_eq!(expected, selected);
+
+ let mut repository_set = RepositorySet::new(
+ "dev",
+ IndexMap::new(),
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ repository_set.add_repository(repo2_handle).unwrap();
+ repository_set.add_repository(repo1_handle).unwrap();
+
+ let pool = repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let expected = vec![package4.get_id()];
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_local_repos_first() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let repo_important = ArrayRepository::new(vec![]).unwrap();
+
+ let package_a = get_package("A", "dev-master");
+ let package_a_alias = CompleteAliasPackageHandle::new(
+ CompletePackageHandle::from_rc_unchecked(package_a.as_rc().clone()),
+ "2.1.9999999.9999999-dev".to_string(),
+ "2.1.x-dev".to_string(),
+ );
+ let package_a_important = get_package("A", "dev-feature-a");
+ let package_a_alias_important = CompleteAliasPackageHandle::new(
+ CompletePackageHandle::from_rc_unchecked(package_a_important.as_rc().clone()),
+ "2.1.9999999.9999999-dev".to_string(),
+ "2.1.x-dev".to_string(),
+ );
+ let package_a2_important = get_package("A", "dev-master");
+ let package_a2_alias_important = CompleteAliasPackageHandle::new(
+ CompletePackageHandle::from_rc_unchecked(package_a2_important.as_rc().clone()),
+ "2.1.9999999.9999999-dev".to_string(),
+ "2.1.x-dev".to_string(),
+ );
+ package_a_alias_important.set_root_package_alias(true);
+
+ fixtures.repo.add_package(package_a).unwrap();
+ fixtures
+ .repo
+ .add_package(package_a_alias.clone().into())
+ .unwrap();
+ repo_important.add_package(package_a_important).unwrap();
+ repo_important
+ .add_package(package_a_alias_important.clone().into())
+ .unwrap();
+ repo_important.add_package(package_a2_important).unwrap();
+ repo_important
+ .add_package(package_a2_alias_important.into())
+ .unwrap();
+
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(repo_important))
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(fixtures.repo_locked.clone().into())
+ .unwrap();
+
+ let mut pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let constraint = AnyConstraint::Simple(SimpleConstraint::new(
+ "=".to_string(),
+ "2.1.9999999.9999999-dev".to_string(),
+ None,
+ ));
+ let packages = pool.what_provides("a", Some(&constraint));
+ assert!(!packages.is_empty());
+ let mut literals = vec![];
+ for package in &packages {
+ literals.push(package.get_id());
+ }
+
+ let expected = vec![package_a_alias_important.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore = "set_provides/set_replaces only exist on RootPackage handles; CompletePackage from get_package has no set_provides"]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_all_providers() {
let _tear_down = TearDown;
let _fixtures = set_up();
todo!()
}
+#[ignore = "set_provides/set_replaces only exist on RootPackage handles; CompletePackage from get_package has no set_replaces"]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_prefer_non_replacing_from_same_repo() {
let _tear_down = TearDown;
let _fixtures = set_up();
todo!()
}
+#[ignore = "set_replaces only exists on RootPackage handles; CompletePackage from get_package has no set_replaces"]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_prefer_replacing_package_from_same_vendor() {
let _tear_down = TearDown;
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_lowest() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let policy = DefaultPolicy::new(false, true, None);
+
+ let package_a1 = get_package("A", "1.0");
+ let package_a2 = get_package("A", "2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a1.get_id()];
+
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
diff --git a/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs b/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
index 617c7b9..4c72091 100644
--- a/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
@@ -3,7 +3,7 @@
// testPoolBuilder is a large fixture-driven case that loads packages from test inputs and
// builds a Pool; constraint parsing uses a look-around regex the regex crate cannot compile.
#[test]
-#[ignore = "not yet ported (fixture-driven PoolBuilder; constraint parsing uses a look-around regex)"]
+#[ignore = "ArrayLoader::load (single-package, pub) and Pool::count are not exposed: the loadPackage closure calls $loader->load($data) per package and getPackageResultSet uses count($pool)"]
fn test_pool_builder() {
todo!()
}
diff --git a/crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs b/crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs
index a25aec6..408c191 100644
--- a/crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs
@@ -1,9 +1,264 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php
-// testPoolOptimizer is a large fixture-driven case building and optimizing a Pool;
-// constraint parsing uses a look-around regex the regex crate cannot compile.
+use std::path::PathBuf;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::dependency_resolver::default_policy::DefaultPolicy;
+use shirabe::dependency_resolver::pool::Pool;
+use shirabe::dependency_resolver::pool_optimizer::PoolOptimizer;
+use shirabe::dependency_resolver::request::Request;
+use shirabe::json::JsonFile;
+use shirabe::package::BasePackageHandle;
+use shirabe::package::loader::{ArrayLoader, LoaderInterface};
+use shirabe::package::version::version_parser::VersionParser;
+use shirabe::repository::handle::LockArrayRepositoryHandle;
+use shirabe::repository::lock_array_repository::LockArrayRepository;
+use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_php_shim::PREG_SPLIT_DELIM_CAPTURE;
+use shirabe_php_shim::PhpMixed;
+
+fn load_package(package_data: &PhpMixed) -> BasePackageHandle {
+ let loader = ArrayLoader::new(None, false);
+ loader
+ .load(package_data.as_array().unwrap().clone(), None)
+ .unwrap()
+}
+
+fn load_packages(packages_data: &[PhpMixed]) -> Vec<BasePackageHandle> {
+ let mut packages: Vec<BasePackageHandle> = Vec::new();
+
+ for package_data in packages_data {
+ let package = load_package(package_data);
+ packages.push(package.clone());
+ if let Some(alias) = package.as_alias() {
+ packages.push(alias.get_alias_of().into());
+ }
+ }
+
+ packages
+}
+
+fn reduce_packages_info_for_comparison(packages: &[BasePackageHandle]) -> Vec<String> {
+ let mut packages_info: Vec<String> = Vec::new();
+
+ for package in packages {
+ let suffix = if let Some(alias) = package.as_alias() {
+ format!(" (alias of {})", alias.get_alias_of().get_version())
+ } else {
+ String::new()
+ };
+ packages_info.push(format!(
+ "{}@{}{}",
+ package.get_name(),
+ package.get_version(),
+ suffix
+ ));
+ }
+
+ packages_info.sort();
+
+ packages_info
+}
+
+fn read_test_file(file: &str, fixtures_dir: &str) -> IndexMap<String, String> {
+ let contents = shirabe_php_shim::file_get_contents(file).unwrap();
+ let tokens = Preg::split4(
+ r"#(?:^|\n*)--([A-Z-]+)--\n#",
+ &contents,
+ -1,
+ PREG_SPLIT_DELIM_CAPTURE,
+ );
+
+ let section_info: Vec<&str> = vec!["TEST", "REQUEST", "POOL-BEFORE", "POOL-AFTER"];
+
+ let mut section: Option<String> = None;
+ let mut data: IndexMap<String, String> = IndexMap::new();
+ for token in tokens {
+ if section.is_none() && token.is_empty() {
+ continue;
+ }
+
+ if section.is_none() {
+ if !section_info.contains(&token.as_str()) {
+ panic!(
+ "The test file \"{}\" must not contain a section named \"{}\".",
+ file.replace(&format!("{}/", fixtures_dir), ""),
+ token
+ );
+ }
+ section = Some(token);
+ continue;
+ }
+
+ let section_data = token;
+ data.insert(section.take().unwrap(), section_data);
+ }
+
+ for required_section in &section_info {
+ if !data.contains_key(*required_section) {
+ panic!(
+ "The test file \"{}\" must have a section named \"{}\".",
+ file.replace(&format!("{}/", fixtures_dir), ""),
+ required_section
+ );
+ }
+ }
+
+ data
+}
+
+fn collect_test_files(dir: &std::path::Path, out: &mut Vec<PathBuf>) {
+ for entry in std::fs::read_dir(dir).unwrap() {
+ let entry = entry.unwrap();
+ let path = entry.path();
+ if path.is_dir() {
+ collect_test_files(&path, out);
+ } else {
+ out.push(path);
+ }
+ }
+}
+
+fn provide_integration_tests() -> IndexMap<
+ String,
+ (
+ PhpMixed,
+ Vec<BasePackageHandle>,
+ Vec<BasePackageHandle>,
+ String,
+ ),
+> {
+ let fixtures_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+ .join("../../composer/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer");
+ let fixtures_dir = std::fs::canonicalize(&fixtures_dir).unwrap();
+ let fixtures_dir_str = fixtures_dir.to_str().unwrap().to_string();
+
+ let mut files: Vec<PathBuf> = Vec::new();
+ collect_test_files(&fixtures_dir, &mut files);
+
+ let mut tests: IndexMap<
+ String,
+ (
+ PhpMixed,
+ Vec<BasePackageHandle>,
+ Vec<BasePackageHandle>,
+ String,
+ ),
+ > = IndexMap::new();
+ for file in files {
+ let file = file.to_str().unwrap().to_string();
+
+ if !Preg::is_match(r"/\.test$/", &file) {
+ continue;
+ }
+
+ let test_data = read_test_file(&file, &fixtures_dir_str);
+ let message = test_data["TEST"].clone();
+ let request_data = JsonFile::parse_json(Some(&test_data["REQUEST"]), None).unwrap();
+ let packages_before = load_packages(
+ JsonFile::parse_json(Some(&test_data["POOL-BEFORE"]), None)
+ .unwrap()
+ .as_list()
+ .unwrap(),
+ );
+ let expected_packages = load_packages(
+ JsonFile::parse_json(Some(&test_data["POOL-AFTER"]), None)
+ .unwrap()
+ .as_list()
+ .unwrap(),
+ );
+
+ let basename = std::path::Path::new(&file)
+ .file_name()
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .to_string();
+ tests.insert(
+ basename,
+ (request_data, packages_before, expected_packages, message),
+ );
+ }
+
+ tests
+}
+
+fn run_test_pool_optimizer(
+ request_data: &PhpMixed,
+ packages_before: Vec<BasePackageHandle>,
+ expected_packages: &[BasePackageHandle],
+ message: &str,
+) {
+ let request_data = request_data.as_array().unwrap();
+
+ let locked_repo = LockArrayRepositoryHandle::new(LockArrayRepository::new(vec![]).unwrap());
+
+ let mut request = Request::new(Some(locked_repo));
+ let parser = VersionParser::new();
+
+ if let Some(locked) = request_data.get("locked") {
+ for package in locked.as_list().unwrap() {
+ request.lock_package(load_package(package));
+ }
+ }
+ if let Some(fixed) = request_data.get("fixed") {
+ for package in fixed.as_list().unwrap() {
+ request.fix_package(load_package(package));
+ }
+ }
+
+ for (package, constraint) in request_data["require"].as_array().unwrap() {
+ request
+ .require_name(
+ package,
+ Some(
+ parser
+ .parse_constraints(constraint.as_string().unwrap())
+ .unwrap(),
+ ),
+ )
+ .unwrap();
+ }
+
+ let prefer_stable = request_data
+ .get("preferStable")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
+ let prefer_lowest = request_data
+ .get("preferLowest")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
+
+ let pool = Pool::new(
+ packages_before,
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let mut pool_optimizer = PoolOptimizer::new(Rc::new(DefaultPolicy::new(
+ prefer_stable,
+ prefer_lowest,
+ None,
+ )));
+
+ let pool = pool_optimizer.optimize(&request, &pool);
+
+ assert_eq!(
+ reduce_packages_info_for_comparison(expected_packages),
+ reduce_packages_info_for_comparison(pool.get_packages()),
+ "{}",
+ message
+ );
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (fixture-driven PoolOptimizer; constraint parsing uses a look-around regex)"]
fn test_pool_optimizer() {
- todo!()
+ let tests = provide_integration_tests();
+ for (_name, (request_data, packages_before, expected_packages, message)) in tests {
+ run_test_pool_optimizer(&request_data, packages_before, &expected_packages, &message);
+ }
}
diff --git a/crates/shirabe/tests/dependency_resolver/rule_set_test.rs b/crates/shirabe/tests/dependency_resolver/rule_set_test.rs
index 5620b2a..f1e573e 100644
--- a/crates/shirabe/tests/dependency_resolver/rule_set_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/rule_set_test.rs
@@ -3,10 +3,14 @@
use std::cell::RefCell;
use std::rc::Rc;
+use indexmap::IndexMap;
use shirabe::dependency_resolver::{
- GenericRule, RULE_LEARNED, RULE_ROOT_REQUIRE, ReasonData, Rule, RuleSet,
+ GenericRule, Pool, RULE_LEARNED, RULE_ROOT_REQUIRE, ReasonData, Request, Rule, RuleSet,
};
-use shirabe_semver::constraint::MatchAllConstraint;
+use shirabe::repository::RepositorySet;
+use shirabe_semver::constraint::{MatchAllConstraint, MatchNoneConstraint};
+
+use crate::test_case::get_package;
fn root_require_reason() -> ReasonData {
ReasonData::RootRequire {
@@ -156,10 +160,54 @@ fn test_get_iterator_without() {
assert!(Rc::ptr_eq(&iterator.current(), &rule2));
}
-// In PHP this mocks RepositorySet and Request to build the pretty string. The mocked
-// collaborators cannot be reproduced here, and add() also reaches hash_raw (todo!()).
+// The constraint is MatchNoneConstraint, so what_provides returns no packages and the
+// "No package found" branch is taken; the RepositorySet/Request collaborators are never
+// actually consulted (PHP mocks them with the constructor disabled).
#[test]
-#[ignore = "getPrettyString needs mocked RepositorySet/Request, and add() reaches hash_raw (todo!())"]
+#[ignore]
fn test_pretty_string() {
- todo!()
+ let p = get_package("foo", "2.1");
+ let mut pool = Pool::new(
+ vec![p.clone()],
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+
+ let repository_set = RepositorySet::new(
+ "stable",
+ IndexMap::new(),
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let request = Request::new(None);
+
+ let mut rule_set = RuleSet::new();
+ let literal = p.get_id();
+ let rule = Rc::new(RefCell::new(Rule::Generic(GenericRule::new(
+ vec![literal],
+ RULE_ROOT_REQUIRE,
+ ReasonData::RootRequire {
+ package_name: "foo/bar".to_string(),
+ constraint: MatchNoneConstraint::new(None).into(),
+ },
+ ))));
+
+ rule_set.add(rule, RuleSet::TYPE_REQUEST).unwrap();
+
+ let pretty = rule_set
+ .get_pretty_string(
+ Some(&repository_set),
+ Some(&request),
+ Some(&mut pool),
+ false,
+ )
+ .unwrap();
+ assert!(
+ pretty.contains("REQUEST : No package found to satisfy root composer.json require foo/bar")
+ );
}
diff --git a/crates/shirabe/tests/dependency_resolver/rule_test.rs b/crates/shirabe/tests/dependency_resolver/rule_test.rs
index 9806820..156931c 100644
--- a/crates/shirabe/tests/dependency_resolver/rule_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/rule_test.rs
@@ -1,8 +1,16 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/RuleTest.php
-use shirabe::dependency_resolver::{GenericRule, RULE_ROOT_REQUIRE, ReasonData, Rule, RuleSet};
+use indexmap::IndexMap;
+use shirabe::dependency_resolver::{
+ GenericRule, Pool, RULE_PACKAGE_REQUIRES, RULE_ROOT_REQUIRE, ReasonData, Request, Rule, RuleSet,
+};
+use shirabe::package::Link;
+use shirabe::repository::RepositorySet;
+use shirabe_php_shim::{PHP_VERSION_ID, hash_raw, unpack};
use shirabe_semver::constraint::MatchAllConstraint;
+use crate::test_case::get_package;
+
fn root_require_reason() -> ReasonData {
ReasonData::RootRequire {
package_name: String::new(),
@@ -18,10 +26,23 @@ fn generic_rule(literals: Vec<i64>) -> Rule {
))
}
+#[ignore]
#[test]
-#[ignore = "Rule::get_hash reaches shirabe_php_shim::hash_raw, which is todo!()"]
fn test_get_hash() {
- todo!()
+ let rule = generic_rule(vec![123]);
+
+ let algo = if PHP_VERSION_ID > 80100 {
+ "xxh3"
+ } else {
+ "sha1"
+ };
+ let binary = hash_raw(algo, "123");
+ let hash = unpack("ihash", &binary).unwrap();
+
+ assert_eq!(
+ hash.get("hash").unwrap().as_int(),
+ rule.get_hash().unwrap().as_int()
+ );
}
#[test]
@@ -85,10 +106,56 @@ fn test_is_assertions() {
assert!(rule2.is_assertion());
}
-// In PHP this mocks RepositorySet and Request and passes a Link reason to build the
-// pretty string. The mocked collaborators cannot be reproduced here.
+// PHP mocks RepositorySet and Request with the constructor disabled; the RULE_PACKAGE_REQUIRES
+// branch with a non-empty requires list never consults them, so real minimal instances suffice.
+#[ignore]
#[test]
-#[ignore = "getPrettyString needs mocked RepositorySet and Request; mocking is not available"]
fn test_pretty_string() {
- todo!()
+ let p1 = get_package("foo", "2.1");
+ let p2 = get_package("baz", "1.1");
+ let mut pool = Pool::new(
+ vec![p1.clone(), p2.clone()],
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+
+ let repository_set = RepositorySet::new(
+ "stable",
+ IndexMap::new(),
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let request = Request::new(None);
+
+ let empty_constraint = MatchAllConstraint::new(Some("*".to_string()));
+
+ let rule = Rule::Generic(GenericRule::new(
+ vec![p1.get_id(), -p2.get_id()],
+ RULE_PACKAGE_REQUIRES,
+ ReasonData::Link(Link::new(
+ "baz".to_string(),
+ "foo".to_string(),
+ empty_constraint.into(),
+ None,
+ "*".to_string(),
+ )),
+ ));
+
+ assert_eq!(
+ "baz 1.1 relates to foo * -> satisfiable by foo[2.1].",
+ rule.get_pretty_string(
+ &repository_set,
+ &request,
+ &mut pool,
+ false,
+ &IndexMap::new(),
+ &vec![],
+ )
+ .unwrap()
+ );
}
diff --git a/crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs b/crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs
index 825d6b4..1232241 100644
--- a/crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs
@@ -5,26 +5,105 @@
// crate cannot compile. The fixtures also build PackageRepository security-advisory data
// and run the Auditor.
+use indexmap::IndexMap;
+use shirabe::advisory::AuditConfig;
+use shirabe::advisory::Auditor;
+use shirabe::dependency_resolver::SecurityAdvisoryPoolFilter;
+use shirabe::dependency_resolver::pool::Pool;
+use shirabe::dependency_resolver::request::Request;
+use shirabe::package::handle::{CompletePackageHandle, PackageHandle, PackageInterfaceHandle};
+use shirabe_php_shim::PhpMixed;
+
#[test]
-#[ignore = "filtering parses affectedVersions via a look-around regex the regex crate cannot compile"]
+#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec<RepositoryInterfaceHandle>) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"]
fn test_filter_packages_by_advisories() {
todo!()
}
#[test]
-#[ignore = "filtering parses affectedVersions via a look-around regex the regex crate cannot compile"]
+#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec<RepositoryInterfaceHandle>) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"]
fn test_dont_filter_packages_by_ignored_advisories() {
todo!()
}
#[test]
-#[ignore = "filtering parses affectedVersions via a look-around regex the regex crate cannot compile"]
+#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec<RepositoryInterfaceHandle>) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"]
fn test_dont_filter_packages_with_block_insecure_disabled() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "filtering parses affectedVersions via a look-around regex the regex crate cannot compile"]
fn test_dont_filter_packages_with_abandoned_package() {
- todo!()
+ let package_name_ignore_abandoned = "acme/ignore-abandoned";
+ let mut ignore_abandoned: IndexMap<String, Option<String>> = IndexMap::new();
+ ignore_abandoned.insert(package_name_ignore_abandoned.to_string(), None);
+ let audit_config = AuditConfig::new(
+ true,
+ Auditor::FORMAT_SUMMARY.to_string(),
+ Auditor::ABANDONED_FAIL.to_string(),
+ true,
+ true,
+ false,
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ ignore_abandoned.clone(),
+ ignore_abandoned,
+ );
+ let filter = SecurityAdvisoryPoolFilter::new(Auditor, audit_config);
+
+ let abandoned_package = CompletePackageHandle::new(
+ "acme/package".to_string(),
+ "1.0.0.0".to_string(),
+ "1.0".to_string(),
+ );
+ abandoned_package.set_abandoned(PhpMixed::Bool(true));
+ let ignore_abandoned_package = CompletePackageHandle::new(
+ package_name_ignore_abandoned.to_string(),
+ "1.0.0.0".to_string(),
+ "1.0".to_string(),
+ );
+ ignore_abandoned_package.set_abandoned(PhpMixed::Bool(true));
+ let expected_package = PackageHandle::new(
+ "acme/other".to_string(),
+ "1.1.0.0".to_string(),
+ "1.1".to_string(),
+ );
+
+ let expected_package: PackageInterfaceHandle = expected_package.into();
+ let abandoned_package: PackageInterfaceHandle = abandoned_package.into();
+ let ignore_abandoned_package: PackageInterfaceHandle = ignore_abandoned_package.into();
+
+ let pool = Pool::new(
+ vec![
+ expected_package.clone(),
+ abandoned_package.clone(),
+ ignore_abandoned_package.clone(),
+ ],
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let filtered_pool = filter.filter(pool, vec![], &Request::new(None)).unwrap();
+
+ let packages = filtered_pool.get_packages();
+ assert_eq!(packages.len(), 2);
+ assert!(packages[0].ptr_eq(&expected_package));
+ assert!(packages[1].ptr_eq(&ignore_abandoned_package));
+ assert_eq!(
+ filtered_pool
+ .get_all_abandoned_removed_package_versions()
+ .len(),
+ 1
+ );
+ assert_eq!(
+ filtered_pool
+ .get_all_security_removed_package_versions()
+ .len(),
+ 0
+ );
}
diff --git a/crates/shirabe/tests/dependency_resolver/solver_test.rs b/crates/shirabe/tests/dependency_resolver/solver_test.rs
index b876c99..26f1312 100644
--- a/crates/shirabe/tests/dependency_resolver/solver_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/solver_test.rs
@@ -1,13 +1,22 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/SolverTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
use indexmap::IndexMap;
+use shirabe::dependency_resolver::PolicyInterface;
use shirabe::dependency_resolver::default_policy::DefaultPolicy;
use shirabe::dependency_resolver::request::Request;
+use shirabe::io::io_interface::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::package::handle::PackageInterfaceHandle;
use shirabe::repository::array_repository::ArrayRepository;
-use shirabe::repository::handle::LockArrayRepositoryHandle;
+use shirabe::repository::handle::{LockArrayRepositoryHandle, RepositoryInterfaceHandle};
use shirabe::repository::lock_array_repository::LockArrayRepository;
use shirabe::repository::repository_set::RepositorySet;
+use crate::test_case::{get_alias_package, get_package, get_version_constraint};
+
#[allow(dead_code)]
struct Fixtures {
repo_set: RepositorySet,
@@ -41,285 +50,657 @@ fn set_up() -> Fixtures {
}
}
-// These run the dependency Solver over packages/requests built from version constraints,
-// whose parsing goes through a look-around regex the regex crate cannot compile; the setup
-// also mirrors the larger solver fixtures.
+/// One expected solver job. Mirrors the PHP `['job' => ..., 'package'|'from'|'to' => ...]` rows.
+enum ExpectedJob {
+ Single {
+ job: &'static str,
+ package: PackageInterfaceHandle,
+ },
+ Update {
+ from: PackageInterfaceHandle,
+ to: PackageInterfaceHandle,
+ },
+}
+
+/// ref: SolverTest::checkSolverResult (with reposComplete + createSolver folded in).
+fn check_solver_result(
+ mut repo_set: RepositorySet,
+ repo: ArrayRepository,
+ repo_locked: LockArrayRepositoryHandle,
+ mut request: Request,
+ expected: Vec<ExpectedJob>,
+) {
+ // reposComplete()
+ repo_set
+ .add_repository(RepositoryInterfaceHandle::new(repo))
+ .unwrap();
+ repo_set.add_repository(repo_locked.into()).unwrap();
+
+ // createSolver()
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let pool = repo_set
+ .create_pool(&mut request, io.clone(), None, None, vec![], None, None)
+ .unwrap();
+ let policy: Rc<dyn PolicyInterface> = Rc::new(DefaultPolicy::new(false, false, None));
+ let mut solver =
+ shirabe::dependency_resolver::solver::Solver::new(policy, Rc::new(RefCell::new(pool)), io);
+
+ let transaction = solver.solve(&request, None).unwrap();
+
+ // Build readable (unique-name) and identity (ptr) representations of the result and
+ // the expectation, mirroring the dual assertEquals in the PHP helper.
+ let mut result_readable: Vec<(String, String)> = Vec::new();
+ let mut result_ids: Vec<(String, Vec<usize>)> = Vec::new();
+ for operation in transaction.get_operations() {
+ if let Some(update) = operation.as_update_operation() {
+ let from = update.get_initial_package();
+ let to = update.get_target_package();
+ result_readable.push((
+ "update".to_string(),
+ format!("{} => {}", from.get_unique_name(), to.get_unique_name()),
+ ));
+ result_ids.push(("update".to_string(), vec![from.ptr_id(), to.ptr_id()]));
+ } else {
+ let op_type = operation.get_operation_type();
+ let job = match op_type.as_str() {
+ "markAliasInstalled" => "markAliasInstalled",
+ "markAliasUninstalled" => "markAliasUninstalled",
+ "uninstall" => "remove",
+ "install" => "install",
+ other => panic!("Unexpected operation: {}", other),
+ };
+ let package = operation.get_package();
+ result_readable.push((job.to_string(), package.get_unique_name()));
+ result_ids.push((job.to_string(), vec![package.ptr_id()]));
+ }
+ }
+
+ let mut expected_readable: Vec<(String, String)> = Vec::new();
+ let mut expected_ids: Vec<(String, Vec<usize>)> = Vec::new();
+ for job in &expected {
+ match job {
+ ExpectedJob::Single { job, package } => {
+ expected_readable.push((job.to_string(), package.get_unique_name()));
+ expected_ids.push((job.to_string(), vec![package.ptr_id()]));
+ }
+ ExpectedJob::Update { from, to } => {
+ expected_readable.push((
+ "update".to_string(),
+ format!("{} => {}", from.get_unique_name(), to.get_unique_name()),
+ ));
+ expected_ids.push(("update".to_string(), vec![from.ptr_id(), to.ptr_id()]));
+ }
+ }
+ }
+
+ assert_eq!(expected_readable, result_readable);
+ assert_eq!(expected_ids, result_ids);
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_single() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo.add_package(package_a.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Single {
+ job: "install",
+ package: package_a,
+ }],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_remove_if_not_requested() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ fixtures.request,
+ vec![ExpectedJob::Single {
+ job: "remove",
+ package: package_a,
+ }],
+ );
}
+#[ignore = "solve() error path discards SolverProblemsException (returns placeholder anyhow error); getProblems/getCode/getPrettyString not retrievable"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_non_existing_package_fails() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_same_package_from_different_repositories() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let mut repo_set = fixtures.repo_set;
+
+ let repo1 = ArrayRepository::new(vec![]).unwrap();
+ let repo2 = ArrayRepository::new(vec![]).unwrap();
+
+ let foo1 = get_package("foo", "1");
+ let foo2 = get_package("foo", "1");
+ repo1.add_package(foo1.clone()).unwrap();
+ repo2.add_package(foo2.clone()).unwrap();
+
+ repo_set
+ .add_repository(RepositoryInterfaceHandle::new(repo1))
+ .unwrap();
+ repo_set
+ .add_repository(RepositoryInterfaceHandle::new(repo2))
+ .unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("foo", None).unwrap();
+
+ // The two repos are already added here; the helper adds the (empty) default repos too.
+ check_solver_result(
+ repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Single {
+ job: "install",
+ package: foo1,
+ }],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_with_deps() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_honours_not_equal_operator() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_with_deps_in_order() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_multi_package_name_version_resolution_depends_on_require_order() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_multi_package_name_version_resolution_is_independent_of_require_order_if_ordered_descending_by_requirement()
{
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_fix_locked() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.fix_package(package_a.clone());
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_fix_locked_with_alternative() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ fixtures.repo.add_package(get_package("A", "1.0")).unwrap();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.fix_package(package_a.clone());
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_does_only_update() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_single() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let new_package_a = get_package("A", "1.1");
+ fixtures.repo.add_package(new_package_a.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Update {
+ from: package_a,
+ to: new_package_a,
+ }],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_all() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_current() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ fixtures
+ .repo_locked
+ .add_package(get_package("A", "1.0"))
+ .unwrap();
+ fixtures.repo.add_package(get_package("A", "1.0")).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_only_updates_selected_package() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let package_b = get_package("B", "1.0");
+ fixtures.repo_locked.add_package(package_b.clone()).unwrap();
+ let package_a_newer = get_package("A", "1.1");
+ fixtures.repo.add_package(package_a_newer.clone()).unwrap();
+ let package_b_newer = get_package("B", "1.1");
+ fixtures.repo.add_package(package_b_newer.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+ request.fix_package(package_b.clone());
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Update {
+ from: package_a,
+ to: package_a_newer,
+ }],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_constrained() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let new_package_a = get_package("A", "1.2");
+ fixtures.repo.add_package(new_package_a.clone()).unwrap();
+ fixtures.repo.add_package(get_package("A", "2.0")).unwrap();
+
+ let mut request = fixtures.request;
+ request
+ .require_name("A", Some(get_version_constraint("<", "2.0.0.0")))
+ .unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Update {
+ from: package_a,
+ to: new_package_a,
+ }],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_fully_constrained() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let new_package_a = get_package("A", "1.2");
+ fixtures.repo.add_package(new_package_a.clone()).unwrap();
+ fixtures.repo.add_package(get_package("A", "2.0")).unwrap();
+
+ let mut request = fixtures.request;
+ request
+ .require_name("A", Some(get_version_constraint("<", "2.0.0.0")))
+ .unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Update {
+ from: package_a,
+ to: new_package_a,
+ }],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_fully_constrained_prunes_installed_packages() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let package_b = get_package("B", "1.0");
+ fixtures.repo_locked.add_package(package_b.clone()).unwrap();
+ let new_package_a = get_package("A", "1.2");
+ fixtures.repo.add_package(new_package_a.clone()).unwrap();
+ fixtures.repo.add_package(get_package("A", "2.0")).unwrap();
+
+ let mut request = fixtures.request;
+ request
+ .require_name("A", Some(get_version_constraint("<", "2.0.0.0")))
+ .unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![
+ ExpectedJob::Single {
+ job: "remove",
+ package: package_b,
+ },
+ ExpectedJob::Update {
+ from: package_a,
+ to: new_package_a,
+ },
+ ],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_all_jobs() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setConflicts not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_three_alternative_require_and_conflict() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_obsolete() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_one_of_two_alternatives() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo.add_package(package_a.clone()).unwrap();
+ let package_b = get_package("A", "1.0");
+ fixtures.repo.add_package(package_b.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Single {
+ job: "install",
+ package: package_a,
+ }],
+ );
}
+#[ignore = "setRequires/setProvides not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_provider() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_skip_replacer_of_existing_package() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_no_install_replacer_of_missing_package() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_skip_replaced_package_if_replacer_is_selected() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_pick_older_if_newer_conflicts() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_circular_require() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setProvides not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_alternative_with_circular_require() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_use_replacer_if_necessary() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_issue265() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setConflicts not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_conflict_result_empty() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle; also asserts SolverProblemsException details which solve() discards"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_unsatisfiable_requires() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle; also asserts SolverProblemsException details which solve() discards"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_require_mismatch_exception() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_learn_literals_with_sorted_rule_literals() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_recursive_alias_dependencies() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_dev_alias() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_root_aliases_if_alias_of_is_installed() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+
+ // root aliased, required
+ let package_a = get_package("A", "1.0");
+ fixtures.repo.add_package(package_a.clone()).unwrap();
+ let package_a_alias = get_alias_package(&package_a, "1.1");
+ fixtures.repo.add_package(package_a_alias.clone()).unwrap();
+ package_a_alias
+ .as_alias()
+ .unwrap()
+ .set_root_package_alias(true);
+ // root aliased, not required, should still be installed as it is root alias
+ let package_b = get_package("B", "1.0");
+ fixtures.repo.add_package(package_b.clone()).unwrap();
+ let package_b_alias = get_alias_package(&package_b, "1.1");
+ fixtures.repo.add_package(package_b_alias.clone()).unwrap();
+ package_b_alias
+ .as_alias()
+ .unwrap()
+ .set_root_package_alias(true);
+ // regular alias, not required, alias should not be installed
+ let package_c = get_package("C", "1.0");
+ fixtures.repo.add_package(package_c.clone()).unwrap();
+ let package_c_alias = get_alias_package(&package_c, "1.1");
+ fixtures.repo.add_package(package_c_alias.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request
+ .require_name("A", Some(get_version_constraint("==", "1.1")))
+ .unwrap();
+ request
+ .require_name("B", Some(get_version_constraint("==", "1.0")))
+ .unwrap();
+ request
+ .require_name("C", Some(get_version_constraint("==", "1.0")))
+ .unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![
+ ExpectedJob::Single {
+ job: "install",
+ package: package_a,
+ },
+ ExpectedJob::Single {
+ job: "markAliasInstalled",
+ package: package_a_alias,
+ },
+ ExpectedJob::Single {
+ job: "install",
+ package: package_b,
+ },
+ ExpectedJob::Single {
+ job: "markAliasInstalled",
+ package: package_b_alias,
+ },
+ ExpectedJob::Single {
+ job: "install",
+ package: package_c,
+ },
+ ExpectedJob::Single {
+ job: "markAliasInstalled",
+ package: package_c_alias,
+ },
+ ],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_learn_positive_literal() {
let _fixtures = set_up();
todo!()
diff --git a/crates/shirabe/tests/dependency_resolver/transaction_test.rs b/crates/shirabe/tests/dependency_resolver/transaction_test.rs
index 2ea74aa..a5ca310 100644
--- a/crates/shirabe/tests/dependency_resolver/transaction_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/transaction_test.rs
@@ -1,10 +1,7 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/TransactionTest.php
-// Transaction::new sorts operations via shirabe_php_shim::uasort_map, which is todo!().
-// The fixture also calls setRequires/setProvides on non-root packages, which the public
-// handle API does not allow, so the scenario cannot be expressed faithfully yet.
#[test]
-#[ignore = "Transaction::new reaches uasort_map (todo!()); fixture needs link setters on non-root packages"]
+#[ignore = "CompletePackageHandle lacks set_type/set_requires/set_provides/set_extra; these setters exist only on RootPackageHandle, so the non-root package fixture cannot be expressed"]
fn test_transaction_generation_and_sorting() {
todo!()
}
diff --git a/crates/shirabe/tests/documentation_test.rs b/crates/shirabe/tests/documentation_test.rs
index 9ea9d37..7c9bef1 100644
--- a/crates/shirabe/tests/documentation_test.rs
+++ b/crates/shirabe/tests/documentation_test.rs
@@ -1,7 +1,7 @@
//! ref: composer/tests/Composer/Test/DocumentationTest.php
#[test]
-#[ignore = "requires the console Application and Symfony ApplicationDescription to enumerate commands, which are not yet ported"]
+#[ignore = "Application::set_auto_exit (setAutoExit) does not exist, required by provideCommandCases"]
fn test_command() {
todo!()
}
diff --git a/crates/shirabe/tests/downloader/archive_downloader_test.rs b/crates/shirabe/tests/downloader/archive_downloader_test.rs
index 2c0e2de..dfba3bf 100644
--- a/crates/shirabe/tests/downloader/archive_downloader_test.rs
+++ b/crates/shirabe/tests/downloader/archive_downloader_test.rs
@@ -5,37 +5,37 @@
// packages.
#[test]
-#[ignore = "constructs an ArchiveDownloader (HttpDownloader reaches curl_multi_init, todo!()) with a mocked subclass/package"]
+#[ignore = "FileDownloader::get_file_name is pub(crate); not reachable from the integration test crate"]
fn test_get_file_name() {
todo!()
}
#[test]
-#[ignore = "constructs an ArchiveDownloader (HttpDownloader reaches curl_multi_init, todo!()) with a mocked subclass/package"]
+#[ignore = "FileDownloader::process_url is pub(crate); not reachable from the integration test crate"]
fn test_process_url() {
todo!()
}
#[test]
-#[ignore = "constructs an ArchiveDownloader (HttpDownloader reaches curl_multi_init, todo!()) with a mocked subclass/package"]
+#[ignore = "FileDownloader::process_url is pub(crate); not reachable from the integration test crate"]
fn test_process_url2() {
todo!()
}
#[test]
-#[ignore = "constructs an ArchiveDownloader (HttpDownloader reaches curl_multi_init, todo!()) with a mocked subclass/package"]
+#[ignore = "FileDownloader::process_url is pub(crate); not reachable from the integration test crate"]
fn test_process_url3() {
todo!()
}
#[test]
-#[ignore = "constructs an ArchiveDownloader (HttpDownloader reaches curl_multi_init, todo!()) with a mocked subclass/package"]
+#[ignore = "FileDownloader::process_url is pub(crate); not reachable from the integration test crate"]
fn test_process_url_rewrite_dist() {
todo!()
}
#[test]
-#[ignore = "constructs an ArchiveDownloader (HttpDownloader reaches curl_multi_init, todo!()) with a mocked subclass/package"]
+#[ignore = "FileDownloader::process_url is pub(crate); not reachable from the integration test crate"]
fn test_process_url_rewrite_bitbucket_dist() {
todo!()
}
diff --git a/crates/shirabe/tests/downloader/download_manager_test.rs b/crates/shirabe/tests/downloader/download_manager_test.rs
index f9c44f4..b7fa976 100644
--- a/crates/shirabe/tests/downloader/download_manager_test.rs
+++ b/crates/shirabe/tests/downloader/download_manager_test.rs
@@ -7,218 +7,218 @@ fn set_up() {
// These mock IO and individual downloaders to drive DownloadManager's selection/download/
// update/remove logic; mocking is not available here.
+#[ignore = "requires PHPUnit mock of DownloaderInterface (createDownloaderMock)"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_set_get_downloader() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mock of PackageInterface (createPackageMock)"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_get_downloader_for_incorrectly_installed_package() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloader"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_get_downloader_for_correctly_installed_dist_package() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloader"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_get_downloader_for_incorrectly_installed_dist_package() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloader"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_get_downloader_for_correctly_installed_source_package() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloader"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_get_downloader_for_incorrectly_installed_source_package() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mock of PackageInterface (createPackageMock)"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_get_downloader_for_metapackage() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_full_package_download() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_full_package_download_failover() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mock of PackageInterface (createPackageMock)"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_bad_package_download() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_dist_only_package_download() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_source_only_package_download() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_metapackage_package_download() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_full_package_download_with_source_preferred() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_dist_only_package_download_with_source_preferred() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_source_only_package_download_with_source_preferred() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mock of PackageInterface (createPackageMock)"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_bad_package_download_with_source_preferred() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks of PackageInterface and DownloaderInterface"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_update_dist_with_equal_types() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks of PackageInterface and DownloaderInterface"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_update_dist_with_not_equal_types() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mock of PackageInterface and ReflectionMethod for private getAvailableSources"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_get_available_sources_update_sticks_to_same_source() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_update_metapackage() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_remove() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_metapackage_remove() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_install_preference_without_preference_dev() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_install_preference_without_preference_no_dev() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_install_preference_without_match_dev() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_install_preference_without_match_no_dev() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_install_preference_with_match_auto_dev() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_install_preference_with_match_auto_no_dev() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_install_preference_with_match_source() {
set_up();
todo!()
}
+#[ignore = "requires PHPUnit mocks and partial mock of DownloadManager::getDownloaderForPackage"]
#[test]
-#[ignore = "mocks IO and individual downloaders to drive DownloadManager; mocking is not available"]
fn test_install_preference_with_match_dist() {
set_up();
todo!()
diff --git a/crates/shirabe/tests/downloader/file_downloader_test.rs b/crates/shirabe/tests/downloader/file_downloader_test.rs
index 9e376be..b99dd93 100644
--- a/crates/shirabe/tests/downloader/file_downloader_test.rs
+++ b/crates/shirabe/tests/downloader/file_downloader_test.rs
@@ -8,63 +8,63 @@ fn set_up() {
// These construct a FileDownloader with a mocked IO/HttpDownloader (curl_multi_init todo!())
// and a mocked Cache/Package to drive download/checksum behaviour.
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mock of HttpDownloader::addCopy (getDownloader helper); no mocking framework and real HttpDownloader reaches curl_multi_init todo!()"]
fn test_download_for_package_without_dist_reference() {
set_up();
todo!()
}
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mock of HttpDownloader::addCopy (getDownloader helper); no mocking framework and real HttpDownloader reaches curl_multi_init todo!()"]
fn test_download_to_existing_file() {
set_up();
todo!()
}
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mock of HttpDownloader::addCopy (getDownloader helper) and ReflectionMethod on private getFileName; no mocking/reflection framework"]
fn test_get_file_name() {
set_up();
todo!()
}
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mock of HttpDownloader::addCopy and IOInterface::write callback; no mocking framework and real HttpDownloader reaches curl_multi_init todo!()"]
fn test_download_but_file_is_unsaved() {
set_up();
todo!()
}
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mocks of Cache::copyTo/copyFrom and HttpDownloader::addCopy with assertion callbacks; no mocking framework"]
fn test_download_with_custom_processed_url() {
set_up();
todo!()
}
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mocks of Cache::copyTo/copyFrom and HttpDownloader::addCopy with assertion callbacks; no mocking framework"]
fn test_download_with_custom_cache_key() {
set_up();
todo!()
}
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mock of Cache::gcIsNecessary/gc with expectation tracking; no mocking framework"]
fn test_cache_garbage_collection_is_called() {
set_up();
todo!()
}
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mock of Filesystem and HttpDownloader::addCopy plus ReflectionMethod on private getFileName; no mocking/reflection framework"]
fn test_download_file_with_invalid_checksum() {
set_up();
todo!()
}
#[test]
-#[ignore = "mocks IO/HttpDownloader (curl_multi_init todo!()) and Cache/Package"]
+#[ignore = "requires PHPUnit mocks of Filesystem::removeDirectoryAsync/normalizePath, HttpDownloader::addCopy, getIOMock expectations and ReflectionMethod on private getFileName; no mocking/reflection framework"]
fn test_downgrade_shows_appropriate_message() {
set_up();
todo!()
diff --git a/crates/shirabe/tests/downloader/fossil_downloader_test.rs b/crates/shirabe/tests/downloader/fossil_downloader_test.rs
index 9c9dbe4..0c45d2c 100644
--- a/crates/shirabe/tests/downloader/fossil_downloader_test.rs
+++ b/crates/shirabe/tests/downloader/fossil_downloader_test.rs
@@ -35,7 +35,7 @@ impl Drop for TearDown {
// curl_multi_init (todo!()), and ProcessExecutor mocking is not available.
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock and PHPUnit mocks of IOInterface/PackageInterface/Filesystem for getDownloaderMock; not available"]
fn test_install_for_package_without_source_reference() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -44,7 +44,7 @@ fn test_install_for_package_without_source_reference() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock with expects() command-sequence assertions and PHPUnit PackageInterface mock; not available"]
fn test_install() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -53,7 +53,7 @@ fn test_install() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock and PHPUnit mocks of IOInterface/PackageInterface/Filesystem for getDownloaderMock; not available"]
fn test_updatefor_package_without_source_reference() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -62,7 +62,7 @@ fn test_updatefor_package_without_source_reference() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock with expects() command-sequence assertions and PHPUnit PackageInterface mock; not available"]
fn test_update() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -71,7 +71,7 @@ fn test_update() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock and a PHPUnit Filesystem mock asserting removeDirectoryAsync; not available"]
fn test_remove() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -80,7 +80,7 @@ fn test_remove() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock and PHPUnit mocks of IOInterface/Filesystem for getDownloaderMock; not available"]
fn test_get_installation_source() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
diff --git a/crates/shirabe/tests/downloader/git_downloader_test.rs b/crates/shirabe/tests/downloader/git_downloader_test.rs
index c820254..69b0a6c 100644
--- a/crates/shirabe/tests/downloader/git_downloader_test.rs
+++ b/crates/shirabe/tests/downloader/git_downloader_test.rs
@@ -44,8 +44,8 @@ impl Drop for TearDown {
// These construct a GitDownloader with a mocked IO/Config and a mocked ProcessExecutor to
// feed git command output; mocking is not available, and a real HttpDownloader reaches
// curl_multi_init (todo!()).
+#[ignore = "requires getProcessExecutorMock/getIOMock and getMockBuilder PackageInterface mock; no ProcessExecutorMock/IOMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_download_for_package_without_source_reference() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -53,8 +53,8 @@ fn test_download_for_package_without_source_reference() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_download() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -62,8 +62,8 @@ fn test_download() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and initGitVersion reflection on Git::version static cache; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_download_with_cache() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -71,8 +71,8 @@ fn test_download_with_cache() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_download_uses_various_protocols_and_sets_push_url_for_github() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -80,8 +80,8 @@ fn test_download_uses_various_protocols_and_sets_push_url_for_github() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and pushUrlProvider dataProvider; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_download_and_set_push_url_use_custom_various_protocols_for_github() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -89,8 +89,8 @@ fn test_download_and_set_push_url_use_custom_various_protocols_for_github() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_download_throws_runtime_exception_if_git_command_fails() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -98,8 +98,8 @@ fn test_download_throws_runtime_exception_if_git_command_fails() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock/getDownloaderMock and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_updatefor_package_without_source_reference() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -107,8 +107,8 @@ fn test_updatefor_package_without_source_reference() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_update() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -116,8 +116,8 @@ fn test_update() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_update_with_new_repo_url() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -125,8 +125,8 @@ fn test_update_with_new_repo_url() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_update_throws_runtime_exception_if_git_command_fails() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -134,8 +134,8 @@ fn test_update_throws_runtime_exception_if_git_command_fails() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_update_doesnt_throws_runtime_exception_if_git_command_fails_at_first_but_is_able_to_recover()
{
let working_dir = set_up();
@@ -144,8 +144,8 @@ fn test_update_doesnt_throws_runtime_exception_if_git_command_fails_at_first_but
todo!()
}
+#[ignore = "requires getIOMock with expects() output expectations, getProcessExecutorMock and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_downgrade_shows_appropriate_message() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -153,8 +153,8 @@ fn test_downgrade_shows_appropriate_message() {
todo!()
}
+#[ignore = "requires getIOMock with expects() output expectations, getProcessExecutorMock and getMockBuilder PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_not_using_downgrading_with_references() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -162,8 +162,8 @@ fn test_not_using_downgrading_with_references() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock, getMockBuilder Filesystem mock with removeDirectoryAsync expectation and PackageInterface mock; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_remove() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -171,8 +171,8 @@ fn test_remove() {
todo!()
}
+#[ignore = "requires getDownloaderMock which mocks IOInterface/Filesystem via getMockBuilder; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
fn test_get_installation_source() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
diff --git a/crates/shirabe/tests/downloader/hg_downloader_test.rs b/crates/shirabe/tests/downloader/hg_downloader_test.rs
index 0bbcdf7..67a13cb 100644
--- a/crates/shirabe/tests/downloader/hg_downloader_test.rs
+++ b/crates/shirabe/tests/downloader/hg_downloader_test.rs
@@ -35,7 +35,7 @@ impl Drop for TearDown {
// curl_multi_init (todo!()), and ProcessExecutor mocking is not available.
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs PHPUnit mocks of IOInterface/Config/Filesystem/PackageInterface for getDownloaderMock; not available"]
fn test_download_for_package_without_source_reference() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -44,7 +44,7 @@ fn test_download_for_package_without_source_reference() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock with expects() command-sequence assertions and PHPUnit PackageInterface mock; not available"]
fn test_download() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -53,7 +53,7 @@ fn test_download() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs PHPUnit mocks of IOInterface/Config/Filesystem/PackageInterface for getDownloaderMock; not available"]
fn test_updatefor_package_without_source_reference() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -62,7 +62,7 @@ fn test_updatefor_package_without_source_reference() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock with expects() command-sequence assertions and PHPUnit PackageInterface mock; not available"]
fn test_update() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -71,7 +71,7 @@ fn test_update() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs ProcessExecutorMock and PHPUnit Filesystem mock with removeDirectoryAsync expectation; not available"]
fn test_remove() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
@@ -80,7 +80,7 @@ fn test_remove() {
}
#[test]
-#[ignore = "mocks ProcessExecutor/IO and needs an HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs PHPUnit mocks of IOInterface/Config/Filesystem for getDownloaderMock; not available"]
fn test_get_installation_source() {
let working_dir = set_up();
let _tear_down = TearDown::new(working_dir.path().to_path_buf());
diff --git a/crates/shirabe/tests/downloader/perforce_downloader_test.rs b/crates/shirabe/tests/downloader/perforce_downloader_test.rs
index e0f7637..63f1de4 100644
--- a/crates/shirabe/tests/downloader/perforce_downloader_test.rs
+++ b/crates/shirabe/tests/downloader/perforce_downloader_test.rs
@@ -15,29 +15,29 @@ fn set_up() -> TempDir {
// These mock Perforce, the repository config and a Package to drive PerforceDownloader's
// initialization and install paths; mocking is not available here.
+#[ignore = "requires PHPUnit getMockBuilder mocks of IOInterface/PackageInterface/VcsRepository and ProcessExecutorMock via unported set_up()"]
#[test]
-#[ignore = "mocks Perforce/repository/Package; mocking is not available"]
fn test_init_perforce_instantiates_a_new_perforce_object() {
let _test_path = set_up();
todo!()
}
+#[ignore = "requires PHPUnit getMockBuilder mock of Composer\\Util\\Perforce and expects()->never() verification, unavailable in the Rust port"]
#[test]
-#[ignore = "mocks Perforce/repository/Package; mocking is not available"]
fn test_init_perforce_does_nothing_if_perforce_already_set() {
let _test_path = set_up();
todo!()
}
+#[ignore = "requires PHPUnit getMockBuilder mock of Composer\\Util\\Perforce with expects()->once()->method() expectation verification, unavailable in the Rust port"]
#[test]
-#[ignore = "mocks Perforce/repository/Package; mocking is not available"]
fn test_do_install_with_tag() {
let _test_path = set_up();
todo!()
}
+#[ignore = "requires PHPUnit getMockBuilder mock of Composer\\Util\\Perforce with expects()->once()->method() expectation verification, unavailable in the Rust port"]
#[test]
-#[ignore = "mocks Perforce/repository/Package; mocking is not available"]
fn test_do_install_with_no_tag() {
let _test_path = set_up();
todo!()
diff --git a/crates/shirabe/tests/downloader/xz_downloader_test.rs b/crates/shirabe/tests/downloader/xz_downloader_test.rs
index d01779b..973a726 100644
--- a/crates/shirabe/tests/downloader/xz_downloader_test.rs
+++ b/crates/shirabe/tests/downloader/xz_downloader_test.rs
@@ -1,9 +1,37 @@
//! ref: composer/tests/Composer/Test/Downloader/XzDownloaderTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::config::Config;
+use shirabe::downloader::DownloaderInterface;
+use shirabe::downloader::xz_downloader::XzDownloader;
+use shirabe::io::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::package::handle::{CompletePackageHandle, PackageInterfaceHandle};
+use shirabe::util::HttpDownloader;
use shirabe::util::Platform;
+use shirabe::util::ProcessExecutor;
use shirabe::util::filesystem::Filesystem;
+use shirabe::util::r#loop::Loop;
+use shirabe_php_shim::PhpMixed;
+use shirabe_semver::version_parser::VersionParser;
use tempfile::TempDir;
+/// ref: TestCase::getPackage (default class CompletePackage)
+fn get_package(name: &str, version: &str) -> PackageInterfaceHandle {
+ let norm_version = VersionParser.normalize(version, None).unwrap();
+ CompletePackageHandle::new(name.to_string(), norm_version, version.to_string()).into()
+}
+
+fn run<F: std::future::Future>(future: F) -> F::Output {
+ tokio::runtime::Builder::new_current_thread()
+ .build()
+ .unwrap()
+ .block_on(future)
+}
+
fn set_up() -> TempDir {
if Platform::is_windows() {
// markTestSkipped('Skip test on Windows')
@@ -40,11 +68,67 @@ impl Drop for TearDown {
}
}
+/// ref: TestCase::getConfig
+fn get_config(config_options: IndexMap<String, PhpMixed>, use_environment: bool) -> Config {
+ let mut config = Config::new(use_environment, None);
+ let mut merged: IndexMap<String, PhpMixed> = IndexMap::new();
+ merged.insert("config".to_string(), PhpMixed::Array(config_options));
+ config.merge(&merged, "test");
+ config
+}
+
+#[ignore]
#[test]
-#[ignore = "needs a real HttpDownloader/Loop and an XzDownloader download cycle; HttpDownloader construction reaches curl_multi_init (todo!()) in the php-shim"]
fn test_error_messages() {
let test_dir = set_up();
let _tear_down = TearDown::new(test_dir.path().to_path_buf());
- let _ = &test_dir;
- todo!()
+ let test_dir = test_dir.path().to_path_buf();
+
+ let package = get_package("dummy/pkg", "1.0.0");
+ let dist_url = format!("file://{}", file!());
+ package.set_dist_url(Some(dist_url));
+
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let mut config_options: IndexMap<String, PhpMixed> = IndexMap::new();
+ config_options.insert(
+ "vendor-dir".to_string(),
+ PhpMixed::String(test_dir.to_string_lossy().into_owned()),
+ );
+ let config = Rc::new(RefCell::new(get_config(config_options, false)));
+ let http_downloader = Rc::new(RefCell::new(HttpDownloader::new(
+ io.clone(),
+ config.clone(),
+ IndexMap::new(),
+ false,
+ )));
+ let filesystem = Rc::new(RefCell::new(Filesystem::new(None)));
+ let process = Rc::new(RefCell::new(ProcessExecutor::new(Some(io.clone()))));
+ let mut downloader = XzDownloader::new(
+ io,
+ config,
+ http_downloader.clone(),
+ None,
+ None,
+ filesystem,
+ process,
+ );
+
+ let install_path = test_dir.join("install-path");
+ let install_path = install_path.to_string_lossy().into_owned();
+
+ let mut loop_ = Loop::new(http_downloader, None);
+ let promise = Box::pin(async {
+ downloader
+ .download3(package.clone(), &install_path, None)
+ .await
+ .map(|_| ())
+ });
+ run(loop_.wait(vec![promise], None)).unwrap();
+ let result = run(downloader.install2(package, &install_path));
+
+ // Download of invalid tarball should throw an exception.
+ let e = result.expect_err("Download of invalid tarball should throw an exception");
+ let re =
+ regex::Regex::new("(?i)(File format not recognized|Unrecognized archive format)").unwrap();
+ assert!(re.is_match(&e.to_string()));
}
diff --git a/crates/shirabe/tests/downloader/zip_downloader_test.rs b/crates/shirabe/tests/downloader/zip_downloader_test.rs
index c22afa1..0bffa89 100644
--- a/crates/shirabe/tests/downloader/zip_downloader_test.rs
+++ b/crates/shirabe/tests/downloader/zip_downloader_test.rs
@@ -47,8 +47,8 @@ impl Drop for TearDown {
// These construct a ZipDownloader with a mocked IO/HttpDownloader/ProcessExecutor and rely
// on ZipArchive extraction (todo!() in the php-shim) plus mocked unzip behaviour.
+#[ignore = "requires PHPUnit mocks of IOInterface/Config/PackageInterface; set_up() is todo!() and real HttpDownloader reaches curl_multi_init todo!(); no mocking framework"]
#[test]
-#[ignore = "mocks IO/HttpDownloader/ProcessExecutor and uses ZipArchive (todo!())"]
fn test_error_messages() {
let set_up = set_up();
let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf());
@@ -56,8 +56,8 @@ fn test_error_messages() {
todo!()
}
+#[ignore = "requires setPrivateProperty reflection on hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and a getMockBuilder('ZipArchive') mock; no mocking/reflection framework"]
#[test]
-#[ignore = "mocks IO/HttpDownloader/ProcessExecutor and uses ZipArchive (todo!())"]
fn test_zip_archive_only_failed() {
let set_up = set_up();
let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf());
@@ -65,8 +65,8 @@ fn test_zip_archive_only_failed() {
todo!()
}
+#[ignore = "requires setPrivateProperty reflection on hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and a getMockBuilder('ZipArchive') mock throwing ErrorException; no mocking/reflection framework"]
#[test]
-#[ignore = "mocks IO/HttpDownloader/ProcessExecutor and uses ZipArchive (todo!())"]
fn test_zip_archive_extract_only_failed() {
let set_up = set_up();
let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf());
@@ -74,8 +74,8 @@ fn test_zip_archive_extract_only_failed() {
todo!()
}
+#[ignore = "requires setPrivateProperty reflection on hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and a getMockBuilder('ZipArchive') mock; no mocking/reflection framework"]
#[test]
-#[ignore = "mocks IO/HttpDownloader/ProcessExecutor and uses ZipArchive (todo!())"]
fn test_zip_archive_only_good() {
let set_up = set_up();
let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf());
@@ -83,8 +83,8 @@ fn test_zip_archive_only_good() {
todo!()
}
+#[ignore = "requires setPrivateProperty reflection on isWindows/hasZipArchive/unzipCommands, a MockedZipDownloader subclass, and getMockBuilder mocks of Process/ProcessExecutor::executeAsync; no mocking/reflection framework"]
#[test]
-#[ignore = "mocks IO/HttpDownloader/ProcessExecutor and uses ZipArchive (todo!())"]
fn test_system_unzip_only_failed() {
let set_up = set_up();
let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf());
@@ -92,8 +92,8 @@ fn test_system_unzip_only_failed() {
todo!()
}
+#[ignore = "requires setPrivateProperty reflection on isWindows/hasZipArchive/unzipCommands, a MockedZipDownloader subclass, and getMockBuilder mocks of Process/ProcessExecutor::executeAsync; no mocking/reflection framework"]
#[test]
-#[ignore = "mocks IO/HttpDownloader/ProcessExecutor and uses ZipArchive (todo!())"]
fn test_system_unzip_only_good() {
let set_up = set_up();
let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf());
@@ -101,8 +101,8 @@ fn test_system_unzip_only_good() {
todo!()
}
+#[ignore = "requires setPrivateProperty reflection on isWindows/hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and getMockBuilder mocks of Process/ProcessExecutor/ZipArchive; no mocking/reflection framework"]
#[test]
-#[ignore = "mocks IO/HttpDownloader/ProcessExecutor and uses ZipArchive (todo!())"]
fn test_non_windows_fallback_good() {
let set_up = set_up();
let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf());
@@ -110,8 +110,8 @@ fn test_non_windows_fallback_good() {
todo!()
}
+#[ignore = "requires setPrivateProperty reflection on isWindows/hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and getMockBuilder mocks of Process/ProcessExecutor/ZipArchive; no mocking/reflection framework"]
#[test]
-#[ignore = "mocks IO/HttpDownloader/ProcessExecutor and uses ZipArchive (todo!())"]
fn test_non_windows_fallback_failed() {
let set_up = set_up();
let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf());
diff --git a/crates/shirabe/tests/event_dispatcher/event_dispatcher_test.rs b/crates/shirabe/tests/event_dispatcher/event_dispatcher_test.rs
index 8e979a0..2222c3f 100644
--- a/crates/shirabe/tests/event_dispatcher/event_dispatcher_test.rs
+++ b/crates/shirabe/tests/event_dispatcher/event_dispatcher_test.rs
@@ -18,105 +18,105 @@ impl Drop for TearDown {
// listeners (executing CLI/PHP callbacks); mocking and the script-execution machinery are
// not available here.
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires PHPUnit getMockBuilder onlyMethods(getListeners) override and getIOMock, which have no Rust equivalent"]
fn test_listener_exceptions_are_caught() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock and getMockBuilder onlyMethods(getListeners) override, which have no Rust equivalent"]
fn test_dispatcher_can_execute_single_command_line_script() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getMockBuilder mocks for AutoloadGenerator/RepositoryManager/RootPackageInterface/Event, which have no Rust equivalent"]
fn test_dispatcher_pass_dev_mode_to_autoload_generator_for_script_events() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getMockBuilder mocks for RepositoryManager/InstallationManager and PHP callable listeners ([\\$this, 'method']), which have no Rust equivalent"]
fn test_dispatcher_remove_listener() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock and getMockBuilder onlyMethods(getListeners) override, which have no Rust equivalent"]
fn test_dispatcher_can_execute_cli_and_php_in_same_event_script_stack() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock and getMockBuilder onlyMethods(getListeners) override, which have no Rust equivalent"]
fn test_dispatcher_can_put_env() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock and getMockBuilder onlyMethods(getListeners) override, which have no Rust equivalent"]
fn test_dispatcher_appends_dir_bin_on_path_for_every_listener() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock, getMockBuilder onlyMethods(getListeners) override and ReflectionMethod(getPhpExecCommand), which have no Rust equivalent"]
fn test_dispatcher_support_for_additional_args() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock and getMockBuilder onlyMethods(getListeners) returnCallback override, which have no Rust equivalent"]
fn test_dispatcher_can_execute_composer_script_groups() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock and getMockBuilder onlyMethods(getListeners) returnCallback override, which have no Rust equivalent"]
fn test_recursion_in_scripts_names() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock, getIOMock and getMockBuilder onlyMethods(getListeners) returnCallback override, which have no Rust equivalent"]
fn test_dispatcher_detect_infinite_recursion() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getMockBuilder IOInterface mock with writeError/writeRaw expectations and onlyMethods(getListeners) override, which have no Rust equivalent"]
fn test_dispatcher_outputs_command() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getIOMock and getMockBuilder onlyMethods(getListeners) override, which have no Rust equivalent"]
fn test_dispatcher_outputs_error_on_failed_command() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getProcessExecutorMock, getMockBuilder onlyMethods(getListeners) override and LockTransaction mock, which have no Rust equivalent"]
fn test_dispatcher_installer_events() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "mocks Composer/IO/ProcessExecutor and executes script listeners; not ported"]
+#[ignore = "requires getMockBuilder mocks for RootPackageInterface and Event, which have no Rust equivalent"]
fn test_dispatcher_doesnt_return_skipped_scripts() {
let _tear_down = TearDown;
todo!()
diff --git a/crates/shirabe/tests/factory_test.rs b/crates/shirabe/tests/factory_test.rs
index cfbbaee..04d407b 100644
--- a/crates/shirabe/tests/factory_test.rs
+++ b/crates/shirabe/tests/factory_test.rs
@@ -16,7 +16,7 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "mocks an IOInterface with a writeError expectation and a Config returning disable-tls=true; mocking is not available"]
+#[ignore = "requires PHPUnit-style mocks: an IOInterface mock verifying writeError is called exactly once with the exact warning, plus a Config mock stubbing get('disable-tls')=>true; no such mock/expectation infrastructure (e.g. mockall) exists"]
fn test_default_values_are_as_expected() {
let _tear_down = TearDown;
diff --git a/crates/shirabe/tests/installed_versions_test.rs b/crates/shirabe/tests/installed_versions_test.rs
index d20bc84..6757e03 100644
--- a/crates/shirabe/tests/installed_versions_test.rs
+++ b/crates/shirabe/tests/installed_versions_test.rs
@@ -1,108 +1,449 @@
//! ref: composer/tests/Composer/Test/InstalledVersionsTest.php
-// setUpBeforeClass reflects into ClassLoader::registeredLoaders and the cases load
-// installed.php fixtures via InstalledVersions::reload; the reflection and fixture loading
-// are not ported.
+// setUpBeforeClass reflects into ClassLoader::registeredLoaders to make it seem like no class
+// loaders are registered; this is not ported because InstalledVersions::reload already disables
+// the multiple-ClassLoader-based checks by setting installedIsLocalDir to false. The PHP setUp
+// loads the installed_relative.php fixture via `require`; here the fixture is built inline as an
+// IndexMap<String, PhpMixed> with the tmp root substituted for `$dir`.
+use indexmap::IndexMap;
+use shirabe::installed_versions::InstalledVersions;
+use shirabe_php_shim::{PhpMixed, realpath};
+use shirabe_semver::version_parser::VersionParser;
use tempfile::TempDir;
-fn set_up() -> TempDir {
+fn arr(entries: Vec<(&str, PhpMixed)>) -> PhpMixed {
+ let mut m = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ PhpMixed::Array(m)
+}
+
+fn list(items: Vec<PhpMixed>) -> PhpMixed {
+ PhpMixed::List(items)
+}
+
+fn s(value: &str) -> PhpMixed {
+ PhpMixed::String(value.to_string())
+}
+
+/// Builds the installed_relative.php fixture with `$dir` substituted by `dir`.
+fn fixture(dir: &str) -> IndexMap<String, PhpMixed> {
+ let root_install_path = format!("{}/./", dir);
+ let mut data = IndexMap::new();
+
+ data.insert(
+ "root".to_string(),
+ arr(vec![
+ ("name", s("__root__")),
+ ("pretty_version", s("dev-master")),
+ ("version", s("dev-master")),
+ ("reference", s("sourceref-by-default")),
+ ("type", s("library")),
+ ("install_path", s(&root_install_path)),
+ ("aliases", list(vec![s("1.10.x-dev")])),
+ ("dev", PhpMixed::Bool(true)),
+ ]),
+ );
+
+ data.insert(
+ "versions".to_string(),
+ arr(vec![
+ (
+ "__root__",
+ arr(vec![
+ ("pretty_version", s("dev-master")),
+ ("version", s("dev-master")),
+ ("reference", s("sourceref-by-default")),
+ ("type", s("library")),
+ ("install_path", s(&root_install_path)),
+ ("aliases", list(vec![s("1.10.x-dev")])),
+ ("dev_requirement", PhpMixed::Bool(false)),
+ ]),
+ ),
+ (
+ "a/provider",
+ arr(vec![
+ ("pretty_version", s("1.1")),
+ ("version", s("1.1.0.0")),
+ ("reference", s("distref-as-no-source")),
+ ("type", s("library")),
+ ("install_path", s(&format!("{}/vendor/a/provider", dir))),
+ ("aliases", list(vec![])),
+ ("dev_requirement", PhpMixed::Bool(false)),
+ ]),
+ ),
+ (
+ "a/provider2",
+ arr(vec![
+ ("pretty_version", s("1.2")),
+ ("version", s("1.2.0.0")),
+ ("reference", s("distref-as-installed-from-dist")),
+ ("type", s("library")),
+ ("install_path", s(&format!("{}/vendor/a/provider2", dir))),
+ ("aliases", list(vec![s("1.4")])),
+ ("dev_requirement", PhpMixed::Bool(false)),
+ ]),
+ ),
+ (
+ "b/replacer",
+ arr(vec![
+ ("pretty_version", s("2.2")),
+ ("version", s("2.2.0.0")),
+ ("reference", PhpMixed::Null),
+ ("type", s("library")),
+ ("install_path", s(&format!("{}/vendor/b/replacer", dir))),
+ ("aliases", list(vec![])),
+ ("dev_requirement", PhpMixed::Bool(false)),
+ ]),
+ ),
+ (
+ "c/c",
+ arr(vec![
+ ("pretty_version", s("3.0")),
+ ("version", s("3.0.0.0")),
+ ("reference", PhpMixed::Null),
+ ("type", s("library")),
+ ("install_path", s("/foo/bar/vendor/c/c")),
+ ("aliases", list(vec![])),
+ ("dev_requirement", PhpMixed::Bool(true)),
+ ]),
+ ),
+ (
+ "foo/impl",
+ arr(vec![
+ ("dev_requirement", PhpMixed::Bool(false)),
+ (
+ "provided",
+ list(vec![s("^1.1"), s("1.2"), s("1.4"), s("2.0")]),
+ ),
+ ]),
+ ),
+ (
+ "foo/impl2",
+ arr(vec![
+ ("dev_requirement", PhpMixed::Bool(false)),
+ ("provided", list(vec![s("2.0")])),
+ ("replaced", list(vec![s("2.2")])),
+ ]),
+ ),
+ (
+ "foo/replaced",
+ arr(vec![
+ ("dev_requirement", PhpMixed::Bool(false)),
+ ("replaced", list(vec![s("^3.0")])),
+ ]),
+ ),
+ (
+ "meta/package",
+ arr(vec![
+ ("pretty_version", s("3.0")),
+ ("version", s("3.0.0.0")),
+ ("reference", PhpMixed::Null),
+ ("type", s("metapackage")),
+ ("install_path", PhpMixed::Null),
+ ("aliases", list(vec![])),
+ ("dev_requirement", PhpMixed::Bool(false)),
+ ]),
+ ),
+ ]),
+ );
+
+ data
+}
+
+/// Returns the tmp root (kept alive for the duration of the test) and its path string.
+fn set_up() -> (TempDir, String) {
let root = TempDir::new().unwrap();
+ let dir = root.path().to_str().unwrap().to_string();
- // Loading the installed_relative.php fixture and InstalledVersions::reload are not ported.
- todo!();
+ InstalledVersions::reload(fixture(&dir));
- #[allow(unreachable_code)]
- root
+ (root, dir)
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_installed_packages() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ let names = vec![
+ "__root__".to_string(),
+ "a/provider".to_string(),
+ "a/provider2".to_string(),
+ "b/replacer".to_string(),
+ "c/c".to_string(),
+ "foo/impl".to_string(),
+ "foo/impl2".to_string(),
+ "foo/replaced".to_string(),
+ "meta/package".to_string(),
+ ];
+ assert_eq!(names, InstalledVersions::get_installed_packages());
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_is_installed() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ let cases: Vec<(bool, &str, bool)> = vec![
+ (true, "foo/impl", true),
+ (true, "foo/replaced", true),
+ (true, "c/c", true),
+ (false, "c/c", false),
+ (true, "__root__", true),
+ (true, "b/replacer", true),
+ (false, "not/there", true),
+ (true, "meta/package", true),
+ ];
+
+ for (expected, name, include_dev_requirements) in cases {
+ assert_eq!(
+ expected,
+ InstalledVersions::is_installed(name, include_dev_requirements)
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_satisfies() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ let cases: Vec<(bool, &str, &str)> = vec![
+ (true, "foo/impl", "1.5"),
+ (true, "foo/impl", "1.2"),
+ (true, "foo/impl", "^1.0"),
+ (true, "foo/impl", "^3 || ^2"),
+ (false, "foo/impl", "^3"),
+ (true, "foo/replaced", "3.5"),
+ (true, "foo/replaced", "^3.2"),
+ (false, "foo/replaced", "4.0"),
+ (true, "c/c", "3.0.0"),
+ (true, "c/c", "^3"),
+ (false, "c/c", "^3.1"),
+ (true, "__root__", "dev-master"),
+ (true, "__root__", "^1.10"),
+ (false, "__root__", "^2"),
+ (true, "b/replacer", "^2.1"),
+ (false, "b/replacer", "^2.3"),
+ (true, "a/provider2", "^1.2"),
+ (true, "a/provider2", "^1.4"),
+ (false, "a/provider2", "^1.5"),
+ ];
+
+ for (expected, name, constraint) in cases {
+ assert_eq!(
+ expected,
+ InstalledVersions::satisfies(&VersionParser, name, Some(constraint)).unwrap()
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_version_ranges() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ let cases: Vec<(&str, &str)> = vec![
+ ("dev-master || 1.10.x-dev", "__root__"),
+ ("^1.1 || 1.2 || 1.4 || 2.0", "foo/impl"),
+ ("2.2 || 2.0", "foo/impl2"),
+ ("^3.0", "foo/replaced"),
+ ("1.1", "a/provider"),
+ ("1.2 || 1.4", "a/provider2"),
+ ("2.2", "b/replacer"),
+ ("3.0", "c/c"),
+ ];
+
+ for (expected, name) in cases {
+ assert_eq!(
+ expected,
+ InstalledVersions::get_version_ranges(name).unwrap()
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_version() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ let cases: Vec<(Option<&str>, &str)> = vec![
+ (Some("dev-master"), "__root__"),
+ (None, "foo/impl"),
+ (None, "foo/impl2"),
+ (None, "foo/replaced"),
+ (Some("1.1.0.0"), "a/provider"),
+ (Some("1.2.0.0"), "a/provider2"),
+ (Some("2.2.0.0"), "b/replacer"),
+ (Some("3.0.0.0"), "c/c"),
+ ];
+
+ for (expected, name) in cases {
+ assert_eq!(
+ expected.map(|s| s.to_string()),
+ InstalledVersions::get_version(name).unwrap()
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_pretty_version() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ let cases: Vec<(Option<&str>, &str)> = vec![
+ (Some("dev-master"), "__root__"),
+ (None, "foo/impl"),
+ (None, "foo/impl2"),
+ (None, "foo/replaced"),
+ (Some("1.1"), "a/provider"),
+ (Some("1.2"), "a/provider2"),
+ (Some("2.2"), "b/replacer"),
+ (Some("3.0"), "c/c"),
+ ];
+
+ for (expected, name) in cases {
+ assert_eq!(
+ expected.map(|s| s.to_string()),
+ InstalledVersions::get_pretty_version(name).unwrap()
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_version_out_of_bounds() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ assert!(InstalledVersions::get_version("not/installed").is_err());
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_root_package() {
- let _root = set_up();
- todo!()
+ let (_root, dir) = set_up();
+
+ let expected = {
+ let mut m = IndexMap::new();
+ m.insert("name".to_string(), s("__root__"));
+ m.insert("pretty_version".to_string(), s("dev-master"));
+ m.insert("version".to_string(), s("dev-master"));
+ m.insert("reference".to_string(), s("sourceref-by-default"));
+ m.insert("type".to_string(), s("library"));
+ m.insert("install_path".to_string(), s(&format!("{}/./", dir)));
+ m.insert("aliases".to_string(), list(vec![s("1.10.x-dev")]));
+ m.insert("dev".to_string(), PhpMixed::Bool(true));
+ m
+ };
+
+ assert_eq!(expected, InstalledVersions::get_root_package());
}
+#[ignore = "InstalledVersions::get_raw_data not ported (only get_all_raw_data exists)"]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_raw_data() {
let _root = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_reference() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ let cases: Vec<(Option<&str>, &str)> = vec![
+ (Some("sourceref-by-default"), "__root__"),
+ (None, "foo/impl"),
+ (None, "foo/impl2"),
+ (None, "foo/replaced"),
+ (Some("distref-as-no-source"), "a/provider"),
+ (Some("distref-as-installed-from-dist"), "a/provider2"),
+ (None, "b/replacer"),
+ (None, "c/c"),
+ ];
+
+ for (expected, name) in cases {
+ assert_eq!(
+ expected.map(|s| s.to_string()),
+ InstalledVersions::get_reference(name).unwrap()
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_installed_packages_by_type() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ let names = vec![
+ "__root__".to_string(),
+ "a/provider".to_string(),
+ "a/provider2".to_string(),
+ "b/replacer".to_string(),
+ "c/c".to_string(),
+ ];
+
+ assert_eq!(
+ names,
+ InstalledVersions::get_installed_packages_by_type("library")
+ );
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_get_install_path() {
- let _root = set_up();
- todo!()
+ let (_root, dir) = set_up();
+
+ assert_eq!(
+ realpath(&dir),
+ realpath(
+ &InstalledVersions::get_install_path("__root__")
+ .unwrap()
+ .unwrap()
+ )
+ );
+ assert_eq!(
+ Some("/foo/bar/vendor/c/c".to_string()),
+ InstalledVersions::get_install_path("c/c").unwrap()
+ );
+ assert_eq!(
+ None,
+ InstalledVersions::get_install_path("foo/impl").unwrap()
+ );
}
+#[ignore]
#[test]
-#[ignore = "needs reflection into ClassLoader::registeredLoaders and installed.php fixtures (not ported)"]
fn test_with_class_loader_loaded() {
- let _root = set_up();
- todo!()
+ let (_root, _dir) = set_up();
+
+ // The reflection into ClassLoader::registeredLoaders is not ported; installedIsLocalDir is
+ // toggled directly via the exposed setter to mirror the PHP reflection on it.
+ InstalledVersions::set_installed_is_local_dir(true);
+
+ assert!(!InstalledVersions::is_installed("foo/bar", true));
+
+ let reload_data = {
+ let mut m = IndexMap::new();
+ m.insert(
+ "root".to_string(),
+ PhpMixed::Array(InstalledVersions::get_root_package()),
+ );
+ m.insert(
+ "versions".to_string(),
+ arr(vec![(
+ "foo/bar",
+ arr(vec![
+ ("version", s("1.0.0")),
+ ("dev_requirement", PhpMixed::Bool(false)),
+ ]),
+ )]),
+ );
+ m
+ };
+ InstalledVersions::reload(reload_data);
+ assert!(InstalledVersions::is_installed("foo/bar", true));
}
diff --git a/crates/shirabe/tests/installer/binary_installer_test.rs b/crates/shirabe/tests/installer/binary_installer_test.rs
index 0a22243..7bd5eea 100644
--- a/crates/shirabe/tests/installer/binary_installer_test.rs
+++ b/crates/shirabe/tests/installer/binary_installer_test.rs
@@ -24,7 +24,7 @@ impl Drop for TearDown {
// program's output. It needs a real PHP runtime, the binary-proxy generation, and a
// mocked Package's getBinaries(), none of which are available here.
#[test]
-#[ignore = "installs and executes a PHP binary via ProcessExecutor (needs a real PHP runtime and binary proxies) and mocks a Package"]
+#[ignore = "needs PHPUnit getMockBuilder mocks of IOInterface and Package::getBinaries() plus a real PHP runtime to execute the installed binary and assert its output"]
fn test_install_and_exec_binary_with_full_compat() {
todo!()
}
diff --git a/crates/shirabe/tests/installer/installation_manager_test.rs b/crates/shirabe/tests/installer/installation_manager_test.rs
index b44a814..a12381b 100644
--- a/crates/shirabe/tests/installer/installation_manager_test.rs
+++ b/crates/shirabe/tests/installer/installation_manager_test.rs
@@ -8,50 +8,50 @@ fn set_up() {
// These mock individual installers, the repository and IO to drive InstallationManager's
// add/execute/install/update/uninstall logic; mocking is not available here.
+#[ignore = "requires PHPUnit mocks of InstallerInterface/IOInterface/Loop with expects() call-count assertions"]
#[test]
-#[ignore = "mocks installers/repository/IO to drive InstallationManager; mocking is not available"]
fn test_add_get_installer() {
todo!()
}
+#[ignore = "requires PHPUnit mocks of InstallerInterface/IOInterface/Loop with expects() call-count assertions"]
#[test]
-#[ignore = "mocks installers/repository/IO to drive InstallationManager; mocking is not available"]
fn test_add_remove_installer() {
todo!()
}
+#[ignore = "requires partial PHPUnit mock of InstallationManager (onlyMethods install/update/uninstall) and PackageInterface mock"]
#[test]
-#[ignore = "mocks installers/repository/IO to drive InstallationManager; mocking is not available"]
fn test_execute() {
todo!()
}
+#[ignore = "requires PHPUnit mocks of InstallerInterface/PackageInterface with expects() call-count assertions"]
#[test]
-#[ignore = "mocks installers/repository/IO to drive InstallationManager; mocking is not available"]
fn test_install() {
todo!()
}
+#[ignore = "requires PHPUnit mocks of InstallerInterface/PackageInterface with expects() call-count assertions"]
#[test]
-#[ignore = "mocks installers/repository/IO to drive InstallationManager; mocking is not available"]
fn test_update_with_equal_types() {
todo!()
}
+#[ignore = "requires PHPUnit mocks of InstallerInterface/PackageInterface with expects() call-count assertions"]
#[test]
-#[ignore = "mocks installers/repository/IO to drive InstallationManager; mocking is not available"]
fn test_update_with_not_equal_types() {
todo!()
}
+#[ignore = "requires PHPUnit mocks of InstallerInterface/PackageInterface with expects() call-count assertions"]
#[test]
-#[ignore = "mocks installers/repository/IO to drive InstallationManager; mocking is not available"]
fn test_uninstall() {
todo!()
}
+#[ignore = "requires PHPUnit mock of LibraryInstaller and PackageInterface with expects() call-count assertions"]
#[test]
-#[ignore = "mocks installers/repository/IO to drive InstallationManager; mocking is not available"]
fn test_install_binary() {
todo!()
}
diff --git a/crates/shirabe/tests/installer/library_installer_test.rs b/crates/shirabe/tests/installer/library_installer_test.rs
index 2182962..62a2c0c 100644
--- a/crates/shirabe/tests/installer/library_installer_test.rs
+++ b/crates/shirabe/tests/installer/library_installer_test.rs
@@ -1,77 +1,188 @@
//! ref: composer/tests/Composer/Test/Installer/LibraryInstallerTest.php
-/// Sets up a Composer/Config over root/vendor/bin temp dirs plus mocked
-/// DownloadManager/repository/IO. The temp-dir helpers and the mocks are not
-/// available here, so this remains a stub.
-fn set_up() {
- todo!()
-}
+use std::cell::RefCell;
+use std::fs;
+use std::rc::Rc;
-/// Removes the root dir created by `set_up`, which is itself a stub.
-fn tear_down() {
- todo!()
+use indexmap::IndexMap;
+use tempfile::TempDir;
+
+use shirabe::composer::{
+ ComposerHandle, PartialComposerHandle, PartialComposerWeakHandle, PartialOrFullComposer,
+};
+use shirabe::config::Config;
+use shirabe::downloader::DownloadManager;
+use shirabe::installer::{InstallerInterface, LibraryInstaller};
+use shirabe::io::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::repository::InstalledArrayRepository;
+use shirabe::repository::WritableRepositoryInterface;
+use shirabe::util::filesystem::Filesystem;
+use shirabe_php_shim::PhpMixed;
+
+use crate::test_case::get_package;
+
+/// Mirror of setUp(): builds the Composer/Config over temp root/vendor/bin dirs
+/// plus a real DownloadManager and a NullIO. The `_composer_rc` keeps the inner
+/// Rc alive for the duration of the test since LibraryInstaller only holds a weak
+/// handle.
+struct SetUp {
+ root: TempDir,
+ vendor_dir: String,
+ bin_dir: String,
+ io: Rc<RefCell<dyn IOInterface>>,
+ composer: PartialComposerWeakHandle,
+ fs: Filesystem,
+ _composer_rc: ComposerHandle,
}
-struct TearDown;
+fn set_up() -> SetUp {
+ let mut fs = Filesystem::new(None);
+
+ let root = TempDir::new().unwrap();
+ let root_dir = fs::canonicalize(root.path())
+ .unwrap()
+ .to_string_lossy()
+ .into_owned();
+
+ let vendor_dir = format!("{}/vendor", root_dir);
+ fs::create_dir_all(&vendor_dir).unwrap();
-impl Drop for TearDown {
- fn drop(&mut self) {
- tear_down();
+ let bin_dir = format!("{}/bin", root_dir);
+ fs::create_dir_all(&bin_dir).unwrap();
+
+ let mut config = Config::new(false, None);
+ let mut config_section: IndexMap<String, PhpMixed> = IndexMap::new();
+ config_section.insert(
+ "vendor-dir".to_string(),
+ PhpMixed::String(vendor_dir.clone()),
+ );
+ config_section.insert("bin-dir".to_string(), PhpMixed::String(bin_dir.clone()));
+ let mut merged: IndexMap<String, PhpMixed> = IndexMap::new();
+ merged.insert("config".to_string(), PhpMixed::Array(config_section));
+ config.merge(&merged, Config::SOURCE_UNKNOWN);
+ let config_rc = Rc::new(RefCell::new(config));
+
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+
+ let dm = DownloadManager::new(io.clone(), false, None);
+ let dm_rc = Rc::new(RefCell::new(dm));
+
+ let composer_rc = Rc::new(RefCell::new(PartialOrFullComposer::new_full()));
+ let composer = ComposerHandle::from_rc_unchecked(composer_rc.clone());
+ composer.borrow_mut().set_config(config_rc);
+ composer.borrow_mut().set_download_manager(dm_rc);
+
+ let weak = PartialComposerHandle::from_rc(composer_rc).downgrade();
+
+ SetUp {
+ root,
+ vendor_dir,
+ bin_dir,
+ io,
+ composer: weak,
+ fs,
+ _composer_rc: composer,
}
}
-// These construct a LibraryInstaller over a temp dir with a mocked IO/Filesystem/repository
-// and mocked packages to drive install/update/uninstall and path resolution.
+fn tear_down(setup: &mut SetUp) {
+ let root = setup.root.path().to_path_buf();
+ setup.fs.remove_directory(&root).ok();
+}
+
+#[ignore]
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
fn test_installer_creation_should_not_create_vendor_directory() {
- todo!()
+ let mut setup = set_up();
+ setup.fs.remove_directory(&setup.vendor_dir).unwrap();
+
+ LibraryInstaller::new(setup.io.clone(), setup.composer.clone(), None, None, None);
+ assert!(!std::path::Path::new(&setup.vendor_dir).exists());
+
+ tear_down(&mut setup);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
fn test_installer_creation_should_not_create_bin_directory() {
- todo!()
+ let mut setup = set_up();
+ setup.fs.remove_directory(&setup.bin_dir).unwrap();
+
+ LibraryInstaller::new(setup.io.clone(), setup.composer.clone(), None, None, None);
+ assert!(!std::path::Path::new(&setup.bin_dir).exists());
+
+ tear_down(&mut setup);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
fn test_is_installed() {
- todo!()
+ let mut setup = set_up();
+ let mut library =
+ LibraryInstaller::new(setup.io.clone(), setup.composer.clone(), None, None, None);
+ let package = get_package("test/pkg", "1.0.0");
+
+ let mut repository = InstalledArrayRepository::new().unwrap();
+ assert!(!library.is_installed(&repository, package.clone()));
+
+ // package being in repo is not enough to be installed
+ repository.add_package(package.clone()).unwrap();
+ assert!(!library.is_installed(&repository, package.clone()));
+
+ // package being in repo and vendor/pkg/foo dir present means it is seen as installed
+ let pkg_dir = format!("{}/{}", setup.vendor_dir, package.get_pretty_name());
+ fs::create_dir_all(&pkg_dir).unwrap();
+ assert!(library.is_installed(&repository, package.clone()));
+
+ repository.remove_package(package.clone()).unwrap();
+ assert!(!library.is_installed(&repository, package));
+
+ tear_down(&mut setup);
}
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
+#[ignore = "requires PHPUnit mock of DownloadManager (expects(once)->method('install')->will(resolve(null))) and InstalledRepositoryInterface (expects(once)->addPackage); a real DownloadManager would attempt a download"]
fn test_install() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
+#[ignore = "requires PHPUnit mocks (Filesystem::rename, DownloadManager::update, repository hasPackage/add/remove with onConsecutiveCalls) and Package::setTargetDir, which is not exposed on PackageInterfaceHandle"]
fn test_update() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
+#[ignore = "requires PHPUnit mock of DownloadManager (expects(once)->method('remove')->will(resolve(null))) and InstalledRepositoryInterface (hasPackage onConsecutiveCalls, removePackage)"]
fn test_uninstall() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
fn test_get_install_path_without_target_dir() {
- todo!()
+ let mut setup = set_up();
+ let mut library =
+ LibraryInstaller::new(setup.io.clone(), setup.composer.clone(), None, None, None);
+ let package = get_package("Vendor/Pkg", "1.0.0");
+
+ assert_eq!(
+ format!("{}/{}", setup.vendor_dir, package.get_pretty_name()),
+ library.get_install_path(package).unwrap()
+ );
+
+ tear_down(&mut setup);
}
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
+#[ignore = "Package::setTargetDir is not exposed on PackageInterfaceHandle, so the target-dir cannot be set on the test package"]
fn test_get_install_path_with_target_dir() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Filesystem/repository and packages to drive LibraryInstaller; mocking is not available"]
+#[ignore = "requires PHPUnit mock of BinaryInstaller (expects(never)->removeBinaries, expects(once)->installBinaries) injected via LibraryInstaller's binaryInstaller argument"]
fn test_ensure_binaries_installed() {
todo!()
}
diff --git a/crates/shirabe/tests/installer/suggested_packages_reporter_test.rs b/crates/shirabe/tests/installer/suggested_packages_reporter_test.rs
index fbdb16f..bd7672e 100644
--- a/crates/shirabe/tests/installer/suggested_packages_reporter_test.rs
+++ b/crates/shirabe/tests/installer/suggested_packages_reporter_test.rs
@@ -1,75 +1,123 @@
//! ref: composer/tests/Composer/Test/Installer/SuggestedPackagesReporterTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::installer::SuggestedPackagesReporter;
+use shirabe::io::IOInterface;
+use shirabe::io::null_io::NullIO;
+
/// Builds an IO mock and a SuggestedPackagesReporter over it. The IO mock
/// (`getIOMock`) is not available here, so this remains a stub.
fn set_up() {
todo!()
}
+/// ref: SuggestedPackagesReporterTest::getSuggestedPackageArray
+fn get_suggested_package_array() -> IndexMap<String, String> {
+ let mut entry = IndexMap::new();
+ entry.insert("source".to_string(), "a".to_string());
+ entry.insert("target".to_string(), "b".to_string());
+ entry.insert("reason".to_string(), "c".to_string());
+ entry
+}
+
+fn reporter() -> SuggestedPackagesReporter {
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ SuggestedPackagesReporter::new(io)
+}
+
// These construct a SuggestedPackagesReporter with a mocked IO and assert its accumulated
// suggestions and formatted output; mocking is not available here.
+#[ignore = "asserts IO mock output via getIOMock()->expects(); no IO mocking infrastructure exists and BufferIO::new/get_output are todo!()"]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_constructor() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_get_packages_empty_by_default() {
- todo!()
+ let reporter = reporter();
+ assert!(reporter.get_packages().is_empty());
}
+#[ignore]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_get_packages() {
- todo!()
+ let suggested_package = get_suggested_package_array();
+ let mut reporter = reporter();
+ reporter.add_package(
+ suggested_package["source"].clone(),
+ suggested_package["target"].clone(),
+ suggested_package["reason"].clone(),
+ );
+ assert_eq!(&vec![suggested_package], reporter.get_packages());
}
+#[ignore]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_add_package_appends() {
- todo!()
+ let suggested_package_a = get_suggested_package_array();
+ let mut suggested_package_b = get_suggested_package_array();
+ suggested_package_b.insert("source".to_string(), "different source".to_string());
+ suggested_package_b.insert("reason".to_string(), "different reason".to_string());
+ let mut reporter = reporter();
+ reporter.add_package(
+ suggested_package_a["source"].clone(),
+ suggested_package_a["target"].clone(),
+ suggested_package_a["reason"].clone(),
+ );
+ reporter.add_package(
+ suggested_package_b["source"].clone(),
+ suggested_package_b["target"].clone(),
+ suggested_package_b["reason"].clone(),
+ );
+ assert_eq!(
+ &vec![suggested_package_a, suggested_package_b],
+ reporter.get_packages()
+ );
}
+#[ignore = "addSuggestionsFromPackage test mocks Package::getSuggests; set_suggests only exists on RootPackageHandle, so the non-root Package fixture with suggests cannot be expressed"]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_add_suggestions_from_package() {
todo!()
}
+#[ignore = "asserts IO mock output via getIOMock()->expects(); no IO mocking infrastructure exists and BufferIO::new/get_output are todo!()"]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_output() {
todo!()
}
+#[ignore = "asserts IO mock output via getIOMock()->expects(); no IO mocking infrastructure exists and BufferIO::new/get_output are todo!()"]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_output_with_no_suggestion_reason() {
todo!()
}
+#[ignore = "asserts IO mock output via getIOMock()->expects(); no IO mocking infrastructure exists and BufferIO::new/get_output are todo!()"]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_output_ignores_formatting() {
todo!()
}
+#[ignore = "asserts IO mock output via getIOMock()->expects(); no IO mocking infrastructure exists and BufferIO::new/get_output are todo!()"]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_output_multiple_packages() {
todo!()
}
+#[ignore = "asserts IO mock output via getIOMock()->expects() and uses getMockBuilder mocks of InstalledRepository/PackageInterface; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_output_skip_installed_packages() {
todo!()
}
+#[ignore = "uses getMockBuilder mock of InstalledRepository with ->expects($this->exactly(0)) call-count assertion; no mocking infrastructure exists"]
#[test]
-#[ignore = "mocks IO to drive SuggestedPackagesReporter output; mocking is not available"]
fn test_output_not_getting_installed_packages_when_no_suggestions() {
todo!()
}
diff --git a/crates/shirabe/tests/installer_test.rs b/crates/shirabe/tests/installer_test.rs
index e4f6c6f..e2d4939 100644
--- a/crates/shirabe/tests/installer_test.rs
+++ b/crates/shirabe/tests/installer_test.rs
@@ -22,28 +22,28 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "not yet ported (end-to-end Installer integration over fixtures; constraint parsing uses a look-around regex)"]
+#[ignore = "requires PHPUnit getMockBuilder mocks of DownloadManager/Config/EventDispatcher/HttpDownloader/JsonFile/AutoloadGenerator plus an unported InstallationManagerMock and the provideInstaller data provider; no mocking infrastructure exists"]
fn test_installer() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "not yet ported (end-to-end Installer integration over fixtures; constraint parsing uses a look-around regex)"]
+#[ignore = "delegates to unported do_test_integration which needs FactoryMock, InstalledFilesystemRepositoryMock, the loadIntegrationTests .test-fixture loader and a symfony console Application; none exist in the Rust port"]
fn test_slow_integration() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "not yet ported (end-to-end Installer integration over fixtures; constraint parsing uses a look-around regex)"]
+#[ignore = "delegates to unported do_test_integration which needs FactoryMock, InstalledFilesystemRepositoryMock, the loadIntegrationTests .test-fixture loader and a symfony console Application; none exist in the Rust port"]
fn test_integration_with_pool_optimizer() {
let _tear_down = TearDown;
todo!()
}
#[test]
-#[ignore = "not yet ported (end-to-end Installer integration over fixtures; constraint parsing uses a look-around regex)"]
+#[ignore = "delegates to unported do_test_integration which needs FactoryMock, InstalledFilesystemRepositoryMock, the loadIntegrationTests .test-fixture loader and a symfony console Application; none exist in the Rust port"]
fn test_integration_with_raw_pool() {
let _tear_down = TearDown;
todo!()
diff --git a/crates/shirabe/tests/io/console_io_test.rs b/crates/shirabe/tests/io/console_io_test.rs
index a931a8b..c1adbd4 100644
--- a/crates/shirabe/tests/io/console_io_test.rs
+++ b/crates/shirabe/tests/io/console_io_test.rs
@@ -2,80 +2,128 @@
// These mock Symfony's InputInterface/OutputInterface/HelperSet (and QuestionHelper) to
// drive ConsoleIO; those console abstractions are not ported.
+
+use indexmap::IndexMap;
+use shirabe::io::ConsoleIO;
+use shirabe::io::IOInterfaceImmutable;
+use shirabe::io::IOInterfaceMutable;
+use shirabe_external_packages::symfony::console::helper::HelperSet;
+use shirabe_external_packages::symfony::console::input::array_input::ArrayInput;
+use shirabe_external_packages::symfony::console::input::input_interface::InputInterface;
+use shirabe_external_packages::symfony::console::output::buffered_output::BufferedOutput;
+use shirabe_external_packages::symfony::console::output::output_interface::OutputInterface;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+/// Builds a ConsoleIO backed by real, side-effect-free Input/Output/HelperSet. PHP uses
+/// PHPUnit mocks here, but for tests that exercise only the authentication map they carry no
+/// expectations, so concrete implementations are an exact substitute.
+fn make_console_io() -> ConsoleIO {
+ let input: Rc<RefCell<dyn InputInterface>> =
+ Rc::new(RefCell::new(ArrayInput::new(vec![], None).unwrap()));
+ let output: Rc<RefCell<dyn OutputInterface>> =
+ Rc::new(RefCell::new(BufferedOutput::new(None, false, None)));
+ let helper_set = HelperSet::default();
+ ConsoleIO::new(input, output, helper_set)
+}
+
+#[ignore = "requires a PHPUnit mock of InputInterface::isInteractive with willReturnOnConsecutiveCalls; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_is_interactive() {
todo!()
}
+#[ignore = "requires a PHPUnit mock of OutputInterface with expects()->method('write')->with() expectation verification; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_write() {
todo!()
}
+#[ignore = "requires a PHPUnit mock of ConsoleOutputInterface with getErrorOutput/write expectation verification; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_write_error() {
todo!()
}
+#[ignore = "requires a PHPUnit mock of OutputInterface with a write() callback expectation verification; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_write_with_multiple_line_string_when_debugging() {
todo!()
}
+#[ignore = "requires a PHPUnit mock of OutputInterface with willReturnCallback series expectation verification; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_overwrite() {
todo!()
}
+#[ignore = "requires a PHPUnit mock of QuestionHelper/HelperSet with ask/get expectation verification; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_ask() {
todo!()
}
+#[ignore = "requires a PHPUnit mock of QuestionHelper/HelperSet with ask/get expectation verification; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_ask_confirmation() {
todo!()
}
+#[ignore = "requires a PHPUnit mock of QuestionHelper/HelperSet with ask/get expectation verification; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_ask_and_validate() {
todo!()
}
+#[ignore = "requires a PHPUnit mock of QuestionHelper/HelperSet with ask/get expectation verification; no mocking framework"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_select() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_set_and_get_authentication() {
- todo!()
+ let mut console_io = make_console_io();
+ console_io.set_authentication(
+ "repoName".to_string(),
+ "l3l0".to_string(),
+ Some("passwd".to_string()),
+ );
+
+ let mut expected: IndexMap<String, Option<String>> = IndexMap::new();
+ expected.insert("username".to_string(), Some("l3l0".to_string()));
+ expected.insert("password".to_string(), Some("passwd".to_string()));
+ assert_eq!(expected, console_io.get_authentication("repoName"));
}
+#[ignore]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_get_authentication_when_did_not_set() {
- todo!()
+ let console_io = make_console_io();
+
+ let mut expected: IndexMap<String, Option<String>> = IndexMap::new();
+ expected.insert("username".to_string(), None);
+ expected.insert("password".to_string(), None);
+ assert_eq!(expected, console_io.get_authentication("repoName"));
}
+#[ignore]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_has_authentication() {
- todo!()
+ let mut console_io = make_console_io();
+ console_io.set_authentication(
+ "repoName".to_string(),
+ "l3l0".to_string(),
+ Some("passwd".to_string()),
+ );
+
+ assert!(console_io.has_authentication("repoName"));
+ assert!(!console_io.has_authentication("repoName2"));
}
+#[ignore = "data provider includes malformed-UTF-8 inputs (e.g. \\xFF, \\xC3\\x28); sanitize() takes PhpMixed::String which is UTF-8-only and cannot carry invalid bytes, so those cases are unrepresentable"]
#[test]
-#[ignore = "mocks Symfony Input/Output/HelperSet to drive ConsoleIO; not ported"]
fn test_sanitize() {
todo!()
}
diff --git a/crates/shirabe/tests/json/composer_schema_test.rs b/crates/shirabe/tests/json/composer_schema_test.rs
index 1679b5d..08415f6 100644
--- a/crates/shirabe/tests/json/composer_schema_test.rs
+++ b/crates/shirabe/tests/json/composer_schema_test.rs
@@ -2,32 +2,32 @@
// These validate documents against the bundled composer-schema.json via JsonFile's
// json-schema validator, which is not ported.
+#[ignore = "JsonSchema Validator::get_errors returns Vec<String>; cannot represent structured property/message/constraint error arrays asserted here, and Validator::validate is not ported"]
#[test]
-#[ignore = "needs JsonFile schema validation against the bundled composer-schema.json (not ported)"]
fn test_name_pattern() {
todo!()
}
+#[ignore = "JsonSchema Validator::get_errors returns Vec<String>; cannot represent structured property/message/constraint error arrays asserted here, and Validator::validate is not ported"]
#[test]
-#[ignore = "needs JsonFile schema validation against the bundled composer-schema.json (not ported)"]
fn test_version_pattern() {
todo!()
}
+#[ignore = "JsonSchema Validator::get_errors returns Vec<String>; cannot represent structured property/message/constraint error arrays asserted here, and Validator::validate is not ported"]
#[test]
-#[ignore = "needs JsonFile schema validation against the bundled composer-schema.json (not ported)"]
fn test_optional_abandoned_property() {
todo!()
}
+#[ignore = "JsonSchema Validator::get_errors returns Vec<String>; cannot represent structured property/message/constraint error arrays asserted here, and Validator::validate is not ported"]
#[test]
-#[ignore = "needs JsonFile schema validation against the bundled composer-schema.json (not ported)"]
fn test_require_types() {
todo!()
}
+#[ignore = "JsonSchema Validator::get_errors returns Vec<String>; cannot represent structured property/message/constraint error arrays asserted here, and Validator::validate is not ported"]
#[test]
-#[ignore = "needs JsonFile schema validation against the bundled composer-schema.json (not ported)"]
fn test_minimum_stability_values() {
todo!()
}
diff --git a/crates/shirabe/tests/json/json_file_test.rs b/crates/shirabe/tests/json/json_file_test.rs
index b6fecc6..0224ae6 100644
--- a/crates/shirabe/tests/json/json_file_test.rs
+++ b/crates/shirabe/tests/json/json_file_test.rs
@@ -1,6 +1,9 @@
//! ref: composer/tests/Composer/Test/Json/JsonFileTest.php
-use shirabe::json::JsonFile;
+use indexmap::IndexMap;
+use shirabe::json::{JsonEncodeOptions, JsonFile, JsonValidationException};
+use shirabe_external_packages::seld::json_lint::ParsingException;
+use shirabe_php_shim::PhpMixed;
/// ref: JsonFileTest::expectParseException
fn expect_parse_exception(text: &str, json: &str) {
@@ -9,6 +12,47 @@ fn expect_parse_exception(text: &str, json: &str) {
assert!(message.contains(text), "expected {text:?} in {message:?}");
}
+/// ref: JsonFileTest::assertJsonFormat
+fn assert_json_format(json: &str, data: &PhpMixed, options: Option<JsonEncodeOptions>) {
+ let json = json.replace('\r', "");
+ match options {
+ None => assert_eq!(json, JsonFile::encode(data)),
+ Some(options) => assert_eq!(json, JsonFile::encode_with_options(data, options)),
+ }
+}
+
+/// PHP's JSON_UNESCAPED_UNICODE-only flag set (used by testOnlyUnicode).
+fn unescaped_unicode_only() -> JsonEncodeOptions {
+ JsonEncodeOptions {
+ unescaped_slashes: false,
+ pretty_print: false,
+ unescaped_unicode: true,
+ indent: JsonFile::INDENT_DEFAULT.to_string(),
+ }
+}
+
+fn fixture_path(name: &str) -> std::path::PathBuf {
+ std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+ .join("../../composer/tests/Composer/Test/Json/Fixtures")
+ .join(name)
+}
+
+/// ref: TestCase::createTempFile (PHP tempnam())
+fn create_temp_file() -> String {
+ let mut path = std::env::temp_dir();
+ let unique = format!(
+ "shirabe_jsonfiletest_{}_{}",
+ std::process::id(),
+ std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .unwrap()
+ .as_nanos()
+ );
+ path.push(unique);
+ std::fs::write(&path, b"").unwrap();
+ path.to_str().unwrap().to_string()
+}
+
#[test]
#[ignore = "JsonFile::parse_json error path reaches JsonParser::new()/lint() (todo!()); the JSON linter is not yet ported"]
fn test_parse_error_detect_extra_comma() {
@@ -79,153 +123,459 @@ fn test_parse_error_detect_missing_colon() {
expect_parse_exception("Parse error on line 3", json);
}
-// The encode cases assert JsonFile::encode output for specific PHP flag combinations and
-// data shapes (incl. stdClass vs array). Faithful flag mapping and value modeling are not
-// reproduced here.
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_simple_json_string() {
- todo!()
+ let mut data: IndexMap<String, PhpMixed> = IndexMap::new();
+ data.insert(
+ "name".to_string(),
+ PhpMixed::String("composer/composer".to_string()),
+ );
+ let json = "{\n \"name\": \"composer/composer\"\n}";
+ assert_json_format(json, &PhpMixed::Array(data), None);
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_trailing_backslash() {
- todo!()
+ let mut data: IndexMap<String, PhpMixed> = IndexMap::new();
+ data.insert(
+ "Metadata\\".to_string(),
+ PhpMixed::String("src/".to_string()),
+ );
+ let json = "{\n \"Metadata\\\\\": \"src/\"\n}";
+ assert_json_format(json, &PhpMixed::Array(data), None);
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_format_empty_array() {
- todo!()
+ let mut data: IndexMap<String, PhpMixed> = IndexMap::new();
+ data.insert("test".to_string(), PhpMixed::List(vec![]));
+ data.insert("test2".to_string(), PhpMixed::Object(IndexMap::new()));
+ let json = "{\n \"test\": [],\n \"test2\": {}\n}";
+ assert_json_format(json, &PhpMixed::Array(data), None);
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_escape() {
- todo!()
+ let mut data: IndexMap<String, PhpMixed> = IndexMap::new();
+ data.insert(
+ "Metadata\\\"".to_string(),
+ PhpMixed::String("src/".to_string()),
+ );
+ let json = "{\n \"Metadata\\\\\\\"\": \"src/\"\n}";
+ assert_json_format(json, &PhpMixed::Array(data), None);
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_unicode() {
- todo!()
+ let mut data: IndexMap<String, PhpMixed> = IndexMap::new();
+ data.insert(
+ "Žluťoučký \" kůň".to_string(),
+ PhpMixed::String("úpěl ďábelské ódy za €".to_string()),
+ );
+ let json = "{\n \"Žluťoučký \\\" kůň\": \"úpěl ďábelské ódy za €\"\n}";
+ assert_json_format(json, &PhpMixed::Array(data), None);
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_only_unicode() {
- todo!()
+ let data = PhpMixed::String("\\/ƌ".to_string());
+ assert_json_format("\"\\\\\\/ƌ\"", &data, Some(unescaped_unicode_only()));
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_escaped_slashes() {
- todo!()
+ let data = PhpMixed::String("\\/foo".to_string());
+ assert_json_format("\"\\\\\\/foo\"", &data, Some(JsonEncodeOptions::none()));
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_escaped_backslashes() {
- todo!()
+ let data = PhpMixed::String("a\\b".to_string());
+ assert_json_format("\"a\\\\b\"", &data, Some(JsonEncodeOptions::none()));
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_escaped_unicode() {
- todo!()
+ let data = PhpMixed::String("ƌ".to_string());
+ assert_json_format("\"\\u018c\"", &data, Some(JsonEncodeOptions::none()));
}
#[test]
-#[ignore = "asserts JsonFile::encode output for specific PHP flag/value combinations; not reproduced here"]
+#[ignore]
fn test_double_escaped_unicode() {
- todo!()
+ let data = PhpMixed::List(vec![
+ PhpMixed::String("Zdjęcia".to_string()),
+ PhpMixed::String("hjkjhl\\u0119kkjk".to_string()),
+ ]);
+ let encoded_data = JsonFile::encode(&data);
+
+ let mut wrapper: IndexMap<String, PhpMixed> = IndexMap::new();
+ wrapper.insert("t".to_string(), PhpMixed::String(encoded_data));
+ let double_encoded_data = JsonFile::encode(&PhpMixed::Array(wrapper));
+
+ let decoded_data = shirabe_php_shim::json_decode(&double_encoded_data, true).unwrap();
+ let t = decoded_data.as_array().unwrap().get("t").unwrap();
+ let double_data = shirabe_php_shim::json_decode(t.as_string().unwrap(), true).unwrap();
+ assert_eq!(data, double_data);
}
-// These read a fixture composer.json and assert read/write indentation behaviour.
#[test]
-#[ignore = "reads a fixture file and asserts indentation behaviour of JsonFile read/write"]
+#[ignore]
fn test_preserve_indentation_after_read() {
- todo!()
+ let src = fixture_path("tabs.json");
+ let dst = fixture_path("tabs2.json");
+ std::fs::copy(&src, &dst).unwrap();
+
+ let mut json_file = JsonFile::new(dst.to_str().unwrap().to_string(), None, None).unwrap();
+ let _data = json_file.read().unwrap();
+ let mut hash: IndexMap<String, PhpMixed> = IndexMap::new();
+ hash.insert("foo".to_string(), PhpMixed::String("baz".to_string()));
+ json_file.write(PhpMixed::Array(hash)).unwrap();
+
+ assert_eq!(
+ "{\n\t\"foo\": \"baz\"\n}\n",
+ std::fs::read_to_string(&dst).unwrap()
+ );
+
+ std::fs::remove_file(&dst).unwrap();
}
#[test]
-#[ignore = "reads a fixture file and asserts indentation behaviour of JsonFile read/write"]
+#[ignore]
fn test_overwrites_indentation_by_default() {
- todo!()
+ let src = fixture_path("tabs.json");
+ let dst = fixture_path("tabs2.json");
+ std::fs::copy(&src, &dst).unwrap();
+
+ let json_file = JsonFile::new(dst.to_str().unwrap().to_string(), None, None).unwrap();
+ let mut hash: IndexMap<String, PhpMixed> = IndexMap::new();
+ hash.insert("foo".to_string(), PhpMixed::String("baz".to_string()));
+ json_file.write(PhpMixed::Array(hash)).unwrap();
+
+ assert_eq!(
+ "{\n \"foo\": \"baz\"\n}\n",
+ std::fs::read_to_string(&dst).unwrap()
+ );
+
+ std::fs::remove_file(&dst).unwrap();
}
-// validateSchema needs the bundled JSON schema and the json-schema validator plus fixtures.
#[test]
-#[ignore = "needs JsonFile::validateSchema (json-schema validation) and the schema/fixtures"]
+#[ignore]
fn test_schema_validation() {
- todo!()
+ let path = fixture_path("composer.json");
+ let json = JsonFile::new(path.to_str().unwrap().to_string(), None, None).unwrap();
+ json.validate_schema(JsonFile::STRICT_SCHEMA, None).unwrap();
+ json.validate_schema(JsonFile::LAX_SCHEMA, None).unwrap();
}
#[test]
-#[ignore = "needs JsonFile::validateSchema (json-schema validation) and the schema/fixtures"]
+#[ignore]
fn test_schema_validation_error() {
- todo!()
+ let file = create_temp_file();
+ std::fs::write(&file, b"{ \"name\": null }").unwrap();
+ let json = JsonFile::new(file.clone(), None, None).unwrap();
+ let expected_message = format!("\"{}\" does not match the expected JSON schema", file);
+ let expected_error = "name : NULL value found, but a string is required".to_string();
+
+ let err = json
+ .validate_schema(JsonFile::STRICT_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(expected_message, e.get_message());
+ assert!(e.get_errors().contains(&expected_error));
+
+ let err = json
+ .validate_schema(JsonFile::LAX_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(expected_message, e.get_message());
+ assert!(e.get_errors().contains(&expected_error));
+
+ std::fs::remove_file(&file).unwrap();
}
#[test]
-#[ignore = "needs JsonFile::validateSchema (json-schema validation) and the schema/fixtures"]
+#[ignore]
fn test_schema_validation_lax_additional_properties() {
- todo!()
+ let file = create_temp_file();
+ std::fs::write(
+ &file,
+ b"{ \"name\": \"vendor/package\", \"description\": \"generic description\", \"foo\": \"bar\" }",
+ )
+ .unwrap();
+ let json = JsonFile::new(file.clone(), None, None).unwrap();
+
+ let err = json
+ .validate_schema(JsonFile::STRICT_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(
+ format!("\"{}\" does not match the expected JSON schema", file),
+ e.get_message()
+ );
+ assert_eq!(
+ &vec![
+ "The property foo is not defined and the definition does not allow additional properties"
+ .to_string()
+ ],
+ e.get_errors()
+ );
+
+ json.validate_schema(JsonFile::LAX_SCHEMA, None).unwrap();
+ std::fs::remove_file(&file).unwrap();
}
#[test]
-#[ignore = "needs JsonFile::validateSchema (json-schema validation) and the schema/fixtures"]
+#[ignore]
fn test_schema_validation_lax_required() {
- todo!()
+ let file = create_temp_file();
+ let json = JsonFile::new(file.clone(), None, None).unwrap();
+
+ let expected_message = format!("\"{}\" does not match the expected JSON schema", file);
+
+ std::fs::write(&file, b"{ }").unwrap();
+ let err = json
+ .validate_schema(JsonFile::STRICT_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(expected_message, e.get_message());
+ let errors = e.get_errors();
+ assert!(errors.contains(&"name : The property name is required".to_string()));
+ assert!(errors.contains(&"description : The property description is required".to_string()));
+ json.validate_schema(JsonFile::LAX_SCHEMA, None).unwrap();
+
+ std::fs::write(&file, b"{ \"name\": \"vendor/package\" }").unwrap();
+ let err = json
+ .validate_schema(JsonFile::STRICT_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(expected_message, e.get_message());
+ assert_eq!(
+ &vec!["description : The property description is required".to_string()],
+ e.get_errors()
+ );
+ json.validate_schema(JsonFile::LAX_SCHEMA, None).unwrap();
+
+ std::fs::write(&file, b"{ \"description\": \"generic description\" }").unwrap();
+ let err = json
+ .validate_schema(JsonFile::STRICT_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(expected_message, e.get_message());
+ assert_eq!(
+ &vec!["name : The property name is required".to_string()],
+ e.get_errors()
+ );
+ json.validate_schema(JsonFile::LAX_SCHEMA, None).unwrap();
+
+ std::fs::write(&file, b"{ \"type\": \"library\" }").unwrap();
+ let err = json
+ .validate_schema(JsonFile::STRICT_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(expected_message, e.get_message());
+ let errors = e.get_errors();
+ assert!(errors.contains(&"name : The property name is required".to_string()));
+ assert!(errors.contains(&"description : The property description is required".to_string()));
+ json.validate_schema(JsonFile::LAX_SCHEMA, None).unwrap();
+
+ std::fs::write(&file, b"{ \"type\": \"project\" }").unwrap();
+ let err = json
+ .validate_schema(JsonFile::STRICT_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(expected_message, e.get_message());
+ let errors = e.get_errors();
+ assert!(errors.contains(&"name : The property name is required".to_string()));
+ assert!(errors.contains(&"description : The property description is required".to_string()));
+ json.validate_schema(JsonFile::LAX_SCHEMA, None).unwrap();
+
+ std::fs::write(
+ &file,
+ b"{ \"name\": \"vendor/package\", \"description\": \"generic description\" }",
+ )
+ .unwrap();
+ json.validate_schema(JsonFile::STRICT_SCHEMA, None).unwrap();
+ json.validate_schema(JsonFile::LAX_SCHEMA, None).unwrap();
+
+ std::fs::remove_file(&file).unwrap();
}
#[test]
-#[ignore = "needs JsonFile::validateSchema (json-schema validation) and the schema/fixtures"]
+#[ignore]
fn test_custom_schema_validation_lax() {
- todo!()
+ let file = create_temp_file();
+ std::fs::write(
+ &file,
+ b"{ \"custom\": \"property\", \"another custom\": \"property\" }",
+ )
+ .unwrap();
+
+ let schema = create_temp_file();
+ std::fs::write(
+ &schema,
+ b"{ \"properties\": { \"custom\": { \"type\": \"string\" }}}",
+ )
+ .unwrap();
+
+ let json = JsonFile::new(file.clone(), None, None).unwrap();
+
+ json.validate_schema(JsonFile::LAX_SCHEMA, Some(&schema))
+ .unwrap();
+
+ std::fs::remove_file(&file).unwrap();
+ std::fs::remove_file(&schema).unwrap();
}
#[test]
-#[ignore = "needs JsonFile::validateSchema (json-schema validation) and the schema/fixtures"]
+#[ignore]
fn test_custom_schema_validation_strict() {
- todo!()
+ let file = create_temp_file();
+ std::fs::write(&file, b"{ \"custom\": \"property\" }").unwrap();
+
+ let schema = create_temp_file();
+ std::fs::write(
+ &schema,
+ b"{ \"properties\": { \"custom\": { \"type\": \"string\" }}}",
+ )
+ .unwrap();
+
+ let json = JsonFile::new(file.clone(), None, None).unwrap();
+
+ json.validate_schema(JsonFile::STRICT_SCHEMA, Some(&schema))
+ .unwrap();
+
+ std::fs::remove_file(&file).unwrap();
+ std::fs::remove_file(&schema).unwrap();
}
#[test]
-#[ignore = "needs JsonFile::validateSchema (json-schema validation) and the schema/fixtures"]
+#[ignore]
fn test_auth_schema_validation_with_custom_data_source() {
- todo!()
+ let json = shirabe_php_shim::json_decode("{\"github-oauth\": \"foo\"}", false).unwrap();
+ let expected_message = "\"COMPOSER_AUTH\" does not match the expected JSON schema".to_string();
+ let expected_error = "github-oauth : String value found, but an object is required".to_string();
+
+ let err = JsonFile::validate_json_schema("COMPOSER_AUTH", &json, JsonFile::AUTH_SCHEMA, None)
+ .unwrap_err();
+ let e = err.downcast_ref::<JsonValidationException>().unwrap();
+ assert_eq!(expected_message, e.get_message());
+ assert_eq!(&vec![expected_error], e.get_errors());
+}
+
+/// ref: shared `$data` for the simple merge-conflict cases.
+fn merge_conflict_simple_data() -> PhpMixed {
+ let mut data: IndexMap<String, PhpMixed> = IndexMap::new();
+ data.insert(
+ "_readme".to_string(),
+ PhpMixed::List(vec![
+ PhpMixed::String(
+ "This file locks the dependencies of your project to a known state".to_string(),
+ ),
+ PhpMixed::String(
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies"
+ .to_string(),
+ ),
+ PhpMixed::String("This file is @generated automatically".to_string()),
+ ]),
+ );
+ data.insert(
+ "content-hash".to_string(),
+ PhpMixed::String(
+ "VCS merge conflict detected. Please run `composer update --lock`.".to_string(),
+ ),
+ );
+ data.insert("packages".to_string(), PhpMixed::List(vec![]));
+ data.insert("packages-dev".to_string(), PhpMixed::List(vec![]));
+ data.insert("aliases".to_string(), PhpMixed::List(vec![]));
+ data.insert(
+ "minimum-stability".to_string(),
+ PhpMixed::String("stable".to_string()),
+ );
+ data.insert("stability-flags".to_string(), PhpMixed::List(vec![]));
+ data.insert("prefer-stable".to_string(), PhpMixed::Bool(false));
+ data.insert("prefer-lowest".to_string(), PhpMixed::Bool(false));
+ data.insert("platform".to_string(), PhpMixed::List(vec![]));
+ data.insert("platform-dev".to_string(), PhpMixed::List(vec![]));
+ data.insert(
+ "plugin-api-version".to_string(),
+ PhpMixed::String("2.3.0".to_string()),
+ );
+ PhpMixed::Array(data)
}
-// The merge-conflict cases build large lock-file structures (with VCS conflict markers) and
-// assert the resulting ParsingException; the fixtures are sizeable and not reproduced here.
#[test]
-#[ignore = "builds a large lock-file structure with VCS merge markers; not reproduced here"]
+#[ignore]
fn test_composer_lock_file_merge_conflict_simple() {
- todo!()
+ let data = merge_conflict_simple_data();
+ let json =
+ std::fs::read_to_string(fixture_path("composer-lock-merge-conflict-simple.txt")).unwrap();
+ assert_eq!(
+ data,
+ JsonFile::parse_json(Some(&json), Some("/path/to/composer.lock")).unwrap()
+ );
}
#[test]
-#[ignore = "builds a large lock-file structure with VCS merge markers; not reproduced here"]
+#[ignore]
fn test_composer_lock_file_merge_conflict_simple_crlf() {
- todo!()
+ let data = merge_conflict_simple_data();
+ let json =
+ std::fs::read_to_string(fixture_path("composer-lock-merge-conflict-simple.txt")).unwrap();
+ assert_eq!(
+ data,
+ JsonFile::parse_json(Some(&json), Some("/path/to/composer.lock")).unwrap()
+ );
}
#[test]
-#[ignore = "builds a large lock-file structure with VCS merge markers; not reproduced here"]
+#[ignore]
fn test_composer_lock_file_merge_conflict_complex() {
- todo!()
+ // complex files have multiple conflict markers and can thus not be simply resolved
+ let data =
+ std::fs::read_to_string(fixture_path("composer-lock-merge-conflict-complex.txt")).unwrap();
+
+ let err = JsonFile::parse_json(Some(&data), Some("/path/to/composer.lock")).unwrap_err();
+ assert!(err.downcast_ref::<ParsingException>().is_some());
}
#[test]
-#[ignore = "builds a large lock-file structure with VCS merge markers; not reproduced here"]
+#[ignore]
fn test_composer_lock_file_merge_conflict_complex_crlf() {
- todo!()
+ // complex files have multiple conflict markers and can thus not be simply resolved
+ let data = std::fs::read_to_string(fixture_path(
+ "composer-lock-merge-conflict-complex-crlf.txt",
+ ))
+ .unwrap();
+
+ let err = JsonFile::parse_json(Some(&data), Some("/path/to/composer.lock")).unwrap_err();
+ assert!(err.downcast_ref::<ParsingException>().is_some());
}
#[test]
-#[ignore = "builds a large lock-file structure with VCS merge markers; not reproduced here"]
+#[ignore]
fn test_composer_lock_file_merge_conflict_extended() {
- todo!()
+ let data =
+ std::fs::read_to_string(fixture_path("composer-lock-merge-conflict-extended.txt")).unwrap();
+
+ let json = JsonFile::parse_json(Some(&data), Some("/path/to/composer.lock")).unwrap();
+ assert_eq!(
+ "VCS merge conflict detected. Please run `composer update --lock`.",
+ json.as_array()
+ .unwrap()
+ .get("content-hash")
+ .unwrap()
+ .as_string()
+ .unwrap()
+ );
}
diff --git a/crates/shirabe/tests/json/json_formatter_test.rs b/crates/shirabe/tests/json/json_formatter_test.rs
index 328c942..b27f25b 100644
--- a/crates/shirabe/tests/json/json_formatter_test.rs
+++ b/crates/shirabe/tests/json/json_formatter_test.rs
@@ -2,16 +2,16 @@
/// Test if ę will get correctly formatted (unescaped)
/// https://github.com/composer/composer/issues/2613
+#[ignore = "JsonFormatter is not implemented in crates/shirabe/src/json"]
#[test]
-#[ignore = "Composer\\Json\\JsonFormatter (json/json_formatter.rs) is not yet ported"]
fn test_unicode_with_prepended_slash() {
todo!()
}
/// Surrogate pairs are intentionally skipped and not unescaped
/// https://github.com/composer/composer/issues/7510
+#[ignore = "JsonFormatter is not implemented in crates/shirabe/src/json"]
#[test]
-#[ignore = "Composer\\Json\\JsonFormatter (json/json_formatter.rs) is not yet ported"]
fn test_utf16_surrogate_pair() {
todo!()
}
diff --git a/crates/shirabe/tests/json/json_manipulator_test.rs b/crates/shirabe/tests/json/json_manipulator_test.rs
index 7cf8e87..96b74f7 100644
--- a/crates/shirabe/tests/json/json_manipulator_test.rs
+++ b/crates/shirabe/tests/json/json_manipulator_test.rs
@@ -1,301 +1,5585 @@
//! ref: composer/tests/Composer/Test/Json/JsonManipulatorTest.php
+use indexmap::IndexMap;
+use shirabe::json::{JsonFile, JsonManipulator};
+use shirabe_php_shim::PhpMixed;
+
+fn s(v: &str) -> PhpMixed {
+ PhpMixed::String(v.to_string())
+}
+
+fn arr(pairs: &[(&str, PhpMixed)]) -> PhpMixed {
+ let mut m: IndexMap<String, PhpMixed> = IndexMap::new();
+ for (k, v) in pairs {
+ m.insert(k.to_string(), v.clone());
+ }
+ PhpMixed::Array(m)
+}
+
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_link() {
- todo!()
+ let cases: Vec<(&str, &str, &str, &str, &str)> = vec![
+ (
+ r#"{}"#,
+ r#"require"#,
+ r#"vendor/baz"#,
+ r#"qux"#,
+ r#"{
+ "require": {
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "foo": "bar"
+}"#,
+ r#"require"#,
+ r#"vendor/baz"#,
+ r#"qux"#,
+ r#"{
+ "foo": "bar",
+ "require": {
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require": {
+ }
+}"#,
+ r#"require"#,
+ r#"vendor/baz"#,
+ r#"qux"#,
+ r#"{
+ "require": {
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "empty": "",
+ "require": {
+ "foo": "bar"
+ }
+}"#,
+ r#"require"#,
+ r#"vendor/baz"#,
+ r#"qux"#,
+ r#"{
+ "empty": "",
+ "require": {
+ "foo": "bar",
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require":
+ {
+ "foo": "bar",
+ "vendor/baz": "baz"
+ }
+}"#,
+ r#"require"#,
+ r#"vendor/baz"#,
+ r#"qux"#,
+ r#"{
+ "require":
+ {
+ "foo": "bar",
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require":
+ {
+ "foo": "bar",
+ "vendor/baz": "baz"
+ }
+}"#,
+ r#"require"#,
+ r#"vEnDoR/bAz"#,
+ r#"qux"#,
+ r#"{
+ "require":
+ {
+ "foo": "bar",
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require":
+ {
+ "foo": "bar",
+ "vendor\/baz": "baz"
+ }
+}"#,
+ r#"require"#,
+ r#"vendor/baz"#,
+ r#"qux"#,
+ r#"{
+ "require":
+ {
+ "foo": "bar",
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require":
+ {
+ "foo": "bar",
+ "vendor\/baz": "baz"
+ }
+}"#,
+ r#"require"#,
+ r#"vEnDoR/bAz"#,
+ r#"qux"#,
+ r#"{
+ "require":
+ {
+ "foo": "bar",
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require": {
+ "foo": "bar"
+ },
+ "repositories": [{
+ "type": "package",
+ "package": {
+ "require": {
+ "foo": "bar"
+ }
+ }
+ }]
+}"#,
+ r#"require"#,
+ r#"foo"#,
+ r#"qux"#,
+ r#"{
+ "require": {
+ "foo": "qux"
+ },
+ "repositories": [{
+ "type": "package",
+ "package": {
+ "require": {
+ "foo": "bar"
+ }
+ }
+ }]
+}
+"#,
+ ),
+ (
+ r#"{
+ "repositories": [{
+ "type": "package",
+ "package": {
+ "require": {
+ "foo": "bar"
+ }
+ }
+ }]
+}"#,
+ r#"require"#,
+ r#"foo"#,
+ r#"qux"#,
+ r#"{
+ "repositories": [{
+ "type": "package",
+ "package": {
+ "require": {
+ "foo": "bar"
+ }
+ }
+ }],
+ "require": {
+ "foo": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require": {
+ "php": "5.*"
+ }
+}"#,
+ r#"require-dev"#,
+ r#"foo"#,
+ r#"qux"#,
+ r#"{
+ "require": {
+ "php": "5.*"
+ },
+ "require-dev": {
+ "foo": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require": {
+ "php": "5.*"
+ },
+ "require-dev": {
+ "foo": "bar"
+ }
+}"#,
+ r#"require-dev"#,
+ r#"foo"#,
+ r#"qux"#,
+ r#"{
+ "require": {
+ "php": "5.*"
+ },
+ "require-dev": {
+ "foo": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "repositories": [{
+ "type": "package",
+ "package": {
+ "bar": "ba[z",
+ "dist": {
+ "url": "http...",
+ "type": "zip"
+ },
+ "autoload": {
+ "classmap": [ "foo/bar" ]
+ }
+ }
+ }],
+ "require": {
+ "php": "5.*"
+ },
+ "require-dev": {
+ "foo": "bar"
+ }
+}"#,
+ r#"require-dev"#,
+ r#"foo"#,
+ r#"qux"#,
+ r#"{
+ "repositories": [{
+ "type": "package",
+ "package": {
+ "bar": "ba[z",
+ "dist": {
+ "url": "http...",
+ "type": "zip"
+ },
+ "autoload": {
+ "classmap": [ "foo/bar" ]
+ }
+ }
+ }],
+ "require": {
+ "php": "5.*"
+ },
+ "require-dev": {
+ "foo": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "config": {
+ "cache-files-ttl": 0,
+ "discard-changes": true
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": false,
+ "provide": {
+ "heroku-sys/cedar": "14.2016.03.22"
+ },
+ "repositories": [
+ {
+ "packagist.org": false
+ },
+ {
+ "type": "package",
+ "package": [
+ {
+ "type": "metapackage",
+ "name": "anthonymartin/geo-location",
+ "version": "v1.0.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "aws/aws-sdk-php",
+ "version": "3.9.4",
+ "require": {
+ "heroku-sys/php": ">=5.5"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "cloudinary/cloudinary_php",
+ "version": "dev-master",
+ "require": {
+ "heroku-sys/ext-curl": "*",
+ "heroku-sys/ext-json": "*",
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/annotations",
+ "version": "v1.2.7",
+ "require": {
+ "heroku-sys/php": ">=5.3.2"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/cache",
+ "version": "v1.6.0",
+ "require": {
+ "heroku-sys/php": "~5.5|~7.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/collections",
+ "version": "v1.3.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.2"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/common",
+ "version": "v2.6.1",
+ "require": {
+ "heroku-sys/php": "~5.5|~7.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/inflector",
+ "version": "v1.1.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.2"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/lexer",
+ "version": "v1.0.1",
+ "require": {
+ "heroku-sys/php": ">=5.3.2"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "geoip/geoip",
+ "version": "v1.16",
+ "require": [],
+ "replace": [],
+ "provide": [],
+ "conflict": {
+ "heroku-sys/ext-geoip": "*"
+ }
+ },
+ {
+ "type": "metapackage",
+ "name": "giggsey/libphonenumber-for-php",
+ "version": "7.2.5",
+ "require": {
+ "heroku-sys/ext-mbstring": "*"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/guzzle",
+ "version": "5.3.0",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/promises",
+ "version": "1.0.3",
+ "require": {
+ "heroku-sys/php": ">=5.5.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/psr7",
+ "version": "1.2.3",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/ringphp",
+ "version": "1.1.0",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/streams",
+ "version": "3.0.0",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "hipchat/hipchat-php",
+ "version": "v1.4",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "kriswallsmith/buzz",
+ "version": "v0.15",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "league/csv",
+ "version": "8.0.0",
+ "require": {
+ "heroku-sys/ext-mbstring": "*",
+ "heroku-sys/php": ">=5.5.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "league/fractal",
+ "version": "0.13.0",
+ "require": {
+ "heroku-sys/php": ">=5.4"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "mashape/unirest-php",
+ "version": "1.2.1",
+ "require": {
+ "heroku-sys/ext-curl": "*",
+ "heroku-sys/ext-json": "*",
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "mtdowling/jmespath.php",
+ "version": "2.3.0",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "palex/phpstructureddata",
+ "version": "v2.0.1",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "psr/http-message",
+ "version": "1.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "react/promise",
+ "version": "v2.2.1",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "rollbar/rollbar",
+ "version": "v0.15.0",
+ "require": {
+ "heroku-sys/ext-curl": "*"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "ronanguilloux/isocodes",
+ "version": "1.2.0",
+ "require": {
+ "heroku-sys/ext-bcmath": "*",
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "sendgrid/sendgrid",
+ "version": "2.1.1",
+ "require": {
+ "heroku-sys/php": ">=5.3"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "sendgrid/smtpapi",
+ "version": "0.0.1",
+ "require": {
+ "heroku-sys/php": ">=5.3"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "symfony/css-selector",
+ "version": "v2.8.2",
+ "require": {
+ "heroku-sys/php": ">=5.3.9"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "symfony/http-foundation",
+ "version": "v2.8.2",
+ "require": {
+ "heroku-sys/php": ">=5.3.9"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "symfony/polyfill-php54",
+ "version": "v1.1.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.3"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "symfony/polyfill-php55",
+ "version": "v1.1.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.3"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "thepixeldeveloper/sitemap",
+ "version": "3.0.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "tijsverkoyen/css-to-inline-styles",
+ "version": "1.5.5",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "yiisoft/yii",
+ "version": "1.1.17",
+ "require": {
+ "heroku-sys/php": ">=5.1.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "composer.json/composer.lock",
+ "version": "dev-597511d6d51b96e4a8afeba2c79982e5",
+ "require": {
+ "heroku-sys/php": "~5.6.0",
+ "heroku-sys/ext-newrelic": "*",
+ "heroku-sys/ext-gd": "*",
+ "heroku-sys/ext-redis": "*"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ }
+ ]
+ }
+ ],
+ "require": {
+ "composer.json/composer.lock": "dev-597511d6d51b96e4a8afeba2c79982e5",
+ "anthonymartin/geo-location": "v1.0.0",
+ "aws/aws-sdk-php": "3.9.4",
+ "cloudinary/cloudinary_php": "dev-master",
+ "doctrine/annotations": "v1.2.7",
+ "doctrine/cache": "v1.6.0",
+ "doctrine/collections": "v1.3.0",
+ "doctrine/common": "v2.6.1",
+ "doctrine/inflector": "v1.1.0",
+ "doctrine/lexer": "v1.0.1",
+ "geoip/geoip": "v1.16",
+ "giggsey/libphonenumber-for-php": "7.2.5",
+ "guzzlehttp/guzzle": "5.3.0",
+ "guzzlehttp/promises": "1.0.3",
+ "guzzlehttp/psr7": "1.2.3",
+ "guzzlehttp/ringphp": "1.1.0",
+ "guzzlehttp/streams": "3.0.0",
+ "hipchat/hipchat-php": "v1.4",
+ "kriswallsmith/buzz": "v0.15",
+ "league/csv": "8.0.0",
+ "league/fractal": "0.13.0",
+ "mashape/unirest-php": "1.2.1",
+ "mtdowling/jmespath.php": "2.3.0",
+ "palex/phpstructureddata": "v2.0.1",
+ "psr/http-message": "1.0",
+ "react/promise": "v2.2.1",
+ "rollbar/rollbar": "v0.15.0",
+ "ronanguilloux/isocodes": "1.2.0",
+ "sendgrid/sendgrid": "2.1.1",
+ "sendgrid/smtpapi": "0.0.1",
+ "symfony/css-selector": "v2.8.2",
+ "symfony/http-foundation": "v2.8.2",
+ "symfony/polyfill-php54": "v1.1.0",
+ "symfony/polyfill-php55": "v1.1.0",
+ "thepixeldeveloper/sitemap": "3.0.0",
+ "tijsverkoyen/css-to-inline-styles": "1.5.5",
+ "yiisoft/yii": "1.1.17",
+ "heroku-sys/apache": "^2.4.10",
+ "heroku-sys/nginx": "~1.8.0"
+ }
+}"#,
+ r#"require"#,
+ r#"foo"#,
+ r#"qux"#,
+ r#"{
+ "config": {
+ "cache-files-ttl": 0,
+ "discard-changes": true
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": false,
+ "provide": {
+ "heroku-sys/cedar": "14.2016.03.22"
+ },
+ "repositories": [
+ {
+ "packagist.org": false
+ },
+ {
+ "type": "package",
+ "package": [
+ {
+ "type": "metapackage",
+ "name": "anthonymartin/geo-location",
+ "version": "v1.0.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "aws/aws-sdk-php",
+ "version": "3.9.4",
+ "require": {
+ "heroku-sys/php": ">=5.5"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "cloudinary/cloudinary_php",
+ "version": "dev-master",
+ "require": {
+ "heroku-sys/ext-curl": "*",
+ "heroku-sys/ext-json": "*",
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/annotations",
+ "version": "v1.2.7",
+ "require": {
+ "heroku-sys/php": ">=5.3.2"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/cache",
+ "version": "v1.6.0",
+ "require": {
+ "heroku-sys/php": "~5.5|~7.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/collections",
+ "version": "v1.3.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.2"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/common",
+ "version": "v2.6.1",
+ "require": {
+ "heroku-sys/php": "~5.5|~7.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/inflector",
+ "version": "v1.1.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.2"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "doctrine/lexer",
+ "version": "v1.0.1",
+ "require": {
+ "heroku-sys/php": ">=5.3.2"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "geoip/geoip",
+ "version": "v1.16",
+ "require": [],
+ "replace": [],
+ "provide": [],
+ "conflict": {
+ "heroku-sys/ext-geoip": "*"
+ }
+ },
+ {
+ "type": "metapackage",
+ "name": "giggsey/libphonenumber-for-php",
+ "version": "7.2.5",
+ "require": {
+ "heroku-sys/ext-mbstring": "*"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/guzzle",
+ "version": "5.3.0",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/promises",
+ "version": "1.0.3",
+ "require": {
+ "heroku-sys/php": ">=5.5.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/psr7",
+ "version": "1.2.3",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/ringphp",
+ "version": "1.1.0",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "guzzlehttp/streams",
+ "version": "3.0.0",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "hipchat/hipchat-php",
+ "version": "v1.4",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "kriswallsmith/buzz",
+ "version": "v0.15",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "league/csv",
+ "version": "8.0.0",
+ "require": {
+ "heroku-sys/ext-mbstring": "*",
+ "heroku-sys/php": ">=5.5.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "league/fractal",
+ "version": "0.13.0",
+ "require": {
+ "heroku-sys/php": ">=5.4"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "mashape/unirest-php",
+ "version": "1.2.1",
+ "require": {
+ "heroku-sys/ext-curl": "*",
+ "heroku-sys/ext-json": "*",
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "mtdowling/jmespath.php",
+ "version": "2.3.0",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "palex/phpstructureddata",
+ "version": "v2.0.1",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "psr/http-message",
+ "version": "1.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "react/promise",
+ "version": "v2.2.1",
+ "require": {
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "rollbar/rollbar",
+ "version": "v0.15.0",
+ "require": {
+ "heroku-sys/ext-curl": "*"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "ronanguilloux/isocodes",
+ "version": "1.2.0",
+ "require": {
+ "heroku-sys/ext-bcmath": "*",
+ "heroku-sys/php": ">=5.4.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "sendgrid/sendgrid",
+ "version": "2.1.1",
+ "require": {
+ "heroku-sys/php": ">=5.3"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "sendgrid/smtpapi",
+ "version": "0.0.1",
+ "require": {
+ "heroku-sys/php": ">=5.3"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "symfony/css-selector",
+ "version": "v2.8.2",
+ "require": {
+ "heroku-sys/php": ">=5.3.9"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "symfony/http-foundation",
+ "version": "v2.8.2",
+ "require": {
+ "heroku-sys/php": ">=5.3.9"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "symfony/polyfill-php54",
+ "version": "v1.1.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.3"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "symfony/polyfill-php55",
+ "version": "v1.1.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.3"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "thepixeldeveloper/sitemap",
+ "version": "3.0.0",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "tijsverkoyen/css-to-inline-styles",
+ "version": "1.5.5",
+ "require": {
+ "heroku-sys/php": ">=5.3.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "yiisoft/yii",
+ "version": "1.1.17",
+ "require": {
+ "heroku-sys/php": ">=5.1.0"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ },
+ {
+ "type": "metapackage",
+ "name": "composer.json/composer.lock",
+ "version": "dev-597511d6d51b96e4a8afeba2c79982e5",
+ "require": {
+ "heroku-sys/php": "~5.6.0",
+ "heroku-sys/ext-newrelic": "*",
+ "heroku-sys/ext-gd": "*",
+ "heroku-sys/ext-redis": "*"
+ },
+ "replace": [],
+ "provide": [],
+ "conflict": []
+ }
+ ]
+ }
+ ],
+ "require": {
+ "composer.json/composer.lock": "dev-597511d6d51b96e4a8afeba2c79982e5",
+ "anthonymartin/geo-location": "v1.0.0",
+ "aws/aws-sdk-php": "3.9.4",
+ "cloudinary/cloudinary_php": "dev-master",
+ "doctrine/annotations": "v1.2.7",
+ "doctrine/cache": "v1.6.0",
+ "doctrine/collections": "v1.3.0",
+ "doctrine/common": "v2.6.1",
+ "doctrine/inflector": "v1.1.0",
+ "doctrine/lexer": "v1.0.1",
+ "geoip/geoip": "v1.16",
+ "giggsey/libphonenumber-for-php": "7.2.5",
+ "guzzlehttp/guzzle": "5.3.0",
+ "guzzlehttp/promises": "1.0.3",
+ "guzzlehttp/psr7": "1.2.3",
+ "guzzlehttp/ringphp": "1.1.0",
+ "guzzlehttp/streams": "3.0.0",
+ "hipchat/hipchat-php": "v1.4",
+ "kriswallsmith/buzz": "v0.15",
+ "league/csv": "8.0.0",
+ "league/fractal": "0.13.0",
+ "mashape/unirest-php": "1.2.1",
+ "mtdowling/jmespath.php": "2.3.0",
+ "palex/phpstructureddata": "v2.0.1",
+ "psr/http-message": "1.0",
+ "react/promise": "v2.2.1",
+ "rollbar/rollbar": "v0.15.0",
+ "ronanguilloux/isocodes": "1.2.0",
+ "sendgrid/sendgrid": "2.1.1",
+ "sendgrid/smtpapi": "0.0.1",
+ "symfony/css-selector": "v2.8.2",
+ "symfony/http-foundation": "v2.8.2",
+ "symfony/polyfill-php54": "v1.1.0",
+ "symfony/polyfill-php55": "v1.1.0",
+ "thepixeldeveloper/sitemap": "3.0.0",
+ "tijsverkoyen/css-to-inline-styles": "1.5.5",
+ "yiisoft/yii": "1.1.17",
+ "heroku-sys/apache": "^2.4.10",
+ "heroku-sys/nginx": "~1.8.0",
+ "foo": "qux"
+ }
+}
+"#,
+ ),
+ ];
+ for (json, r#type, package, constraint, expected) in cases {
+ let mut manipulator = JsonManipulator::new(json.to_string()).unwrap();
+ assert!(
+ manipulator
+ .add_link(r#type, package, constraint, false)
+ .unwrap()
+ );
+ assert_eq!(expected, manipulator.get_contents());
+ }
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_link_and_sort_packages() {
- todo!()
+ let cases: Vec<(&str, &str, &str, &str, bool, &str)> = vec![
+ (
+ r#"{
+ "require": {
+ "vendor/baz": "qux"
+ }
+}"#,
+ r#"require"#,
+ r#"foo"#,
+ r#"bar"#,
+ true,
+ r#"{
+ "require": {
+ "foo": "bar",
+ "vendor/baz": "qux"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require": {
+ "vendor/baz": "qux"
+ }
+}"#,
+ r#"require"#,
+ r#"foo"#,
+ r#"bar"#,
+ false,
+ r#"{
+ "require": {
+ "vendor/baz": "qux",
+ "foo": "bar"
+ }
+}
+"#,
+ ),
+ (
+ r#"{
+ "require": {
+ "foo": "baz",
+ "ext-10gd": "*",
+ "ext-2mcrypt": "*",
+ "lib-foo": "*",
+ "hhvm": "*",
+ "php": ">=5.5"
+ }
+}"#,
+ r#"require"#,
+ r#"igorw/retry"#,
+ r#"*"#,
+ true,
+ r#"{
+ "require": {
+ "php": ">=5.5",
+ "hhvm": "*",
+ "ext-2mcrypt": "*",
+ "ext-10gd": "*",
+ "lib-foo": "*",
+ "foo": "baz",
+ "igorw/retry": "*"
+ }
+}
+"#,
+ ),
+ ];
+ for (json, r#type, package, constraint, sort_packages, expected) in cases {
+ let mut manipulator = JsonManipulator::new(json.to_string()).unwrap();
+ assert!(
+ manipulator
+ .add_link(r#type, package, constraint, sort_packages)
+ .unwrap()
+ );
+ assert_eq!(expected, manipulator.get_contents());
+ }
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_sub_node() {
- todo!()
+ let cases: Vec<(&str, &str, bool, Option<&str>)> = vec![
+ (
+ r#"{
+ "repositories": {
+ "foo": {
+ "foo": "bar",
+ "bar": "baz"
+ },
+ "bar": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}"#,
+ r#"foo"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ "bar": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "foo": {
+ "foo": "bar",
+ "bar": "baz"
+ },
+ "bar": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}"#,
+ r#"bar"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ "foo": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "foo": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}"#,
+ r#"foo"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "foo\/bar": {
+ "bar": "baz"
+ }
+ }
+}"#,
+ r#"foo/bar"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "foo": {
+ "foo": "bar",
+ "bar": "baz"
+ },
+ "bar": {
+ "foo": "bar",
+ "bar": "baz"
+ },
+ "baz": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}"#,
+ r#"bar"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ "foo": {
+ "foo": "bar",
+ "bar": "baz"
+ },
+ "baz": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "main": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}"#,
+ r#"removenotthere"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ "main": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "baz": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}"#,
+ r#"bar"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ "baz": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "foo": {
+ "baz": "qux"
+ },
+ "baz": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+ }
+}"#,
+ r#"baz"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ "foo": {
+ "baz": "qux"
+ }
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ }
+}"#,
+ r#"bar"#,
+ true,
+ None,
+ ),
+ (
+ r#"{
+ "repositories": {}
+}"#,
+ r#"bar"#,
+ true,
+ None,
+ ),
+ (
+ r#"{
+}"#, r#"bar"#, true, None,
+ ),
+ (
+ r#"{
+ "repositories": {
+ "foo": {
+ "package": { "bar": "baz" }
+ }
+ }
+}"#,
+ r#"foo"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "foo": {
+ "package": { "bar": "ba{z" }
+ }
+ }
+}"#,
+ r#"bar"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ "foo": {
+ "package": { "bar": "ba{z" }
+ }
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": {
+ "foo": {
+ "package": { "bar": "ba}z" }
+ }
+ }
+}"#,
+ r#"bar"#,
+ true,
+ Some(
+ r#"{
+ "repositories": {
+ "foo": {
+ "package": { "bar": "ba}z" }
+ }
+ }
+}
+"#,
+ ),
+ ),
+ (
+ r#"{
+ "repositories": [
+ {
+ "package": { "bar": "ba[z" }
+ }
+ ]
+}"#,
+ r#"bar"#,
+ false,
+ None,
+ ),
+ (
+ r#"{
+ "repositories": [
+ {
+ "package": { "bar": "ba]z" }
+ }
+ ]
+}"#,
+ r#"bar"#,
+ false,
+ None,
+ ),
+ ];
+ for (json, name, expected, expected_content) in cases {
+ let mut manipulator = JsonManipulator::new(json.to_string()).unwrap();
+ assert_eq!(
+ expected,
+ manipulator.remove_sub_node("repositories", name).unwrap()
+ );
+ if let Some(expected_content) = expected_content {
+ assert_eq!(expected_content, manipulator.get_contents());
+ }
+ }
+}
+
+#[test]
+#[ignore]
+fn test_add_repository() {
+ let cases: Vec<(&str, &str, &str, PhpMixed, bool)> = vec![
+ (
+ r#"{
+ "repositories": [
+ {
+ "type": "git",
+ "url": "example.tld"
+ }
+ ]
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "type": "path",
+ "url": "foo/bar"
+ },
+ {
+ "type": "git",
+ "url": "example.tld"
+ }
+ ]
+}
+"#,
+ r#""#,
+ arr(&[(r#"type"#, s(r#"path"#)), (r#"url"#, s(r#"foo/bar"#))]),
+ false,
+ ),
+ (
+ r#"{
+ "repositories": [
+ {
+ "type": "git",
+ "url": "example.tld"
+ }
+ ]
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "type": "git",
+ "url": "example.tld"
+ },
+ {
+ "type": "path",
+ "url": "foo/bar"
+ }
+ ]
+}
+"#,
+ r#""#,
+ arr(&[(r#"type"#, s(r#"path"#)), (r#"url"#, s(r#"foo/bar"#))]),
+ true,
+ ),
+ (
+ r#"{
+ "repositories": {
+ "0": {
+ "type": "git",
+ "url": "example.tld"
+ },
+ "packagist.org": false
+ }
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "name": "foo",
+ "type": "path",
+ "url": "foo/bar"
+ },
+ {
+ "type": "git",
+ "url": "example.tld"
+ },
+ {
+ "packagist.org": false
+ }
+ ]
+}
+"#,
+ r#"foo"#,
+ arr(&[(r#"type"#, s(r#"path"#)), (r#"url"#, s(r#"foo/bar"#))]),
+ false,
+ ),
+ (
+ r#"{
+ "repositories": {
+ "0": {
+ "type": "git",
+ "url": "example.tld"
+ },
+ "packagist.org": false
+ }
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "type": "git",
+ "url": "example.tld"
+ },
+ {
+ "packagist.org": false
+ },
+ {
+ "name": "foo",
+ "type": "path",
+ "url": "foo/bar"
+ }
+ ]
+}
+"#,
+ r#"foo"#,
+ arr(&[(r#"type"#, s(r#"path"#)), (r#"url"#, s(r#"foo/bar"#))]),
+ true,
+ ),
+ (
+ r#"{
+ "repositories": [
+ {
+ "type": "git",
+ "url": "example.tld"
+ }
+ ]
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "name": "foo",
+ "type": "path",
+ "url": "foo/bar"
+ },
+ {
+ "type": "git",
+ "url": "example.tld"
+ }
+ ]
+}
+"#,
+ r#"foo"#,
+ arr(&[(r#"type"#, s(r#"path"#)), (r#"url"#, s(r#"foo/bar"#))]),
+ false,
+ ),
+ (
+ r#"{
+ "repositories": [
+ {
+ "type": "git",
+ "url": "example.tld"
+ }
+ ]
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "type": "git",
+ "url": "example.tld"
+ },
+ {
+ "name": "foo",
+ "type": "path",
+ "url": "foo/bar"
+ }
+ ]
+}
+"#,
+ r#"foo"#,
+ arr(&[(r#"type"#, s(r#"path"#)), (r#"url"#, s(r#"foo/bar"#))]),
+ true,
+ ),
+ (
+ r#"{
+ "repositories": {
+ "0": {
+ "type": "git",
+ "url": "example.tld"
+ },
+ "packagist.org": false
+ }
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "type": "path",
+ "url": "foo/bar"
+ },
+ {
+ "type": "git",
+ "url": "example.tld"
+ },
+ {
+ "packagist.org": false
+ }
+ ]
+}
+"#,
+ r#""#,
+ arr(&[(r#"type"#, s(r#"path"#)), (r#"url"#, s(r#"foo/bar"#))]),
+ false,
+ ),
+ (
+ r#"{
+ "repositories": {
+ "0": {
+ "type": "git",
+ "url": "example.tld"
+ },
+ "packagist.org": false
+ }
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "type": "git",
+ "url": "example.tld"
+ },
+ {
+ "packagist.org": false
+ },
+ {
+ "type": "path",
+ "url": "foo/bar"
+ }
+ ]
+}
+"#,
+ r#""#,
+ arr(&[(r#"type"#, s(r#"path"#)), (r#"url"#, s(r#"foo/bar"#))]),
+ true,
+ ),
+ ];
+ for (from, to, name, config, append) in cases {
+ let mut manipulator = JsonManipulator::new(from.to_string()).unwrap();
+ assert!(manipulator.add_repository(name, config, append).unwrap());
+ assert_eq!(to, manipulator.get_contents());
+ }
+}
+
+#[test]
+#[ignore]
+fn test_set_url_in_repository() {
+ let cases: Vec<(&str, &str, &str, &str)> = vec![
+ (
+ r#"{
+ "repositories": {
+ "first": {
+ "type": "package",
+ "url": "https://first.test"
+ },
+ "foo": {
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ "bar": {
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ }
+}
+"#,
+ r#"{
+ "repositories": {
+ "first": {
+ "type": "package",
+ "url": "https://new.example.org"
+ },
+ "foo": {
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ "bar": {
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ }
+}
+"#,
+ r#"first"#,
+ r#"https://new.example.org"#,
+ ),
+ (
+ r#"{
+ "repositories": {
+ "first": {
+ "type": "package",
+ "url": "https://first.test"
+ },
+ "foo": {
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ "bar": {
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ }
+}
+"#,
+ r#"{
+ "repositories": {
+ "first": {
+ "type": "package",
+ "url": "https://first.test"
+ },
+ "foo": {
+ "type": "vcs",
+ "url": "https://new.example.org"
+ },
+ "bar": {
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ }
+}
+"#,
+ r#"foo"#,
+ r#"https://new.example.org"#,
+ ),
+ (
+ r#"{
+ "repositories": {
+ "first": {
+ "type": "package",
+ "url": "https://first.test"
+ },
+ "foo": {
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ "bar": {
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ }
+}
+"#,
+ r#"{
+ "repositories": {
+ "first": {
+ "type": "package",
+ "url": "https://first.test"
+ },
+ "foo": {
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ "bar": {
+ "type": "vcs",
+ "url": "https://new.example.org"
+ }
+ }
+}
+"#,
+ r#"bar"#,
+ r#"https://new.example.org"#,
+ ),
+ (
+ r#"{
+ "repositories": [
+ {
+ "name": "first",
+ "type": "package",
+ "url": "https://first.test"
+ },
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ {
+ "name": "bar",
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ ]
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "name": "first",
+ "type": "package",
+ "url": "https://new.example.org"
+ },
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ {
+ "name": "bar",
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ ]
+}
+"#,
+ r#"first"#,
+ r#"https://new.example.org"#,
+ ),
+ (
+ r#"{
+ "repositories": [
+ {
+ "name": "first",
+ "type": "package",
+ "url": "https://first.test"
+ },
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ {
+ "name": "bar",
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ ]
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "name": "first",
+ "type": "package",
+ "url": "https://first.test"
+ },
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "https://new.example.org"
+ },
+ {
+ "name": "bar",
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ ]
+}
+"#,
+ r#"foo"#,
+ r#"https://new.example.org"#,
+ ),
+ (
+ r#"{
+ "repositories": [
+ {
+ "name": "first",
+ "type": "package",
+ "url": "https://first.test"
+ },
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ {
+ "name": "bar",
+ "type": "vcs",
+ "url": "https://other.example.org"
+ }
+ ]
+}
+"#,
+ r#"{
+ "repositories": [
+ {
+ "name": "first",
+ "type": "package",
+ "url": "https://first.test"
+ },
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "https://old.example.org"
+ },
+ {
+ "name": "bar",
+ "type": "vcs",
+ "url": "https://new.example.org"
+ }
+ ]
+}
+"#,
+ r#"bar"#,
+ r#"https://new.example.org"#,
+ ),
+ ];
+ for (from, to, name, url) in cases {
+ let mut manipulator = JsonManipulator::new(from.to_string()).unwrap();
+ assert!(manipulator.set_repository_url(name, url).unwrap());
+ assert_eq!(to, manipulator.get_contents());
+ }
+}
+
+#[test]
+#[ignore]
+fn test_add_list_item() {
+ let cases: Vec<(&str, &str, &str, PhpMixed, bool)> = vec![
+ (
+ r#"{}"#,
+ r#"{
+ "main": [1]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(1),
+ true,
+ ),
+ (
+ r#"{
+ "main": [ ]
+}
+"#,
+ r#"{
+ "main": [1]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(1),
+ true,
+ ),
+ (
+ r#"{
+ "main": [ 1 ]
+}
+"#,
+ r#"{
+ "main": [ 1, 2 ]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(2),
+ true,
+ ),
+ (
+ r#"{}"#,
+ r#"{
+ "main": [{
+ "value": 1
+ }]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(1))]),
+ true,
+ ),
+ (
+ r#"{
+ "main": [ ]
+}
+"#,
+ r#"{
+ "main": [{
+ "value": 2
+ }]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(2))]),
+ true,
+ ),
+ (
+ r#"{
+ "main": [ 1 ]
+}
+"#,
+ r#"{
+ "main": [ 1, {
+ "value": 2
+ } ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(2))]),
+ true,
+ ),
+ (
+ r#"{
+ "main": [
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ 1
+ ]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(1),
+ true,
+ ),
+ (
+ r#"{
+ "main": [
+ 1
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ 1,
+ 2
+ ]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(2),
+ true,
+ ),
+ (
+ r#"{
+ "main": [
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ {
+ "value": 1
+ }
+ ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(1))]),
+ true,
+ ),
+ (
+ r#"{
+ "main": [
+ 1
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ 1,
+ {
+ "value": 2
+ }
+ ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(2))]),
+ true,
+ ),
+ (
+ r#"{}"#,
+ r#"{
+ "main": [1]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(1),
+ false,
+ ),
+ (
+ r#"{
+ "main": [ ]
+}
+"#,
+ r#"{
+ "main": [1]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(1),
+ false,
+ ),
+ (
+ r#"{
+ "main": [ 1 ]
+}
+"#,
+ r#"{
+ "main": [ 2, 1 ]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(2),
+ false,
+ ),
+ (
+ r#"{}"#,
+ r#"{
+ "main": [{
+ "value": 1
+ }]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(1))]),
+ false,
+ ),
+ (
+ r#"{
+ "main": [ ]
+}
+"#,
+ r#"{
+ "main": [{
+ "value": 1
+ }]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(1))]),
+ false,
+ ),
+ (
+ r#"{
+ "main": [ 1 ]
+}
+"#,
+ r#"{
+ "main": [ {
+ "value": 2
+ }, 1 ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(2))]),
+ false,
+ ),
+ (
+ r#"{
+ "main": [
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ 1
+ ]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(1),
+ false,
+ ),
+ (
+ r#"{
+ "main": [
+ 1
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ 2,
+ 1
+ ]
+}
+"#,
+ r#"main"#,
+ PhpMixed::Int(2),
+ false,
+ ),
+ (
+ r#"{
+ "main": [
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ {
+ "value": 1
+ }
+ ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(1))]),
+ false,
+ ),
+ (
+ r#"{
+ "main": [
+ 1
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ {
+ "value": 2
+ },
+ 1
+ ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"value"#, PhpMixed::Int(2))]),
+ false,
+ ),
+ ];
+ for (from, to, main_node, value, append) in cases {
+ let mut manipulator = JsonManipulator::new(from.to_string()).unwrap();
+ assert!(manipulator.add_list_item(main_node, value, append).unwrap());
+ assert_eq!(to, manipulator.get_contents());
+ }
+}
+
+#[test]
+#[ignore]
+fn test_remove_list_item() {
+ let cases: Vec<(&str, &str, &str, i64)> = vec![
+ (
+ r#"{
+ "main": [
+ 1, 2, 3
+ ]
+}"#,
+ r#"{
+ "main": [
+ 2, 3
+ ]
+}
+"#,
+ r#"main"#,
+ 0,
+ ),
+ (
+ r#"{
+ "main": [
+ 1, 2, 3
+ ]
+}"#,
+ r#"{
+ "main": [
+ 1, 3
+ ]
+}
+"#,
+ r#"main"#,
+ 1,
+ ),
+ (
+ r#"{
+ "main": [
+ 1, 2, 3
+ ]
+}"#,
+ r#"{
+ "main": [
+ 1, 2
+ ]
+}
+"#,
+ r#"main"#,
+ 2,
+ ),
+ (
+ r#"{
+ "main": [
+ 1,
+ 2,
+ 3
+ ]
+}"#,
+ r#"{
+ "main": [
+ 2,
+ 3
+ ]
+}
+"#,
+ r#"main"#,
+ 0,
+ ),
+ (
+ r#"{
+ "main": [
+ 1,
+ 2,
+ 3
+ ]
+}"#,
+ r#"{
+ "main": [
+ 1,
+ 3
+ ]
+}
+"#,
+ r#"main"#,
+ 1,
+ ),
+ (
+ r#"{
+ "main": [
+ 1,
+ 2,
+ 3
+ ]
+}"#,
+ r#"{
+ "main": [
+ 1,
+ 2
+ ]
+}
+"#,
+ r#"main"#,
+ 2,
+ ),
+ ];
+ for (from, to, main_node, index_to_remove) in cases {
+ let mut manipulator = JsonManipulator::new(from.to_string()).unwrap();
+ assert!(
+ manipulator
+ .remove_list_item(main_node, index_to_remove)
+ .unwrap()
+ );
+ assert_eq!(to, manipulator.get_contents());
+ }
+}
+
+#[test]
+#[ignore]
+fn test_insert_list_item() {
+ let cases: Vec<(&str, &str, &str, PhpMixed, i64)> = vec![
+ (
+ r#"{
+}
+"#,
+ r#"{
+ "main": [{
+ "foo": 1
+ }]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"foo"#, PhpMixed::Int(1))]),
+ 0,
+ ),
+ (
+ r#"{
+ "main": [
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ {
+ "foo": 1
+ }
+ ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"foo"#, PhpMixed::Int(1))]),
+ 0,
+ ),
+ (
+ r#"{
+ "main": [
+ {
+ "foo": 2
+ },
+ {
+ "foo": 4
+ }
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ {
+ "foo": 1
+ },
+ {
+ "foo": 2
+ },
+ {
+ "foo": 4
+ }
+ ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"foo"#, PhpMixed::Int(1))]),
+ 0,
+ ),
+ (
+ r#"{
+ "main": [
+ {
+ "foo": 2
+ },
+ {
+ "foo": 4
+ }
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ {
+ "foo": 2
+ },
+ {
+ "foo": 3
+ },
+ {
+ "foo": 4
+ }
+ ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"foo"#, PhpMixed::Int(3))]),
+ 1,
+ ),
+ (
+ r#"{
+ "main": [
+ {
+ "foo": 2
+ },
+ {
+ "foo": 4
+ }
+ ]
+}
+"#,
+ r#"{
+ "main": [
+ {
+ "foo": 2
+ },
+ {
+ "foo": 4
+ },
+ {
+ "foo": 5
+ }
+ ]
+}
+"#,
+ r#"main"#,
+ arr(&[(r#"foo"#, PhpMixed::Int(5))]),
+ 2,
+ ),
+ ];
+ for (from, to, main_node, value, index_to_insert_at) in cases {
+ let mut manipulator = JsonManipulator::new(from.to_string()).unwrap();
+ assert!(
+ manipulator
+ .insert_list_item(main_node, value, index_to_insert_at)
+ .unwrap()
+ );
+ assert_eq!(to, manipulator.get_contents());
+ }
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_sub_node_from_require() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "package": {
+ "require": {
+ "this/should-not-end-up-in-root-require": "~2.0"
+ },
+ "require-dev": {
+ "this/should-not-end-up-in-root-require-dev": "~2.0"
+ }
+ }
+ }
+ ],
+ "require": {
+ "package/a": "*",
+ "package/b": "*",
+ "package/c": "*"
+ },
+ "require-dev": {
+ "package/d": "*"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.remove_sub_node("require", "package/c").unwrap());
+ assert!(
+ manipulator
+ .remove_sub_node("require-dev", "package/d")
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "package": {
+ "require": {
+ "this/should-not-end-up-in-root-require": "~2.0"
+ },
+ "require-dev": {
+ "this/should-not-end-up-in-root-require-dev": "~2.0"
+ }
+ }
+ }
+ ],
+ "require": {
+ "package/a": "*",
+ "package/b": "*"
+ },
+ "require-dev": {
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_sub_node_preserves_object_type_when_empty() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "test": {"0": "foo"}
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.remove_sub_node("test", "0").unwrap());
+ assert_eq!(
+ r#"{
+ "test": {
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_sub_node_preserves_object_type_when_empty2() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "preferred-install": {"foo/*": "source"}
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .remove_config_setting("preferred-install.foo/*")
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "preferred-install": {
+ }
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_sub_node_in_require() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "package": {
+ "require": {
+ "this/should-not-end-up-in-root-require": "~2.0"
+ },
+ "require-dev": {
+ "this/should-not-end-up-in-root-require-dev": "~2.0"
+ }
+ }
+ }
+ ],
+ "require": {
+ "package/a": "*",
+ "package/b": "*"
+ },
+ "require-dev": {
+ "package/d": "*"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_sub_node("require", "package/c", s("*"), true)
+ .unwrap()
+ );
+ assert!(
+ manipulator
+ .add_sub_node("require-dev", "package/e", s("*"), true)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "package": {
+ "require": {
+ "this/should-not-end-up-in-root-require": "~2.0"
+ },
+ "require-dev": {
+ "this/should-not-end-up-in-root-require-dev": "~2.0"
+ }
+ }
+ }
+ ],
+ "require": {
+ "package/a": "*",
+ "package/b": "*",
+ "package/c": "*"
+ },
+ "require-dev": {
+ "package/d": "*",
+ "package/e": "*"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_extra_with_package() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "type": "package",
+ "package": {
+ "authors": [],
+ "extra": {
+ "package-xml": "package.xml"
+ }
+ }
+ }
+ ],
+ "extra": {
+ "auto-append-gitignore": true
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_property("extra.foo-bar", PhpMixed::Bool(true))
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "type": "package",
+ "package": {
+ "authors": [],
+ "extra": {
+ "package-xml": "package.xml"
+ }
+ }
+ }
+ ],
+ "extra": {
+ "auto-append-gitignore": true,
+ "foo-bar": true
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_with_package() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "type": "package",
+ "package": {
+ "authors": [],
+ "extra": {
+ "package-xml": "package.xml"
+ }
+ }
+ }
+ ],
+ "config": {
+ "platform": {
+ "php": "5.3.9"
+ }
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_config_setting(
+ "preferred-install.my-organization/stable-package",
+ s("dist")
+ )
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "type": "package",
+ "package": {
+ "authors": [],
+ "extra": {
+ "package-xml": "package.xml"
+ }
+ }
+ }
+ ],
+ "config": {
+ "platform": {
+ "php": "5.3.9"
+ },
+ "preferred-install": {
+ "my-organization/stable-package": "dist"
+ }
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_suggest_with_package() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "type": "package",
+ "package": {
+ "authors": [],
+ "extra": {
+ "package-xml": "package.xml"
+ }
+ }
+ }
+ ],
+ "suggest": {
+ "package": "Description"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_property("suggest.new-package", s("new-description"))
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "type": "package",
+ "package": {
+ "authors": [],
+ "extra": {
+ "package-xml": "package.xml"
+ }
+ }
+ }
+ ],
+ "suggest": {
+ "package": "Description",
+ "new-package": "new-description"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_repository_can_initialize_empty_repositories() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": {
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_repository("bar", arr(&[("type", s("composer"))]), false)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "name": "bar",
+ "type": "composer"
+ }
+ ]
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_repository_can_initialize_from_scratch() {
- todo!()
+ let mut manipulator = JsonManipulator::new("{\n\t\"a\": \"b\"\n}".to_string()).unwrap();
+
+ assert!(
+ manipulator
+ .add_repository("bar2", arr(&[("type", s("composer"))]), false)
+ .unwrap()
+ );
+ assert_eq!(
+ "{\n\t\"a\": \"b\",\n\t\"repositories\": [{\n\t\t\"name\": \"bar2\",\n\t\t\"type\": \"composer\"\n\t}]\n}\n",
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_repository_can_append() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "lala"
+ }
+ ]
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_repository("bar", arr(&[("type", s("composer"))]), true)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "lala"
+ },
+ {
+ "name": "bar",
+ "type": "composer"
+ }
+ ]
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_repository_can_prepend() {
- todo!()
-}
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "lala"
+ }
+ ]
+}"#
+ .to_string(),
+ )
+ .unwrap();
-#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
-fn test_add_repository() {
- todo!()
+ assert!(
+ manipulator
+ .add_repository("bar", arr(&[("type", s("composer"))]), false)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "name": "bar",
+ "type": "composer"
+ },
+ {
+ "name": "foo",
+ "type": "vcs",
+ "url": "lala"
+ }
+ ]
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_repository_can_override_deep_repos() {
- todo!()
-}
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": {
+ "baz": {
+ "type": "package",
+ "package": {}
+ }
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
-#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
-fn test_set_url_in_repository() {
- todo!()
+ assert!(
+ manipulator
+ .add_repository("baz", arr(&[("type", s("composer"))]), false)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "name": "baz",
+ "type": "composer"
+ }
+ ]
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_insert_repository_before_and_after_by_name() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": {
+ "alpha": {
+ "type": "vcs",
+ "url": "https://example.org/a"
+ },
+ "omega": {
+ "type": "vcs",
+ "url": "https://example.org/o"
+ },
+ "packagist.org": false
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+ assert!(
+ manipulator
+ .insert_repository(
+ "beta",
+ arr(&[("type", s("vcs")), ("url", s("https://example.org/b"))]),
+ "omega",
+ 0
+ )
+ .unwrap()
+ );
+ assert!(
+ manipulator
+ .insert_repository(
+ "gamma",
+ arr(&[("type", s("vcs")), ("url", s("https://example.org/g"))]),
+ "alpha",
+ 1
+ )
+ .unwrap()
+ );
+ assert!(
+ manipulator
+ .insert_repository(
+ "alpha",
+ arr(&[("type", s("vcs")), ("url", s("https://example.org/alpha"))]),
+ "gamma",
+ 0
+ )
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "name": "alpha",
+ "type": "vcs",
+ "url": "https://example.org/alpha"
+ },
+ {
+ "name": "gamma",
+ "type": "vcs",
+ "url": "https://example.org/g"
+ },
+ {
+ "name": "beta",
+ "type": "vcs",
+ "url": "https://example.org/b"
+ },
+ {
+ "name": "omega",
+ "type": "vcs",
+ "url": "https://example.org/o"
+ },
+ {
+ "packagist.org": false
+ }
+ ]
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_repository_removes_from_assoc_but_does_not_converts_from_assoc_to_list() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": {
+ "baz": {
+ "type": "package",
+ "package": {}
+ },
+ "packagist.org": false
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.remove_repository("baz").unwrap());
+ assert_eq!(
+ r#"{
+ "repositories": {
+ "packagist.org": false
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_repository_removes_from_list() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "name": "baz",
+ "type": "package",
+ "package": {
+ }
+ },
+ {
+ "packagist.org": false
+ }
+ ]
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.remove_repository("baz").unwrap());
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "packagist.org": false
+ }
+ ]
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_repository_converts_from_assoc_to_list() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": {
+ "baz": {
+ "type": "package",
+ "package": {}
+ },
+ "packagist.org": false
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_repository("foo", arr(&[("type", s("composer"))]), false)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "repositories": [
+ {
+ "name": "baz",
+ "type": "package",
+ "package": {
+ }
+ },
+ {
+ "packagist.org": false
+ },
+ {
+ "name": "foo",
+ "type": "composer"
+ }
+ ]
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_escapes() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_config_setting("test", s(r#"a\b"#)).unwrap());
+ assert!(
+ manipulator
+ .add_config_setting("test2", s("a\nb\u{0C}a"))
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "test": "a\\b",
+ "test2": "a\nb\fa"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_works_from_scratch() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_config_setting("foo.bar", s("baz")).unwrap());
+ assert_eq!(
+ r#"{
+ "config": {
+ "foo": {
+ "bar": "baz"
+ }
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_can_add() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "foo": "bar"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_config_setting("bar", s("baz")).unwrap());
+ assert_eq!(
+ r#"{
+ "config": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_can_overwrite() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "foo": "bar",
+ "bar": "baz"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_config_setting("foo", s("zomg")).unwrap());
+ assert_eq!(
+ r#"{
+ "config": {
+ "foo": "zomg",
+ "bar": "baz"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_can_overwrite_numbers() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "foo": 500
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_config_setting("foo", PhpMixed::Int(50))
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "foo": 50
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_can_overwrite_arrays() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "github.com": "foo"
+ },
+ "github-protocols": ["https"]
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_config_setting(
+ "github-protocols",
+ PhpMixed::List(vec![s("https"), s("http")])
+ )
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "github.com": "foo"
+ },
+ "github-protocols": ["https", "http"]
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
+
+ assert!(
+ manipulator
+ .add_config_setting(
+ "github-oauth",
+ arr(&[("github.com", s("bar")), ("alt.example.org", s("baz"))])
+ )
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "github.com": "bar",
+ "alt.example.org": "baz"
+ },
+ "github-protocols": ["https", "http"]
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_can_add_sub_key_in_empty_config() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_config_setting("github-oauth.bar", s("baz"))
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "bar": "baz"
+ }
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_can_add_sub_key_in_empty_val() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "github-oauth": {},
+ "github-oauth2": {
+ }
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_config_setting("github-oauth.bar", s("baz"))
+ .unwrap()
+ );
+ assert!(
+ manipulator
+ .add_config_setting("github-oauth2.a.bar", s("baz2"))
+ .unwrap()
+ );
+ assert!(
+ manipulator
+ .add_config_setting("github-oauth3.b", s("c"))
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "bar": "baz"
+ },
+ "github-oauth2": {
+ "a.bar": "baz2"
+ },
+ "github-oauth3": {
+ "b": "c"
+ }
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_config_setting_can_add_sub_key_in_hash() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "github.com": "foo"
+ }
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_config_setting("github-oauth.bar", s("baz"))
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "github.com": "foo",
+ "bar": "baz"
+ }
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_root_setting_does_not_break_dots() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "github-oauth": {
+ "github.com": "foo"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_sub_node("github-oauth", "bar", s("baz"), true)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "github-oauth": {
+ "github.com": "foo",
+ "bar": "baz"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_config_setting_can_remove_sub_key_in_hash() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "github.com": "foo",
+ "bar": "baz"
+ }
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .remove_config_setting("github-oauth.bar")
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "github-oauth": {
+ "github.com": "foo"
+ }
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_config_setting_can_remove_sub_key_in_hash_with_siblings() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "config": {
+ "foo": "bar",
+ "github-oauth": {
+ "github.com": "foo",
+ "bar": "baz"
+ }
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .remove_config_setting("github-oauth.bar")
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "config": {
+ "foo": "bar",
+ "github-oauth": {
+ "github.com": "foo"
+ }
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_main_key() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "foo": "bar"
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_main_key("bar", s("baz")).unwrap());
+ assert_eq!(
+ r#"{
+ "foo": "bar",
+ "bar": "baz"
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_main_key_with_content_having_dollar_sign_followed_by_digit() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "foo": "bar"
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_main_key("bar", s("$1baz")).unwrap());
+ assert_eq!(
+ r#"{
+ "foo": "bar",
+ "bar": "$1baz"
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_add_main_key_with_content_having_dollar_sign_followed_by_digit2() {
- todo!()
+ let mut manipulator = JsonManipulator::new("{}".to_string()).unwrap();
+
+ assert!(manipulator.add_main_key("foo", s("$1bar")).unwrap());
+ assert_eq!(
+ r#"{
+ "foo": "$1bar"
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_update_main_key() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "foo": "bar"
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_main_key("foo", s("baz")).unwrap());
+ assert_eq!(
+ r#"{
+ "foo": "baz"
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_update_main_key2() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "a": {
+ "foo": "bar",
+ "baz": "qux"
+ },
+ "foo": "bar",
+ "baz": "bar"
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_main_key("foo", s("baz")).unwrap());
+ assert!(manipulator.add_main_key("baz", s("quux")).unwrap());
+ assert_eq!(
+ r#"{
+ "a": {
+ "foo": "bar",
+ "baz": "qux"
+ },
+ "foo": "baz",
+ "baz": "quux"
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_update_main_key3() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "require": {
+ "php": "5.*"
+ },
+ "require-dev": {
+ "foo": "bar"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_main_key("require-dev", arr(&[("foo", s("qux"))]))
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "require": {
+ "php": "5.*"
+ },
+ "require-dev": {
+ "foo": "qux"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_update_main_key_with_content_having_dollar_sign_followed_by_digit() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "foo": "bar"
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.add_main_key("foo", s("$1bar")).unwrap());
+ assert_eq!(
+ r#"{
+ "foo": "$1bar"
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_main_key() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ {
+ "package": {
+ "require": {
+ "this/should-not-end-up-in-root-require": "~2.0"
+ },
+ "require-dev": {
+ "this/should-not-end-up-in-root-require-dev": "~2.0"
+ }
+ }
+ }
+ ],
+ "require": {
+ "package/a": "*",
+ "package/b": "*",
+ "package/c": "*"
+ },
+ "foo": "bar",
+ "require-dev": {
+ "package/d": "*"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(manipulator.remove_main_key("repositories").unwrap());
+ assert_eq!(
+ r#"{
+ "require": {
+ "package/a": "*",
+ "package/b": "*",
+ "package/c": "*"
+ },
+ "foo": "bar",
+ "require-dev": {
+ "package/d": "*"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
+
+ assert!(manipulator.remove_main_key("foo").unwrap());
+ assert_eq!(
+ r#"{
+ "require": {
+ "package/a": "*",
+ "package/b": "*",
+ "package/c": "*"
+ },
+ "require-dev": {
+ "package/d": "*"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
+
+ assert!(manipulator.remove_main_key("require").unwrap());
+ assert!(manipulator.remove_main_key("require-dev").unwrap());
+ assert_eq!(
+ r#"{
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_main_key_if_empty() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "repositories": [
+ ],
+ "require": {
+ "package/a": "*",
+ "package/b": "*",
+ "package/c": "*"
+ },
+ "foo": "bar",
+ "require-dev": {
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .remove_main_key_if_empty("repositories")
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "require": {
+ "package/a": "*",
+ "package/b": "*",
+ "package/c": "*"
+ },
+ "foo": "bar",
+ "require-dev": {
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
+
+ assert!(manipulator.remove_main_key_if_empty("foo").unwrap());
+ assert!(manipulator.remove_main_key_if_empty("require").unwrap());
+ assert!(manipulator.remove_main_key_if_empty("require-dev").unwrap());
+ assert_eq!(
+ r#"{
+ "require": {
+ "package/a": "*",
+ "package/b": "*",
+ "package/c": "*"
+ },
+ "foo": "bar"
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_remove_main_key_removes_key_where_value_is_null() {
- todo!()
+ let mut manipulator = JsonManipulator::new(r#"{"foo":9000,"bar":null}"#.to_string()).unwrap();
+
+ manipulator.remove_main_key("bar").unwrap();
+
+ let expected = JsonFile::encode(&arr(&[("foo", PhpMixed::Int(9000))]));
+
+ assert_eq!(
+ JsonFile::parse_json(Some(&expected), None).unwrap(),
+ JsonFile::parse_json(Some(&manipulator.get_contents()), None).unwrap()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_indent_detection() {
- todo!()
-}
+ let mut manipulator =
+ JsonManipulator::new("{\n\n \"require\": {\n \"php\": \"5.*\"\n }\n}".to_string())
+ .unwrap();
-#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
-fn test_remove_main_key_at_end_of_file() {
- todo!()
+ assert!(
+ manipulator
+ .add_main_key("require-dev", arr(&[("foo", s("qux"))]))
+ .unwrap()
+ );
+ assert_eq!(
+ "{\n\n \"require\": {\n \"php\": \"5.*\"\n },\n \"require-dev\": {\n \"foo\": \"qux\"\n }\n}\n",
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
-fn test_add_list_item() {
- todo!()
+#[ignore]
+fn test_remove_main_key_at_end_of_file() {
+ let mut manipulator = JsonManipulator::new(
+ "{\n \"require\": {\n \"package/a\": \"*\"\n }\n}\n".to_string(),
+ )
+ .unwrap();
+ assert!(manipulator.add_main_key("homepage", s("http...")).unwrap());
+ assert!(manipulator.add_main_key("license", s("mit")).unwrap());
+ assert_eq!(
+ r#"{
+ "require": {
+ "package/a": "*"
+ },
+ "homepage": "http...",
+ "license": "mit"
}
+"#,
+ manipulator.get_contents()
+ );
-#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
-fn test_remove_list_item() {
- todo!()
+ assert!(manipulator.remove_main_key("homepage").unwrap());
+ assert!(manipulator.remove_main_key("license").unwrap());
+ assert_eq!(
+ r#"{
+ "require": {
+ "package/a": "*"
+ }
}
-
-#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
-fn test_insert_list_item() {
- todo!()
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_escaped_unicode_does_not_cause_backtrack_limit_error_github_issue8131() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "description": "Some U\u00F1icode",
+ "require": {
+ "foo/bar": "^1.0"
+ }
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_link("require", "foo/baz", "^1.0", false)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "description": "Some U\u00F1icode",
+ "require": {
+ "foo/bar": "^1.0",
+ "foo/baz": "^1.0"
+ }
+}
+"#,
+ manipulator.get_contents()
+ );
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore]
fn test_large_file_does_not_cause_backtrack_limit_error_github_issue9595() {
- todo!()
+ let mut manipulator = JsonManipulator::new(
+ r#"{
+ "name": "leoloso/pop",
+ "require": {
+ "php": "^7.4|^8.0",
+ "ext-mbstring": "*",
+ "brain/cortex": "~1.0.0",
+ "composer/installers": "~1.0",
+ "composer/semver": "^1.5",
+ "erusev/parsedown": "^1.7",
+ "guzzlehttp/guzzle": "~6.3",
+ "jrfnl/php-cast-to-type": "^2.0",
+ "league/pipeline": "^1.0",
+ "lkwdwrd/wp-muplugin-loader": "dev-feature-composer-v2",
+ "obsidian/polyfill-hrtime": "^0.1",
+ "psr/cache": "^1.0",
+ "symfony/cache": "^5.1",
+ "symfony/config": "^5.1",
+ "symfony/dependency-injection": "^5.1",
+ "symfony/dotenv": "^5.1",
+ "symfony/expression-language": "^5.1",
+ "symfony/polyfill-php72": "^1.18",
+ "symfony/polyfill-php73": "^1.18",
+ "symfony/polyfill-php74": "^1.18",
+ "symfony/polyfill-php80": "^1.18",
+ "symfony/property-access": "^5.1",
+ "symfony/yaml": "^5.1"
+ },
+ "require-dev": {
+ "johnpbloch/wordpress": ">=5.5",
+ "phpstan/phpstan": "^0.12",
+ "phpunit/phpunit": ">=9.3",
+ "rector/rector": "^0.9",
+ "squizlabs/php_codesniffer": "^3.0",
+ "symfony/var-dumper": "^5.1",
+ "symplify/monorepo-builder": "^9.0",
+ "szepeviktor/phpstan-wordpress": "^0.6.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "GraphQLAPI\\ConvertCaseDirectives\\": "layers/GraphQLAPIForWP/plugins/convert-case-directives/src",
+ "GraphQLAPI\\GraphQLAPI\\": "layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/src",
+ "GraphQLAPI\\SchemaFeedback\\": "layers/GraphQLAPIForWP/plugins/schema-feedback/src",
+ "GraphQLByPoP\\GraphQLClientsForWP\\": "layers/GraphQLByPoP/packages/graphql-clients-for-wp/src",
+ "GraphQLByPoP\\GraphQLEndpointForWP\\": "layers/GraphQLByPoP/packages/graphql-endpoint-for-wp/src",
+ "GraphQLByPoP\\GraphQLParser\\": "layers/GraphQLByPoP/packages/graphql-parser/src",
+ "GraphQLByPoP\\GraphQLQuery\\": "layers/GraphQLByPoP/packages/graphql-query/src",
+ "GraphQLByPoP\\GraphQLRequest\\": "layers/GraphQLByPoP/packages/graphql-request/src",
+ "GraphQLByPoP\\GraphQLServer\\": "layers/GraphQLByPoP/packages/graphql-server/src",
+ "Leoloso\\ExamplesForPoP\\": "layers/Misc/packages/examples-for-pop/src",
+ "PoPSchema\\BasicDirectives\\": "layers/Schema/packages/basic-directives/src",
+ "PoPSchema\\BlockMetadataWP\\": "layers/Schema/packages/block-metadata-for-wp/src",
+ "PoPSchema\\CDNDirective\\": "layers/Schema/packages/cdn-directive/src",
+ "PoPSchema\\CategoriesWP\\": "layers/Schema/packages/categories-wp/src",
+ "PoPSchema\\Categories\\": "layers/Schema/packages/categories/src",
+ "PoPSchema\\CommentMetaWP\\": "layers/Schema/packages/commentmeta-wp/src",
+ "PoPSchema\\CommentMeta\\": "layers/Schema/packages/commentmeta/src",
+ "PoPSchema\\CommentMutationsWP\\": "layers/Schema/packages/comment-mutations-wp/src",
+ "PoPSchema\\CommentMutations\\": "layers/Schema/packages/comment-mutations/src",
+ "PoPSchema\\CommentsWP\\": "layers/Schema/packages/comments-wp/src",
+ "PoPSchema\\Comments\\": "layers/Schema/packages/comments/src",
+ "PoPSchema\\ConvertCaseDirectives\\": "layers/Schema/packages/convert-case-directives/src",
+ "PoPSchema\\CustomPostMediaMutationsWP\\": "layers/Schema/packages/custompostmedia-mutations-wp/src",
+ "PoPSchema\\CustomPostMediaMutations\\": "layers/Schema/packages/custompostmedia-mutations/src",
+ "PoPSchema\\CustomPostMediaWP\\": "layers/Schema/packages/custompostmedia-wp/src",
+ "PoPSchema\\CustomPostMedia\\": "layers/Schema/packages/custompostmedia/src",
+ "PoPSchema\\CustomPostMetaWP\\": "layers/Schema/packages/custompostmeta-wp/src",
+ "PoPSchema\\CustomPostMeta\\": "layers/Schema/packages/custompostmeta/src",
+ "PoPSchema\\CustomPostMutationsWP\\": "layers/Schema/packages/custompost-mutations-wp/src",
+ "PoPSchema\\CustomPostMutations\\": "layers/Schema/packages/custompost-mutations/src",
+ "PoPSchema\\CustomPostsWP\\": "layers/Schema/packages/customposts-wp/src",
+ "PoPSchema\\CustomPosts\\": "layers/Schema/packages/customposts/src",
+ "PoPSchema\\EventMutationsWPEM\\": "layers/Schema/packages/event-mutations-wp-em/src",
+ "PoPSchema\\EventMutations\\": "layers/Schema/packages/event-mutations/src",
+ "PoPSchema\\EventsWPEM\\": "layers/Schema/packages/events-wp-em/src",
+ "PoPSchema\\Events\\": "layers/Schema/packages/events/src",
+ "PoPSchema\\EverythingElseWP\\": "layers/Schema/packages/everythingelse-wp/src",
+ "PoPSchema\\EverythingElse\\": "layers/Schema/packages/everythingelse/src",
+ "PoPSchema\\GenericCustomPosts\\": "layers/Schema/packages/generic-customposts/src",
+ "PoPSchema\\GoogleTranslateDirectiveForCustomPosts\\": "layers/Schema/packages/google-translate-directive-for-customposts/src",
+ "PoPSchema\\GoogleTranslateDirective\\": "layers/Schema/packages/google-translate-directive/src",
+ "PoPSchema\\HighlightsWP\\": "layers/Schema/packages/highlights-wp/src",
+ "PoPSchema\\Highlights\\": "layers/Schema/packages/highlights/src",
+ "PoPSchema\\LocationPostsWP\\": "layers/Schema/packages/locationposts-wp/src",
+ "PoPSchema\\LocationPosts\\": "layers/Schema/packages/locationposts/src",
+ "PoPSchema\\LocationsWPEM\\": "layers/Schema/packages/locations-wp-em/src",
+ "PoPSchema\\Locations\\": "layers/Schema/packages/locations/src",
+ "PoPSchema\\MediaWP\\": "layers/Schema/packages/media-wp/src",
+ "PoPSchema\\Media\\": "layers/Schema/packages/media/src",
+ "PoPSchema\\MenusWP\\": "layers/Schema/packages/menus-wp/src",
+ "PoPSchema\\Menus\\": "layers/Schema/packages/menus/src",
+ "PoPSchema\\MetaQueryWP\\": "layers/Schema/packages/metaquery-wp/src",
+ "PoPSchema\\MetaQuery\\": "layers/Schema/packages/metaquery/src",
+ "PoPSchema\\Meta\\": "layers/Schema/packages/meta/src",
+ "PoPSchema\\NotificationsWP\\": "layers/Schema/packages/notifications-wp/src",
+ "PoPSchema\\Notifications\\": "layers/Schema/packages/notifications/src",
+ "PoPSchema\\PagesWP\\": "layers/Schema/packages/pages-wp/src",
+ "PoPSchema\\Pages\\": "layers/Schema/packages/pages/src",
+ "PoPSchema\\PostMutations\\": "layers/Schema/packages/post-mutations/src",
+ "PoPSchema\\PostTagsWP\\": "layers/Schema/packages/post-tags-wp/src",
+ "PoPSchema\\PostTags\\": "layers/Schema/packages/post-tags/src",
+ "PoPSchema\\PostsWP\\": "layers/Schema/packages/posts-wp/src",
+ "PoPSchema\\Posts\\": "layers/Schema/packages/posts/src",
+ "PoPSchema\\QueriedObjectWP\\": "layers/Schema/packages/queriedobject-wp/src",
+ "PoPSchema\\QueriedObject\\": "layers/Schema/packages/queriedobject/src",
+ "PoPSchema\\SchemaCommons\\": "layers/Schema/packages/schema-commons/src",
+ "PoPSchema\\StancesWP\\": "layers/Schema/packages/stances-wp/src",
+ "PoPSchema\\Stances\\": "layers/Schema/packages/stances/src",
+ "PoPSchema\\TagsWP\\": "layers/Schema/packages/tags-wp/src",
+ "PoPSchema\\Tags\\": "layers/Schema/packages/tags/src",
+ "PoPSchema\\TaxonomiesWP\\": "layers/Schema/packages/taxonomies-wp/src",
+ "PoPSchema\\Taxonomies\\": "layers/Schema/packages/taxonomies/src",
+ "PoPSchema\\TaxonomyMetaWP\\": "layers/Schema/packages/taxonomymeta-wp/src",
+ "PoPSchema\\TaxonomyMeta\\": "layers/Schema/packages/taxonomymeta/src",
+ "PoPSchema\\TaxonomyQueryWP\\": "layers/Schema/packages/taxonomyquery-wp/src",
+ "PoPSchema\\TaxonomyQuery\\": "layers/Schema/packages/taxonomyquery/src",
+ "PoPSchema\\TranslateDirectiveACL\\": "layers/Schema/packages/translate-directive-acl/src",
+ "PoPSchema\\TranslateDirective\\": "layers/Schema/packages/translate-directive/src",
+ "PoPSchema\\UserMetaWP\\": "layers/Schema/packages/usermeta-wp/src",
+ "PoPSchema\\UserMeta\\": "layers/Schema/packages/usermeta/src",
+ "PoPSchema\\UserRolesACL\\": "layers/Schema/packages/user-roles-acl/src",
+ "PoPSchema\\UserRolesAccessControl\\": "layers/Schema/packages/user-roles-access-control/src",
+ "PoPSchema\\UserRolesWP\\": "layers/Schema/packages/user-roles-wp/src",
+ "PoPSchema\\UserRoles\\": "layers/Schema/packages/user-roles/src",
+ "PoPSchema\\UserStateAccessControl\\": "layers/Schema/packages/user-state-access-control/src",
+ "PoPSchema\\UserStateMutationsWP\\": "layers/Schema/packages/user-state-mutations-wp/src",
+ "PoPSchema\\UserStateMutations\\": "layers/Schema/packages/user-state-mutations/src",
+ "PoPSchema\\UserStateWP\\": "layers/Schema/packages/user-state-wp/src",
+ "PoPSchema\\UserState\\": "layers/Schema/packages/user-state/src",
+ "PoPSchema\\UsersWP\\": "layers/Schema/packages/users-wp/src",
+ "PoPSchema\\Users\\": "layers/Schema/packages/users/src",
+ "PoPSitesWassup\\CommentMutations\\": "layers/Wassup/packages/comment-mutations/src",
+ "PoPSitesWassup\\ContactUsMutations\\": "layers/Wassup/packages/contactus-mutations/src",
+ "PoPSitesWassup\\ContactUserMutations\\": "layers/Wassup/packages/contactuser-mutations/src",
+ "PoPSitesWassup\\CustomPostLinkMutations\\": "layers/Wassup/packages/custompostlink-mutations/src",
+ "PoPSitesWassup\\CustomPostMutations\\": "layers/Wassup/packages/custompost-mutations/src",
+ "PoPSitesWassup\\EventLinkMutations\\": "layers/Wassup/packages/eventlink-mutations/src",
+ "PoPSitesWassup\\EventMutations\\": "layers/Wassup/packages/event-mutations/src",
+ "PoPSitesWassup\\EverythingElseMutations\\": "layers/Wassup/packages/everythingelse-mutations/src",
+ "PoPSitesWassup\\FlagMutations\\": "layers/Wassup/packages/flag-mutations/src",
+ "PoPSitesWassup\\FormMutations\\": "layers/Wassup/packages/form-mutations/src",
+ "PoPSitesWassup\\GravityFormsMutations\\": "layers/Wassup/packages/gravityforms-mutations/src",
+ "PoPSitesWassup\\HighlightMutations\\": "layers/Wassup/packages/highlight-mutations/src",
+ "PoPSitesWassup\\LocationMutations\\": "layers/Wassup/packages/location-mutations/src",
+ "PoPSitesWassup\\LocationPostLinkMutations\\": "layers/Wassup/packages/locationpostlink-mutations/src",
+ "PoPSitesWassup\\LocationPostMutations\\": "layers/Wassup/packages/locationpost-mutations/src",
+ "PoPSitesWassup\\NewsletterMutations\\": "layers/Wassup/packages/newsletter-mutations/src",
+ "PoPSitesWassup\\NotificationMutations\\": "layers/Wassup/packages/notification-mutations/src",
+ "PoPSitesWassup\\PostLinkMutations\\": "layers/Wassup/packages/postlink-mutations/src",
+ "PoPSitesWassup\\PostMutations\\": "layers/Wassup/packages/post-mutations/src",
+ "PoPSitesWassup\\ShareMutations\\": "layers/Wassup/packages/share-mutations/src",
+ "PoPSitesWassup\\SocialNetworkMutations\\": "layers/Wassup/packages/socialnetwork-mutations/src",
+ "PoPSitesWassup\\StanceMutations\\": "layers/Wassup/packages/stance-mutations/src",
+ "PoPSitesWassup\\SystemMutations\\": "layers/Wassup/packages/system-mutations/src",
+ "PoPSitesWassup\\UserStateMutations\\": "layers/Wassup/packages/user-state-mutations/src",
+ "PoPSitesWassup\\VolunteerMutations\\": "layers/Wassup/packages/volunteer-mutations/src",
+ "PoPSitesWassup\\Wassup\\": "layers/Wassup/packages/wassup/src",
+ "PoP\\APIClients\\": "layers/API/packages/api-clients/src",
+ "PoP\\APIEndpointsForWP\\": "layers/API/packages/api-endpoints-for-wp/src",
+ "PoP\\APIEndpoints\\": "layers/API/packages/api-endpoints/src",
+ "PoP\\APIMirrorQuery\\": "layers/API/packages/api-mirrorquery/src",
+ "PoP\\API\\": "layers/API/packages/api/src",
+ "PoP\\AccessControl\\": "layers/Engine/packages/access-control/src",
+ "PoP\\ApplicationWP\\": "layers/SiteBuilder/packages/application-wp/src",
+ "PoP\\Application\\": "layers/SiteBuilder/packages/application/src",
+ "PoP\\Base36Definitions\\": "layers/SiteBuilder/packages/definitions-base36/src",
+ "PoP\\CacheControl\\": "layers/Engine/packages/cache-control/src",
+ "PoP\\ComponentModel\\": "layers/Engine/packages/component-model/src",
+ "PoP\\ConfigurableSchemaFeedback\\": "layers/Engine/packages/configurable-schema-feedback/src",
+ "PoP\\ConfigurationComponentModel\\": "layers/SiteBuilder/packages/component-model-configuration/src",
+ "PoP\\DefinitionPersistence\\": "layers/SiteBuilder/packages/definitionpersistence/src",
+ "PoP\\Definitions\\": "layers/Engine/packages/definitions/src",
+ "PoP\\EmojiDefinitions\\": "layers/SiteBuilder/packages/definitions-emoji/src",
+ "PoP\\EngineWP\\": "layers/Engine/packages/engine-wp/src",
+ "PoP\\Engine\\": "layers/Engine/packages/engine/src",
+ "PoP\\FieldQuery\\": "layers/Engine/packages/field-query/src",
+ "PoP\\FileStore\\": "layers/Engine/packages/filestore/src",
+ "PoP\\FunctionFields\\": "layers/Engine/packages/function-fields/src",
+ "PoP\\GraphQLAPI\\": "layers/API/packages/api-graphql/src",
+ "PoP\\GuzzleHelpers\\": "layers/Engine/packages/guzzle-helpers/src",
+ "PoP\\HooksWP\\": "layers/Engine/packages/hooks-wp/src",
+ "PoP\\Hooks\\": "layers/Engine/packages/hooks/src",
+ "PoP\\LooseContracts\\": "layers/Engine/packages/loosecontracts/src",
+ "PoP\\MandatoryDirectivesByConfiguration\\": "layers/Engine/packages/mandatory-directives-by-configuration/src",
+ "PoP\\ModuleRouting\\": "layers/Engine/packages/modulerouting/src",
+ "PoP\\Multisite\\": "layers/SiteBuilder/packages/multisite/src",
+ "PoP\\PoP\\": "src",
+ "PoP\\QueryParsing\\": "layers/Engine/packages/query-parsing/src",
+ "PoP\\RESTAPI\\": "layers/API/packages/api-rest/src",
+ "PoP\\ResourceLoader\\": "layers/SiteBuilder/packages/resourceloader/src",
+ "PoP\\Resources\\": "layers/SiteBuilder/packages/resources/src",
+ "PoP\\Root\\": "layers/Engine/packages/root/src",
+ "PoP\\RoutingWP\\": "layers/Engine/packages/routing-wp/src",
+ "PoP\\Routing\\": "layers/Engine/packages/routing/src",
+ "PoP\\SPA\\": "layers/SiteBuilder/packages/spa/src",
+ "PoP\\SSG\\": "layers/SiteBuilder/packages/static-site-generator/src",
+ "PoP\\SiteWP\\": "layers/SiteBuilder/packages/site-wp/src",
+ "PoP\\Site\\": "layers/SiteBuilder/packages/site/src",
+ "PoP\\TraceTools\\": "layers/Engine/packages/trace-tools/src",
+ "PoP\\TranslationWP\\": "layers/Engine/packages/translation-wp/src",
+ "PoP\\Translation\\": "layers/Engine/packages/translation/src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "GraphQLAPI\\ConvertCaseDirectives\\": "layers/GraphQLAPIForWP/plugins/convert-case-directives/tests",
+ "GraphQLAPI\\GraphQLAPI\\": "layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/tests",
+ "GraphQLAPI\\SchemaFeedback\\": "layers/GraphQLAPIForWP/plugins/schema-feedback/tests",
+ "GraphQLByPoP\\GraphQLClientsForWP\\": "layers/GraphQLByPoP/packages/graphql-clients-for-wp/tests",
+ "GraphQLByPoP\\GraphQLEndpointForWP\\": "layers/GraphQLByPoP/packages/graphql-endpoint-for-wp/tests",
+ "GraphQLByPoP\\GraphQLParser\\": "layers/GraphQLByPoP/packages/graphql-parser/tests",
+ "GraphQLByPoP\\GraphQLQuery\\": "layers/GraphQLByPoP/packages/graphql-query/tests",
+ "GraphQLByPoP\\GraphQLRequest\\": "layers/GraphQLByPoP/packages/graphql-request/tests",
+ "GraphQLByPoP\\GraphQLServer\\": "layers/GraphQLByPoP/packages/graphql-server/tests",
+ "Leoloso\\ExamplesForPoP\\": "layers/Misc/packages/examples-for-pop/tests",
+ "PoPSchema\\BasicDirectives\\": "layers/Schema/packages/basic-directives/tests",
+ "PoPSchema\\BlockMetadataWP\\": "layers/Schema/packages/block-metadata-for-wp/tests",
+ "PoPSchema\\CDNDirective\\": "layers/Schema/packages/cdn-directive/tests",
+ "PoPSchema\\CategoriesWP\\": "layers/Schema/packages/categories-wp/tests",
+ "PoPSchema\\Categories\\": "layers/Schema/packages/categories/tests",
+ "PoPSchema\\CommentMetaWP\\": "layers/Schema/packages/commentmeta-wp/tests",
+ "PoPSchema\\CommentMeta\\": "layers/Schema/packages/commentmeta/tests",
+ "PoPSchema\\CommentMutationsWP\\": "layers/Schema/packages/comment-mutations-wp/tests",
+ "PoPSchema\\CommentMutations\\": "layers/Schema/packages/comment-mutations/tests",
+ "PoPSchema\\CommentsWP\\": "layers/Schema/packages/comments-wp/tests",
+ "PoPSchema\\Comments\\": "layers/Schema/packages/comments/tests",
+ "PoPSchema\\ConvertCaseDirectives\\": "layers/Schema/packages/convert-case-directives/tests",
+ "PoPSchema\\CustomPostMediaMutationsWP\\": "layers/Schema/packages/custompostmedia-mutations-wp/tests",
+ "PoPSchema\\CustomPostMediaMutations\\": "layers/Schema/packages/custompostmedia-mutations/tests",
+ "PoPSchema\\CustomPostMediaWP\\": "layers/Schema/packages/custompostmedia-wp/tests",
+ "PoPSchema\\CustomPostMedia\\": "layers/Schema/packages/custompostmedia/tests",
+ "PoPSchema\\CustomPostMetaWP\\": "layers/Schema/packages/custompostmeta-wp/tests",
+ "PoPSchema\\CustomPostMeta\\": "layers/Schema/packages/custompostmeta/tests",
+ "PoPSchema\\CustomPostMutationsWP\\": "layers/Schema/packages/custompost-mutations-wp/tests",
+ "PoPSchema\\CustomPostMutations\\": "layers/Schema/packages/custompost-mutations/tests",
+ "PoPSchema\\CustomPostsWP\\": "layers/Schema/packages/customposts-wp/tests",
+ "PoPSchema\\CustomPosts\\": "layers/Schema/packages/customposts/tests",
+ "PoPSchema\\EventMutationsWPEM\\": "layers/Schema/packages/event-mutations-wp-em/tests",
+ "PoPSchema\\EventMutations\\": "layers/Schema/packages/event-mutations/tests",
+ "PoPSchema\\EventsWPEM\\": "layers/Schema/packages/events-wp-em/tests",
+ "PoPSchema\\Events\\": "layers/Schema/packages/events/tests",
+ "PoPSchema\\EverythingElseWP\\": "layers/Schema/packages/everythingelse-wp/tests",
+ "PoPSchema\\EverythingElse\\": "layers/Schema/packages/everythingelse/tests",
+ "PoPSchema\\GenericCustomPosts\\": "layers/Schema/packages/generic-customposts/tests",
+ "PoPSchema\\GoogleTranslateDirectiveForCustomPosts\\": "layers/Schema/packages/google-translate-directive-for-customposts/tests",
+ "PoPSchema\\GoogleTranslateDirective\\": "layers/Schema/packages/google-translate-directive/tests",
+ "PoPSchema\\HighlightsWP\\": "layers/Schema/packages/highlights-wp/tests",
+ "PoPSchema\\Highlights\\": "layers/Schema/packages/highlights/tests",
+ "PoPSchema\\LocationPostsWP\\": "layers/Schema/packages/locationposts-wp/tests",
+ "PoPSchema\\LocationPosts\\": "layers/Schema/packages/locationposts/tests",
+ "PoPSchema\\LocationsWPEM\\": "layers/Schema/packages/locations-wp-em/tests",
+ "PoPSchema\\Locations\\": "layers/Schema/packages/locations/tests",
+ "PoPSchema\\MediaWP\\": "layers/Schema/packages/media-wp/tests",
+ "PoPSchema\\Media\\": "layers/Schema/packages/media/tests",
+ "PoPSchema\\MenusWP\\": "layers/Schema/packages/menus-wp/tests",
+ "PoPSchema\\Menus\\": "layers/Schema/packages/menus/tests",
+ "PoPSchema\\MetaQueryWP\\": "layers/Schema/packages/metaquery-wp/tests",
+ "PoPSchema\\MetaQuery\\": "layers/Schema/packages/metaquery/tests",
+ "PoPSchema\\Meta\\": "layers/Schema/packages/meta/tests",
+ "PoPSchema\\NotificationsWP\\": "layers/Schema/packages/notifications-wp/tests",
+ "PoPSchema\\Notifications\\": "layers/Schema/packages/notifications/tests",
+ "PoPSchema\\PagesWP\\": "layers/Schema/packages/pages-wp/tests",
+ "PoPSchema\\Pages\\": "layers/Schema/packages/pages/tests",
+ "PoPSchema\\PostMutations\\": "layers/Schema/packages/post-mutations/tests",
+ "PoPSchema\\PostTagsWP\\": "layers/Schema/packages/post-tags-wp/tests",
+ "PoPSchema\\PostTags\\": "layers/Schema/packages/post-tags/tests",
+ "PoPSchema\\PostsWP\\": "layers/Schema/packages/posts-wp/tests",
+ "PoPSchema\\Posts\\": "layers/Schema/packages/posts/tests",
+ "PoPSchema\\QueriedObjectWP\\": "layers/Schema/packages/queriedobject-wp/tests",
+ "PoPSchema\\QueriedObject\\": "layers/Schema/packages/queriedobject/tests",
+ "PoPSchema\\SchemaCommons\\": "layers/Schema/packages/schema-commons/tests",
+ "PoPSchema\\StancesWP\\": "layers/Schema/packages/stances-wp/tests",
+ "PoPSchema\\Stances\\": "layers/Schema/packages/stances/tests",
+ "PoPSchema\\TagsWP\\": "layers/Schema/packages/tags-wp/tests",
+ "PoPSchema\\Tags\\": "layers/Schema/packages/tags/tests",
+ "PoPSchema\\TaxonomiesWP\\": "layers/Schema/packages/taxonomies-wp/tests",
+ "PoPSchema\\Taxonomies\\": "layers/Schema/packages/taxonomies/tests",
+ "PoPSchema\\TaxonomyMetaWP\\": "layers/Schema/packages/taxonomymeta-wp/tests",
+ "PoPSchema\\TaxonomyMeta\\": "layers/Schema/packages/taxonomymeta/tests",
+ "PoPSchema\\TaxonomyQueryWP\\": "layers/Schema/packages/taxonomyquery-wp/tests",
+ "PoPSchema\\TaxonomyQuery\\": "layers/Schema/packages/taxonomyquery/tests",
+ "PoPSchema\\TranslateDirectiveACL\\": "layers/Schema/packages/translate-directive-acl/tests",
+ "PoPSchema\\TranslateDirective\\": "layers/Schema/packages/translate-directive/tests",
+ "PoPSchema\\UserMetaWP\\": "layers/Schema/packages/usermeta-wp/tests",
+ "PoPSchema\\UserMeta\\": "layers/Schema/packages/usermeta/tests",
+ "PoPSchema\\UserRolesACL\\": "layers/Schema/packages/user-roles-acl/tests",
+ "PoPSchema\\UserRolesAccessControl\\": "layers/Schema/packages/user-roles-access-control/tests",
+ "PoPSchema\\UserRolesWP\\": "layers/Schema/packages/user-roles-wp/tests",
+ "PoPSchema\\UserRoles\\": "layers/Schema/packages/user-roles/tests",
+ "PoPSchema\\UserStateAccessControl\\": "layers/Schema/packages/user-state-access-control/tests",
+ "PoPSchema\\UserStateMutationsWP\\": "layers/Schema/packages/user-state-mutations-wp/tests",
+ "PoPSchema\\UserStateMutations\\": "layers/Schema/packages/user-state-mutations/tests",
+ "PoPSchema\\UserStateWP\\": "layers/Schema/packages/user-state-wp/tests",
+ "PoPSchema\\UserState\\": "layers/Schema/packages/user-state/tests",
+ "PoPSchema\\UsersWP\\": "layers/Schema/packages/users-wp/tests",
+ "PoPSchema\\Users\\": "layers/Schema/packages/users/tests",
+ "PoPSitesWassup\\CommentMutations\\": "layers/Wassup/packages/comment-mutations/tests",
+ "PoPSitesWassup\\ContactUsMutations\\": "layers/Wassup/packages/contactus-mutations/tests",
+ "PoPSitesWassup\\ContactUserMutations\\": "layers/Wassup/packages/contactuser-mutations/tests",
+ "PoPSitesWassup\\CustomPostLinkMutations\\": "layers/Wassup/packages/custompostlink-mutations/tests",
+ "PoPSitesWassup\\CustomPostMutations\\": "layers/Wassup/packages/custompost-mutations/tests",
+ "PoPSitesWassup\\EventLinkMutations\\": "layers/Wassup/packages/eventlink-mutations/tests",
+ "PoPSitesWassup\\EventMutations\\": "layers/Wassup/packages/event-mutations/tests",
+ "PoPSitesWassup\\EverythingElseMutations\\": "layers/Wassup/packages/everythingelse-mutations/tests",
+ "PoPSitesWassup\\FlagMutations\\": "layers/Wassup/packages/flag-mutations/tests",
+ "PoPSitesWassup\\FormMutations\\": "layers/Wassup/packages/form-mutations/tests",
+ "PoPSitesWassup\\GravityFormsMutations\\": "layers/Wassup/packages/gravityforms-mutations/tests",
+ "PoPSitesWassup\\HighlightMutations\\": "layers/Wassup/packages/highlight-mutations/tests",
+ "PoPSitesWassup\\LocationMutations\\": "layers/Wassup/packages/location-mutations/tests",
+ "PoPSitesWassup\\LocationPostLinkMutations\\": "layers/Wassup/packages/locationpostlink-mutations/tests",
+ "PoPSitesWassup\\LocationPostMutations\\": "layers/Wassup/packages/locationpost-mutations/tests",
+ "PoPSitesWassup\\NewsletterMutations\\": "layers/Wassup/packages/newsletter-mutations/tests",
+ "PoPSitesWassup\\NotificationMutations\\": "layers/Wassup/packages/notification-mutations/tests",
+ "PoPSitesWassup\\PostLinkMutations\\": "layers/Wassup/packages/postlink-mutations/tests",
+ "PoPSitesWassup\\PostMutations\\": "layers/Wassup/packages/post-mutations/tests",
+ "PoPSitesWassup\\ShareMutations\\": "layers/Wassup/packages/share-mutations/tests",
+ "PoPSitesWassup\\SocialNetworkMutations\\": "layers/Wassup/packages/socialnetwork-mutations/tests",
+ "PoPSitesWassup\\StanceMutations\\": "layers/Wassup/packages/stance-mutations/tests",
+ "PoPSitesWassup\\SystemMutations\\": "layers/Wassup/packages/system-mutations/tests",
+ "PoPSitesWassup\\UserStateMutations\\": "layers/Wassup/packages/user-state-mutations/tests",
+ "PoPSitesWassup\\VolunteerMutations\\": "layers/Wassup/packages/volunteer-mutations/tests",
+ "PoPSitesWassup\\Wassup\\": "layers/Wassup/packages/wassup/tests",
+ "PoP\\APIClients\\": "layers/API/packages/api-clients/tests",
+ "PoP\\APIEndpointsForWP\\": "layers/API/packages/api-endpoints-for-wp/tests",
+ "PoP\\APIEndpoints\\": "layers/API/packages/api-endpoints/tests",
+ "PoP\\APIMirrorQuery\\": "layers/API/packages/api-mirrorquery/tests",
+ "PoP\\API\\": "layers/API/packages/api/tests",
+ "PoP\\AccessControl\\": "layers/Engine/packages/access-control/tests",
+ "PoP\\ApplicationWP\\": "layers/SiteBuilder/packages/application-wp/tests",
+ "PoP\\Application\\": "layers/SiteBuilder/packages/application/tests",
+ "PoP\\Base36Definitions\\": "layers/SiteBuilder/packages/definitions-base36/tests",
+ "PoP\\CacheControl\\": "layers/Engine/packages/cache-control/tests",
+ "PoP\\ComponentModel\\": "layers/Engine/packages/component-model/tests",
+ "PoP\\ConfigurableSchemaFeedback\\": "layers/Engine/packages/configurable-schema-feedback/tests",
+ "PoP\\ConfigurationComponentModel\\": "layers/SiteBuilder/packages/component-model-configuration/tests",
+ "PoP\\DefinitionPersistence\\": "layers/SiteBuilder/packages/definitionpersistence/tests",
+ "PoP\\Definitions\\": "layers/Engine/packages/definitions/tests",
+ "PoP\\EmojiDefinitions\\": "layers/SiteBuilder/packages/definitions-emoji/tests",
+ "PoP\\EngineWP\\": "layers/Engine/packages/engine-wp/tests",
+ "PoP\\Engine\\": "layers/Engine/packages/engine/tests",
+ "PoP\\FieldQuery\\": "layers/Engine/packages/field-query/tests",
+ "PoP\\FileStore\\": "layers/Engine/packages/filestore/tests",
+ "PoP\\FunctionFields\\": "layers/Engine/packages/function-fields/tests",
+ "PoP\\GraphQLAPI\\": "layers/API/packages/api-graphql/tests",
+ "PoP\\GuzzleHelpers\\": "layers/Engine/packages/guzzle-helpers/tests",
+ "PoP\\HooksWP\\": "layers/Engine/packages/hooks-wp/tests",
+ "PoP\\Hooks\\": "layers/Engine/packages/hooks/tests",
+ "PoP\\LooseContracts\\": "layers/Engine/packages/loosecontracts/tests",
+ "PoP\\MandatoryDirectivesByConfiguration\\": "layers/Engine/packages/mandatory-directives-by-configuration/tests",
+ "PoP\\ModuleRouting\\": "layers/Engine/packages/modulerouting/tests",
+ "PoP\\Multisite\\": "layers/SiteBuilder/packages/multisite/tests",
+ "PoP\\QueryParsing\\": "layers/Engine/packages/query-parsing/tests",
+ "PoP\\RESTAPI\\": "layers/API/packages/api-rest/tests",
+ "PoP\\ResourceLoader\\": "layers/SiteBuilder/packages/resourceloader/tests",
+ "PoP\\Resources\\": "layers/SiteBuilder/packages/resources/tests",
+ "PoP\\Root\\": "layers/Engine/packages/root/tests",
+ "PoP\\RoutingWP\\": "layers/Engine/packages/routing-wp/tests",
+ "PoP\\Routing\\": "layers/Engine/packages/routing/tests",
+ "PoP\\SPA\\": "layers/SiteBuilder/packages/spa/tests",
+ "PoP\\SSG\\": "layers/SiteBuilder/packages/static-site-generator/tests",
+ "PoP\\SiteWP\\": "layers/SiteBuilder/packages/site-wp/tests",
+ "PoP\\Site\\": "layers/SiteBuilder/packages/site/tests",
+ "PoP\\TraceTools\\": "layers/Engine/packages/trace-tools/tests",
+ "PoP\\TranslationWP\\": "layers/Engine/packages/translation-wp/tests",
+ "PoP\\Translation\\": "layers/Engine/packages/translation/tests"
+ }
+ },
+ "extra": {
+ "wordpress-install-dir": "vendor/wordpress/wordpress",
+ "merge-plugin": {
+ "include": [
+ "composer.local.json"
+ ],
+ "recurse": true,
+ "replace": false,
+ "ignore-duplicates": false,
+ "merge-dev": true,
+ "merge-extra": false,
+ "merge-extra-deep": false,
+ "merge-scripts": false
+ }
+ },
+ "replace": {
+ "getpop/access-control": "self.version",
+ "getpop/api": "self.version",
+ "getpop/api-clients": "self.version",
+ "getpop/api-endpoints": "self.version",
+ "getpop/api-endpoints-for-wp": "self.version",
+ "getpop/api-graphql": "self.version",
+ "getpop/api-mirrorquery": "self.version",
+ "getpop/api-rest": "self.version",
+ "getpop/application": "self.version",
+ "getpop/application-wp": "self.version",
+ "getpop/cache-control": "self.version",
+ "getpop/component-model": "self.version",
+ "getpop/component-model-configuration": "self.version",
+ "getpop/configurable-schema-feedback": "self.version",
+ "getpop/definitionpersistence": "self.version",
+ "getpop/definitions": "self.version",
+ "getpop/definitions-base36": "self.version",
+ "getpop/definitions-emoji": "self.version",
+ "getpop/engine": "self.version",
+ "getpop/engine-wp": "self.version",
+ "getpop/engine-wp-bootloader": "self.version",
+ "getpop/field-query": "self.version",
+ "getpop/filestore": "self.version",
+ "getpop/function-fields": "self.version",
+ "getpop/guzzle-helpers": "self.version",
+ "getpop/hooks": "self.version",
+ "getpop/hooks-wp": "self.version",
+ "getpop/loosecontracts": "self.version",
+ "getpop/mandatory-directives-by-configuration": "self.version",
+ "getpop/migrate-api": "self.version",
+ "getpop/migrate-api-graphql": "self.version",
+ "getpop/migrate-component-model": "self.version",
+ "getpop/migrate-component-model-configuration": "self.version",
+ "getpop/migrate-engine": "self.version",
+ "getpop/migrate-engine-wp": "self.version",
+ "getpop/migrate-static-site-generator": "self.version",
+ "getpop/modulerouting": "self.version",
+ "getpop/multisite": "self.version",
+ "getpop/query-parsing": "self.version",
+ "getpop/resourceloader": "self.version",
+ "getpop/resources": "self.version",
+ "getpop/root": "self.version",
+ "getpop/routing": "self.version",
+ "getpop/routing-wp": "self.version",
+ "getpop/site": "self.version",
+ "getpop/site-wp": "self.version",
+ "getpop/spa": "self.version",
+ "getpop/static-site-generator": "self.version",
+ "getpop/trace-tools": "self.version",
+ "getpop/translation": "self.version",
+ "getpop/translation-wp": "self.version",
+ "graphql-api/convert-case-directives": "self.version",
+ "graphql-api/graphql-api-for-wp": "self.version",
+ "graphql-api/schema-feedback": "self.version",
+ "graphql-by-pop/graphql-clients-for-wp": "self.version",
+ "graphql-by-pop/graphql-endpoint-for-wp": "self.version",
+ "graphql-by-pop/graphql-parser": "self.version",
+ "graphql-by-pop/graphql-query": "self.version",
+ "graphql-by-pop/graphql-request": "self.version",
+ "graphql-by-pop/graphql-server": "self.version",
+ "leoloso/examples-for-pop": "self.version",
+ "pop-migrate-everythingelse/cssconverter": "self.version",
+ "pop-migrate-everythingelse/ssr": "self.version",
+ "pop-schema/basic-directives": "self.version",
+ "pop-schema/block-metadata-for-wp": "self.version",
+ "pop-schema/categories": "self.version",
+ "pop-schema/categories-wp": "self.version",
+ "pop-schema/cdn-directive": "self.version",
+ "pop-schema/comment-mutations": "self.version",
+ "pop-schema/comment-mutations-wp": "self.version",
+ "pop-schema/commentmeta": "self.version",
+ "pop-schema/commentmeta-wp": "self.version",
+ "pop-schema/comments": "self.version",
+ "pop-schema/comments-wp": "self.version",
+ "pop-schema/convert-case-directives": "self.version",
+ "pop-schema/custompost-mutations": "self.version",
+ "pop-schema/custompost-mutations-wp": "self.version",
+ "pop-schema/custompostmedia": "self.version",
+ "pop-schema/custompostmedia-mutations": "self.version",
+ "pop-schema/custompostmedia-mutations-wp": "self.version",
+ "pop-schema/custompostmedia-wp": "self.version",
+ "pop-schema/custompostmeta": "self.version",
+ "pop-schema/custompostmeta-wp": "self.version",
+ "pop-schema/customposts": "self.version",
+ "pop-schema/customposts-wp": "self.version",
+ "pop-schema/event-mutations": "self.version",
+ "pop-schema/event-mutations-wp-em": "self.version",
+ "pop-schema/events": "self.version",
+ "pop-schema/events-wp-em": "self.version",
+ "pop-schema/everythingelse": "self.version",
+ "pop-schema/everythingelse-wp": "self.version",
+ "pop-schema/generic-customposts": "self.version",
+ "pop-schema/google-translate-directive": "self.version",
+ "pop-schema/google-translate-directive-for-customposts": "self.version",
+ "pop-schema/highlights": "self.version",
+ "pop-schema/highlights-wp": "self.version",
+ "pop-schema/locationposts": "self.version",
+ "pop-schema/locationposts-wp": "self.version",
+ "pop-schema/locations": "self.version",
+ "pop-schema/locations-wp-em": "self.version",
+ "pop-schema/media": "self.version",
+ "pop-schema/media-wp": "self.version",
+ "pop-schema/menus": "self.version",
+ "pop-schema/menus-wp": "self.version",
+ "pop-schema/meta": "self.version",
+ "pop-schema/metaquery": "self.version",
+ "pop-schema/metaquery-wp": "self.version",
+ "pop-schema/migrate-categories": "self.version",
+ "pop-schema/migrate-categories-wp": "self.version",
+ "pop-schema/migrate-commentmeta": "self.version",
+ "pop-schema/migrate-commentmeta-wp": "self.version",
+ "pop-schema/migrate-comments": "self.version",
+ "pop-schema/migrate-comments-wp": "self.version",
+ "pop-schema/migrate-custompostmedia": "self.version",
+ "pop-schema/migrate-custompostmedia-wp": "self.version",
+ "pop-schema/migrate-custompostmeta": "self.version",
+ "pop-schema/migrate-custompostmeta-wp": "self.version",
+ "pop-schema/migrate-customposts": "self.version",
+ "pop-schema/migrate-customposts-wp": "self.version",
+ "pop-schema/migrate-events": "self.version",
+ "pop-schema/migrate-events-wp-em": "self.version",
+ "pop-schema/migrate-everythingelse": "self.version",
+ "pop-schema/migrate-locations": "self.version",
+ "pop-schema/migrate-locations-wp-em": "self.version",
+ "pop-schema/migrate-media": "self.version",
+ "pop-schema/migrate-media-wp": "self.version",
+ "pop-schema/migrate-meta": "self.version",
+ "pop-schema/migrate-metaquery": "self.version",
+ "pop-schema/migrate-metaquery-wp": "self.version",
+ "pop-schema/migrate-pages": "self.version",
+ "pop-schema/migrate-pages-wp": "self.version",
+ "pop-schema/migrate-post-tags": "self.version",
+ "pop-schema/migrate-post-tags-wp": "self.version",
+ "pop-schema/migrate-posts": "self.version",
+ "pop-schema/migrate-posts-wp": "self.version",
+ "pop-schema/migrate-queriedobject": "self.version",
+ "pop-schema/migrate-queriedobject-wp": "self.version",
+ "pop-schema/migrate-tags": "self.version",
+ "pop-schema/migrate-tags-wp": "self.version",
+ "pop-schema/migrate-taxonomies": "self.version",
+ "pop-schema/migrate-taxonomies-wp": "self.version",
+ "pop-schema/migrate-taxonomymeta": "self.version",
+ "pop-schema/migrate-taxonomymeta-wp": "self.version",
+ "pop-schema/migrate-taxonomyquery": "self.version",
+ "pop-schema/migrate-taxonomyquery-wp": "self.version",
+ "pop-schema/migrate-usermeta": "self.version",
+ "pop-schema/migrate-usermeta-wp": "self.version",
+ "pop-schema/migrate-users": "self.version",
+ "pop-schema/migrate-users-wp": "self.version",
+ "pop-schema/notifications": "self.version",
+ "pop-schema/notifications-wp": "self.version",
+ "pop-schema/pages": "self.version",
+ "pop-schema/pages-wp": "self.version",
+ "pop-schema/post-mutations": "self.version",
+ "pop-schema/post-tags": "self.version",
+ "pop-schema/post-tags-wp": "self.version",
+ "pop-schema/posts": "self.version",
+ "pop-schema/posts-wp": "self.version",
+ "pop-schema/queriedobject": "self.version",
+ "pop-schema/queriedobject-wp": "self.version",
+ "pop-schema/schema-commons": "self.version",
+ "pop-schema/stances": "self.version",
+ "pop-schema/stances-wp": "self.version",
+ "pop-schema/tags": "self.version",
+ "pop-schema/tags-wp": "self.version",
+ "pop-schema/taxonomies": "self.version",
+ "pop-schema/taxonomies-wp": "self.version",
+ "pop-schema/taxonomymeta": "self.version",
+ "pop-schema/taxonomymeta-wp": "self.version",
+ "pop-schema/taxonomyquery": "self.version",
+ "pop-schema/taxonomyquery-wp": "self.version",
+ "pop-schema/translate-directive": "self.version",
+ "pop-schema/translate-directive-acl": "self.version",
+ "pop-schema/user-roles": "self.version",
+ "pop-schema/user-roles-access-control": "self.version",
+ "pop-schema/user-roles-acl": "self.version",
+ "pop-schema/user-roles-wp": "self.version",
+ "pop-schema/user-state": "self.version",
+ "pop-schema/user-state-access-control": "self.version",
+ "pop-schema/user-state-mutations": "self.version",
+ "pop-schema/user-state-mutations-wp": "self.version",
+ "pop-schema/user-state-wp": "self.version",
+ "pop-schema/usermeta": "self.version",
+ "pop-schema/usermeta-wp": "self.version",
+ "pop-schema/users": "self.version",
+ "pop-schema/users-wp": "self.version",
+ "pop-sites-wassup/comment-mutations": "self.version",
+ "pop-sites-wassup/contactus-mutations": "self.version",
+ "pop-sites-wassup/contactuser-mutations": "self.version",
+ "pop-sites-wassup/custompost-mutations": "self.version",
+ "pop-sites-wassup/custompostlink-mutations": "self.version",
+ "pop-sites-wassup/event-mutations": "self.version",
+ "pop-sites-wassup/eventlink-mutations": "self.version",
+ "pop-sites-wassup/everythingelse-mutations": "self.version",
+ "pop-sites-wassup/flag-mutations": "self.version",
+ "pop-sites-wassup/form-mutations": "self.version",
+ "pop-sites-wassup/gravityforms-mutations": "self.version",
+ "pop-sites-wassup/highlight-mutations": "self.version",
+ "pop-sites-wassup/location-mutations": "self.version",
+ "pop-sites-wassup/locationpost-mutations": "self.version",
+ "pop-sites-wassup/locationpostlink-mutations": "self.version",
+ "pop-sites-wassup/newsletter-mutations": "self.version",
+ "pop-sites-wassup/notification-mutations": "self.version",
+ "pop-sites-wassup/post-mutations": "self.version",
+ "pop-sites-wassup/postlink-mutations": "self.version",
+ "pop-sites-wassup/share-mutations": "self.version",
+ "pop-sites-wassup/socialnetwork-mutations": "self.version",
+ "pop-sites-wassup/stance-mutations": "self.version",
+ "pop-sites-wassup/system-mutations": "self.version",
+ "pop-sites-wassup/user-state-mutations": "self.version",
+ "pop-sites-wassup/volunteer-mutations": "self.version",
+ "pop-sites-wassup/wassup": "self.version"
+ },
+ "authors": [
+ {
+ "name": "Leonardo Losoviz",
+ "email": "leo@getpop.org",
+ "homepage": "https://getpop.org"
+ }
+ ],
+ "description": "Monorepo for all the PoP packages",
+ "license": "GPL-2.0-or-later",
+ "config": {
+ "sort-packages": true
+ },
+ "repositories": [
+ {
+ "type": "composer",
+ "url": "https://wpackagist.org"
+ },
+ {
+ "type": "vcs",
+ "url": "https://github.com/leoloso/wp-muplugin-loader.git"
+ },
+ {
+ "type": "vcs",
+ "url": "https://github.com/mcaskill/composer-merge-plugin.git"
+ }
+ ],
+ "scripts": {
+ "test": "phpunit",
+ "check-style": "phpcs -n src $(monorepo-builder source-packages --subfolder=src --subfolder=tests)",
+ "fix-style": "phpcbf -n src $(monorepo-builder source-packages --subfolder=src --subfolder=tests)",
+ "analyse": "ci/phpstan.sh \". $(monorepo-builder source-packages --skip-unmigrated)\"",
+ "preview-src-downgrade": "rector process $(monorepo-builder source-packages --subfolder=src) --config=rector-downgrade-code.php --ansi --dry-run || true",
+ "preview-vendor-downgrade": "layers/Engine/packages/root/ci/downgrade_code.sh 7.1 rector-downgrade-code.php --dry-run || true",
+ "preview-code-downgrade": [
+ "@preview-src-downgrade",
+ "@preview-vendor-downgrade"
+ ],
+ "build-server": [
+ "lando init --source remote --remote-url https://wordpress.org/latest.tar.gz --recipe wordpress --webroot wordpress --name graphql-api-dev",
+ "@start-server"
+ ],
+ "start-server": [
+ "cd layers/GraphQLAPIForWP/plugins/graphql-api-for-wp && composer install",
+ "lando start"
+ ],
+ "rebuild-server": "lando rebuild -y",
+ "merge-monorepo": "monorepo-builder merge --ansi",
+ "propagate-monorepo": "monorepo-builder propagate --ansi",
+ "validate-monorepo": "monorepo-builder validate --ansi",
+ "release": "monorepo-builder release patch --ansi"
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true
+}"#
+ .to_string(),
+ )
+ .unwrap();
+
+ assert!(
+ manipulator
+ .add_sub_node("config", "platform-check", PhpMixed::Bool(false), true)
+ .unwrap()
+ );
+ assert_eq!(
+ r#"{
+ "name": "leoloso/pop",
+ "require": {
+ "php": "^7.4|^8.0",
+ "ext-mbstring": "*",
+ "brain/cortex": "~1.0.0",
+ "composer/installers": "~1.0",
+ "composer/semver": "^1.5",
+ "erusev/parsedown": "^1.7",
+ "guzzlehttp/guzzle": "~6.3",
+ "jrfnl/php-cast-to-type": "^2.0",
+ "league/pipeline": "^1.0",
+ "lkwdwrd/wp-muplugin-loader": "dev-feature-composer-v2",
+ "obsidian/polyfill-hrtime": "^0.1",
+ "psr/cache": "^1.0",
+ "symfony/cache": "^5.1",
+ "symfony/config": "^5.1",
+ "symfony/dependency-injection": "^5.1",
+ "symfony/dotenv": "^5.1",
+ "symfony/expression-language": "^5.1",
+ "symfony/polyfill-php72": "^1.18",
+ "symfony/polyfill-php73": "^1.18",
+ "symfony/polyfill-php74": "^1.18",
+ "symfony/polyfill-php80": "^1.18",
+ "symfony/property-access": "^5.1",
+ "symfony/yaml": "^5.1"
+ },
+ "require-dev": {
+ "johnpbloch/wordpress": ">=5.5",
+ "phpstan/phpstan": "^0.12",
+ "phpunit/phpunit": ">=9.3",
+ "rector/rector": "^0.9",
+ "squizlabs/php_codesniffer": "^3.0",
+ "symfony/var-dumper": "^5.1",
+ "symplify/monorepo-builder": "^9.0",
+ "szepeviktor/phpstan-wordpress": "^0.6.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "GraphQLAPI\\ConvertCaseDirectives\\": "layers/GraphQLAPIForWP/plugins/convert-case-directives/src",
+ "GraphQLAPI\\GraphQLAPI\\": "layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/src",
+ "GraphQLAPI\\SchemaFeedback\\": "layers/GraphQLAPIForWP/plugins/schema-feedback/src",
+ "GraphQLByPoP\\GraphQLClientsForWP\\": "layers/GraphQLByPoP/packages/graphql-clients-for-wp/src",
+ "GraphQLByPoP\\GraphQLEndpointForWP\\": "layers/GraphQLByPoP/packages/graphql-endpoint-for-wp/src",
+ "GraphQLByPoP\\GraphQLParser\\": "layers/GraphQLByPoP/packages/graphql-parser/src",
+ "GraphQLByPoP\\GraphQLQuery\\": "layers/GraphQLByPoP/packages/graphql-query/src",
+ "GraphQLByPoP\\GraphQLRequest\\": "layers/GraphQLByPoP/packages/graphql-request/src",
+ "GraphQLByPoP\\GraphQLServer\\": "layers/GraphQLByPoP/packages/graphql-server/src",
+ "Leoloso\\ExamplesForPoP\\": "layers/Misc/packages/examples-for-pop/src",
+ "PoPSchema\\BasicDirectives\\": "layers/Schema/packages/basic-directives/src",
+ "PoPSchema\\BlockMetadataWP\\": "layers/Schema/packages/block-metadata-for-wp/src",
+ "PoPSchema\\CDNDirective\\": "layers/Schema/packages/cdn-directive/src",
+ "PoPSchema\\CategoriesWP\\": "layers/Schema/packages/categories-wp/src",
+ "PoPSchema\\Categories\\": "layers/Schema/packages/categories/src",
+ "PoPSchema\\CommentMetaWP\\": "layers/Schema/packages/commentmeta-wp/src",
+ "PoPSchema\\CommentMeta\\": "layers/Schema/packages/commentmeta/src",
+ "PoPSchema\\CommentMutationsWP\\": "layers/Schema/packages/comment-mutations-wp/src",
+ "PoPSchema\\CommentMutations\\": "layers/Schema/packages/comment-mutations/src",
+ "PoPSchema\\CommentsWP\\": "layers/Schema/packages/comments-wp/src",
+ "PoPSchema\\Comments\\": "layers/Schema/packages/comments/src",
+ "PoPSchema\\ConvertCaseDirectives\\": "layers/Schema/packages/convert-case-directives/src",
+ "PoPSchema\\CustomPostMediaMutationsWP\\": "layers/Schema/packages/custompostmedia-mutations-wp/src",
+ "PoPSchema\\CustomPostMediaMutations\\": "layers/Schema/packages/custompostmedia-mutations/src",
+ "PoPSchema\\CustomPostMediaWP\\": "layers/Schema/packages/custompostmedia-wp/src",
+ "PoPSchema\\CustomPostMedia\\": "layers/Schema/packages/custompostmedia/src",
+ "PoPSchema\\CustomPostMetaWP\\": "layers/Schema/packages/custompostmeta-wp/src",
+ "PoPSchema\\CustomPostMeta\\": "layers/Schema/packages/custompostmeta/src",
+ "PoPSchema\\CustomPostMutationsWP\\": "layers/Schema/packages/custompost-mutations-wp/src",
+ "PoPSchema\\CustomPostMutations\\": "layers/Schema/packages/custompost-mutations/src",
+ "PoPSchema\\CustomPostsWP\\": "layers/Schema/packages/customposts-wp/src",
+ "PoPSchema\\CustomPosts\\": "layers/Schema/packages/customposts/src",
+ "PoPSchema\\EventMutationsWPEM\\": "layers/Schema/packages/event-mutations-wp-em/src",
+ "PoPSchema\\EventMutations\\": "layers/Schema/packages/event-mutations/src",
+ "PoPSchema\\EventsWPEM\\": "layers/Schema/packages/events-wp-em/src",
+ "PoPSchema\\Events\\": "layers/Schema/packages/events/src",
+ "PoPSchema\\EverythingElseWP\\": "layers/Schema/packages/everythingelse-wp/src",
+ "PoPSchema\\EverythingElse\\": "layers/Schema/packages/everythingelse/src",
+ "PoPSchema\\GenericCustomPosts\\": "layers/Schema/packages/generic-customposts/src",
+ "PoPSchema\\GoogleTranslateDirectiveForCustomPosts\\": "layers/Schema/packages/google-translate-directive-for-customposts/src",
+ "PoPSchema\\GoogleTranslateDirective\\": "layers/Schema/packages/google-translate-directive/src",
+ "PoPSchema\\HighlightsWP\\": "layers/Schema/packages/highlights-wp/src",
+ "PoPSchema\\Highlights\\": "layers/Schema/packages/highlights/src",
+ "PoPSchema\\LocationPostsWP\\": "layers/Schema/packages/locationposts-wp/src",
+ "PoPSchema\\LocationPosts\\": "layers/Schema/packages/locationposts/src",
+ "PoPSchema\\LocationsWPEM\\": "layers/Schema/packages/locations-wp-em/src",
+ "PoPSchema\\Locations\\": "layers/Schema/packages/locations/src",
+ "PoPSchema\\MediaWP\\": "layers/Schema/packages/media-wp/src",
+ "PoPSchema\\Media\\": "layers/Schema/packages/media/src",
+ "PoPSchema\\MenusWP\\": "layers/Schema/packages/menus-wp/src",
+ "PoPSchema\\Menus\\": "layers/Schema/packages/menus/src",
+ "PoPSchema\\MetaQueryWP\\": "layers/Schema/packages/metaquery-wp/src",
+ "PoPSchema\\MetaQuery\\": "layers/Schema/packages/metaquery/src",
+ "PoPSchema\\Meta\\": "layers/Schema/packages/meta/src",
+ "PoPSchema\\NotificationsWP\\": "layers/Schema/packages/notifications-wp/src",
+ "PoPSchema\\Notifications\\": "layers/Schema/packages/notifications/src",
+ "PoPSchema\\PagesWP\\": "layers/Schema/packages/pages-wp/src",
+ "PoPSchema\\Pages\\": "layers/Schema/packages/pages/src",
+ "PoPSchema\\PostMutations\\": "layers/Schema/packages/post-mutations/src",
+ "PoPSchema\\PostTagsWP\\": "layers/Schema/packages/post-tags-wp/src",
+ "PoPSchema\\PostTags\\": "layers/Schema/packages/post-tags/src",
+ "PoPSchema\\PostsWP\\": "layers/Schema/packages/posts-wp/src",
+ "PoPSchema\\Posts\\": "layers/Schema/packages/posts/src",
+ "PoPSchema\\QueriedObjectWP\\": "layers/Schema/packages/queriedobject-wp/src",
+ "PoPSchema\\QueriedObject\\": "layers/Schema/packages/queriedobject/src",
+ "PoPSchema\\SchemaCommons\\": "layers/Schema/packages/schema-commons/src",
+ "PoPSchema\\StancesWP\\": "layers/Schema/packages/stances-wp/src",
+ "PoPSchema\\Stances\\": "layers/Schema/packages/stances/src",
+ "PoPSchema\\TagsWP\\": "layers/Schema/packages/tags-wp/src",
+ "PoPSchema\\Tags\\": "layers/Schema/packages/tags/src",
+ "PoPSchema\\TaxonomiesWP\\": "layers/Schema/packages/taxonomies-wp/src",
+ "PoPSchema\\Taxonomies\\": "layers/Schema/packages/taxonomies/src",
+ "PoPSchema\\TaxonomyMetaWP\\": "layers/Schema/packages/taxonomymeta-wp/src",
+ "PoPSchema\\TaxonomyMeta\\": "layers/Schema/packages/taxonomymeta/src",
+ "PoPSchema\\TaxonomyQueryWP\\": "layers/Schema/packages/taxonomyquery-wp/src",
+ "PoPSchema\\TaxonomyQuery\\": "layers/Schema/packages/taxonomyquery/src",
+ "PoPSchema\\TranslateDirectiveACL\\": "layers/Schema/packages/translate-directive-acl/src",
+ "PoPSchema\\TranslateDirective\\": "layers/Schema/packages/translate-directive/src",
+ "PoPSchema\\UserMetaWP\\": "layers/Schema/packages/usermeta-wp/src",
+ "PoPSchema\\UserMeta\\": "layers/Schema/packages/usermeta/src",
+ "PoPSchema\\UserRolesACL\\": "layers/Schema/packages/user-roles-acl/src",
+ "PoPSchema\\UserRolesAccessControl\\": "layers/Schema/packages/user-roles-access-control/src",
+ "PoPSchema\\UserRolesWP\\": "layers/Schema/packages/user-roles-wp/src",
+ "PoPSchema\\UserRoles\\": "layers/Schema/packages/user-roles/src",
+ "PoPSchema\\UserStateAccessControl\\": "layers/Schema/packages/user-state-access-control/src",
+ "PoPSchema\\UserStateMutationsWP\\": "layers/Schema/packages/user-state-mutations-wp/src",
+ "PoPSchema\\UserStateMutations\\": "layers/Schema/packages/user-state-mutations/src",
+ "PoPSchema\\UserStateWP\\": "layers/Schema/packages/user-state-wp/src",
+ "PoPSchema\\UserState\\": "layers/Schema/packages/user-state/src",
+ "PoPSchema\\UsersWP\\": "layers/Schema/packages/users-wp/src",
+ "PoPSchema\\Users\\": "layers/Schema/packages/users/src",
+ "PoPSitesWassup\\CommentMutations\\": "layers/Wassup/packages/comment-mutations/src",
+ "PoPSitesWassup\\ContactUsMutations\\": "layers/Wassup/packages/contactus-mutations/src",
+ "PoPSitesWassup\\ContactUserMutations\\": "layers/Wassup/packages/contactuser-mutations/src",
+ "PoPSitesWassup\\CustomPostLinkMutations\\": "layers/Wassup/packages/custompostlink-mutations/src",
+ "PoPSitesWassup\\CustomPostMutations\\": "layers/Wassup/packages/custompost-mutations/src",
+ "PoPSitesWassup\\EventLinkMutations\\": "layers/Wassup/packages/eventlink-mutations/src",
+ "PoPSitesWassup\\EventMutations\\": "layers/Wassup/packages/event-mutations/src",
+ "PoPSitesWassup\\EverythingElseMutations\\": "layers/Wassup/packages/everythingelse-mutations/src",
+ "PoPSitesWassup\\FlagMutations\\": "layers/Wassup/packages/flag-mutations/src",
+ "PoPSitesWassup\\FormMutations\\": "layers/Wassup/packages/form-mutations/src",
+ "PoPSitesWassup\\GravityFormsMutations\\": "layers/Wassup/packages/gravityforms-mutations/src",
+ "PoPSitesWassup\\HighlightMutations\\": "layers/Wassup/packages/highlight-mutations/src",
+ "PoPSitesWassup\\LocationMutations\\": "layers/Wassup/packages/location-mutations/src",
+ "PoPSitesWassup\\LocationPostLinkMutations\\": "layers/Wassup/packages/locationpostlink-mutations/src",
+ "PoPSitesWassup\\LocationPostMutations\\": "layers/Wassup/packages/locationpost-mutations/src",
+ "PoPSitesWassup\\NewsletterMutations\\": "layers/Wassup/packages/newsletter-mutations/src",
+ "PoPSitesWassup\\NotificationMutations\\": "layers/Wassup/packages/notification-mutations/src",
+ "PoPSitesWassup\\PostLinkMutations\\": "layers/Wassup/packages/postlink-mutations/src",
+ "PoPSitesWassup\\PostMutations\\": "layers/Wassup/packages/post-mutations/src",
+ "PoPSitesWassup\\ShareMutations\\": "layers/Wassup/packages/share-mutations/src",
+ "PoPSitesWassup\\SocialNetworkMutations\\": "layers/Wassup/packages/socialnetwork-mutations/src",
+ "PoPSitesWassup\\StanceMutations\\": "layers/Wassup/packages/stance-mutations/src",
+ "PoPSitesWassup\\SystemMutations\\": "layers/Wassup/packages/system-mutations/src",
+ "PoPSitesWassup\\UserStateMutations\\": "layers/Wassup/packages/user-state-mutations/src",
+ "PoPSitesWassup\\VolunteerMutations\\": "layers/Wassup/packages/volunteer-mutations/src",
+ "PoPSitesWassup\\Wassup\\": "layers/Wassup/packages/wassup/src",
+ "PoP\\APIClients\\": "layers/API/packages/api-clients/src",
+ "PoP\\APIEndpointsForWP\\": "layers/API/packages/api-endpoints-for-wp/src",
+ "PoP\\APIEndpoints\\": "layers/API/packages/api-endpoints/src",
+ "PoP\\APIMirrorQuery\\": "layers/API/packages/api-mirrorquery/src",
+ "PoP\\API\\": "layers/API/packages/api/src",
+ "PoP\\AccessControl\\": "layers/Engine/packages/access-control/src",
+ "PoP\\ApplicationWP\\": "layers/SiteBuilder/packages/application-wp/src",
+ "PoP\\Application\\": "layers/SiteBuilder/packages/application/src",
+ "PoP\\Base36Definitions\\": "layers/SiteBuilder/packages/definitions-base36/src",
+ "PoP\\CacheControl\\": "layers/Engine/packages/cache-control/src",
+ "PoP\\ComponentModel\\": "layers/Engine/packages/component-model/src",
+ "PoP\\ConfigurableSchemaFeedback\\": "layers/Engine/packages/configurable-schema-feedback/src",
+ "PoP\\ConfigurationComponentModel\\": "layers/SiteBuilder/packages/component-model-configuration/src",
+ "PoP\\DefinitionPersistence\\": "layers/SiteBuilder/packages/definitionpersistence/src",
+ "PoP\\Definitions\\": "layers/Engine/packages/definitions/src",
+ "PoP\\EmojiDefinitions\\": "layers/SiteBuilder/packages/definitions-emoji/src",
+ "PoP\\EngineWP\\": "layers/Engine/packages/engine-wp/src",
+ "PoP\\Engine\\": "layers/Engine/packages/engine/src",
+ "PoP\\FieldQuery\\": "layers/Engine/packages/field-query/src",
+ "PoP\\FileStore\\": "layers/Engine/packages/filestore/src",
+ "PoP\\FunctionFields\\": "layers/Engine/packages/function-fields/src",
+ "PoP\\GraphQLAPI\\": "layers/API/packages/api-graphql/src",
+ "PoP\\GuzzleHelpers\\": "layers/Engine/packages/guzzle-helpers/src",
+ "PoP\\HooksWP\\": "layers/Engine/packages/hooks-wp/src",
+ "PoP\\Hooks\\": "layers/Engine/packages/hooks/src",
+ "PoP\\LooseContracts\\": "layers/Engine/packages/loosecontracts/src",
+ "PoP\\MandatoryDirectivesByConfiguration\\": "layers/Engine/packages/mandatory-directives-by-configuration/src",
+ "PoP\\ModuleRouting\\": "layers/Engine/packages/modulerouting/src",
+ "PoP\\Multisite\\": "layers/SiteBuilder/packages/multisite/src",
+ "PoP\\PoP\\": "src",
+ "PoP\\QueryParsing\\": "layers/Engine/packages/query-parsing/src",
+ "PoP\\RESTAPI\\": "layers/API/packages/api-rest/src",
+ "PoP\\ResourceLoader\\": "layers/SiteBuilder/packages/resourceloader/src",
+ "PoP\\Resources\\": "layers/SiteBuilder/packages/resources/src",
+ "PoP\\Root\\": "layers/Engine/packages/root/src",
+ "PoP\\RoutingWP\\": "layers/Engine/packages/routing-wp/src",
+ "PoP\\Routing\\": "layers/Engine/packages/routing/src",
+ "PoP\\SPA\\": "layers/SiteBuilder/packages/spa/src",
+ "PoP\\SSG\\": "layers/SiteBuilder/packages/static-site-generator/src",
+ "PoP\\SiteWP\\": "layers/SiteBuilder/packages/site-wp/src",
+ "PoP\\Site\\": "layers/SiteBuilder/packages/site/src",
+ "PoP\\TraceTools\\": "layers/Engine/packages/trace-tools/src",
+ "PoP\\TranslationWP\\": "layers/Engine/packages/translation-wp/src",
+ "PoP\\Translation\\": "layers/Engine/packages/translation/src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "GraphQLAPI\\ConvertCaseDirectives\\": "layers/GraphQLAPIForWP/plugins/convert-case-directives/tests",
+ "GraphQLAPI\\GraphQLAPI\\": "layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/tests",
+ "GraphQLAPI\\SchemaFeedback\\": "layers/GraphQLAPIForWP/plugins/schema-feedback/tests",
+ "GraphQLByPoP\\GraphQLClientsForWP\\": "layers/GraphQLByPoP/packages/graphql-clients-for-wp/tests",
+ "GraphQLByPoP\\GraphQLEndpointForWP\\": "layers/GraphQLByPoP/packages/graphql-endpoint-for-wp/tests",
+ "GraphQLByPoP\\GraphQLParser\\": "layers/GraphQLByPoP/packages/graphql-parser/tests",
+ "GraphQLByPoP\\GraphQLQuery\\": "layers/GraphQLByPoP/packages/graphql-query/tests",
+ "GraphQLByPoP\\GraphQLRequest\\": "layers/GraphQLByPoP/packages/graphql-request/tests",
+ "GraphQLByPoP\\GraphQLServer\\": "layers/GraphQLByPoP/packages/graphql-server/tests",
+ "Leoloso\\ExamplesForPoP\\": "layers/Misc/packages/examples-for-pop/tests",
+ "PoPSchema\\BasicDirectives\\": "layers/Schema/packages/basic-directives/tests",
+ "PoPSchema\\BlockMetadataWP\\": "layers/Schema/packages/block-metadata-for-wp/tests",
+ "PoPSchema\\CDNDirective\\": "layers/Schema/packages/cdn-directive/tests",
+ "PoPSchema\\CategoriesWP\\": "layers/Schema/packages/categories-wp/tests",
+ "PoPSchema\\Categories\\": "layers/Schema/packages/categories/tests",
+ "PoPSchema\\CommentMetaWP\\": "layers/Schema/packages/commentmeta-wp/tests",
+ "PoPSchema\\CommentMeta\\": "layers/Schema/packages/commentmeta/tests",
+ "PoPSchema\\CommentMutationsWP\\": "layers/Schema/packages/comment-mutations-wp/tests",
+ "PoPSchema\\CommentMutations\\": "layers/Schema/packages/comment-mutations/tests",
+ "PoPSchema\\CommentsWP\\": "layers/Schema/packages/comments-wp/tests",
+ "PoPSchema\\Comments\\": "layers/Schema/packages/comments/tests",
+ "PoPSchema\\ConvertCaseDirectives\\": "layers/Schema/packages/convert-case-directives/tests",
+ "PoPSchema\\CustomPostMediaMutationsWP\\": "layers/Schema/packages/custompostmedia-mutations-wp/tests",
+ "PoPSchema\\CustomPostMediaMutations\\": "layers/Schema/packages/custompostmedia-mutations/tests",
+ "PoPSchema\\CustomPostMediaWP\\": "layers/Schema/packages/custompostmedia-wp/tests",
+ "PoPSchema\\CustomPostMedia\\": "layers/Schema/packages/custompostmedia/tests",
+ "PoPSchema\\CustomPostMetaWP\\": "layers/Schema/packages/custompostmeta-wp/tests",
+ "PoPSchema\\CustomPostMeta\\": "layers/Schema/packages/custompostmeta/tests",
+ "PoPSchema\\CustomPostMutationsWP\\": "layers/Schema/packages/custompost-mutations-wp/tests",
+ "PoPSchema\\CustomPostMutations\\": "layers/Schema/packages/custompost-mutations/tests",
+ "PoPSchema\\CustomPostsWP\\": "layers/Schema/packages/customposts-wp/tests",
+ "PoPSchema\\CustomPosts\\": "layers/Schema/packages/customposts/tests",
+ "PoPSchema\\EventMutationsWPEM\\": "layers/Schema/packages/event-mutations-wp-em/tests",
+ "PoPSchema\\EventMutations\\": "layers/Schema/packages/event-mutations/tests",
+ "PoPSchema\\EventsWPEM\\": "layers/Schema/packages/events-wp-em/tests",
+ "PoPSchema\\Events\\": "layers/Schema/packages/events/tests",
+ "PoPSchema\\EverythingElseWP\\": "layers/Schema/packages/everythingelse-wp/tests",
+ "PoPSchema\\EverythingElse\\": "layers/Schema/packages/everythingelse/tests",
+ "PoPSchema\\GenericCustomPosts\\": "layers/Schema/packages/generic-customposts/tests",
+ "PoPSchema\\GoogleTranslateDirectiveForCustomPosts\\": "layers/Schema/packages/google-translate-directive-for-customposts/tests",
+ "PoPSchema\\GoogleTranslateDirective\\": "layers/Schema/packages/google-translate-directive/tests",
+ "PoPSchema\\HighlightsWP\\": "layers/Schema/packages/highlights-wp/tests",
+ "PoPSchema\\Highlights\\": "layers/Schema/packages/highlights/tests",
+ "PoPSchema\\LocationPostsWP\\": "layers/Schema/packages/locationposts-wp/tests",
+ "PoPSchema\\LocationPosts\\": "layers/Schema/packages/locationposts/tests",
+ "PoPSchema\\LocationsWPEM\\": "layers/Schema/packages/locations-wp-em/tests",
+ "PoPSchema\\Locations\\": "layers/Schema/packages/locations/tests",
+ "PoPSchema\\MediaWP\\": "layers/Schema/packages/media-wp/tests",
+ "PoPSchema\\Media\\": "layers/Schema/packages/media/tests",
+ "PoPSchema\\MenusWP\\": "layers/Schema/packages/menus-wp/tests",
+ "PoPSchema\\Menus\\": "layers/Schema/packages/menus/tests",
+ "PoPSchema\\MetaQueryWP\\": "layers/Schema/packages/metaquery-wp/tests",
+ "PoPSchema\\MetaQuery\\": "layers/Schema/packages/metaquery/tests",
+ "PoPSchema\\Meta\\": "layers/Schema/packages/meta/tests",
+ "PoPSchema\\NotificationsWP\\": "layers/Schema/packages/notifications-wp/tests",
+ "PoPSchema\\Notifications\\": "layers/Schema/packages/notifications/tests",
+ "PoPSchema\\PagesWP\\": "layers/Schema/packages/pages-wp/tests",
+ "PoPSchema\\Pages\\": "layers/Schema/packages/pages/tests",
+ "PoPSchema\\PostMutations\\": "layers/Schema/packages/post-mutations/tests",
+ "PoPSchema\\PostTagsWP\\": "layers/Schema/packages/post-tags-wp/tests",
+ "PoPSchema\\PostTags\\": "layers/Schema/packages/post-tags/tests",
+ "PoPSchema\\PostsWP\\": "layers/Schema/packages/posts-wp/tests",
+ "PoPSchema\\Posts\\": "layers/Schema/packages/posts/tests",
+ "PoPSchema\\QueriedObjectWP\\": "layers/Schema/packages/queriedobject-wp/tests",
+ "PoPSchema\\QueriedObject\\": "layers/Schema/packages/queriedobject/tests",
+ "PoPSchema\\SchemaCommons\\": "layers/Schema/packages/schema-commons/tests",
+ "PoPSchema\\StancesWP\\": "layers/Schema/packages/stances-wp/tests",
+ "PoPSchema\\Stances\\": "layers/Schema/packages/stances/tests",
+ "PoPSchema\\TagsWP\\": "layers/Schema/packages/tags-wp/tests",
+ "PoPSchema\\Tags\\": "layers/Schema/packages/tags/tests",
+ "PoPSchema\\TaxonomiesWP\\": "layers/Schema/packages/taxonomies-wp/tests",
+ "PoPSchema\\Taxonomies\\": "layers/Schema/packages/taxonomies/tests",
+ "PoPSchema\\TaxonomyMetaWP\\": "layers/Schema/packages/taxonomymeta-wp/tests",
+ "PoPSchema\\TaxonomyMeta\\": "layers/Schema/packages/taxonomymeta/tests",
+ "PoPSchema\\TaxonomyQueryWP\\": "layers/Schema/packages/taxonomyquery-wp/tests",
+ "PoPSchema\\TaxonomyQuery\\": "layers/Schema/packages/taxonomyquery/tests",
+ "PoPSchema\\TranslateDirectiveACL\\": "layers/Schema/packages/translate-directive-acl/tests",
+ "PoPSchema\\TranslateDirective\\": "layers/Schema/packages/translate-directive/tests",
+ "PoPSchema\\UserMetaWP\\": "layers/Schema/packages/usermeta-wp/tests",
+ "PoPSchema\\UserMeta\\": "layers/Schema/packages/usermeta/tests",
+ "PoPSchema\\UserRolesACL\\": "layers/Schema/packages/user-roles-acl/tests",
+ "PoPSchema\\UserRolesAccessControl\\": "layers/Schema/packages/user-roles-access-control/tests",
+ "PoPSchema\\UserRolesWP\\": "layers/Schema/packages/user-roles-wp/tests",
+ "PoPSchema\\UserRoles\\": "layers/Schema/packages/user-roles/tests",
+ "PoPSchema\\UserStateAccessControl\\": "layers/Schema/packages/user-state-access-control/tests",
+ "PoPSchema\\UserStateMutationsWP\\": "layers/Schema/packages/user-state-mutations-wp/tests",
+ "PoPSchema\\UserStateMutations\\": "layers/Schema/packages/user-state-mutations/tests",
+ "PoPSchema\\UserStateWP\\": "layers/Schema/packages/user-state-wp/tests",
+ "PoPSchema\\UserState\\": "layers/Schema/packages/user-state/tests",
+ "PoPSchema\\UsersWP\\": "layers/Schema/packages/users-wp/tests",
+ "PoPSchema\\Users\\": "layers/Schema/packages/users/tests",
+ "PoPSitesWassup\\CommentMutations\\": "layers/Wassup/packages/comment-mutations/tests",
+ "PoPSitesWassup\\ContactUsMutations\\": "layers/Wassup/packages/contactus-mutations/tests",
+ "PoPSitesWassup\\ContactUserMutations\\": "layers/Wassup/packages/contactuser-mutations/tests",
+ "PoPSitesWassup\\CustomPostLinkMutations\\": "layers/Wassup/packages/custompostlink-mutations/tests",
+ "PoPSitesWassup\\CustomPostMutations\\": "layers/Wassup/packages/custompost-mutations/tests",
+ "PoPSitesWassup\\EventLinkMutations\\": "layers/Wassup/packages/eventlink-mutations/tests",
+ "PoPSitesWassup\\EventMutations\\": "layers/Wassup/packages/event-mutations/tests",
+ "PoPSitesWassup\\EverythingElseMutations\\": "layers/Wassup/packages/everythingelse-mutations/tests",
+ "PoPSitesWassup\\FlagMutations\\": "layers/Wassup/packages/flag-mutations/tests",
+ "PoPSitesWassup\\FormMutations\\": "layers/Wassup/packages/form-mutations/tests",
+ "PoPSitesWassup\\GravityFormsMutations\\": "layers/Wassup/packages/gravityforms-mutations/tests",
+ "PoPSitesWassup\\HighlightMutations\\": "layers/Wassup/packages/highlight-mutations/tests",
+ "PoPSitesWassup\\LocationMutations\\": "layers/Wassup/packages/location-mutations/tests",
+ "PoPSitesWassup\\LocationPostLinkMutations\\": "layers/Wassup/packages/locationpostlink-mutations/tests",
+ "PoPSitesWassup\\LocationPostMutations\\": "layers/Wassup/packages/locationpost-mutations/tests",
+ "PoPSitesWassup\\NewsletterMutations\\": "layers/Wassup/packages/newsletter-mutations/tests",
+ "PoPSitesWassup\\NotificationMutations\\": "layers/Wassup/packages/notification-mutations/tests",
+ "PoPSitesWassup\\PostLinkMutations\\": "layers/Wassup/packages/postlink-mutations/tests",
+ "PoPSitesWassup\\PostMutations\\": "layers/Wassup/packages/post-mutations/tests",
+ "PoPSitesWassup\\ShareMutations\\": "layers/Wassup/packages/share-mutations/tests",
+ "PoPSitesWassup\\SocialNetworkMutations\\": "layers/Wassup/packages/socialnetwork-mutations/tests",
+ "PoPSitesWassup\\StanceMutations\\": "layers/Wassup/packages/stance-mutations/tests",
+ "PoPSitesWassup\\SystemMutations\\": "layers/Wassup/packages/system-mutations/tests",
+ "PoPSitesWassup\\UserStateMutations\\": "layers/Wassup/packages/user-state-mutations/tests",
+ "PoPSitesWassup\\VolunteerMutations\\": "layers/Wassup/packages/volunteer-mutations/tests",
+ "PoPSitesWassup\\Wassup\\": "layers/Wassup/packages/wassup/tests",
+ "PoP\\APIClients\\": "layers/API/packages/api-clients/tests",
+ "PoP\\APIEndpointsForWP\\": "layers/API/packages/api-endpoints-for-wp/tests",
+ "PoP\\APIEndpoints\\": "layers/API/packages/api-endpoints/tests",
+ "PoP\\APIMirrorQuery\\": "layers/API/packages/api-mirrorquery/tests",
+ "PoP\\API\\": "layers/API/packages/api/tests",
+ "PoP\\AccessControl\\": "layers/Engine/packages/access-control/tests",
+ "PoP\\ApplicationWP\\": "layers/SiteBuilder/packages/application-wp/tests",
+ "PoP\\Application\\": "layers/SiteBuilder/packages/application/tests",
+ "PoP\\Base36Definitions\\": "layers/SiteBuilder/packages/definitions-base36/tests",
+ "PoP\\CacheControl\\": "layers/Engine/packages/cache-control/tests",
+ "PoP\\ComponentModel\\": "layers/Engine/packages/component-model/tests",
+ "PoP\\ConfigurableSchemaFeedback\\": "layers/Engine/packages/configurable-schema-feedback/tests",
+ "PoP\\ConfigurationComponentModel\\": "layers/SiteBuilder/packages/component-model-configuration/tests",
+ "PoP\\DefinitionPersistence\\": "layers/SiteBuilder/packages/definitionpersistence/tests",
+ "PoP\\Definitions\\": "layers/Engine/packages/definitions/tests",
+ "PoP\\EmojiDefinitions\\": "layers/SiteBuilder/packages/definitions-emoji/tests",
+ "PoP\\EngineWP\\": "layers/Engine/packages/engine-wp/tests",
+ "PoP\\Engine\\": "layers/Engine/packages/engine/tests",
+ "PoP\\FieldQuery\\": "layers/Engine/packages/field-query/tests",
+ "PoP\\FileStore\\": "layers/Engine/packages/filestore/tests",
+ "PoP\\FunctionFields\\": "layers/Engine/packages/function-fields/tests",
+ "PoP\\GraphQLAPI\\": "layers/API/packages/api-graphql/tests",
+ "PoP\\GuzzleHelpers\\": "layers/Engine/packages/guzzle-helpers/tests",
+ "PoP\\HooksWP\\": "layers/Engine/packages/hooks-wp/tests",
+ "PoP\\Hooks\\": "layers/Engine/packages/hooks/tests",
+ "PoP\\LooseContracts\\": "layers/Engine/packages/loosecontracts/tests",
+ "PoP\\MandatoryDirectivesByConfiguration\\": "layers/Engine/packages/mandatory-directives-by-configuration/tests",
+ "PoP\\ModuleRouting\\": "layers/Engine/packages/modulerouting/tests",
+ "PoP\\Multisite\\": "layers/SiteBuilder/packages/multisite/tests",
+ "PoP\\QueryParsing\\": "layers/Engine/packages/query-parsing/tests",
+ "PoP\\RESTAPI\\": "layers/API/packages/api-rest/tests",
+ "PoP\\ResourceLoader\\": "layers/SiteBuilder/packages/resourceloader/tests",
+ "PoP\\Resources\\": "layers/SiteBuilder/packages/resources/tests",
+ "PoP\\Root\\": "layers/Engine/packages/root/tests",
+ "PoP\\RoutingWP\\": "layers/Engine/packages/routing-wp/tests",
+ "PoP\\Routing\\": "layers/Engine/packages/routing/tests",
+ "PoP\\SPA\\": "layers/SiteBuilder/packages/spa/tests",
+ "PoP\\SSG\\": "layers/SiteBuilder/packages/static-site-generator/tests",
+ "PoP\\SiteWP\\": "layers/SiteBuilder/packages/site-wp/tests",
+ "PoP\\Site\\": "layers/SiteBuilder/packages/site/tests",
+ "PoP\\TraceTools\\": "layers/Engine/packages/trace-tools/tests",
+ "PoP\\TranslationWP\\": "layers/Engine/packages/translation-wp/tests",
+ "PoP\\Translation\\": "layers/Engine/packages/translation/tests"
+ }
+ },
+ "extra": {
+ "wordpress-install-dir": "vendor/wordpress/wordpress",
+ "merge-plugin": {
+ "include": [
+ "composer.local.json"
+ ],
+ "recurse": true,
+ "replace": false,
+ "ignore-duplicates": false,
+ "merge-dev": true,
+ "merge-extra": false,
+ "merge-extra-deep": false,
+ "merge-scripts": false
+ }
+ },
+ "replace": {
+ "getpop/access-control": "self.version",
+ "getpop/api": "self.version",
+ "getpop/api-clients": "self.version",
+ "getpop/api-endpoints": "self.version",
+ "getpop/api-endpoints-for-wp": "self.version",
+ "getpop/api-graphql": "self.version",
+ "getpop/api-mirrorquery": "self.version",
+ "getpop/api-rest": "self.version",
+ "getpop/application": "self.version",
+ "getpop/application-wp": "self.version",
+ "getpop/cache-control": "self.version",
+ "getpop/component-model": "self.version",
+ "getpop/component-model-configuration": "self.version",
+ "getpop/configurable-schema-feedback": "self.version",
+ "getpop/definitionpersistence": "self.version",
+ "getpop/definitions": "self.version",
+ "getpop/definitions-base36": "self.version",
+ "getpop/definitions-emoji": "self.version",
+ "getpop/engine": "self.version",
+ "getpop/engine-wp": "self.version",
+ "getpop/engine-wp-bootloader": "self.version",
+ "getpop/field-query": "self.version",
+ "getpop/filestore": "self.version",
+ "getpop/function-fields": "self.version",
+ "getpop/guzzle-helpers": "self.version",
+ "getpop/hooks": "self.version",
+ "getpop/hooks-wp": "self.version",
+ "getpop/loosecontracts": "self.version",
+ "getpop/mandatory-directives-by-configuration": "self.version",
+ "getpop/migrate-api": "self.version",
+ "getpop/migrate-api-graphql": "self.version",
+ "getpop/migrate-component-model": "self.version",
+ "getpop/migrate-component-model-configuration": "self.version",
+ "getpop/migrate-engine": "self.version",
+ "getpop/migrate-engine-wp": "self.version",
+ "getpop/migrate-static-site-generator": "self.version",
+ "getpop/modulerouting": "self.version",
+ "getpop/multisite": "self.version",
+ "getpop/query-parsing": "self.version",
+ "getpop/resourceloader": "self.version",
+ "getpop/resources": "self.version",
+ "getpop/root": "self.version",
+ "getpop/routing": "self.version",
+ "getpop/routing-wp": "self.version",
+ "getpop/site": "self.version",
+ "getpop/site-wp": "self.version",
+ "getpop/spa": "self.version",
+ "getpop/static-site-generator": "self.version",
+ "getpop/trace-tools": "self.version",
+ "getpop/translation": "self.version",
+ "getpop/translation-wp": "self.version",
+ "graphql-api/convert-case-directives": "self.version",
+ "graphql-api/graphql-api-for-wp": "self.version",
+ "graphql-api/schema-feedback": "self.version",
+ "graphql-by-pop/graphql-clients-for-wp": "self.version",
+ "graphql-by-pop/graphql-endpoint-for-wp": "self.version",
+ "graphql-by-pop/graphql-parser": "self.version",
+ "graphql-by-pop/graphql-query": "self.version",
+ "graphql-by-pop/graphql-request": "self.version",
+ "graphql-by-pop/graphql-server": "self.version",
+ "leoloso/examples-for-pop": "self.version",
+ "pop-migrate-everythingelse/cssconverter": "self.version",
+ "pop-migrate-everythingelse/ssr": "self.version",
+ "pop-schema/basic-directives": "self.version",
+ "pop-schema/block-metadata-for-wp": "self.version",
+ "pop-schema/categories": "self.version",
+ "pop-schema/categories-wp": "self.version",
+ "pop-schema/cdn-directive": "self.version",
+ "pop-schema/comment-mutations": "self.version",
+ "pop-schema/comment-mutations-wp": "self.version",
+ "pop-schema/commentmeta": "self.version",
+ "pop-schema/commentmeta-wp": "self.version",
+ "pop-schema/comments": "self.version",
+ "pop-schema/comments-wp": "self.version",
+ "pop-schema/convert-case-directives": "self.version",
+ "pop-schema/custompost-mutations": "self.version",
+ "pop-schema/custompost-mutations-wp": "self.version",
+ "pop-schema/custompostmedia": "self.version",
+ "pop-schema/custompostmedia-mutations": "self.version",
+ "pop-schema/custompostmedia-mutations-wp": "self.version",
+ "pop-schema/custompostmedia-wp": "self.version",
+ "pop-schema/custompostmeta": "self.version",
+ "pop-schema/custompostmeta-wp": "self.version",
+ "pop-schema/customposts": "self.version",
+ "pop-schema/customposts-wp": "self.version",
+ "pop-schema/event-mutations": "self.version",
+ "pop-schema/event-mutations-wp-em": "self.version",
+ "pop-schema/events": "self.version",
+ "pop-schema/events-wp-em": "self.version",
+ "pop-schema/everythingelse": "self.version",
+ "pop-schema/everythingelse-wp": "self.version",
+ "pop-schema/generic-customposts": "self.version",
+ "pop-schema/google-translate-directive": "self.version",
+ "pop-schema/google-translate-directive-for-customposts": "self.version",
+ "pop-schema/highlights": "self.version",
+ "pop-schema/highlights-wp": "self.version",
+ "pop-schema/locationposts": "self.version",
+ "pop-schema/locationposts-wp": "self.version",
+ "pop-schema/locations": "self.version",
+ "pop-schema/locations-wp-em": "self.version",
+ "pop-schema/media": "self.version",
+ "pop-schema/media-wp": "self.version",
+ "pop-schema/menus": "self.version",
+ "pop-schema/menus-wp": "self.version",
+ "pop-schema/meta": "self.version",
+ "pop-schema/metaquery": "self.version",
+ "pop-schema/metaquery-wp": "self.version",
+ "pop-schema/migrate-categories": "self.version",
+ "pop-schema/migrate-categories-wp": "self.version",
+ "pop-schema/migrate-commentmeta": "self.version",
+ "pop-schema/migrate-commentmeta-wp": "self.version",
+ "pop-schema/migrate-comments": "self.version",
+ "pop-schema/migrate-comments-wp": "self.version",
+ "pop-schema/migrate-custompostmedia": "self.version",
+ "pop-schema/migrate-custompostmedia-wp": "self.version",
+ "pop-schema/migrate-custompostmeta": "self.version",
+ "pop-schema/migrate-custompostmeta-wp": "self.version",
+ "pop-schema/migrate-customposts": "self.version",
+ "pop-schema/migrate-customposts-wp": "self.version",
+ "pop-schema/migrate-events": "self.version",
+ "pop-schema/migrate-events-wp-em": "self.version",
+ "pop-schema/migrate-everythingelse": "self.version",
+ "pop-schema/migrate-locations": "self.version",
+ "pop-schema/migrate-locations-wp-em": "self.version",
+ "pop-schema/migrate-media": "self.version",
+ "pop-schema/migrate-media-wp": "self.version",
+ "pop-schema/migrate-meta": "self.version",
+ "pop-schema/migrate-metaquery": "self.version",
+ "pop-schema/migrate-metaquery-wp": "self.version",
+ "pop-schema/migrate-pages": "self.version",
+ "pop-schema/migrate-pages-wp": "self.version",
+ "pop-schema/migrate-post-tags": "self.version",
+ "pop-schema/migrate-post-tags-wp": "self.version",
+ "pop-schema/migrate-posts": "self.version",
+ "pop-schema/migrate-posts-wp": "self.version",
+ "pop-schema/migrate-queriedobject": "self.version",
+ "pop-schema/migrate-queriedobject-wp": "self.version",
+ "pop-schema/migrate-tags": "self.version",
+ "pop-schema/migrate-tags-wp": "self.version",
+ "pop-schema/migrate-taxonomies": "self.version",
+ "pop-schema/migrate-taxonomies-wp": "self.version",
+ "pop-schema/migrate-taxonomymeta": "self.version",
+ "pop-schema/migrate-taxonomymeta-wp": "self.version",
+ "pop-schema/migrate-taxonomyquery": "self.version",
+ "pop-schema/migrate-taxonomyquery-wp": "self.version",
+ "pop-schema/migrate-usermeta": "self.version",
+ "pop-schema/migrate-usermeta-wp": "self.version",
+ "pop-schema/migrate-users": "self.version",
+ "pop-schema/migrate-users-wp": "self.version",
+ "pop-schema/notifications": "self.version",
+ "pop-schema/notifications-wp": "self.version",
+ "pop-schema/pages": "self.version",
+ "pop-schema/pages-wp": "self.version",
+ "pop-schema/post-mutations": "self.version",
+ "pop-schema/post-tags": "self.version",
+ "pop-schema/post-tags-wp": "self.version",
+ "pop-schema/posts": "self.version",
+ "pop-schema/posts-wp": "self.version",
+ "pop-schema/queriedobject": "self.version",
+ "pop-schema/queriedobject-wp": "self.version",
+ "pop-schema/schema-commons": "self.version",
+ "pop-schema/stances": "self.version",
+ "pop-schema/stances-wp": "self.version",
+ "pop-schema/tags": "self.version",
+ "pop-schema/tags-wp": "self.version",
+ "pop-schema/taxonomies": "self.version",
+ "pop-schema/taxonomies-wp": "self.version",
+ "pop-schema/taxonomymeta": "self.version",
+ "pop-schema/taxonomymeta-wp": "self.version",
+ "pop-schema/taxonomyquery": "self.version",
+ "pop-schema/taxonomyquery-wp": "self.version",
+ "pop-schema/translate-directive": "self.version",
+ "pop-schema/translate-directive-acl": "self.version",
+ "pop-schema/user-roles": "self.version",
+ "pop-schema/user-roles-access-control": "self.version",
+ "pop-schema/user-roles-acl": "self.version",
+ "pop-schema/user-roles-wp": "self.version",
+ "pop-schema/user-state": "self.version",
+ "pop-schema/user-state-access-control": "self.version",
+ "pop-schema/user-state-mutations": "self.version",
+ "pop-schema/user-state-mutations-wp": "self.version",
+ "pop-schema/user-state-wp": "self.version",
+ "pop-schema/usermeta": "self.version",
+ "pop-schema/usermeta-wp": "self.version",
+ "pop-schema/users": "self.version",
+ "pop-schema/users-wp": "self.version",
+ "pop-sites-wassup/comment-mutations": "self.version",
+ "pop-sites-wassup/contactus-mutations": "self.version",
+ "pop-sites-wassup/contactuser-mutations": "self.version",
+ "pop-sites-wassup/custompost-mutations": "self.version",
+ "pop-sites-wassup/custompostlink-mutations": "self.version",
+ "pop-sites-wassup/event-mutations": "self.version",
+ "pop-sites-wassup/eventlink-mutations": "self.version",
+ "pop-sites-wassup/everythingelse-mutations": "self.version",
+ "pop-sites-wassup/flag-mutations": "self.version",
+ "pop-sites-wassup/form-mutations": "self.version",
+ "pop-sites-wassup/gravityforms-mutations": "self.version",
+ "pop-sites-wassup/highlight-mutations": "self.version",
+ "pop-sites-wassup/location-mutations": "self.version",
+ "pop-sites-wassup/locationpost-mutations": "self.version",
+ "pop-sites-wassup/locationpostlink-mutations": "self.version",
+ "pop-sites-wassup/newsletter-mutations": "self.version",
+ "pop-sites-wassup/notification-mutations": "self.version",
+ "pop-sites-wassup/post-mutations": "self.version",
+ "pop-sites-wassup/postlink-mutations": "self.version",
+ "pop-sites-wassup/share-mutations": "self.version",
+ "pop-sites-wassup/socialnetwork-mutations": "self.version",
+ "pop-sites-wassup/stance-mutations": "self.version",
+ "pop-sites-wassup/system-mutations": "self.version",
+ "pop-sites-wassup/user-state-mutations": "self.version",
+ "pop-sites-wassup/volunteer-mutations": "self.version",
+ "pop-sites-wassup/wassup": "self.version"
+ },
+ "authors": [
+ {
+ "name": "Leonardo Losoviz",
+ "email": "leo@getpop.org",
+ "homepage": "https://getpop.org"
+ }
+ ],
+ "description": "Monorepo for all the PoP packages",
+ "license": "GPL-2.0-or-later",
+ "config": {
+ "sort-packages": true,
+ "platform-check": false
+ },
+ "repositories": [
+ {
+ "type": "composer",
+ "url": "https://wpackagist.org"
+ },
+ {
+ "type": "vcs",
+ "url": "https://github.com/leoloso/wp-muplugin-loader.git"
+ },
+ {
+ "type": "vcs",
+ "url": "https://github.com/mcaskill/composer-merge-plugin.git"
+ }
+ ],
+ "scripts": {
+ "test": "phpunit",
+ "check-style": "phpcs -n src $(monorepo-builder source-packages --subfolder=src --subfolder=tests)",
+ "fix-style": "phpcbf -n src $(monorepo-builder source-packages --subfolder=src --subfolder=tests)",
+ "analyse": "ci/phpstan.sh \". $(monorepo-builder source-packages --skip-unmigrated)\"",
+ "preview-src-downgrade": "rector process $(monorepo-builder source-packages --subfolder=src) --config=rector-downgrade-code.php --ansi --dry-run || true",
+ "preview-vendor-downgrade": "layers/Engine/packages/root/ci/downgrade_code.sh 7.1 rector-downgrade-code.php --dry-run || true",
+ "preview-code-downgrade": [
+ "@preview-src-downgrade",
+ "@preview-vendor-downgrade"
+ ],
+ "build-server": [
+ "lando init --source remote --remote-url https://wordpress.org/latest.tar.gz --recipe wordpress --webroot wordpress --name graphql-api-dev",
+ "@start-server"
+ ],
+ "start-server": [
+ "cd layers/GraphQLAPIForWP/plugins/graphql-api-for-wp && composer install",
+ "lando start"
+ ],
+ "rebuild-server": "lando rebuild -y",
+ "merge-monorepo": "monorepo-builder merge --ansi",
+ "propagate-monorepo": "monorepo-builder propagate --ansi",
+ "validate-monorepo": "monorepo-builder validate --ansi",
+ "release": "monorepo-builder release patch --ansi"
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true
+}
+"#,
+ manipulator.get_contents()
+ );
}
diff --git a/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs b/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs
index 5454074..48f0fc5 100644
--- a/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs
+++ b/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs
@@ -26,20 +26,20 @@ impl Drop for TearDown {
// These set up a temp directory tree (including a git repo) and assert the files the finder
// selects with manual/git/skip excludes; the git-backed fixture setup is not ported.
+#[ignore = "setUp needs TestCase::getUniqueTmpDirectory to build the on-disk fixture tree; not ported"]
#[test]
-#[ignore = "needs a temp directory tree and git-backed fixtures to drive ArchivableFilesFinder; not ported"]
fn test_manual_excludes() {
todo!()
}
+#[ignore = "setUp needs TestCase::getUniqueTmpDirectory plus skipIfNotExecutable/Process::fromShellCommandline/PharData/RecursiveIteratorIterator; none ported"]
#[test]
-#[ignore = "needs a temp directory tree and git-backed fixtures to drive ArchivableFilesFinder; not ported"]
fn test_git_excludes() {
todo!()
}
+#[ignore = "setUp needs TestCase::getUniqueTmpDirectory to build the on-disk fixture tree; not ported"]
#[test]
-#[ignore = "needs a temp directory tree and git-backed fixtures to drive ArchivableFilesFinder; not ported"]
fn test_skip_excludes() {
todo!()
}
diff --git a/crates/shirabe/tests/package/archiver/archive_manager_test.rs b/crates/shirabe/tests/package/archiver/archive_manager_test.rs
index b3b61f8..2712da6 100644
--- a/crates/shirabe/tests/package/archiver/archive_manager_test.rs
+++ b/crates/shirabe/tests/package/archiver/archive_manager_test.rs
@@ -29,31 +29,31 @@ impl Drop for TearDown {
// the filename-derivation helpers over packages; the archiving and fixture setup are not
// ported.
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (set_up) which is unported"]
fn test_unknown_format() {
todo!()
}
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[ignore = "needs setupGitRepo + PharData tar archiving and Factory-built ArchiveManager (set_up), and setupPackage's setSourceType which is not exposed on the package handle API"]
fn test_archive_tar() {
todo!()
}
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[ignore = "needs setupGitRepo + PharData tar archiving and Factory-built ArchiveManager (set_up), and setupPackage's setSourceType which is not exposed on the package handle API"]
fn test_archive_custom_file_name() {
todo!()
}
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (set_up) which is unported"]
fn test_get_package_filename_parts() {
todo!()
}
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (set_up) which is unported"]
fn test_get_package_filename() {
todo!()
}
diff --git a/crates/shirabe/tests/package/archiver/phar_archiver_test.rs b/crates/shirabe/tests/package/archiver/phar_archiver_test.rs
index 414aa36..385177b 100644
--- a/crates/shirabe/tests/package/archiver/phar_archiver_test.rs
+++ b/crates/shirabe/tests/package/archiver/phar_archiver_test.rs
@@ -1,13 +1,13 @@
//! ref: composer/tests/Composer/Test/Package/Archiver/PharArchiverTest.php
+#[ignore = "setUp/setupDummyRepo need TestCase::getUniqueTmpDirectory plus Filesystem to build the on-disk fixture tree; not ported"]
#[test]
-#[ignore = "PharArchiver::archive builds a tar via PharData, which is todo!() in the php-shim"]
fn test_tar_archive() {
todo!()
}
+#[ignore = "setUp/setupDummyRepo need TestCase::getUniqueTmpDirectory plus Filesystem to build the on-disk fixture tree; not ported"]
#[test]
-#[ignore = "PharArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim"]
fn test_zip_archive() {
todo!()
}
diff --git a/crates/shirabe/tests/package/archiver/zip_archiver_test.rs b/crates/shirabe/tests/package/archiver/zip_archiver_test.rs
index 5f41c78..5b51ce9 100644
--- a/crates/shirabe/tests/package/archiver/zip_archiver_test.rs
+++ b/crates/shirabe/tests/package/archiver/zip_archiver_test.rs
@@ -28,19 +28,19 @@ impl Drop for TearDown {
// ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim.
#[test]
-#[ignore = "ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim"]
+#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"]
fn test_simple_files() {
todo!()
}
#[test]
-#[ignore = "ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim"]
+#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"]
fn test_gitignore_exclude_negation() {
todo!()
}
#[test]
-#[ignore = "ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim"]
+#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"]
fn test_folder_with_backslashes() {
todo!()
}
diff --git a/crates/shirabe/tests/package/base_package_test.rs b/crates/shirabe/tests/package/base_package_test.rs
index 0d77f49..1056de1 100644
--- a/crates/shirabe/tests/package/base_package_test.rs
+++ b/crates/shirabe/tests/package/base_package_test.rs
@@ -35,8 +35,8 @@ fn test_set_another_repository() {
// on an abstract BasePackage to drive getFullPrettyVersion(). Reproducing those exact
// getter values requires mocking; a real package cannot carry the pretty version
// "PrettyVersion" together with isDev() == true.
+#[ignore = "requires mocking isDev/getSourceType/getPrettyVersion/getSourceReference on an abstract BasePackage; no mock infrastructure exists and a real package cannot carry prettyVersion \"PrettyVersion\" with isDev() == true"]
#[test]
-#[ignore = "mocks isDev/getSourceType/getPrettyVersion/getSourceReference on an abstract BasePackage; not reproducible with a real package"]
fn test_format_version_for_dev_package() {
todo!()
}
diff --git a/crates/shirabe/tests/package/dumper/array_dumper_test.rs b/crates/shirabe/tests/package/dumper/array_dumper_test.rs
index 6ed12fe..64880f1 100644
--- a/crates/shirabe/tests/package/dumper/array_dumper_test.rs
+++ b/crates/shirabe/tests/package/dumper/array_dumper_test.rs
@@ -83,7 +83,7 @@ fn test_dump_abandoned_replacement() {
// arrays, a DateTime and Link maps, then checks the corresponding dumped key. Reproducing
// that dynamic dispatch faithfully would require per-case wiring for every property type.
#[test]
-#[ignore = "exercises ~25 dynamic set<Property> calls over heterogeneous value types; not reproduced here"]
+#[ignore = "RootPackageHandle lacks set_type/set_release_date/set_binaries/set_php_ext setters required by the data provider's type/time/bin/php-ext cases"]
fn test_keys() {
todo!()
}
diff --git a/crates/shirabe/tests/package/loader/array_loader_test.rs b/crates/shirabe/tests/package/loader/array_loader_test.rs
index 2dc4f3e..d35f671 100644
--- a/crates/shirabe/tests/package/loader/array_loader_test.rs
+++ b/crates/shirabe/tests/package/loader/array_loader_test.rs
@@ -1,170 +1,647 @@
//! ref: composer/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php
-use shirabe::package::loader::ArrayLoader;
+use indexmap::IndexMap;
+use shirabe::package::ArrayDumper;
+use shirabe::package::Link;
+use shirabe::package::loader::{ArrayLoader, LoaderInterface};
+use shirabe::package::version::VersionParser;
+use shirabe_php_shim::PhpMixed;
fn set_up() -> ArrayLoader {
ArrayLoader::new(None, false)
}
-// ArrayLoader::load parses version/link constraints through a look-around regex the regex
-// crate cannot compile.
+fn s(value: &str) -> PhpMixed {
+ PhpMixed::String(value.to_string())
+}
+
+fn map(entries: Vec<(&str, PhpMixed)>) -> PhpMixed {
+ let mut m: IndexMap<String, PhpMixed> = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ PhpMixed::Array(m)
+}
+
+fn make_config(entries: Vec<(&str, PhpMixed)>) -> IndexMap<String, PhpMixed> {
+ let mut m: IndexMap<String, PhpMixed> = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ m
+}
+
+fn list(items: Vec<PhpMixed>) -> PhpMixed {
+ PhpMixed::List(items)
+}
+
+/// ref: ArrayLoaderTest::parseDumpProvider valid config
+fn valid_config() -> IndexMap<String, PhpMixed> {
+ make_config(vec![
+ ("name", s("A/B")),
+ ("version", s("1.2.3")),
+ ("version_normalized", s("1.2.3.0")),
+ ("description", s("Foo bar")),
+ ("type", s("library")),
+ ("keywords", list(vec![s("a"), s("b"), s("c")])),
+ ("homepage", s("http://example.com")),
+ ("license", list(vec![s("MIT"), s("GPLv3")])),
+ (
+ "authors",
+ list(vec![map(vec![
+ ("name", s("Bob")),
+ ("email", s("bob@example.org")),
+ ("homepage", s("example.org")),
+ ("role", s("Developer")),
+ ])]),
+ ),
+ (
+ "funding",
+ list(vec![map(vec![
+ ("type", s("example")),
+ ("url", s("https://example.org/fund")),
+ ])]),
+ ),
+ ("require", map(vec![("foo/bar", s("1.0"))])),
+ ("require-dev", map(vec![("foo/baz", s("1.0"))])),
+ ("replace", map(vec![("foo/qux", s("1.0"))])),
+ ("conflict", map(vec![("foo/quux", s("1.0"))])),
+ ("provide", map(vec![("foo/quuux", s("1.0"))])),
+ (
+ "autoload",
+ map(vec![
+ ("psr-0", map(vec![("Ns\\Prefix", s("path"))])),
+ ("classmap", list(vec![s("path"), s("path2")])),
+ ]),
+ ),
+ ("include-path", list(vec![s("path3"), s("path4")])),
+ ("target-dir", s("some/prefix")),
+ (
+ "extra",
+ map(vec![(
+ "random",
+ map(vec![("things", s("of")), ("any", s("shape"))]),
+ )]),
+ ),
+ ("bin", list(vec![s("bin1"), s("bin/foo")])),
+ (
+ "archive",
+ map(vec![(
+ "exclude",
+ list(vec![s("/foo/bar"), s("baz"), s("!/foo/bar/baz")]),
+ )]),
+ ),
+ (
+ "transport-options",
+ map(vec![(
+ "ssl",
+ map(vec![("local_cert", s("/opt/certs/test.pem"))]),
+ )]),
+ ),
+ ("abandoned", s("foo/bar")),
+ ])
+}
+
+/// ref: ArrayLoaderTest::fixConfigWhenLoadConfigIsFalse
+fn fix_config_when_load_config_is_false(
+ config: &IndexMap<String, PhpMixed>,
+) -> IndexMap<String, PhpMixed> {
+ let mut expected_config = config.clone();
+ expected_config.shift_remove("transport-options");
+ expected_config
+}
+
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_self_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("1.2.3.4")),
+ ("replace", map(vec![("foo", s("self.version"))])),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ let replaces = package.get_replaces();
+ assert_eq!(
+ "== 1.2.3.4",
+ replaces.get("foo").unwrap().get_constraint().to_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_type_default() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![("name", s("A")), ("version", s("1.0"))]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("library", package.get_type());
+
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("1.0")),
+ ("type", s("foo")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("foo", package.get_type());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_normalized_version_optimization() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![("name", s("A")), ("version", s("1.2.3"))]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("1.2.3.0", package.get_version());
+
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("1.2.3")),
+ ("version_normalized", s("1.2.3.4")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("1.2.3.4", package.get_version());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_dump_default_load_config() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = valid_config();
+ let package = loader.load(config.clone(), None).unwrap();
+ let dumper = ArrayDumper::new();
+ let expected_config = fix_config_when_load_config_is_false(&config);
+ assert_eq!(expected_config, dumper.dump(package));
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_dump_true_load_config() {
- let _loader = set_up();
- todo!()
+ let config = valid_config();
+ let loader = ArrayLoader::new(None, true);
+ let package = loader.load(config.clone(), None).unwrap();
+ let dumper = ArrayDumper::new();
+ let expected_config = config;
+ assert_eq!(expected_config, dumper.dump(package));
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_dump_false_load_config() {
- let _loader = set_up();
- todo!()
+ let config = valid_config();
+ let loader = ArrayLoader::new(None, false);
+ let package = loader.load(config.clone(), None).unwrap();
+ let dumper = ArrayDumper::new();
+ let expected_config = fix_config_when_load_config_is_false(&config);
+ assert_eq!(expected_config, dumper.dump(package));
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_with_branch_alias() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("dev-master")),
+ (
+ "extra",
+ map(vec![(
+ "branch-alias",
+ map(vec![("dev-master", s("1.0.x-dev"))]),
+ )]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!("1.0.x-dev", package.get_pretty_version());
+
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("dev-master")),
+ (
+ "extra",
+ map(vec![(
+ "branch-alias",
+ map(vec![("dev-master", s("1.0-dev"))]),
+ )]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!("1.0.x-dev", package.get_pretty_version());
+
+ let config = make_config(vec![
+ ("name", s("B")),
+ ("version", s("4.x-dev")),
+ (
+ "extra",
+ map(vec![(
+ "branch-alias",
+ map(vec![("4.x-dev", s("4.0.x-dev"))]),
+ )]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!("4.0.x-dev", package.get_pretty_version());
+
+ let config = make_config(vec![
+ ("name", s("B")),
+ ("version", s("4.x-dev")),
+ (
+ "extra",
+ map(vec![("branch-alias", map(vec![("4.x-dev", s("4.0-dev"))]))]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!("4.0.x-dev", package.get_pretty_version());
+
+ let config = make_config(vec![
+ ("name", s("C")),
+ ("version", s("4.x-dev")),
+ (
+ "extra",
+ map(vec![(
+ "branch-alias",
+ map(vec![("4.x-dev", s("3.4.x-dev"))]),
+ )]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_package().is_some());
+ assert_eq!("4.x-dev", package.get_pretty_version());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_aliasing_without_branch_alias() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ // non-numeric gets a default alias
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("dev-main")),
+ ("default-branch", PhpMixed::Bool(true)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!(
+ VersionParser::DEFAULT_BRANCH_ALIAS,
+ package.get_pretty_version()
+ );
+
+ // non-default branch gets no alias even if non-numeric
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("dev-main")),
+ ("default-branch", PhpMixed::Bool(false)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_package().is_some());
+ assert_eq!("dev-main", package.get_pretty_version());
+
+ // default branch gets no alias if already numeric
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("2.x-dev")),
+ ("default-branch", PhpMixed::Bool(true)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_package().is_some());
+ assert_eq!("2.9999999.9999999.9999999-dev", package.get_version());
+
+ // default branch gets no alias if already numeric, with v prefix
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("v2.x-dev")),
+ ("default-branch", PhpMixed::Bool(true)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_package().is_some());
+ assert_eq!("2.9999999.9999999.9999999-dev", package.get_version());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_abandoned() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("1.2.3.4")),
+ ("abandoned", s("foo/bar")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ let package = package.as_complete().unwrap();
+ assert!(package.is_abandoned());
+ assert_eq!(
+ Some("foo/bar".to_string()),
+ package.get_replacement_package()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_not_abandoned() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![("name", s("A")), ("version", s("1.2.3.4"))]);
+
+ let package = loader.load(config, None).unwrap();
+ let package = package.as_complete().unwrap();
+ assert!(!package.is_abandoned());
+}
+
+/// ref: ArrayLoaderTest::providePluginApiVersions
+fn provide_plugin_api_versions() -> Vec<&'static str> {
+ vec![
+ "1.0",
+ "1.0.0",
+ "1.0.0.0",
+ "1",
+ "=1.0.0",
+ "==1.0",
+ "~1.0.0",
+ "*",
+ "3.0.*",
+ "@stable",
+ "1.0.0@stable",
+ "^5.1",
+ ">=1.0.0 <2.5",
+ "x",
+ "1.0.0-dev",
+ ]
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_plugin_api_version_are_kept_as_declared() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ for api_version in provide_plugin_api_versions() {
+ let links = loader
+ .parse_links(
+ "Plugin",
+ "9.9.9",
+ Link::TYPE_REQUIRE,
+ make_config(vec![("composer-plugin-api", s(api_version))]),
+ )
+ .unwrap();
+
+ assert!(links.contains_key("composer-plugin-api"));
+ assert_eq!(
+ api_version,
+ links
+ .get("composer-plugin-api")
+ .unwrap()
+ .get_constraint()
+ .get_pretty_string()
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_plugin_api_version_does_support_self_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let links = loader
+ .parse_links(
+ "Plugin",
+ "6.6.6",
+ Link::TYPE_REQUIRE,
+ make_config(vec![("composer-plugin-api", s("self.version"))]),
+ )
+ .unwrap();
+
+ assert!(links.contains_key("composer-plugin-api"));
+ assert_eq!(
+ "6.6.6",
+ links
+ .get("composer-plugin-api")
+ .unwrap()
+ .get_constraint()
+ .get_pretty_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_links_integer_target() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let links = loader
+ .parse_links(
+ "Plugin",
+ "9.9.9",
+ Link::TYPE_REQUIRE,
+ make_config(vec![("1", s("dev-main"))]),
+ )
+ .unwrap();
+
+ assert!(links.contains_key("1"));
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_links_invalid_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let err = loader
+ .parse_links(
+ "Plugin",
+ "9.9.9",
+ Link::TYPE_REQUIRE,
+ make_config(vec![("composer-plugin-api", s("^^^"))]),
+ )
+ .unwrap_err();
+ assert_eq!(
+ "Link constraint in Plugin requires > composer-plugin-api should be a valid version constraint, got \"^^^\"",
+ err.to_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_none_string_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", PhpMixed::Int(1)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("1", package.get_pretty_version());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_none_string_source_dist_reference() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-main")),
+ (
+ "source",
+ map(vec![
+ ("type", s("svn")),
+ ("url", s("https://example.org/")),
+ ("reference", PhpMixed::Int(2019)),
+ ]),
+ ),
+ (
+ "dist",
+ map(vec![
+ ("type", s("zip")),
+ ("url", s("https://example.org/")),
+ ("reference", PhpMixed::Int(2019)),
+ ]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!(Some("2019".to_string()), package.get_source_reference());
+ assert_eq!(Some("2019".to_string()), package.get_dist_reference());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_branch_alias_integer_index() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ (
+ "extra",
+ map(vec![("branch-alias", map(vec![("1", s("1.3-dev"))]))]),
+ ),
+ (
+ "dist",
+ map(vec![("type", s("zip")), ("url", s("https://example.org/"))]),
+ ),
+ ]);
+
+ assert_eq!(None, loader.get_branch_alias(&config).unwrap());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_links_require() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ ("require", map(vec![("foo/bar", s("1.0"))])),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert!(package.get_requires().contains_key("foo/bar"));
+ assert_eq!(
+ "1.0",
+ package
+ .get_requires()
+ .get("foo/bar")
+ .unwrap()
+ .get_constraint()
+ .get_pretty_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_links_require_invalid() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ (
+ "require",
+ map(vec![("foo/bar", map(vec![("random-string", s("1.0"))]))]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!(0, package.get_requires().len());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_links_replace() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ ("replace", map(vec![("coyote/package", s("self.version"))])),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert!(package.get_replaces().contains_key("coyote/package"));
+ assert_eq!(
+ "dev-1",
+ package
+ .get_replaces()
+ .get("coyote/package")
+ .unwrap()
+ .get_constraint()
+ .get_pretty_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_links_replace_invalid() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ ("replace", s("coyote/package")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!(0, package.get_replaces().len());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_support_string_value() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ ("support", s("https://example.org")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ let package = package.as_complete().unwrap();
+ assert_eq!(0, package.get_support().len());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_invalid_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![("name", s("acme/package")), ("version", s("AA"))]);
+
+ let err = loader.load(config, None).unwrap_err();
+ assert_eq!(
+ "Failed to normalize version for package \"acme/package\": Invalid version string \"AA\"",
+ err.to_string()
+ );
}
diff --git a/crates/shirabe/tests/package/loader/root_package_loader_test.rs b/crates/shirabe/tests/package/loader/root_package_loader_test.rs
index 82d60ba..e78967e 100644
--- a/crates/shirabe/tests/package/loader/root_package_loader_test.rs
+++ b/crates/shirabe/tests/package/loader/root_package_loader_test.rs
@@ -4,32 +4,157 @@
// ProcessExecutor / VersionGuesser or require constraints whose parsing goes through a
// look-around regex the regex crate cannot compile.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::config::Config;
+use shirabe::io::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::package::loader::RootPackageLoader;
+use shirabe::package::version::{VersionGuesser, VersionParser};
+use shirabe::package::{STABILITY_ALPHA, STABILITY_DEV, STABILITY_RC};
+use shirabe::repository::RepositoryManager;
+use shirabe::util::http_downloader::HttpDownloader;
+use shirabe::util::process_executor::ProcessExecutor;
+use shirabe_php_shim::PhpMixed;
+
+fn null_io() -> Rc<RefCell<dyn IOInterface>> {
+ Rc::new(RefCell::new(NullIO::new()))
+}
+
+fn http_downloader(
+ io: &Rc<RefCell<dyn IOInterface>>,
+ config: &Rc<RefCell<Config>>,
+) -> Rc<RefCell<HttpDownloader>> {
+ Rc::new(RefCell::new(HttpDownloader::new(
+ io.clone(),
+ config.clone(),
+ IndexMap::new(),
+ true,
+ )))
+}
+
#[test]
-#[ignore = "RootPackageLoader::load parses require constraints via a look-around regex; mocks RepositoryManager"]
+#[ignore]
fn test_stability_flags_parsing() {
- todo!()
+ let io = null_io();
+ let config = Rc::new(RefCell::new(Config::new(true, None)));
+ {
+ let mut cfg = IndexMap::new();
+ cfg.insert(
+ "repositories".to_string(),
+ PhpMixed::Array({
+ let mut m = IndexMap::new();
+ m.insert("packagist".to_string(), PhpMixed::Bool(false));
+ m
+ }),
+ );
+ config.borrow_mut().merge(&cfg, "test");
+ }
+
+ let manager = Rc::new(RefCell::new(RepositoryManager::new(
+ io.clone(),
+ config.clone(),
+ http_downloader(&io, &config),
+ None,
+ None,
+ )));
+
+ let mut process_executor = ProcessExecutor::new(Some(io.clone()));
+ process_executor.enable_async();
+ let guesser = VersionGuesser::new(
+ config.clone(),
+ Rc::new(RefCell::new(process_executor)),
+ VersionParser::new(),
+ Some(io.clone()),
+ );
+
+ let mut loader = RootPackageLoader::new(manager, config.clone(), None, Some(guesser), None);
+
+ let mut data = IndexMap::new();
+ data.insert(
+ "require".to_string(),
+ PhpMixed::Array({
+ let mut m = IndexMap::new();
+ m.insert(
+ "foo/bar".to_string(),
+ PhpMixed::String("~2.1.0-beta2".to_string()),
+ );
+ m.insert(
+ "bar/baz".to_string(),
+ PhpMixed::String("1.0.x-dev as 1.2.0".to_string()),
+ );
+ m.insert(
+ "qux/quux".to_string(),
+ PhpMixed::String("1.0.*@rc".to_string()),
+ );
+ m.insert(
+ "zux/complex".to_string(),
+ PhpMixed::String("~1.0,>=1.0.2@dev".to_string()),
+ );
+ m.insert(
+ "or/op".to_string(),
+ PhpMixed::String("^2.0@dev || ^2.0@dev".to_string()),
+ );
+ m.insert(
+ "multi/lowest-wins".to_string(),
+ PhpMixed::String("^2.0@rc || >=3.0@dev , ~3.5@alpha".to_string()),
+ );
+ m.insert(
+ "or/op-without-flags".to_string(),
+ PhpMixed::String("dev-master || 2.0 , ~3.5-alpha".to_string()),
+ );
+ m.insert(
+ "or/op-without-flags2".to_string(),
+ PhpMixed::String("3.0-beta || 2.0 , ~3.5-alpha".to_string()),
+ );
+ m
+ }),
+ );
+ data.insert(
+ "minimum-stability".to_string(),
+ PhpMixed::String("alpha".to_string()),
+ );
+
+ let package = loader
+ .load(data, "Composer\\Package\\RootPackage", None)
+ .unwrap();
+ let package = package.as_root().unwrap();
+
+ assert_eq!("alpha", package.get_minimum_stability());
+
+ let mut expected = IndexMap::new();
+ expected.insert("bar/baz".to_string(), STABILITY_DEV);
+ expected.insert("qux/quux".to_string(), STABILITY_RC);
+ expected.insert("zux/complex".to_string(), STABILITY_DEV);
+ expected.insert("or/op".to_string(), STABILITY_DEV);
+ expected.insert("multi/lowest-wins".to_string(), STABILITY_DEV);
+ expected.insert("or/op-without-flags".to_string(), STABILITY_DEV);
+ expected.insert("or/op-without-flags2".to_string(), STABILITY_ALPHA);
+ assert_eq!(expected, package.get_stability_flags());
}
#[test]
-#[ignore = "mocks RepositoryManager and a ProcessExecutor returning a non-zero git result"]
+#[ignore = "requires getProcessExecutorMock with expects(['return' => 1]); no ProcessExecutorMock mocking infrastructure exists"]
fn test_no_version_is_visible_in_pretty_version() {
todo!()
}
#[test]
-#[ignore = "mocks RepositoryManager and a VersionGuesser returning a fixed guessed version"]
+#[ignore = "requires getMockBuilder VersionGuesser mock with guessVersion expectation; no VersionGuesser mocking infrastructure exists"]
fn test_pretty_version_for_root_package_in_version_branch() {
todo!()
}
#[test]
-#[ignore = "mocks RepositoryManager and a ProcessExecutor feeding git branch output"]
+#[ignore = "requires getProcessExecutorMock with expects() git command expectations; no ProcessExecutorMock mocking infrastructure exists"]
fn test_feature_branch_pretty_version() {
todo!()
}
#[test]
-#[ignore = "mocks RepositoryManager and a ProcessExecutor feeding git branch output"]
+#[ignore = "requires getProcessExecutorMock with expects() git command expectations; no ProcessExecutorMock mocking infrastructure exists"]
fn test_non_feature_branch_pretty_version() {
todo!()
}
diff --git a/crates/shirabe/tests/package/loader/validating_array_loader_test.rs b/crates/shirabe/tests/package/loader/validating_array_loader_test.rs
index 9858df1..db5ff07 100644
--- a/crates/shirabe/tests/package/loader/validating_array_loader_test.rs
+++ b/crates/shirabe/tests/package/loader/validating_array_loader_test.rs
@@ -1,27 +1,1029 @@
//! ref: composer/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php
-// ValidatingArrayLoader wraps ArrayLoader, whose constraint parsing uses a look-around
-// regex the regex crate cannot compile; the success/warning data sets are large.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::package::handle::PackageInterfaceHandle;
+use shirabe::package::loader::{InvalidPackageException, LoaderInterface, ValidatingArrayLoader};
+use shirabe_php_shim::PhpMixed;
+
+#[path = "../../common/test_case.rs"]
+mod test_case;
+
+fn s(v: &str) -> PhpMixed {
+ PhpMixed::String(v.to_string())
+}
+
+fn i(v: i64) -> PhpMixed {
+ PhpMixed::Int(v)
+}
+
+fn b(v: bool) -> PhpMixed {
+ PhpMixed::Bool(v)
+}
+
+/// Build a PHP assoc array (string-keyed). The impl reads every PHP `array`,
+/// list or assoc, via `PhpMixed::as_array`, so both shapes are `PhpMixed::Array`.
+fn arr(entries: Vec<(&str, PhpMixed)>) -> PhpMixed {
+ let mut m = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ PhpMixed::Array(m)
+}
+
+/// Build a PHP list array as a `PhpMixed::Array` with sequential string keys.
+fn list(items: Vec<PhpMixed>) -> PhpMixed {
+ let mut m = IndexMap::new();
+ for (idx, v) in items.into_iter().enumerate() {
+ m.insert(idx.to_string(), v);
+ }
+ PhpMixed::Array(m)
+}
+
+fn config(entries: Vec<(&str, PhpMixed)>) -> IndexMap<String, PhpMixed> {
+ let mut m = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ m
+}
+
+type Calls = Rc<RefCell<Vec<IndexMap<String, PhpMixed>>>>;
+
+/// Mock LoaderInterface recording every `load` invocation, mirroring PHPUnit's
+/// `expects($this->once())->method('load')->with(...)`.
+#[derive(Debug)]
+struct MockLoader {
+ calls: Calls,
+}
+
+impl MockLoader {
+ fn new() -> (Self, Calls) {
+ let calls: Calls = Rc::new(RefCell::new(Vec::new()));
+ (
+ MockLoader {
+ calls: calls.clone(),
+ },
+ calls,
+ )
+ }
+}
+
+impl LoaderInterface for MockLoader {
+ fn load(
+ &self,
+ config: IndexMap<String, PhpMixed>,
+ _class: Option<String>,
+ ) -> anyhow::Result<PackageInterfaceHandle> {
+ self.calls.borrow_mut().push(config);
+ Ok(test_case::get_package("mock/mock", "1.0.0"))
+ }
+
+ fn as_any(&self) -> &dyn std::any::Any {
+ self
+ }
+}
+
+fn invalid_naming_error(name: &str) -> Vec<String> {
+ vec![format!(
+ "name : {} is invalid, it should have a vendor name, a forward slash, and a package name. The vendor and package name can be words separated by -, . or _. The complete name should match \"^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]?|-{{0,2}})[a-z0-9]+)*$\".",
+ name
+ )]
+}
+
+/// ref: ValidatingArrayLoaderTest::successProvider
+fn success_provider() -> Vec<IndexMap<String, PhpMixed>> {
+ vec![
+ // minimal
+ config(vec![("name", s("foo/bar"))]),
+ // complete
+ config(vec![
+ ("name", s("foo/bar")),
+ ("description", s("Foo bar")),
+ ("version", s("1.0.0")),
+ ("type", s("library")),
+ (
+ "keywords",
+ list(vec![s("a"), s("b_c"), s("D E"), s("éîüø"), s("微信")]),
+ ),
+ ("homepage", s("https://foo.com")),
+ ("time", s("2010-10-10T10:10:10+00:00")),
+ ("license", list(vec![s("MIT"), s("WTFPL")])),
+ (
+ "authors",
+ list(vec![
+ arr(vec![
+ ("name", s("Alice")),
+ ("email", s("alice@example.org")),
+ ("role", s("Lead")),
+ ("homepage", s("http://example.org")),
+ ]),
+ arr(vec![("name", s("Bob")), ("homepage", s(""))]),
+ ]),
+ ),
+ (
+ "support",
+ arr(vec![
+ ("email", s("mail@example.org")),
+ ("issues", s("http://example.org/")),
+ ("forum", s("http://example.org/")),
+ ("wiki", s("http://example.org/")),
+ ("source", s("http://example.org/")),
+ ("irc", s("irc://example.org/example")),
+ ("rss", s("http://example.org/rss")),
+ ("chat", s("http://example.org/chat")),
+ ("security", s("https://example.org/security")),
+ ]),
+ ),
+ (
+ "funding",
+ list(vec![
+ arr(vec![
+ ("type", s("example")),
+ ("url", s("https://example.org/fund")),
+ ]),
+ arr(vec![("url", s("https://example.org/fund"))]),
+ ]),
+ ),
+ (
+ "require",
+ arr(vec![
+ ("a/b", s("1.*")),
+ ("b/c", s("~2")),
+ ("example/pkg", s(">2.0-dev,<2.4-dev")),
+ ("composer-runtime-api", s("*")),
+ ]),
+ ),
+ (
+ "require-dev",
+ arr(vec![
+ ("a/b", s("1.*")),
+ ("b/c", s("*")),
+ ("example/pkg", s(">2.0-dev,<2.4-dev")),
+ ]),
+ ),
+ (
+ "conflict",
+ arr(vec![
+ ("a/bx", s("1.*")),
+ ("b/cx", s(">2.7")),
+ ("example/pkgx", s(">2.0-dev,<2.4-dev")),
+ ]),
+ ),
+ (
+ "replace",
+ arr(vec![
+ ("a/b", s("1.*")),
+ ("example/pkg", s(">2.0-dev,<2.4-dev")),
+ ]),
+ ),
+ (
+ "provide",
+ arr(vec![
+ ("a/b", s("1.*")),
+ ("example/pkg", s(">2.0-dev,<2.4-dev")),
+ ]),
+ ),
+ (
+ "suggest",
+ arr(vec![("foo/bar", s("Foo bar is very useful"))]),
+ ),
+ (
+ "autoload",
+ arr(vec![
+ (
+ "psr-0",
+ arr(vec![("Foo\\Bar", s("src/")), ("", s("fallback/libs/"))]),
+ ),
+ ("classmap", list(vec![s("dir/"), s("dir2/file.php")])),
+ ("files", list(vec![s("functions.php")])),
+ ]),
+ ),
+ ("include-path", list(vec![s("lib/")])),
+ ("target-dir", s("Foo/Bar")),
+ ("minimum-stability", s("dev")),
+ (
+ "repositories",
+ list(vec![arr(vec![
+ ("type", s("composer")),
+ ("url", s("https://repo.packagist.org/")),
+ ])]),
+ ),
+ (
+ "config",
+ arr(vec![
+ ("bin-dir", s("bin")),
+ ("vendor-dir", s("vendor")),
+ ("process-timeout", i(10000)),
+ ]),
+ ),
+ (
+ "archive",
+ arr(vec![(
+ "exclude",
+ list(vec![s("/foo/bar"), s("baz"), s("!/foo/bar/baz")]),
+ )]),
+ ),
+ (
+ "scripts",
+ arr(vec![
+ ("post-update-cmd", s("Foo\\Bar\\Baz::doSomething")),
+ (
+ "post-install-cmd",
+ list(vec![s("Foo\\Bar\\Baz::doSomething")]),
+ ),
+ ]),
+ ),
+ (
+ "extra",
+ arr(vec![
+ (
+ "random",
+ arr(vec![("stuff", arr(vec![("deeply", s("nested"))]))]),
+ ),
+ (
+ "branch-alias",
+ arr(vec![
+ ("dev-master", s("2.0-dev")),
+ ("dev-old", s("1.0.x-dev")),
+ ("3.x-dev", s("3.1.x-dev")),
+ ]),
+ ),
+ ]),
+ ),
+ ("bin", list(vec![s("bin/foo"), s("bin/bar")])),
+ (
+ "transport-options",
+ arr(vec![(
+ "ssl",
+ arr(vec![("local_cert", s("/opt/certs/test.pem"))]),
+ )]),
+ ),
+ ]),
+ // test bin as string
+ config(vec![("name", s("foo/bar")), ("bin", s("bin1"))]),
+ // package name with dashes
+ config(vec![("name", s("foo/bar-baz"))]),
+ config(vec![("name", s("foo/bar--baz"))]),
+ config(vec![("name", s("foo/b-ar--ba-z"))]),
+ config(vec![("name", s("npm-asset/angular--core"))]),
+ // refs as int or string
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "source",
+ arr(vec![
+ ("url", s("https://example.org")),
+ ("reference", i(1234)),
+ ("type", s("baz")),
+ ]),
+ ),
+ (
+ "dist",
+ arr(vec![
+ ("url", s("https://example.org")),
+ ("reference", s("foobar")),
+ ("type", s("baz")),
+ ]),
+ ),
+ ]),
+ // valid php-ext configuration
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![
+ ("extension-name", s("ext-xdebug")),
+ ("priority", i(80)),
+ ("support-zts", b(true)),
+ ("support-nts", b(false)),
+ ("build-path", s("my-extension-source")),
+ ("download-url-method", s("composer-default")),
+ ("os-families", list(vec![s("linux"), s("darwin")])),
+ (
+ "configure-options",
+ list(vec![
+ arr(vec![
+ ("name", s("enable-xdebug")),
+ ("needs-value", b(false)),
+ ("description", s("Enable xdebug support")),
+ ]),
+ arr(vec![
+ ("name", s("with-xdebug-path")),
+ ("needs-value", b(true)),
+ ]),
+ ]),
+ ),
+ ]),
+ ),
+ ]),
+ // valid php-ext with os-families-exclude
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext-zend")),
+ (
+ "php-ext",
+ arr(vec![("os-families-exclude", list(vec![s("windows")]))]),
+ ),
+ ]),
+ // valid php-ext with null build-path
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("build-path", PhpMixed::Null)])),
+ ]),
+ // valid php-ext with one download-url-method in a list
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![s("pre-packaged-binary")]),
+ )]),
+ ),
+ ]),
+ // valid php-ext with multiple download-url-methods
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![
+ s("pre-packaged-binary"),
+ s("pre-packaged-source"),
+ s("composer-default"),
+ ]),
+ )]),
+ ),
+ ]),
+ ]
+}
+
+/// ref: ValidatingArrayLoaderTest::testLoadSuccess
+#[ignore]
#[test]
-#[ignore = "ValidatingArrayLoader -> ArrayLoader parses constraints via a look-around regex the regex crate cannot compile"]
fn test_load_success() {
- todo!()
+ for cfg in success_provider() {
+ let (internal_loader, _calls) = MockLoader::new();
+ let mut loader = ValidatingArrayLoader::new(
+ Box::new(internal_loader),
+ true,
+ None,
+ ValidatingArrayLoader::CHECK_ALL,
+ );
+ loader
+ .load(cfg, "Composer\\Package\\CompletePackage")
+ .unwrap();
+ }
}
+/// ref: ValidatingArrayLoaderTest::errorProvider
+fn error_provider() -> Vec<(IndexMap<String, PhpMixed>, Vec<String>)> {
+ let mut data: Vec<(IndexMap<String, PhpMixed>, Vec<String>)> = Vec::new();
+
+ for invalid_name in ["foo", "foo/-bar-", "foo/-bar"] {
+ data.push((
+ config(vec![("name", s(invalid_name))]),
+ invalid_naming_error(invalid_name),
+ ));
+ }
+ for invalid_name in [
+ "fo--oo/bar",
+ "fo-oo/bar__baz",
+ "fo-oo/bar_.baz",
+ "foo/bar---baz",
+ ] {
+ data.push((
+ config(vec![("name", s(invalid_name))]),
+ invalid_naming_error(invalid_name),
+ ));
+ }
+
+ data.push((
+ config(vec![("name", s("foo/bar")), ("homepage", i(43))]),
+ vec!["homepage : should be a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("support", arr(vec![("source", list(vec![]))])),
+ ]),
+ vec!["support.source : invalid value, must be a string".to_string()],
+ ));
+ data.push((
+ config(vec![("name", s("foo/bar.json"))]),
+ vec!["name : foo/bar.json is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.".to_string()],
+ ));
+ data.push((
+ config(vec![("name", s("com1/foo"))]),
+ vec!["name : com1/foo is reserved, package and vendor names can not match any of: nul, con, prn, aux, com1, com2, com3, com4, com5, com6, com7, com8, com9, lpt1, lpt2, lpt3, lpt4, lpt5, lpt6, lpt7, lpt8, lpt9.".to_string()],
+ ));
+ data.push((
+ config(vec![("name", s("Foo/Bar"))]),
+ vec!["name : Foo/Bar is invalid, it should not contain uppercase characters. We suggest using foo/bar instead.".to_string()],
+ ));
+ data.push((
+ config(vec![("name", s("foo/bar")), ("autoload", s("strings"))]),
+ vec!["autoload : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("autoload", arr(vec![("psr0", arr(vec![("foo", s("src"))]))])),
+ ]),
+ vec!["autoload : invalid value (psr0), must be one of psr-0, psr-4, classmap, files, exclude-from-classmap".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("transport-options", s("test")),
+ ]),
+ vec!["transport-options : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "source",
+ arr(vec![
+ ("url", s("--foo")),
+ ("reference", s(" --bar")),
+ ("type", s("baz")),
+ ]),
+ ),
+ (
+ "dist",
+ arr(vec![
+ ("url", s(" --foox")),
+ ("reference", s("--barx")),
+ ("type", s("baz")),
+ ]),
+ ),
+ ]),
+ vec![
+ "dist.reference : must not start with a \"-\", \"--barx\" given".to_string(),
+ "dist.url : must not start with a \"-\", \" --foox\" given".to_string(),
+ "source.reference : must not start with a \"-\", \" --bar\" given".to_string(),
+ "source.url : must not start with a \"-\", \"--foo\" given".to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("require", arr(vec![("foo/Bar", s("1.*"))])),
+ ]),
+ vec!["require.foo/Bar : a package cannot set a require on itself".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("source", arr(vec![("url", i(1))])),
+ ("dist", arr(vec![("url", PhpMixed::Null)])),
+ ]),
+ vec![
+ "source.type : must be present".to_string(),
+ "source.url : should be a string, int given".to_string(),
+ "source.reference : must be present".to_string(),
+ "dist.type : must be present".to_string(),
+ "dist.url : must be present".to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("replace", list(vec![s("acme/bar")])),
+ ]),
+ vec!["replace.0 : invalid version constraint (Could not parse version constraint acme/bar: Invalid version string \"acme/bar\")".to_string()],
+ ));
+ data.push((
+ config(vec![("require", arr(vec![("acme/bar", s("^1.0"))]))]),
+ vec!["name : must be present".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("library")),
+ ("php-ext", arr(vec![("extension-name", s("ext-foobar"))])),
+ ]),
+ vec!["php-ext can only be set by packages of type \"php-ext\" or \"php-ext-zend\" which must be C extensions".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("extension-name", i(123))])),
+ ]),
+ vec!["php-ext.extension-name : should be a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("priority", s("invalid"))])),
+ ]),
+ vec!["php-ext.priority : should be an integer, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("support-zts", s("yes"))])),
+ ]),
+ vec!["php-ext.support-zts : should be a boolean, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("support-nts", i(1))])),
+ ]),
+ vec!["php-ext.support-nts : should be a boolean, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("build-path", i(123))])),
+ ]),
+ vec!["php-ext.build-path : should be a string or null, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("download-url-method", i(123))])),
+ ]),
+ vec!["php-ext.download-url-method : should be an array or a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![("download-url-method", s("invalid-method"))]),
+ ),
+ ]),
+ vec!["php-ext.download-url-method.0 : invalid value (invalid-method), must be one of composer-default, pre-packaged-source, pre-packaged-binary".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("download-url-method", list(vec![]))])),
+ ]),
+ vec!["php-ext.download-url-method : must contain at least one element".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![i(1), b(true), list(vec![])]),
+ )]),
+ ),
+ ]),
+ vec![
+ "php-ext.download-url-method.0 : should be a string, int given".to_string(),
+ "php-ext.download-url-method.1 : should be a string, bool given".to_string(),
+ "php-ext.download-url-method.2 : should be a string, array given".to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![s("invalid-method"), s("composer-default")]),
+ )]),
+ ),
+ ]),
+ vec!["php-ext.download-url-method.0 : invalid value (invalid-method), must be one of composer-default, pre-packaged-source, pre-packaged-binary".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![s("invalid-method"), s("another-invalid-method")]),
+ )]),
+ ),
+ ]),
+ vec![
+ "php-ext.download-url-method.0 : invalid value (invalid-method), must be one of composer-default, pre-packaged-source, pre-packaged-binary".to_string(),
+ "php-ext.download-url-method.1 : invalid value (another-invalid-method), must be one of composer-default, pre-packaged-source, pre-packaged-binary".to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![
+ ("os-families", list(vec![s("linux")])),
+ ("os-families-exclude", list(vec![s("windows")])),
+ ]),
+ ),
+ ]),
+ vec!["php-ext : os-families and os-families-exclude cannot both be specified".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families", s("linux"))])),
+ ]),
+ vec!["php-ext.os-families : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families", list(vec![]))])),
+ ]),
+ vec!["php-ext.os-families : must contain at least one element".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![("os-families", list(vec![s("invalid-os"), s("linux")]))]),
+ ),
+ ]),
+ vec!["php-ext.os-families.0 : invalid value (invalid-os), must be one of windows, bsd, darwin, solaris, linux, unknown".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families", list(vec![i(123)]))])),
+ ]),
+ vec!["php-ext.os-families.0 : should be a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families-exclude", s("windows"))])),
+ ]),
+ vec!["php-ext.os-families-exclude : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families-exclude", list(vec![]))])),
+ ]),
+ vec!["php-ext.os-families-exclude : must contain at least one element".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![("os-families-exclude", list(vec![s("invalid")]))]),
+ ),
+ ]),
+ vec!["php-ext.os-families-exclude.0 : invalid value (invalid), must be one of windows, bsd, darwin, solaris, linux, unknown".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("configure-options", s("invalid"))])),
+ ]),
+ vec!["php-ext.configure-options : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![("configure-options", list(vec![s("invalid")]))]),
+ ),
+ ]),
+ vec!["php-ext.configure-options.0 : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "configure-options",
+ list(vec![arr(vec![("description", s("test"))])]),
+ )]),
+ ),
+ ]),
+ vec!["php-ext.configure-options.0.name : must be present".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "configure-options",
+ list(vec![arr(vec![("name", i(123))])]),
+ )]),
+ ),
+ ]),
+ vec!["php-ext.configure-options.0.name : should be a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "configure-options",
+ list(vec![arr(vec![
+ ("name", s("valid-name")),
+ ("needs-value", s("yes")),
+ ])]),
+ )]),
+ ),
+ ]),
+ vec![
+ "php-ext.configure-options.0.needs-value : should be a boolean, string given"
+ .to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "configure-options",
+ list(vec![arr(vec![
+ ("name", s("valid-name")),
+ ("description", i(123)),
+ ])]),
+ )]),
+ ),
+ ]),
+ vec!["php-ext.configure-options.0.description : should be a string, int given".to_string()],
+ ));
+
+ data
+}
+
+/// ref: ValidatingArrayLoaderTest::testLoadFailureThrowsException
+#[ignore]
#[test]
-#[ignore = "ValidatingArrayLoader -> ArrayLoader parses constraints via a look-around regex the regex crate cannot compile"]
fn test_load_failure_throws_exception() {
- todo!()
+ for (cfg, mut expected_errors) in error_provider() {
+ let (internal_loader, _calls) = MockLoader::new();
+ let mut loader = ValidatingArrayLoader::new(
+ Box::new(internal_loader),
+ true,
+ None,
+ ValidatingArrayLoader::CHECK_ALL,
+ );
+ match loader.load(cfg, "Composer\\Package\\CompletePackage") {
+ Ok(_) => panic!("Expected exception to be thrown"),
+ Err(e) => {
+ let exception = e
+ .downcast_ref::<InvalidPackageException>()
+ .expect("Expected InvalidPackageException");
+ let mut errors: Vec<String> = exception.get_errors().to_vec();
+ expected_errors.sort();
+ errors.sort();
+ assert_eq!(expected_errors, errors);
+ }
+ }
+ }
}
+/// ref: ValidatingArrayLoaderTest::warningProvider
+/// Returns (config, expected_warnings, must_check, expected_array).
+fn warning_provider() -> Vec<(
+ IndexMap<String, PhpMixed>,
+ Vec<String>,
+ bool,
+ Option<IndexMap<String, PhpMixed>>,
+)> {
+ vec![
+ (
+ config(vec![("name", s("foo/bar")), ("homepage", s("foo:bar"))]),
+ vec!["homepage : invalid value (foo:bar), must be an http/https URL".to_string()],
+ true,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "support",
+ arr(vec![
+ ("source", s("foo:bar")),
+ ("forum", s("foo:bar")),
+ ("issues", s("foo:bar")),
+ ("wiki", s("foo:bar")),
+ ("chat", s("foo:bar")),
+ ("security", s("foo:bar")),
+ ]),
+ ),
+ ]),
+ vec![
+ "support.source : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.forum : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.issues : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.wiki : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.chat : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.security : invalid value (foo:bar), must be an http/https URL".to_string(),
+ ],
+ true,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "require",
+ arr(vec![
+ ("foo/baz", s("*")),
+ ("bar/baz", s(">=1.0")),
+ ("bar/hacked", s("@stable")),
+ ("bar/woo", s("1.0.0")),
+ ]),
+ ),
+ ]),
+ vec![
+ "require.foo/baz : unbound version constraints (*) should be avoided".to_string(),
+ "require.bar/baz : unbound version constraints (>=1.0) should be avoided"
+ .to_string(),
+ "require.bar/hacked : unbound version constraints (@stable) should be avoided"
+ .to_string(),
+ "require.bar/woo : exact version constraints (1.0.0) should be avoided if the package follows semantic versioning".to_string(),
+ ],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "require",
+ arr(vec![
+ ("foo/baz", s(">1, <0.5")),
+ ("bar/baz", s("dev-main, >0.5")),
+ ]),
+ ),
+ ]),
+ vec![
+ "require.foo/baz : this version constraint cannot possibly match anything (>1, <0.5)".to_string(),
+ "require.bar/baz : this version constraint cannot possibly match anything (dev-main, >0.5)".to_string(),
+ ],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ ("require", arr(vec![("bar/unstable", s("0.3.0"))])),
+ ]),
+ vec![],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "extra",
+ arr(vec![(
+ "branch-alias",
+ arr(vec![("5.x-dev", s("3.1.x-dev"))]),
+ )]),
+ ),
+ ]),
+ vec!["extra.branch-alias.5.x-dev : the target branch (3.1.x-dev) is not a valid numeric alias for this version".to_string()],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "extra",
+ arr(vec![("branch-alias", arr(vec![("5.x-dev", s("3.1-dev"))]))]),
+ ),
+ ]),
+ vec!["extra.branch-alias.5.x-dev : the target branch (3.1-dev) is not a valid numeric alias for this version".to_string()],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ ("require", arr(vec![("Foo/Baz", s("^1.0"))])),
+ ]),
+ vec!["require.Foo/Baz is invalid, it should not contain uppercase characters. Please use foo/baz instead.".to_string()],
+ false,
+ None,
+ ),
+ (
+ config(vec![("name", s("a/b")), ("license", s("XXXXX"))]),
+ vec![format!(
+ "License \"XXXXX\" is not a valid SPDX license identifier, see https://spdx.org/licenses/ if you use an open license.{}If the software is closed-source, you may use \"proprietary\" as license.",
+ shirabe_php_shim::PHP_EOL
+ )],
+ true,
+ Some(config(vec![
+ ("name", s("a/b")),
+ ("license", list(vec![s("XXXXX")])),
+ ])),
+ ),
+ (
+ config(vec![
+ ("name", s("a/b")),
+ ("license", list(vec![arr(vec![("author", s("bar"))]), s("MIT")])),
+ ]),
+ vec!["License {\"author\":\"bar\"} should be a string.".to_string()],
+ true,
+ Some(config(vec![
+ ("name", s("a/b")),
+ ("license", list(vec![s("MIT")])),
+ ])),
+ ),
+ ]
+}
+
+/// ref: ValidatingArrayLoaderTest::testLoadWarnings
+#[ignore]
#[test]
-#[ignore = "ValidatingArrayLoader -> ArrayLoader parses constraints via a look-around regex the regex crate cannot compile"]
fn test_load_warnings() {
- todo!()
+ for (cfg, mut expected_warnings, _must_check, _expected_array) in warning_provider() {
+ let (internal_loader, _calls) = MockLoader::new();
+ let mut loader = ValidatingArrayLoader::new(
+ Box::new(internal_loader),
+ true,
+ None,
+ ValidatingArrayLoader::CHECK_ALL,
+ );
+ loader
+ .load(cfg, "Composer\\Package\\CompletePackage")
+ .unwrap();
+ let mut warnings: Vec<String> = loader.get_warnings().to_vec();
+ expected_warnings.sort();
+ warnings.sort();
+ assert_eq!(expected_warnings, warnings);
+ }
}
+/// ref: ValidatingArrayLoaderTest::testLoadSkipsWarningDataWhenIgnoringErrors
+#[ignore]
#[test]
-#[ignore = "ValidatingArrayLoader -> ArrayLoader parses constraints via a look-around regex the regex crate cannot compile"]
fn test_load_skips_warning_data_when_ignoring_errors() {
- todo!()
+ for (mut cfg, _expected_warnings, must_check, expected_array) in warning_provider() {
+ if !must_check {
+ assert!(true);
+ continue;
+ }
+ let (internal_loader, calls) = MockLoader::new();
+ let expected = expected_array.unwrap_or_else(|| config(vec![("name", s("a/b"))]));
+
+ let mut loader = ValidatingArrayLoader::new(
+ Box::new(internal_loader),
+ true,
+ None,
+ ValidatingArrayLoader::CHECK_ALL,
+ );
+ cfg.insert("name".to_string(), s("a/b"));
+ loader
+ .load(cfg, "Composer\\Package\\CompletePackage")
+ .unwrap();
+
+ // The mock recorded exactly the (post-validation) config passed to the inner loader.
+ let recorded = calls.borrow();
+ assert_eq!(recorded.len(), 1);
+ assert_eq!(recorded[0], expected);
+ }
}
diff --git a/crates/shirabe/tests/package/locker_test.rs b/crates/shirabe/tests/package/locker_test.rs
index 7b5d39f..c793a8a 100644
--- a/crates/shirabe/tests/package/locker_test.rs
+++ b/crates/shirabe/tests/package/locker_test.rs
@@ -4,61 +4,61 @@
// mocked ProcessExecutor to drive lock read/write and freshness checks; mocking is not
// available here.
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (exists/read) which is not available"]
fn test_is_locked() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (exists) which is not available"]
fn test_get_not_locked_packages() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (exists/read) which is not available"]
fn test_get_locked_packages() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (write) which is not available"]
fn test_set_lock_data() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile and PackageInterface (createPackageMock) which is not available"]
fn test_lock_bad_packages() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh_false() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh_with_content_hash() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh_with_content_hash_and_no_hash() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh_false_with_content_hash() {
todo!()
}
diff --git a/crates/shirabe/tests/package/version/version_guesser_test.rs b/crates/shirabe/tests/package/version/version_guesser_test.rs
index 75d4ae0..76cd672 100644
--- a/crates/shirabe/tests/package/version/version_guesser_test.rs
+++ b/crates/shirabe/tests/package/version/version_guesser_test.rs
@@ -1,5 +1,13 @@
//! ref: composer/tests/Composer/Test/Package/Version/VersionGuesserTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use shirabe::config::Config;
+use shirabe::package::version::{VersionGuesser, VersionParser};
+use shirabe::util::platform::Platform;
+use shirabe::util::process_executor::ProcessExecutor;
+
#[allow(dead_code)]
fn set_up() {
// Resets GitUtil's cached `version` static via ReflectionProperty; the static is not
@@ -23,94 +31,113 @@ impl Drop for TearDown {
// These drive VersionGuesser with a mocked ProcessExecutor feeding git/hg command output;
// mocking is not available here.
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_hg_guess_version_returns_data() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_returns_data() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_does_not_see_custom_default_branch_as_non_feature_branch() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_reads_and_respects_non_feature_branches_configuration_for_arbitrary_naming() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_reads_and_respects_non_feature_branches_configuration_for_arbitrary_naming_regex()
{
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_reads_and_respects_non_feature_branches_configuration_for_arbitrary_naming_when_on_non_feature_branch()
{
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_detached_head_becomes_dev_hash() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_detached_fetch_head_becomes_dev_hash_git2() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_detached_commit_head_becomes_dev_hash_git2() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_tag_becomes_version() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_tag_becomes_pretty_version() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_invalid_tag_becomes_version() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_numeric_branches_show_nicely() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_remote_branches_are_selected() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_get_root_version_from_env() {
- todo!()
+ // @dataProvider rootEnvVersionsProvider
+ let root_env_versions: Vec<(&str, &str)> = vec![
+ ("1.0-dev", "1.0.x-dev"),
+ ("1.0.x-dev", "1.0.x-dev"),
+ ("1-dev", "1.x-dev"),
+ ("1.x-dev", "1.x-dev"),
+ ("1.0.0", "1.0.0"),
+ ];
+
+ for (env, expected_version) in root_env_versions {
+ Platform::put_env("COMPOSER_ROOT_VERSION", env);
+ let config = Rc::new(RefCell::new(Config::new(true, None)));
+ let process = Rc::new(RefCell::new(ProcessExecutor::new(None)));
+ let guesser = VersionGuesser::new(config, process, VersionParser::new(), None);
+ assert_eq!(
+ expected_version,
+ guesser.get_root_version_from_env().unwrap()
+ );
+ Platform::clear_env("COMPOSER_ROOT_VERSION");
+ }
}
diff --git a/crates/shirabe/tests/package/version/version_selector_test.rs b/crates/shirabe/tests/package/version/version_selector_test.rs
index fd426ce..fa288cd 100644
--- a/crates/shirabe/tests/package/version/version_selector_test.rs
+++ b/crates/shirabe/tests/package/version/version_selector_test.rs
@@ -3,79 +3,79 @@
// VersionSelector ranks candidate packages whose versions/constraints are parsed through a
// look-around regex the regex crate cannot compile; the setup also mocks a repository.
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned_that_matches_php_requirements() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned_that_matches_ext_requirements() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned_that_matches_platform_ext() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned_that_matches_composer_requirements() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_most_stable_version_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages with willReturnOnConsecutiveCalls; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_most_stable_version_is_returned_regardless_of_order() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_highest_version_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_highest_version_matching_stability_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_most_stable_unstable_version_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_default_branch_alias_is_never_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return an empty list; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_false_returned_on_no_packages() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "branch-alias cases need Package::set_extra, exposed only on RootPackageHandle, not on the PackageHandle/PackageInterfaceHandle passed to find_recommended_require_version"]
fn test_find_recommended_require_version() {
todo!()
}
diff --git a/crates/shirabe/tests/platform/hhvm_detector_test.rs b/crates/shirabe/tests/platform/hhvm_detector_test.rs
index 1b35450..12a966a 100644
--- a/crates/shirabe/tests/platform/hhvm_detector_test.rs
+++ b/crates/shirabe/tests/platform/hhvm_detector_test.rs
@@ -1,6 +1,11 @@
//! ref: composer/tests/Composer/Test/Platform/HhvmDetectorTest.php
use shirabe::platform::hhvm_detector::HhvmDetector;
+use shirabe::util::Platform;
+use shirabe::util::ProcessExecutor;
+use shirabe_external_packages::symfony::process::ExecutableFinder;
+use shirabe_php_shim::{PhpMixed, defined};
+use shirabe_semver::version_parser::VersionParser;
fn set_up() -> HhvmDetector {
let hhvm_detector = HhvmDetector::new(None, None);
@@ -9,15 +14,55 @@ fn set_up() -> HhvmDetector {
}
#[test]
-#[ignore = "skipped unless running under HHVM (HHVM_VERSION_ID defined), which never holds here"]
+#[ignore = "requires HHVM_VERSION_ID constant, which the shim does not define"]
fn test_hhvm_version_when_executing_in_hhvm() {
let _hhvm_detector = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "needs an installed hhvm executable plus ExecutableFinder/ProcessExecutor; skipped in PHP when hhvm is absent"]
fn test_hhvm_version_when_executing_in_php() {
- let _hhvm_detector = set_up();
- todo!()
+ let mut hhvm_detector = set_up();
+ if defined("HHVM_VERSION_ID") {
+ // markTestSkipped('Running with HHVM')
+ return;
+ }
+ if Platform::is_windows() {
+ // markTestSkipped('Test does not run on Windows')
+ return;
+ }
+ let finder = ExecutableFinder::new();
+ let hhvm = finder.find("hhvm", None, &[]);
+ let hhvm = match hhvm {
+ Some(hhvm) => hhvm,
+ None => {
+ // markTestSkipped('HHVM is not installed')
+ return;
+ }
+ };
+
+ let detected_version = hhvm_detector.get_version();
+ assert!(detected_version.is_some(), "Failed to detect HHVM version");
+ let detected_version = detected_version.unwrap();
+
+ let mut process = ProcessExecutor::new(None);
+ let mut version = PhpMixed::Null;
+ let cmd = format!(
+ "{} --php -d hhvm.jit=0 -r \"echo HHVM_VERSION;\" 2>/dev/null",
+ ProcessExecutor::escape(&hhvm)
+ );
+ let exit_code = process
+ .execute(cmd.as_str(), Some(&mut version), ())
+ .unwrap();
+ assert_eq!(0, exit_code);
+
+ let version = version
+ .as_string()
+ .map(|s| s.to_string())
+ .unwrap_or_default();
+ assert_eq!(
+ VersionParser.normalize(&version, None).unwrap(),
+ VersionParser.normalize(&detected_version, None).unwrap()
+ );
}
diff --git a/crates/shirabe/tests/plugin/plugin_installer_test.rs b/crates/shirabe/tests/plugin/plugin_installer_test.rs
index 6442b5c..6f67c68 100644
--- a/crates/shirabe/tests/plugin/plugin_installer_test.rs
+++ b/crates/shirabe/tests/plugin/plugin_installer_test.rs
@@ -23,98 +23,98 @@ impl Drop for TearDown {
// The plugin system requires the PHP runtime to load and instantiate plugin classes; the
// PluginManager/PluginInstaller is intentionally not implemented yet (TODO(plugin)).
+#[ignore = "PluginInstaller and runtime loading of fixture plugin PHP classes (plugin-v1) are not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_install_new_plugin() {
todo!()
}
+#[ignore = "PluginInstaller and runtime loading of fixture plugin PHP classes are not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_install_plugin_with_root_package_having_files_autoload() {
todo!()
}
+#[ignore = "PluginInstaller and runtime loading of fixture plugin PHP classes (plugin-v4) are not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_install_multiple_plugins() {
todo!()
}
+#[ignore = "PluginInstaller.update and runtime plugin class loading/deactivation are not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_upgrade_with_new_class_name() {
todo!()
}
+#[ignore = "PluginInstaller.uninstall and runtime plugin class loading/uninstall hook are not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_uninstall() {
todo!()
}
+#[ignore = "PluginInstaller.update and runtime plugin class loading/deactivation are not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_upgrade_with_same_class_name() {
todo!()
}
+#[ignore = "PluginInstaller and runtime loading of fixture plugin PHP classes are not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_register_plugin_only_one_time() {
todo!()
}
+#[ignore = "Requires mocking getPluginApiVersion and runtime loading of fixture plugin PHP classes; not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_star_plugin_version_works_with_any_api_version() {
todo!()
}
+#[ignore = "Requires mocking getPluginApiVersion and runtime loading of fixture plugin PHP classes; not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_plugin_constraint_works_only_with_certain_api_version() {
todo!()
}
+#[ignore = "Requires mocking getPluginApiVersion and runtime loading of fixture plugin PHP classes; not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_plugin_range_constraints_work_only_with_certain_api_version() {
todo!()
}
+#[ignore = "get_plugin_capabilities and runtime loading of fixture plugin/capability PHP classes (plugin-v8) are not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_command_provider_capability() {
todo!()
}
+#[ignore = "Requires a PHP-runtime mock of PluginInterface and get_plugin_capability; not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_incapable_plugin_is_correctly_detected() {
todo!()
}
+#[ignore = "Requires runtime instantiation of Mock\\Capability via get_plugin_capability; not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_capability_implements_composer_plugin_api_class_and_is_constructed_with_args() {
todo!()
}
+#[ignore = "Requires runtime get_plugin_capability with a mocked Capable plugin and PHP-class-name capability lookup; not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_querying_with_invalid_capability_class_name_throws() {
todo!()
}
+#[ignore = "Requires runtime get_plugin_capability with a mocked Capable plugin; not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_querying_non_provided_capability_returns_null_safely() {
todo!()
}
+#[ignore = "Requires runtime get_plugin_capability with PHP-class-name capability lookup; not implemented (TODO(plugin))"]
#[test]
-#[ignore = "the plugin API (PluginManager/PluginInstaller loading PHP plugin classes) is not implemented yet"]
fn test_querying_with_non_existing_or_wrong_capability_class_types_throws() {
todo!()
}
diff --git a/crates/shirabe/tests/question/strict_confirmation_question_test.rs b/crates/shirabe/tests/question/strict_confirmation_question_test.rs
index 9045461..4444289 100644
--- a/crates/shirabe/tests/question/strict_confirmation_question_test.rs
+++ b/crates/shirabe/tests/question/strict_confirmation_question_test.rs
@@ -5,19 +5,19 @@
// validator are private, so they cannot be exercised directly either.
#[test]
-#[ignore = "needs Symfony QuestionHelper::ask with ArrayInput/StreamOutput, which are not ported"]
+#[ignore = "ArrayInput exposes no public set_stream (its inner Input is pub(crate)), and fopen returns PhpMixed which cannot be bridged to StreamOutput::new's PhpResource"]
fn test_ask_confirmation_bad_answer() {
todo!()
}
#[test]
-#[ignore = "needs Symfony QuestionHelper::ask with ArrayInput/StreamOutput, which are not ported"]
+#[ignore = "ArrayInput exposes no public set_stream (its inner Input is pub(crate)), and fopen returns PhpMixed which cannot be bridged to StreamOutput::new's PhpResource"]
fn test_ask_confirmation() {
todo!()
}
#[test]
-#[ignore = "needs Symfony QuestionHelper::ask with ArrayInput/StreamOutput, which are not ported"]
+#[ignore = "ArrayInput exposes no public set_stream (its inner Input is pub(crate)), and fopen returns PhpMixed which cannot be bridged to StreamOutput::new's PhpResource"]
fn test_ask_confirmation_with_custom_true_and_false_answer() {
todo!()
}
diff --git a/crates/shirabe/tests/repository/artifact_repository_test.rs b/crates/shirabe/tests/repository/artifact_repository_test.rs
index 5e70650..14475da 100644
--- a/crates/shirabe/tests/repository/artifact_repository_test.rs
+++ b/crates/shirabe/tests/repository/artifact_repository_test.rs
@@ -13,21 +13,21 @@ fn set_up() {
}
#[test]
-#[ignore = "ArtifactRepository reads archives via ZipArchive/PharData, which are todo!() in the php-shim"]
+#[ignore = "ArtifactRepository exposes no public get_packages(); it does not impl RepositoryInterface and initialize/scan_directory are private"]
fn test_extracts_configs_from_zip_archives() {
set_up();
todo!()
}
#[test]
-#[ignore = "ArtifactRepository reads archives via ZipArchive/PharData, which are todo!() in the php-shim"]
+#[ignore = "ArtifactRepository exposes no public get_packages(); it does not impl RepositoryInterface and initialize/scan_directory are private"]
fn test_absolute_repo_url_creates_absolute_url_packages() {
set_up();
todo!()
}
#[test]
-#[ignore = "ArtifactRepository reads archives via ZipArchive/PharData, which are todo!() in the php-shim"]
+#[ignore = "ArtifactRepository exposes no public get_packages(); it does not impl RepositoryInterface and initialize/scan_directory are private"]
fn test_relative_repo_url_creates_relative_url_packages() {
set_up();
todo!()
diff --git a/crates/shirabe/tests/repository/composer_repository_test.rs b/crates/shirabe/tests/repository/composer_repository_test.rs
index f600a55..d36c2e1 100644
--- a/crates/shirabe/tests/repository/composer_repository_test.rs
+++ b/crates/shirabe/tests/repository/composer_repository_test.rs
@@ -3,56 +3,56 @@
// These construct a ComposerRepository with a mocked HttpDownloader/IO/Config and parse
// provider/package data whose constraints go through a look-around regex; mocking is not
// available and a real HttpDownloader reaches curl_multi_init (todo!()).
+#[ignore = "needs PHPUnit getMockBuilder to override loadRootServerFile; no method-mocking framework ported"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_load_data() {
todo!()
}
+#[ignore = "needs getMockBuilder to override fetchFile plus ReflectionProperty/ReflectionMethod to set private props and invoke whatProvides; no mocking/reflection ported"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_what_provides() {
todo!()
}
+#[ignore = "needs getHttpDownloaderMock test helper (HttpDownloaderMock not ported); real HttpDownloader hits todo!() curl I/O"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_search_with_type() {
todo!()
}
+#[ignore = "needs getHttpDownloaderMock test helper (HttpDownloaderMock not ported); real HttpDownloader hits todo!() curl I/O"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_search_with_special_chars() {
todo!()
}
+#[ignore = "needs getHttpDownloaderMock test helper (HttpDownloaderMock not ported); real HttpDownloader hits todo!() curl I/O"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_search_with_abandoned_packages() {
todo!()
}
+#[ignore = "needs getMockBuilder HttpDownloader mock plus ReflectionObject getMethod/getProperty to set private url and invoke canonicalizeUrl; no mocking/reflection ported"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_canonicalize_url() {
todo!()
}
+#[ignore = "needs getHttpDownloaderMock test helper (HttpDownloaderMock not ported); real HttpDownloader hits todo!() curl I/O"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_get_provider_names_will_return_partial_package_names() {
todo!()
}
+#[ignore = "needs getHttpDownloaderMock test helper (HttpDownloaderMock not ported); real HttpDownloader hits todo!() curl I/O"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_get_security_advisories_assert_repository_http_options_are_used() {
todo!()
}
+#[ignore = "needs getHttpDownloaderMock test helper (HttpDownloaderMock not ported); real HttpDownloader hits todo!() curl I/O"]
#[test]
-#[ignore = "mocks HttpDownloader/IO (curl_multi_init todo!()) and parses constraints via a look-around regex"]
fn test_get_security_advisories_assert_repository_advisories_is_zero_indexed_array_with_consecutive_keys()
{
todo!()
diff --git a/crates/shirabe/tests/repository/filesystem_repository_test.rs b/crates/shirabe/tests/repository/filesystem_repository_test.rs
index a14804b..ae6e4ef 100644
--- a/crates/shirabe/tests/repository/filesystem_repository_test.rs
+++ b/crates/shirabe/tests/repository/filesystem_repository_test.rs
@@ -1,37 +1,161 @@
//! ref: composer/tests/Composer/Test/Repository/FilesystemRepositoryTest.php
+use indexmap::IndexMap;
+use shirabe::installed_versions::InstalledVersions;
+use shirabe::json::json_file::JsonFile;
+use shirabe::repository::RepositoryInterface;
+use shirabe::repository::filesystem_repository::FilesystemRepository;
+use shirabe_php_shim::PhpMixed;
+
+/// PHP mocks JsonFile::read()/exists(); without a mocking framework the canned read value is
+/// materialized as a real temp file whose decoded JSON reproduces the mock return value exactly.
+fn create_temp_json_file(contents: &str) -> String {
+ let mut path = std::env::temp_dir();
+ let unique = format!(
+ "shirabe_filesystemrepositorytest_{}_{}",
+ std::process::id(),
+ std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .unwrap()
+ .as_nanos()
+ );
+ path.push(unique);
+ std::fs::write(&path, contents.as_bytes()).unwrap();
+ path.to_str().unwrap().to_string()
+}
+
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_repository_read() {
- todo!()
+ let path = create_temp_json_file(
+ r#"[{"name": "package1", "version": "1.0.0-beta", "type": "vendor"}]"#,
+ );
+ let json = JsonFile::new(path, None, None).unwrap();
+
+ let mut repository = FilesystemRepository::new(json, false, None, None).unwrap();
+
+ let packages = repository.get_packages().unwrap();
+
+ assert_eq!(packages.len(), 1);
+ assert_eq!(packages[0].get_name(), "package1");
+ assert_eq!(packages[0].get_version(), "1.0.0.0-beta");
+ assert_eq!(packages[0].get_type(), "vendor");
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_corrupted_repository_file() {
- todo!()
+ // PHP mocks read() to return the scalar string 'foo'; a real file containing the JSON string
+ // "foo" decodes to the same value, which the repository rejects as a non-array package list.
+ let path = create_temp_json_file(r#""foo""#);
+ let json = JsonFile::new(path, None, None).unwrap();
+
+ let mut repository = FilesystemRepository::new(json, false, None, None).unwrap();
+
+ let result = repository.get_packages();
+ let err = result.unwrap_err();
+ assert!(
+ err.is::<shirabe::repository::InvalidRepositoryException>(),
+ "expected InvalidRepositoryException, got: {err}"
+ );
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_unexistent_repository_file() {
- todo!()
+ let mut path = std::env::temp_dir();
+ path.push(format!(
+ "shirabe_filesystemrepositorytest_missing_{}_{}",
+ std::process::id(),
+ std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .unwrap()
+ .as_nanos()
+ ));
+ let json = JsonFile::new(path.to_str().unwrap().to_string(), None, None).unwrap();
+
+ let mut repository = FilesystemRepository::new(json, false, None, None).unwrap();
+
+ let packages = repository.get_packages().unwrap();
+ assert_eq!(packages.len(), 0);
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore = "requires mocking InstallationManager::get_install_path; write() takes a concrete InstallationManager with no trait/seam to stub the canned per-package paths the PHP test relies on"]
fn test_repository_write() {
todo!()
}
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
+#[ignore = "requires mocking InstallationManager::get_install_path (concrete method, no stub seam) plus missing test helpers get_root_package and configure_links"]
fn test_repository_writes_installed_php() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "test body not yet ported (todo!() stub)"]
fn test_safely_load_installed_versions() {
- todo!()
+ let fixtures_dir = format!(
+ "{}/../../composer/tests/Composer/Test/Repository/Fixtures",
+ env!("CARGO_MANIFEST_DIR")
+ );
+ let path = format!("{}/installed_complex.php", fixtures_dir);
+
+ let result = FilesystemRepository::safely_load_installed_versions(&path);
+ assert!(result, "The file should be considered valid");
+
+ let raw_data = InstalledVersions::get_all_raw_data();
+ let raw_data = raw_data.last().cloned().unwrap();
+
+ let mut root: IndexMap<String, PhpMixed> = IndexMap::new();
+ root.insert(
+ "install_path".to_string(),
+ PhpMixed::String(format!("{}/./", fixtures_dir)),
+ );
+ root.insert(
+ "aliases".to_string(),
+ PhpMixed::List(vec![
+ PhpMixed::String("1.10.x-dev".to_string()),
+ PhpMixed::String("2.10.x-dev".to_string()),
+ ]),
+ );
+ root.insert("name".to_string(), PhpMixed::String("__root__".to_string()));
+ root.insert("true".to_string(), PhpMixed::Bool(true));
+ root.insert("false".to_string(), PhpMixed::Bool(false));
+ root.insert("null".to_string(), PhpMixed::Null);
+
+ let mut a_provider: IndexMap<String, PhpMixed> = IndexMap::new();
+ a_provider.insert(
+ "foo".to_string(),
+ PhpMixed::String("simple string/no backslash".to_string()),
+ );
+ a_provider.insert(
+ "install_path".to_string(),
+ PhpMixed::String(format!(
+ "{}/vendor/{{${{passthru('bash -i')}}}}",
+ fixtures_dir
+ )),
+ );
+ a_provider.insert("empty array".to_string(), PhpMixed::List(vec![]));
+
+ let mut c_c: IndexMap<String, PhpMixed> = IndexMap::new();
+ c_c.insert(
+ "install_path".to_string(),
+ PhpMixed::String("/foo/bar/ven/do{}r/c/c${}".to_string()),
+ );
+ c_c.insert("aliases".to_string(), PhpMixed::List(vec![]));
+ c_c.insert(
+ "reference".to_string(),
+ PhpMixed::String("{${passthru('bash -i')}} Foo\\Bar\n\ttab\u{0b}verticaltab\0".to_string()),
+ );
+
+ let mut versions: IndexMap<String, PhpMixed> = IndexMap::new();
+ versions.insert("a/provider".to_string(), PhpMixed::Array(a_provider));
+ versions.insert("c/c".to_string(), PhpMixed::Array(c_c));
+
+ let mut expected: IndexMap<String, PhpMixed> = IndexMap::new();
+ expected.insert("root".to_string(), PhpMixed::Array(root));
+ expected.insert("versions".to_string(), PhpMixed::Array(versions));
+
+ assert_eq!(raw_data, expected);
}
diff --git a/crates/shirabe/tests/repository/path_repository_test.rs b/crates/shirabe/tests/repository/path_repository_test.rs
index c2e8e72..c2cf892 100644
--- a/crates/shirabe/tests/repository/path_repository_test.rs
+++ b/crates/shirabe/tests/repository/path_repository_test.rs
@@ -5,50 +5,50 @@
// ported, so there is no way to drive these tests. The unversioned cases additionally
// require the VersionGuesser (git).
+#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"]
#[test]
-#[ignore = "PathRepository exposes no public getPackages/count/hasPackage (RepositoryInterface delegation not ported)"]
fn test_load_package_from_file_system_with_incorrect_path() {
todo!()
}
+#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"]
#[test]
-#[ignore = "PathRepository exposes no public getPackages/count/hasPackage (RepositoryInterface delegation not ported)"]
fn test_load_package_from_file_system_with_version() {
todo!()
}
+#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"]
#[test]
-#[ignore = "PathRepository exposes no public getPackages/count/hasPackage (RepositoryInterface delegation not ported)"]
fn test_load_package_from_file_system_without_version() {
todo!()
}
+#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"]
#[test]
-#[ignore = "PathRepository exposes no public getPackages/count/hasPackage (RepositoryInterface delegation not ported)"]
fn test_load_package_from_file_system_with_wildcard() {
todo!()
}
+#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"]
#[test]
-#[ignore = "PathRepository exposes no public getPackages/count/hasPackage (RepositoryInterface delegation not ported)"]
fn test_load_package_with_explicit_versions() {
todo!()
}
+#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"]
#[test]
-#[ignore = "PathRepository exposes no public getPackages/count/hasPackage (RepositoryInterface delegation not ported)"]
fn test_url_remains_relative() {
todo!()
}
+#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"]
#[test]
-#[ignore = "PathRepository exposes no public getPackages/count/hasPackage (RepositoryInterface delegation not ported)"]
fn test_reference_none() {
todo!()
}
+#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"]
#[test]
-#[ignore = "PathRepository exposes no public getPackages/count/hasPackage (RepositoryInterface delegation not ported)"]
fn test_reference_config() {
todo!()
}
diff --git a/crates/shirabe/tests/repository/platform_repository_test.rs b/crates/shirabe/tests/repository/platform_repository_test.rs
index d19b615..fb84fd6 100644
--- a/crates/shirabe/tests/repository/platform_repository_test.rs
+++ b/crates/shirabe/tests/repository/platform_repository_test.rs
@@ -1,40 +1,71 @@
//! ref: composer/tests/Composer/Test/Repository/PlatformRepositoryTest.php
+use shirabe::repository::PlatformRepository;
+
// These probe runtime/extension/library versions and assert the synthesized platform
// packages; the detection mocks ProcessExecutor/Runtime/HhvmDetector and the package
// versions are parsed through a look-around regex.
#[test]
-#[ignore = "not yet ported (platform detection mocks Runtime/ProcessExecutor; version parsing uses a look-around regex)"]
+#[ignore = "requires PHPUnit getMockBuilder mock of Composer\\Platform\\HhvmDetector (willReturn getVersion); Runtime/HhvmDetector are concrete structs with no mock/override mechanism"]
fn test_hhvm_package() {
todo!()
}
#[test]
-#[ignore = "not yet ported (platform detection mocks Runtime/ProcessExecutor; version parsing uses a look-around regex)"]
+#[ignore = "requires PHPUnit getMockBuilder mock of Composer\\Platform\\Runtime (willReturnCallback/willReturnMap for hasConstant/getConstant/invoke/getExtensions); no mocking framework and Runtime is a concrete struct"]
fn test_php_version() {
todo!()
}
#[test]
-#[ignore = "not yet ported (platform detection mocks Runtime/ProcessExecutor; version parsing uses a look-around regex)"]
+#[ignore = "requires PHPUnit getMockBuilder mock of Composer\\Platform\\Runtime (expects(once)/with/willReturn for invoke, willReturnCallback for getConstant); no mocking framework"]
fn test_inet_pton_regression() {
todo!()
}
#[test]
-#[ignore = "not yet ported (platform detection mocks Runtime/ProcessExecutor; version parsing uses a look-around regex)"]
+#[ignore = "requires PHPUnit getMockBuilder mock of Composer\\Platform\\Runtime (willReturnMap/willReturnCallback for getExtensions/getExtensionVersion/getExtensionInfo/invoke/hasConstant/getConstant/hasClass/construct) plus ResourceBundleStub/ImagickStub; no mocking framework"]
fn test_library_information() {
todo!()
}
#[test]
-#[ignore = "not yet ported (platform detection mocks Runtime/ProcessExecutor; version parsing uses a look-around regex)"]
+#[ignore = "requires PHPUnit getMockBuilder mock of Composer\\Platform\\Runtime (willReturnMap for getConstant/getExtensions); no mocking framework and Runtime is a concrete struct"]
fn test_composer_platform_version() {
todo!()
}
#[test]
-#[ignore = "not yet ported (platform detection mocks Runtime/ProcessExecutor; version parsing uses a look-around regex)"]
+#[ignore]
fn test_valid_platform_packages() {
- todo!()
+ let cases: Vec<(&str, bool)> = vec![
+ ("php", true),
+ ("php-debug", true),
+ ("php-ipv6", true),
+ ("php-64bit", true),
+ ("php-zts", true),
+ ("hhvm", true),
+ ("hhvm-foo", false),
+ ("ext-foo", true),
+ ("ext-123", true),
+ ("extfoo", false),
+ ("ext", false),
+ ("lib-foo", true),
+ ("lib-123", true),
+ ("libfoo", false),
+ ("lib", false),
+ ("composer", true),
+ ("composer-foo", false),
+ ("composer-plugin-api", true),
+ ("composer-plugin", false),
+ ("composer-runtime-api", true),
+ ("composer-runtime", false),
+ ];
+
+ for (package_name, expectation) in cases {
+ assert_eq!(
+ expectation,
+ PlatformRepository::is_platform_package(package_name)
+ );
+ }
}
diff --git a/crates/shirabe/tests/repository/repository_factory_test.rs b/crates/shirabe/tests/repository/repository_factory_test.rs
index 98e2c85..a0eb81f 100644
--- a/crates/shirabe/tests/repository/repository_factory_test.rs
+++ b/crates/shirabe/tests/repository/repository_factory_test.rs
@@ -5,7 +5,7 @@ use shirabe::repository::RepositoryFactory;
use shirabe_php_shim::PhpMixed;
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader/EventDispatcher and reads the private repositoryClasses via reflection; not portable"]
+#[ignore = "PHP test uses ReflectionProperty to read the private RepositoryManager::repository_classes field; no public accessor for repository_classes keys exists in the Rust impl"]
fn test_manager_with_all_repository_types() {
todo!()
}
diff --git a/crates/shirabe/tests/repository/repository_manager_test.rs b/crates/shirabe/tests/repository/repository_manager_test.rs
index dec018a..bb85d6a 100644
--- a/crates/shirabe/tests/repository/repository_manager_test.rs
+++ b/crates/shirabe/tests/repository/repository_manager_test.rs
@@ -4,7 +4,17 @@
// curl_multi_init, todo!()) with a mocked IO/Config/EventDispatcher and exercise repo
// creation/prepending/wrapping.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::config::Config;
+use shirabe::io::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::repository::{ArrayRepository, RepositoryInterfaceHandle, RepositoryManager};
use shirabe::util::filesystem::Filesystem;
+use shirabe::util::http_downloader::HttpDownloader;
+use shirabe_php_shim::PhpMixed;
use tempfile::TempDir;
struct SetUp {
@@ -39,32 +49,171 @@ impl Drop for TearDown {
}
}
+fn null_io() -> Rc<RefCell<dyn IOInterface>> {
+ Rc::new(RefCell::new(NullIO::new()))
+}
+
+fn http_downloader(io: &Rc<RefCell<dyn IOInterface>>) -> Rc<RefCell<HttpDownloader>> {
+ let config = Rc::new(RefCell::new(Config::new(false, None)));
+ Rc::new(RefCell::new(HttpDownloader::new(
+ io.clone(),
+ config,
+ IndexMap::new(),
+ true,
+ )))
+}
+
+fn str_config(pairs: &[(&str, PhpMixed)]) -> IndexMap<String, PhpMixed> {
+ let mut c: IndexMap<String, PhpMixed> = IndexMap::new();
+ for (k, v) in pairs {
+ c.insert(k.to_string(), v.clone());
+ }
+ c
+}
+
#[test]
-#[ignore = "RepositoryManager::new builds an HttpDownloader (curl_multi_init todo!()) and mocks IO/Config"]
+#[ignore]
fn test_prepend() {
let SetUp { tmpdir } = set_up();
let _tear_down = TearDown::new(tmpdir.path().to_path_buf());
- todo!()
+
+ let io = null_io();
+ let config = Rc::new(RefCell::new(Config::new(false, None)));
+ let mut rm = RepositoryManager::new(io.clone(), config, http_downloader(&io), None, None);
+
+ let repository1 = RepositoryInterfaceHandle::new(ArrayRepository::new(vec![]).unwrap());
+ let repository2 = RepositoryInterfaceHandle::new(ArrayRepository::new(vec![]).unwrap());
+ rm.add_repository(repository1.clone());
+ rm.prepend_repository(repository2.clone());
+
+ assert_eq!(&vec![repository2, repository1], rm.get_repositories());
}
#[test]
-#[ignore = "RepositoryManager::new builds an HttpDownloader (curl_multi_init todo!()) and mocks IO/Config"]
+#[ignore]
fn test_repo_creation() {
let SetUp { tmpdir } = set_up();
let _tear_down = TearDown::new(tmpdir.path().to_path_buf());
- todo!()
+
+ let io = null_io();
+ let config = Rc::new(RefCell::new(Config::new(false, None)));
+ let mut rm =
+ RepositoryManager::new(io.clone(), config.clone(), http_downloader(&io), None, None);
+
+ config.borrow_mut().merge(
+ &str_config(&[(
+ "config",
+ PhpMixed::Array(str_config(&[(
+ "cache-repo-dir",
+ PhpMixed::String(tmpdir.path().to_string_lossy().to_string()),
+ )])),
+ )]),
+ "unknown",
+ );
+
+ rm.set_repository_class("composer", "Composer\\Repository\\ComposerRepository");
+ rm.set_repository_class("vcs", "Composer\\Repository\\VcsRepository");
+ rm.set_repository_class("package", "Composer\\Repository\\PackageRepository");
+ rm.set_repository_class("pear", "Composer\\Repository\\PearRepository");
+ rm.set_repository_class("git", "Composer\\Repository\\VcsRepository");
+ rm.set_repository_class("svn", "Composer\\Repository\\VcsRepository");
+ rm.set_repository_class("perforce", "Composer\\Repository\\VcsRepository");
+ rm.set_repository_class("hg", "Composer\\Repository\\VcsRepository");
+ rm.set_repository_class("artifact", "Composer\\Repository\\ArtifactRepository");
+
+ let cases: Vec<(&str, IndexMap<String, PhpMixed>)> = vec![
+ (
+ "composer",
+ str_config(&[("url", PhpMixed::String("http://example.org".to_string()))]),
+ ),
+ (
+ "vcs",
+ str_config(&[(
+ "url",
+ PhpMixed::String("http://github.com/foo/bar".to_string()),
+ )]),
+ ),
+ (
+ "git",
+ str_config(&[(
+ "url",
+ PhpMixed::String("http://github.com/foo/bar".to_string()),
+ )]),
+ ),
+ (
+ "git",
+ str_config(&[(
+ "url",
+ PhpMixed::String("git@example.org:foo/bar.git".to_string()),
+ )]),
+ ),
+ (
+ "svn",
+ str_config(&[(
+ "url",
+ PhpMixed::String("svn://example.org/foo/bar".to_string()),
+ )]),
+ ),
+ (
+ "package",
+ str_config(&[("package", PhpMixed::Array(IndexMap::new()))]),
+ ),
+ (
+ "artifact",
+ str_config(&[("url", PhpMixed::String("/path/to/zips".to_string()))]),
+ ),
+ ];
+
+ for (r#type, options) in cases {
+ rm.create_repository(
+ "composer",
+ str_config(&[("url", PhpMixed::String("http://example.org".to_string()))]),
+ None,
+ )
+ .unwrap();
+ rm.create_repository(r#type, options, None).unwrap();
+ }
}
#[test]
-#[ignore = "RepositoryManager::new builds an HttpDownloader (curl_multi_init todo!()) and mocks IO/Config"]
+#[ignore]
fn test_invalid_repo_creation_throws() {
let SetUp { tmpdir } = set_up();
let _tear_down = TearDown::new(tmpdir.path().to_path_buf());
- todo!()
+
+ let io = null_io();
+ let config = Rc::new(RefCell::new(Config::new(false, None)));
+ let rm = RepositoryManager::new(io.clone(), config.clone(), http_downloader(&io), None, None);
+
+ config.borrow_mut().merge(
+ &str_config(&[(
+ "config",
+ PhpMixed::Array(str_config(&[(
+ "cache-repo-dir",
+ PhpMixed::String(tmpdir.path().to_string_lossy().to_string()),
+ )])),
+ )]),
+ "unknown",
+ );
+
+ let cases: Vec<(&str, IndexMap<String, PhpMixed>)> = vec![
+ (
+ "pear",
+ str_config(&[(
+ "url",
+ PhpMixed::String("http://pear.example.org/foo".to_string()),
+ )]),
+ ),
+ ("invalid", IndexMap::new()),
+ ];
+
+ for (r#type, options) in cases {
+ assert!(rm.create_repository(r#type, options, None).is_err());
+ }
}
#[test]
-#[ignore = "RepositoryManager::new builds an HttpDownloader (curl_multi_init todo!()) and mocks IO/Config"]
+#[ignore = "PathRepository does not implement RepositoryInterface (only ConfigurableRepositoryInterface), so it cannot live inside a RepositoryInterfaceHandle nor be recovered via as_any().downcast_ref::<PathRepository>(); the assertInstanceOf(PathRepository) check is unportable"]
fn test_filter_repo_wrapping() {
let SetUp { tmpdir } = set_up();
let _tear_down = TearDown::new(tmpdir.path().to_path_buf());
diff --git a/crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs b/crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs
index a67bce3..0836fc5 100644
--- a/crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs
+++ b/crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs
@@ -93,7 +93,7 @@ fn test_supports() {
// Forgejo API responses; mocking is not available, and a real HttpDownloader reaches
// curl_multi_init (todo!()).
#[test]
-#[ignore = "constructs a ForgejoDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_public_repository() {
let SetUp {
home,
@@ -107,7 +107,7 @@ fn test_public_repository() {
}
#[test]
-#[ignore = "constructs a ForgejoDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_get_branches() {
let SetUp {
home,
@@ -121,7 +121,7 @@ fn test_get_branches() {
}
#[test]
-#[ignore = "constructs a ForgejoDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_get_tags() {
let SetUp {
home,
@@ -135,7 +135,7 @@ fn test_get_tags() {
}
#[test]
-#[ignore = "constructs a ForgejoDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_get_empty_file_content() {
let SetUp {
home,
diff --git a/crates/shirabe/tests/repository/vcs/git_bitbucket_driver_test.rs b/crates/shirabe/tests/repository/vcs/git_bitbucket_driver_test.rs
index b6759b5..2fedba1 100644
--- a/crates/shirabe/tests/repository/vcs/git_bitbucket_driver_test.rs
+++ b/crates/shirabe/tests/repository/vcs/git_bitbucket_driver_test.rs
@@ -103,7 +103,7 @@ fn test_supports() {
// Bitbucket API responses; mocking is not available, and a real HttpDownloader reaches
// curl_multi_init (todo!()).
#[test]
-#[ignore = "constructs a GitBitbucketDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs IOInterface mock (getMockBuilder) and getHttpDownloaderMock/HttpDownloaderMock (not ported); set_up()'s io and http_downloader are todo!() and real HttpDownloader hits todo!() curl I/O"]
fn test_get_root_identifier_wrong_scm_type() {
let SetUp {
home,
@@ -116,7 +116,7 @@ fn test_get_root_identifier_wrong_scm_type() {
}
#[test]
-#[ignore = "constructs a GitBitbucketDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs IOInterface mock (getMockBuilder) and getHttpDownloaderMock/HttpDownloaderMock (not ported); set_up()'s io and http_downloader are todo!() and real HttpDownloader hits todo!() curl I/O"]
fn test_driver() {
let SetUp {
home,
@@ -129,7 +129,7 @@ fn test_driver() {
}
#[test]
-#[ignore = "constructs a GitBitbucketDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs IOInterface mock (getMockBuilder) and getHttpDownloaderMock/HttpDownloaderMock (not ported); depends on test_driver's driver and set_up()'s todo!() mocks"]
fn test_get_params() {
let SetUp {
home,
@@ -142,7 +142,7 @@ fn test_get_params() {
}
#[test]
-#[ignore = "constructs a GitBitbucketDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs IOInterface mock (getMockBuilder) and getHttpDownloaderMock/HttpDownloaderMock (not ported); set_up()'s io and http_downloader are todo!()"]
fn test_initialize_invalid_repository_url() {
let SetUp {
home,
@@ -155,7 +155,7 @@ fn test_initialize_invalid_repository_url() {
}
#[test]
-#[ignore = "constructs a GitBitbucketDriver and mocks the HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "needs IOInterface mock (getMockBuilder) and getHttpDownloaderMock/HttpDownloaderMock (not ported); set_up()'s io and http_downloader are todo!() and real HttpDownloader hits todo!() curl I/O"]
fn test_invalid_support_data() {
let SetUp {
home,
diff --git a/crates/shirabe/tests/repository/vcs/git_driver_test.rs b/crates/shirabe/tests/repository/vcs/git_driver_test.rs
index 1aacbf9..56c2755 100644
--- a/crates/shirabe/tests/repository/vcs/git_driver_test.rs
+++ b/crates/shirabe/tests/repository/vcs/git_driver_test.rs
@@ -64,7 +64,7 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "constructs a GitDriver and mocks a ProcessExecutor/HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "requires ProcessExecutor mock (getProcessExecutorMock/expects) and Reflection setRepoDir, neither available"]
fn test_get_root_identifier_from_remote_local_repository() {
let SetUp {
home,
@@ -76,7 +76,7 @@ fn test_get_root_identifier_from_remote_local_repository() {
}
#[test]
-#[ignore = "constructs a GitDriver and mocks a ProcessExecutor/HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "requires ProcessExecutor mock (getProcessExecutorMock/expects), IO mock and Reflection setRepoDir, none available"]
fn test_get_root_identifier_from_remote() {
let SetUp {
home,
@@ -88,7 +88,7 @@ fn test_get_root_identifier_from_remote() {
}
#[test]
-#[ignore = "constructs a GitDriver and mocks a ProcessExecutor/HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "requires ProcessExecutor mock (getProcessExecutorMock/expects) and Reflection setRepoDir, neither available"]
fn test_get_root_identifier_from_local_with_network_disabled() {
let SetUp {
home,
@@ -100,7 +100,7 @@ fn test_get_root_identifier_from_local_with_network_disabled() {
}
#[test]
-#[ignore = "constructs a GitDriver and mocks a ProcessExecutor/HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "requires ProcessExecutor mock (getProcessExecutorMock/expects), IOInterface mock and Reflection setRepoDir, none available"]
fn test_get_branches_filter_invalid_branch_names() {
let SetUp {
home,
@@ -112,7 +112,7 @@ fn test_get_branches_filter_invalid_branch_names() {
}
#[test]
-#[ignore = "constructs a GitDriver and mocks a ProcessExecutor/HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "requires ProcessExecutor mock (getProcessExecutorMock) and IOInterface/HttpDownloader mocks, none available"]
fn test_file_get_content_invalid_identifier() {
let SetUp {
home,
@@ -124,7 +124,7 @@ fn test_file_get_content_invalid_identifier() {
}
#[test]
-#[ignore = "constructs a GitDriver and mocks a ProcessExecutor/HttpDownloader (curl_multi_init todo!())"]
+#[ignore = "requires ProcessExecutor mock (getProcessExecutorMock) and IOInterface/HttpDownloader mocks, none available"]
fn test_get_change_date_invalid_identifier() {
let SetUp {
home,
diff --git a/crates/shirabe/tests/repository/vcs/github_driver_test.rs b/crates/shirabe/tests/repository/vcs/github_driver_test.rs
index 3e97599..5313c0b 100644
--- a/crates/shirabe/tests/repository/vcs/github_driver_test.rs
+++ b/crates/shirabe/tests/repository/vcs/github_driver_test.rs
@@ -84,7 +84,7 @@ fn test_supports() {
// GitHub API responses; mocking is not available, and a real HttpDownloader reaches
// curl_multi_init (todo!()).
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock), ProcessExecutorMock, the IOInterface MockObject (askAndHideAnswer/setAuthentication), and setAttribute reflection are not ported"]
fn test_private_repository() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -92,7 +92,7 @@ fn test_private_repository() {
}
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock), ProcessExecutorMock, the IOInterface MockObject, and setAttribute reflection are not ported"]
fn test_public_repository() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -100,7 +100,7 @@ fn test_public_repository() {
}
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock), ProcessExecutorMock, the IOInterface MockObject, and setAttribute reflection are not ported"]
fn test_public_repository2() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -108,7 +108,7 @@ fn test_public_repository2() {
}
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock), ProcessExecutorMock, the IOInterface MockObject, and setAttribute reflection are not ported"]
fn test_invalid_support_data() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -116,7 +116,7 @@ fn test_invalid_support_data() {
}
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock), ProcessExecutorMock, the IOInterface MockObject, setAttribute reflection, and the fundingUrlProvider data provider are not ported"]
fn test_funding_format() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -124,7 +124,7 @@ fn test_funding_format() {
}
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock), ProcessExecutorMock, the IOInterface MockObject, and setAttribute reflection are not ported"]
fn test_public_repository_archived() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -132,7 +132,7 @@ fn test_public_repository_archived() {
}
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock), ProcessExecutorMock, and the IOInterface MockObject are not ported"]
fn test_private_repository_no_interaction() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -140,7 +140,7 @@ fn test_private_repository_no_interaction() {
}
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "IOInterface MockObject (getMockBuilder) and HttpDownloader MockObject (getMockBuilder) plus the invalidUrlProvider data provider are not ported"]
fn test_initialize_invalid_repo_url() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -148,7 +148,7 @@ fn test_initialize_invalid_repo_url() {
}
#[test]
-#[ignore = "constructs a GitHubDriver and mocks the HttpDownloader/IO (curl_multi_init todo!())"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock), ProcessExecutorMock, and the IOInterface MockObject are not ported"]
fn test_get_empty_file_content() {
let SetUp { home, config: _ } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
diff --git a/crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs b/crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs
index 1e13ada..0333a2b 100644
--- a/crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs
+++ b/crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs
@@ -1,107 +1,177 @@
//! ref: composer/tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php
-// All cases either mock the HttpDownloader/IO to return GitLab API responses (a real
-// HttpDownloader reaches curl_multi_init, todo!()), or — for testSupports — rely on the
-// gitlab-domains configured in setUp plus the openssl extension, which are not modeled.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::config::Config;
+use shirabe::io::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::repository::vcs::GitLabDriver;
+use shirabe_php_shim::{PhpMixed, extension_loaded};
+
+// Mirrors GitLabDriverTest::setUp's `gitlab-domains` configuration.
+fn make_config() -> Config {
+ let mut config = Config::new(true, None);
+ let mut top: IndexMap<String, PhpMixed> = IndexMap::new();
+ let mut config_section: IndexMap<String, PhpMixed> = IndexMap::new();
+ config_section.insert(
+ "gitlab-domains".to_string(),
+ PhpMixed::List(vec![
+ PhpMixed::String("mycompany.com/gitlab".to_string()),
+ PhpMixed::String("gitlab.mycompany.com".to_string()),
+ PhpMixed::String("othercompany.com/nested/gitlab".to_string()),
+ PhpMixed::String("gitlab.com".to_string()),
+ PhpMixed::String("gitlab.mycompany.local".to_string()),
+ ]),
+ );
+ top.insert("config".to_string(), PhpMixed::Array(config_section));
+ config.merge(&top, Config::SOURCE_UNKNOWN);
+ config
+}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_initialize() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_initialize_public_project() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_initialize_public_project_as_anonymous() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_initialize_with_port_number() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + setAttribute (\\ReflectionProperty) not ported"]
fn test_invalid_support_data() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"]
fn test_get_dist() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"]
fn test_get_source() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "depends on testInitializePublicProject, which needs HttpDownloaderMock + the IOInterface MockObject not ported"]
fn test_get_source_given_public_project() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"]
fn test_get_tags() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"]
fn test_get_paginated_refs() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"]
fn test_get_branches() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore]
fn test_supports() {
- todo!()
+ for (url, expected) in data_for_test_supports() {
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let config = Rc::new(RefCell::new(make_config()));
+
+ assert_eq!(
+ expected,
+ GitLabDriver::supports(io, config, url, false).unwrap()
+ );
+ }
+}
+
+fn data_for_test_supports() -> Vec<(&'static str, bool)> {
+ let openssl = extension_loaded("openssl");
+ vec![
+ ("http://gitlab.com/foo/bar", true),
+ ("http://gitlab.mycompany.com:5443/foo/bar", true),
+ ("http://gitlab.com/foo/bar/", true),
+ ("http://gitlab.com/foo/bar/", true),
+ ("http://gitlab.com/foo/bar.git", true),
+ ("http://gitlab.com/foo/bar.git", true),
+ ("http://gitlab.com/foo/bar.baz.git", true),
+ ("https://gitlab.com/foo/bar", openssl),
+ ("https://gitlab.mycompany.com:5443/foo/bar", openssl),
+ ("git@gitlab.com:foo/bar.git", openssl),
+ ("git@example.com:foo/bar.git", false),
+ ("http://example.com/foo/bar", false),
+ ("http://mycompany.com/gitlab/mygroup/myproject", true),
+ ("https://mycompany.com/gitlab/mygroup/myproject", openssl),
+ (
+ "http://othercompany.com/nested/gitlab/mygroup/myproject",
+ true,
+ ),
+ (
+ "https://othercompany.com/nested/gitlab/mygroup/myproject",
+ openssl,
+ ),
+ (
+ "http://gitlab.com/mygroup/mysubgroup/mysubsubgroup/myproject",
+ true,
+ ),
+ (
+ "https://gitlab.com/mygroup/mysubgroup/mysubsubgroup/myproject",
+ openssl,
+ ),
+ ]
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_gitlab_sub_directory() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_gitlab_sub_group() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_gitlab_sub_directory_sub_group() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_forwards_options() {
todo!()
}
#[test]
-#[ignore = "GitLabDriver tests mock HttpDownloader/IO (curl_multi_init todo!()) or need setUp gitlab-domains config"]
+#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"]
fn test_protocol_override_repository_url_generation() {
todo!()
}
diff --git a/crates/shirabe/tests/repository/vcs/hg_driver_test.rs b/crates/shirabe/tests/repository/vcs/hg_driver_test.rs
index 155d7ce..7b6f1e6 100644
--- a/crates/shirabe/tests/repository/vcs/hg_driver_test.rs
+++ b/crates/shirabe/tests/repository/vcs/hg_driver_test.rs
@@ -80,7 +80,7 @@ fn test_supports() {
// (curl_multi_init is todo!() in the php-shim) and a mocked ProcessExecutor to feed
// hg command output, neither of which is available here.
#[test]
-#[ignore = "needs an HgDriver instance (HttpDownloader reaches curl_multi_init, todo!()) and a mocked ProcessExecutor"]
+#[ignore = "requires getProcessExecutorMock with expects() hg branches/bookmarks command-sequence assertions and a getMockBuilder HttpDownloader mock; no ProcessExecutorMock/HttpDownloader mocking infrastructure exists"]
fn test_get_branches_filter_invalid_branch_names() {
let SetUp { home, config, io } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -89,7 +89,7 @@ fn test_get_branches_filter_invalid_branch_names() {
}
#[test]
-#[ignore = "needs an HgDriver instance (HttpDownloader reaches curl_multi_init, todo!()) and a mocked ProcessExecutor"]
+#[ignore = "requires getProcessExecutorMock and a getMockBuilder HttpDownloader mock to construct HgDriver; no ProcessExecutorMock/HttpDownloader mocking infrastructure exists"]
fn test_file_get_content_invalid_identifier() {
let SetUp { home, config, io } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
@@ -98,7 +98,7 @@ fn test_file_get_content_invalid_identifier() {
}
#[test]
-#[ignore = "needs an HgDriver instance (HttpDownloader reaches curl_multi_init, todo!()) and a mocked ProcessExecutor"]
+#[ignore = "requires getProcessExecutorMock and a getMockBuilder HttpDownloader mock to construct HgDriver; no ProcessExecutorMock/HttpDownloader mocking infrastructure exists"]
fn test_get_change_date_invalid_identifier() {
let SetUp { home, config, io } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
diff --git a/crates/shirabe/tests/repository/vcs/perforce_driver_test.rs b/crates/shirabe/tests/repository/vcs/perforce_driver_test.rs
index 1c28487..d9178dd 100644
--- a/crates/shirabe/tests/repository/vcs/perforce_driver_test.rs
+++ b/crates/shirabe/tests/repository/vcs/perforce_driver_test.rs
@@ -108,8 +108,8 @@ fn test_supports_returns_false_no_deep_check() {
// The remaining cases mock Perforce, the repository config and IO to drive initialization,
// composer-file detection and cleanup; mocking is not available here.
+#[ignore]
#[test]
-#[ignore = "mocks Perforce/repository/IO; mocking is not available"]
fn test_initialize_captures_variables_from_repo_config() {
let SetUp {
test_path,
@@ -122,20 +122,29 @@ fn test_initialize_captures_variables_from_repo_config() {
driver,
} = set_up();
let _tear_down = TearDown::new(test_path.path().to_path_buf());
- let _ = (
- &config,
- &repo_config,
- &io,
- &process,
- &http_downloader,
- &perforce,
- &driver,
- );
- todo!()
+ let _ = (&io, &process, &http_downloader, &perforce, &driver);
+
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let config = Rc::new(RefCell::new(config));
+ let http_downloader = Rc::new(RefCell::new(shirabe::util::HttpDownloader::new(
+ io.clone(),
+ config.clone(),
+ IndexMap::new(),
+ false,
+ )));
+ let process = Rc::new(RefCell::new(shirabe::util::ProcessExecutor::new(Some(
+ io.clone(),
+ ))));
+
+ let mut driver = PerforceDriver::new(repo_config, io, config, http_downloader, process);
+ driver.initialize().unwrap();
+ assert_eq!(TEST_URL, driver.get_url());
+ assert_eq!(TEST_DEPOT, driver.get_depot());
+ assert_eq!(TEST_BRANCH, driver.get_branch());
}
+#[ignore = "needs a Perforce mock injected via reflection (overrideDriverInternalPerforce) to assert p4Login/checkStream/writeP4ClientSpec/connectClient are each called once; the perforce field is pub(crate) and no mock infra exists"]
#[test]
-#[ignore = "mocks Perforce/repository/IO; mocking is not available"]
fn test_initialize_logs_in_and_connects_client() {
let SetUp {
test_path,
@@ -160,8 +169,8 @@ fn test_initialize_logs_in_and_connects_client() {
todo!()
}
+#[ignore = "needs a Perforce mock injected via reflection (overrideDriverInternalPerforce) to stub getComposerInformation; the perforce field is pub(crate) and no mock infra exists"]
#[test]
-#[ignore = "mocks Perforce/repository/IO; mocking is not available"]
fn test_has_composer_file_returns_false_on_no_composer_file() {
let SetUp {
test_path,
@@ -186,8 +195,8 @@ fn test_has_composer_file_returns_false_on_no_composer_file() {
todo!()
}
+#[ignore = "needs a Perforce mock injected via reflection (overrideDriverInternalPerforce) to stub getComposerInformation; the perforce field is pub(crate) and no mock infra exists"]
#[test]
-#[ignore = "mocks Perforce/repository/IO; mocking is not available"]
fn test_has_composer_file_returns_true_with_one_or_more_composer_files() {
let SetUp {
test_path,
@@ -212,8 +221,8 @@ fn test_has_composer_file_returns_true_with_one_or_more_composer_files() {
todo!()
}
+#[ignore = "needs a Perforce mock injected via reflection (overrideDriverInternalPerforce) to assert cleanupClientSpec is called once; the perforce field is pub(crate) and no mock infra exists"]
#[test]
-#[ignore = "mocks Perforce/repository/IO; mocking is not available"]
fn test_cleanup() {
let SetUp {
test_path,
diff --git a/crates/shirabe/tests/repository/vcs/svn_driver_test.rs b/crates/shirabe/tests/repository/vcs/svn_driver_test.rs
index 9625088..5ec9097 100644
--- a/crates/shirabe/tests/repository/vcs/svn_driver_test.rs
+++ b/crates/shirabe/tests/repository/vcs/svn_driver_test.rs
@@ -77,8 +77,8 @@ fn test_support() {
// Constructs an SvnDriver and runs an svn command via a mocked ProcessExecutor; mocking is
// not available here.
+#[ignore = "requires ProcessExecutor mock (getProcessExecutorMock/expects) and IOInterface/HttpDownloader mocks, none available"]
#[test]
-#[ignore = "constructs an SvnDriver and mocks a ProcessExecutor for the svn invocation"]
fn test_wrong_credentials_in_url() {
let SetUp { home, config } = set_up();
let _tear_down = TearDown::new(home.path().to_path_buf());
diff --git a/crates/shirabe/tests/repository/vcs_repository_test.rs b/crates/shirabe/tests/repository/vcs_repository_test.rs
index c687b3d..d84ed51 100644
--- a/crates/shirabe/tests/repository/vcs_repository_test.rs
+++ b/crates/shirabe/tests/repository/vcs_repository_test.rs
@@ -1,6 +1,18 @@
//! ref: composer/tests/Composer/Test/Repository/VcsRepositoryTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::config::Config;
+use shirabe::io::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::package::dumper::ArrayDumper;
+use shirabe::repository::RepositoryInterface;
+use shirabe::repository::VcsRepository;
use shirabe::util::filesystem::Filesystem;
+use shirabe::util::http_downloader::HttpDownloader;
+use shirabe_php_shim::PhpMixed;
struct SetUp {
composer_home: std::path::PathBuf,
@@ -42,14 +54,11 @@ impl Drop for TearDown {
// testLoadVersions initialises a real git repository on disk and drives a VcsRepository over
// it, then asserts the loaded package versions; the git fixture setup and constraint parsing
-// (look-around regex) are not ported.
+// (look-around regex) are not ported. In addition, VcsRepository does not implement
+// RepositoryInterface and keeps its inner ArrayRepository pub(crate), so getPackages() (inherited
+// from ArrayRepository in PHP) is not reachable from the test crate.
#[test]
-#[ignore = "not yet ported (initialises a git repo on disk and loads versions; constraint parsing uses a look-around regex)"]
+#[ignore = "VcsRepository does not expose get_packages() to the test crate; git fixture setup not ported"]
fn test_load_versions() {
- let SetUp {
- composer_home,
- git_repo,
- } = set_up();
- let _tear_down = TearDown::new(composer_home, git_repo);
todo!()
}
diff --git a/crates/shirabe/tests/script/event_test.rs b/crates/shirabe/tests/script/event_test.rs
index e2aab3c..b045bc4 100644
--- a/crates/shirabe/tests/script/event_test.rs
+++ b/crates/shirabe/tests/script/event_test.rs
@@ -60,7 +60,7 @@ fn test_event_sets_originating_event() {
// Event cannot be passed as the originating event (it is not polymorphic), and
// the test cannot be expressed faithfully.
#[test]
-#[ignore = "set_originating_event takes a concrete event_dispatcher::Event; a Script Event cannot be passed as originating event, and calculate_originating_event is todo!()"]
+#[ignore = "Event::set_originating_event takes a concrete event_dispatcher::Event, so a nested script::Event cannot be passed as originating event; the recursive calculate_originating_event behavior is not expressible"]
fn test_event_calculates_nested_originating_event() {
todo!()
}
diff --git a/crates/shirabe/tests/util/auth_helper_test.rs b/crates/shirabe/tests/util/auth_helper_test.rs
index 9eaeac1..21bf1c6 100644
--- a/crates/shirabe/tests/util/auth_helper_test.rs
+++ b/crates/shirabe/tests/util/auth_helper_test.rs
@@ -10,121 +10,121 @@ fn set_up() {
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_without_auth_credentials() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_bearer_password() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_github_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_gitlab_oath_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_options_for_client_certificate() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_gitlab_private_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_bitbucket_oath_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_bitbucket_public_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_basic_http_authentication() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_custom_headers() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config in setUp; no mocking framework"]
fn test_is_public_bit_bucket_download_with_bitbucket_public_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config in setUp; no mocking framework"]
fn test_is_public_bit_bucket_download_with_non_bitbucket_public_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock Config/ConfigSourceInterface with expects()/willReturn(); no mocking framework"]
fn test_store_auth_automatically() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config/ConfigSourceInterface with willReturnCallback(); no mocking framework"]
fn test_store_auth_with_prompt_yes_answer() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config/ConfigSourceInterface with willReturnCallback(); no mocking framework"]
fn test_store_auth_with_prompt_no_answer() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config/ConfigSourceInterface with willReturnCallback(); no mocking framework"]
fn test_store_auth_with_prompt_invalid_answer() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config with expects()/willReturnMap(); no mocking framework"]
fn test_prompt_auth_if_needed_git_lab_no_auth_change() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config with willReturnMap()/willReturnCallback(); no mocking framework"]
fn test_prompt_auth_if_needed_multiple_bitbucket_downloads() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn() plus set_error_handler; no mocking framework"]
fn test_add_authentication_header_is_working() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface in setUp plus set_error_handler deprecation capture; no mocking framework"]
fn test_add_authentication_header_deprecation() {
todo!()
}
diff --git a/crates/shirabe/tests/util/bitbucket_test.rs b/crates/shirabe/tests/util/bitbucket_test.rs
index 4087294..3e3fad8 100644
--- a/crates/shirabe/tests/util/bitbucket_test.rs
+++ b/crates/shirabe/tests/util/bitbucket_test.rs
@@ -10,91 +10,91 @@ fn set_up() {
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_valid_oauth_consumer() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getMockBuilder mock for Config (no mock infrastructure)"]
fn test_request_access_token_with_valid_oauth_consumer_and_valid_stored_access_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_valid_oauth_consumer_and_expired_access_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_username_and_password() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_username_and_password_with_unauthorized_response() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_username_and_password_with_not_found_response() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_username_password_authentication_flow() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mock for Config (no mock infrastructure)"]
fn test_authorize_oauth_interactively_with_empty_username() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mock for Config (no mock infrastructure)"]
fn test_authorize_oauth_interactively_with_empty_password() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_authorize_oauth_interactively_with_request_access_token_failure() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config to construct Bitbucket (no mock infrastructure)"]
fn test_get_token_without_access_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getMockBuilder mock for Config and @depends-injected Bitbucket from a mock-based test (no mock infrastructure)"]
fn test_get_token_with_access_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config to construct Bitbucket (no mock infrastructure)"]
fn test_authorize_oauth_with_wrong_origin_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock, getProcessExecutorMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_authorize_oauth_without_available_git_config_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock, getProcessExecutorMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_authorize_oauth_with_available_git_config_token() {
todo!()
}
diff --git a/crates/shirabe/tests/util/error_handler_test.rs b/crates/shirabe/tests/util/error_handler_test.rs
index 8f42bca..7295cf2 100644
--- a/crates/shirabe/tests/util/error_handler_test.rs
+++ b/crates/shirabe/tests/util/error_handler_test.rs
@@ -26,20 +26,20 @@ impl Drop for TearDown {
}
}
+#[ignore = "depends on PHP runtime routing an undefined-index notice through set_error_handler; no Rust equivalent for $array['baz'] triggering ErrorHandler::handle"]
#[test]
-#[ignore = "relies on PHP's set_error_handler converting an undefined-array-key notice into an ErrorException; no Rust equivalent"]
fn test_error_handler_capture_notice() {
todo!()
}
+#[ignore = "depends on PHP runtime emitting a TypeError/warning from array_merge([], 'string') via set_error_handler; no Rust equivalent"]
#[test]
-#[ignore = "relies on PHP's runtime turning an invalid array_merge call into a TypeError/ErrorException; no Rust equivalent"]
fn test_error_handler_capture_warning() {
todo!()
}
+#[ignore = "depends on the PHP @ error-suppression operator and trigger_error routing through set_error_handler; no Rust equivalent"]
#[test]
-#[ignore = "relies on PHP's @ error-suppression operator and set_error_handler; no Rust equivalent"]
fn test_error_handler_respects_at_operator() {
todo!()
}
diff --git a/crates/shirabe/tests/util/filesystem_test.rs b/crates/shirabe/tests/util/filesystem_test.rs
index 39fa256..9e41b1f 100644
--- a/crates/shirabe/tests/util/filesystem_test.rs
+++ b/crates/shirabe/tests/util/filesystem_test.rs
@@ -1,10 +1,13 @@
//! ref: composer/tests/Composer/Test/Util/FilesystemTest.php
// These exercise Filesystem path helpers and on-disk operations (sizes, copy, symlinks and
-// junctions over a temp tree). The filesystem fixtures and platform-specific symlink/junction
-// behaviour are not ported.
+// junctions over a temp tree). The on-disk tests build their temp tree with tempfile::TempDir in
+// place of TestCase::getUniqueTmpDirectory, which is not ported.
use shirabe::util::filesystem::Filesystem;
-use shirabe_php_shim::{dirname, is_dir, is_file};
+use shirabe::util::platform::Platform;
+use shirabe_php_shim::{
+ dirname, file_exists, file_put_contents, is_dir, is_file, mkdir, symlink, touch,
+};
#[allow(dead_code)]
struct SetUp {
@@ -51,74 +54,769 @@ impl Drop for TearDown {
}
}
+/// providePathCouplesAsCode: (a, b, directory, expected, static, prefer_relative)
+fn provide_path_couples_as_code()
+-> Vec<(&'static str, &'static str, bool, &'static str, bool, bool)> {
+ vec![
+ ("/foo/bar", "/foo/bar", false, "__FILE__", false, false),
+ (
+ "/foo/bar",
+ "/foo/baz",
+ false,
+ "__DIR__.'/baz'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bin/run",
+ "/foo/vendor/acme/bin/run",
+ false,
+ "dirname(__DIR__).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bin/run",
+ "/bar/bin/run",
+ false,
+ "'/bar/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "c:/vendor/acme/bin/run",
+ false,
+ "dirname(__DIR__).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "c:/vendor/acme/bin/run",
+ false,
+ "dirname(__DIR__).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "D:/vendor/acme/bin/run",
+ false,
+ "'D:/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "d:/vendor/acme/bin/run",
+ false,
+ "'D:/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ ("/foo/bar", "/foo/bar", true, "__DIR__", false, false),
+ ("/foo/bar/", "/foo/bar", true, "__DIR__", false, false),
+ (
+ "/foo",
+ "/baz",
+ true,
+ "dirname(__DIR__).'/baz'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar",
+ "/foo/baz",
+ true,
+ "dirname(__DIR__).'/baz'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bin/run",
+ "/foo/vendor/acme/bin/run",
+ true,
+ "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bin/run",
+ "/bar/bin/run",
+ true,
+ "'/bar/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "/app/vendor/foo/bar",
+ "/lib",
+ true,
+ "dirname(dirname(dirname(dirname(__DIR__)))).'/lib'",
+ false,
+ true,
+ ),
+ ("/bin/run", "/bin/run", true, "__DIR__", false, false),
+ ("c:/bin/run", "C:\\bin/run", true, "__DIR__", false, false),
+ (
+ "c:/bin/run",
+ "c:/vendor/acme/bin/run",
+ true,
+ "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "c:/vendor/acme/bin/run",
+ true,
+ "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "d:/vendor/acme/bin/run",
+ true,
+ "'D:/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "d:/vendor/acme/bin/run",
+ true,
+ "'D:/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "C:/Temp/test",
+ "C:\\Temp",
+ true,
+ "dirname(__DIR__)",
+ false,
+ false,
+ ),
+ (
+ "C:/Temp",
+ "C:\\Temp\\test",
+ true,
+ "__DIR__ . '/test'",
+ false,
+ false,
+ ),
+ ("/tmp/test", "/tmp", true, "dirname(__DIR__)", false, false),
+ ("/tmp", "/tmp/test", true, "__DIR__ . '/test'", false, false),
+ (
+ "C:/Temp",
+ "c:\\Temp\\test",
+ true,
+ "__DIR__ . '/test'",
+ false,
+ false,
+ ),
+ ("/tmp/test/./", "/tmp/test/", true, "__DIR__", false, false),
+ (
+ "/tmp/test/../vendor",
+ "/tmp/test",
+ true,
+ "dirname(__DIR__).'/test'",
+ false,
+ false,
+ ),
+ (
+ "/tmp/test/.././vendor",
+ "/tmp/test",
+ true,
+ "dirname(__DIR__).'/test'",
+ false,
+ false,
+ ),
+ (
+ "C:/Temp",
+ "c:\\Temp\\..\\..\\test",
+ true,
+ "dirname(__DIR__).'/test'",
+ false,
+ false,
+ ),
+ (
+ "C:/Temp/../..",
+ "d:\\Temp\\..\\..\\test",
+ true,
+ "'D:/test'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar",
+ "/foo/bar_vendor",
+ true,
+ "dirname(__DIR__).'/bar_vendor'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar_vendor",
+ "/foo/bar",
+ true,
+ "dirname(__DIR__).'/bar'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar_vendor",
+ "/foo/bar/src",
+ true,
+ "dirname(__DIR__).'/bar/src'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar_vendor/src2",
+ "/foo/bar/src/lib",
+ true,
+ "dirname(dirname(__DIR__)).'/bar/src/lib'",
+ false,
+ false,
+ ),
+ // static use case
+ (
+ "/tmp/test/../vendor",
+ "/tmp/test",
+ true,
+ "__DIR__ . '/..'.'/test'",
+ true,
+ false,
+ ),
+ (
+ "/tmp/test/.././vendor",
+ "/tmp/test",
+ true,
+ "__DIR__ . '/..'.'/test'",
+ true,
+ false,
+ ),
+ (
+ "C:/Temp",
+ "c:\\Temp\\..\\..\\test",
+ true,
+ "__DIR__ . '/..'.'/test'",
+ true,
+ false,
+ ),
+ (
+ "C:/Temp/../..",
+ "d:\\Temp\\..\\..\\test",
+ true,
+ "'D:/test'",
+ true,
+ false,
+ ),
+ (
+ "/foo/bar",
+ "/foo/bar_vendor",
+ true,
+ "__DIR__ . '/..'.'/bar_vendor'",
+ true,
+ false,
+ ),
+ (
+ "/foo/bar_vendor",
+ "/foo/bar",
+ true,
+ "__DIR__ . '/..'.'/bar'",
+ true,
+ false,
+ ),
+ (
+ "/foo/bar_vendor",
+ "/foo/bar/src",
+ true,
+ "__DIR__ . '/..'.'/bar/src'",
+ true,
+ false,
+ ),
+ (
+ "/foo/bar_vendor/src2",
+ "/foo/bar/src/lib",
+ true,
+ "__DIR__ . '/../..'.'/bar/src/lib'",
+ true,
+ false,
+ ),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_find_shortest_path_code() {
- todo!()
+ let fs = Filesystem::new(None);
+ for (a, b, directory, expected, static_code, prefer_relative) in provide_path_couples_as_code()
+ {
+ assert_eq!(
+ expected,
+ fs.find_shortest_path_code(a, b, directory, static_code, prefer_relative)
+ );
+ }
}
+/// providePathCouples: (a, b, expected, directory, prefer_relative)
+fn provide_path_couples() -> Vec<(&'static str, &'static str, &'static str, bool, bool)> {
+ vec![
+ ("/foo/bar", "/foo/bar", "./bar", false, false),
+ ("/foo/bar", "/foo/baz", "./baz", false, false),
+ ("/foo/bar/", "/foo/baz", "./baz", false, false),
+ ("/foo/bar", "/foo/bar", "./", true, false),
+ ("/foo/bar", "/foo/baz", "../baz", true, false),
+ ("/foo/bar/", "/foo/baz", "../baz", true, false),
+ ("C:/foo/bar/", "c:/foo/baz", "../baz", true, false),
+ (
+ "/foo/bin/run",
+ "/foo/vendor/acme/bin/run",
+ "../vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ ("/foo/bin/run", "/bar/bin/run", "/bar/bin/run", false, false),
+ ("/foo/bin/run", "/bar/bin/run", "/bar/bin/run", true, false),
+ (
+ "c:/foo/bin/run",
+ "d:/bar/bin/run",
+ "D:/bar/bin/run",
+ true,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "c:/vendor/acme/bin/run",
+ "../vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "c:/vendor/acme/bin/run",
+ "../vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "d:/vendor/acme/bin/run",
+ "D:/vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "d:/vendor/acme/bin/run",
+ "D:/vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ ("C:/Temp/test", "C:\\Temp", "./", false, false),
+ ("/tmp/test", "/tmp", "./", false, false),
+ ("C:/Temp/test/sub", "C:\\Temp", "../", false, false),
+ ("/tmp/test/sub", "/tmp", "../", false, false),
+ ("/tmp/test/sub", "/tmp", "../../", true, false),
+ ("c:/tmp/test/sub", "c:/tmp", "../../", true, false),
+ ("/tmp", "/tmp/test", "test", false, false),
+ ("C:/Temp", "C:\\Temp\\test", "test", false, false),
+ ("C:/Temp", "c:\\Temp\\test", "test", false, false),
+ ("/tmp/test/./", "/tmp/test", "./", true, false),
+ ("/tmp/test/../vendor", "/tmp/test", "../test", true, false),
+ ("/tmp/test/.././vendor", "/tmp/test", "../test", true, false),
+ ("C:/Temp", "c:\\Temp\\..\\..\\test", "../test", true, false),
+ (
+ "C:/Temp/../..",
+ "c:\\Temp\\..\\..\\test",
+ "./test",
+ true,
+ false,
+ ),
+ (
+ "C:/Temp/../..",
+ "D:\\Temp\\..\\..\\test",
+ "D:/test",
+ true,
+ false,
+ ),
+ ("/app/vendor/foo/bar", "/lib", "../../../../lib", true, true),
+ ("/tmp", "/tmp/../../test", "../test", true, false),
+ ("/tmp", "/test", "../test", true, false),
+ ("/foo/bar", "/foo/bar_vendor", "../bar_vendor", true, false),
+ ("/foo/bar_vendor", "/foo/bar", "../bar", true, false),
+ ("/foo/bar_vendor", "/foo/bar/src", "../bar/src", true, false),
+ (
+ "/foo/bar_vendor/src2",
+ "/foo/bar/src/lib",
+ "../../bar/src/lib",
+ true,
+ false,
+ ),
+ ("C:/", "C:/foo/bar/", "foo/bar", true, false),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_find_shortest_path() {
- todo!()
+ let fs = Filesystem::new(None);
+ for (a, b, expected, directory, prefer_relative) in provide_path_couples() {
+ assert_eq!(
+ expected,
+ fs.find_shortest_path(a, b, directory, prefer_relative)
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_remove_directory_php() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&format!("{working_dir}/level1/level2"), 0o777, true);
+ file_put_contents(
+ &format!("{working_dir}/level1/level2/hello.txt"),
+ b"hello world",
+ );
+
+ let mut fs = Filesystem::new(None);
+ assert!(fs.remove_directory_php(&working_dir).unwrap());
+ assert!(!file_exists(format!(
+ "{working_dir}/level1/level2/hello.txt"
+ )));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_file_size() {
- todo!()
+ let unique_tmp = tempfile::TempDir::new().unwrap();
+ let test_file = format!("{}/composer_test_file", unique_tmp.path().to_str().unwrap());
+
+ file_put_contents(&test_file, b"Hello");
+
+ let fs = Filesystem::new(None);
+ assert!(fs.size(&test_file).unwrap() >= 5);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_directory_size() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&working_dir, 0o777, true);
+ file_put_contents(&format!("{working_dir}/file1.txt"), b"Hello");
+ file_put_contents(&format!("{working_dir}/file2.txt"), b"World");
+
+ let fs = Filesystem::new(None);
+ assert!(fs.size(&working_dir).unwrap() >= 10);
}
+/// provideNormalizedPaths: (expected, actual)
+fn provide_normalized_paths() -> Vec<(&'static str, &'static str)> {
+ vec![
+ ("../foo", "../foo"),
+ ("C:/foo/bar", "c:/foo//bar"),
+ ("C:/foo/bar", "C:/foo/./bar"),
+ ("C:/foo/bar", "C://foo//bar"),
+ ("C:/foo/bar", "C:///foo//bar"),
+ ("C:/bar", "C:/foo/../bar"),
+ ("/bar", "/foo/../bar/"),
+ ("phar://C:/Foo", "phar://c:/Foo/Bar/.."),
+ ("phar://C:/Foo", "phar://c:///Foo/Bar/.."),
+ ("phar://C:/", "phar://c:/Foo/Bar/../../../.."),
+ ("/", "/Foo/Bar/../../../.."),
+ ("/", "/"),
+ ("/", "//"),
+ ("/", "///"),
+ ("/Foo", "///Foo"),
+ ("C:/", "c:\\"),
+ ("../src", "Foo/Bar/../../../src"),
+ ("C:../b", "c:.\\..\\a\\..\\b"),
+ ("phar://C:../Foo", "phar://c:../Foo"),
+ ("//foo/bar", "\\\\foo\\bar"),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_normalize_path() {
- todo!()
+ let fs = Filesystem::new(None);
+ for (expected, actual) in provide_normalized_paths() {
+ assert_eq!(expected, fs.normalize_path(actual));
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_unlink_symlinked_directory() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let basepath = working_dir.path().to_str().unwrap().to_string();
+ let symlinked = format!("{basepath}/linked");
+ mkdir(&format!("{basepath}/real"), 0o777, true);
+ touch(&format!("{basepath}/real/FILE"));
+
+ let result = symlink(&format!("{basepath}/real"), &symlinked);
+
+ if !result {
+ // Symbolic links for directories not supported on this platform.
+ return;
+ }
+
+ if !is_dir(&symlinked) {
+ panic!("Precondition assertion failed (is_dir is false on symbolic link to directory).");
+ }
+
+ let fs = Filesystem::new(None);
+ let result = fs.unlink(&symlinked).unwrap();
+ assert!(result);
+ assert!(!file_exists(&symlinked));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_remove_symlinked_directory_with_trailing_slash() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&format!("{working_dir}/real"), 0o777, true);
+ touch(&format!("{working_dir}/real/FILE"));
+ let symlinked = format!("{working_dir}/linked");
+ let symlinked_trailing_slash = format!("{symlinked}/");
+
+ let result = symlink(&format!("{working_dir}/real"), &symlinked);
+
+ if !result {
+ // Symbolic links for directories not supported on this platform.
+ return;
+ }
+
+ if !is_dir(&symlinked) {
+ panic!("Precondition assertion failed (is_dir is false on symbolic link to directory).");
+ }
+
+ if !is_dir(&symlinked_trailing_slash) {
+ panic!("Precondition assertion failed (is_dir false w trailing slash).");
+ }
+
+ let mut fs = Filesystem::new(None);
+
+ let result = fs.remove_directory(&symlinked_trailing_slash).unwrap();
+ assert!(result);
+ assert!(!file_exists(&symlinked_trailing_slash));
+ assert!(!file_exists(&symlinked));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_junctions() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&format!("{working_dir}/real/nesting/testing"), 0o777, true);
+ let mut fs = Filesystem::new(None);
+
+ // Non-Windows systems do not support this and will return false on all tests, and an exception
+ // on creation.
+ if !Platform::is_windows() {
+ assert!(!fs.is_junction(&working_dir));
+ assert!(!fs.remove_junction(&working_dir).unwrap());
+
+ let target = format!("{working_dir}/real/../real/nesting");
+ let junction = format!("{working_dir}/junction");
+ let err = fs.junction(&target, &junction).unwrap_err();
+ assert!(
+ err.to_string()
+ .contains("not available on non-Windows platform")
+ );
+ return;
+ }
+
+ let target = format!("{working_dir}/real/../real/nesting");
+ let junction = format!("{working_dir}/junction");
+
+ // Create and detect junction
+ fs.junction(&target, &junction).unwrap();
+ assert!(fs.is_junction(&junction), "{junction}: is a junction");
+ assert!(!fs.is_junction(&target), "{target}: is not a junction");
+ assert!(
+ fs.is_junction(&format!("{target}/../../junction")),
+ "{target}/../../junction: is a junction"
+ );
+ assert!(
+ !fs.is_junction(&format!("{junction}/../real")),
+ "{junction}/../real: is not a junction"
+ );
+ assert!(
+ fs.is_junction(&format!("{junction}/../junction")),
+ "{junction}/../junction: is a junction"
+ );
+
+ // Remove junction
+ assert!(is_dir(&junction), "{junction} is a directory");
+ assert!(
+ fs.remove_junction(&junction).unwrap(),
+ "{junction} has been removed"
+ );
+ assert!(!is_dir(&junction), "{junction} is not a directory");
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_override_junctions() {
- todo!()
+ if !Platform::is_windows() {
+ // Only runs on windows.
+ return;
+ }
+
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&format!("{working_dir}/real/nesting/testing"), 0o777, true);
+ let mut fs = Filesystem::new(None);
+
+ let old_target = format!("{working_dir}/real/nesting/testing");
+ let target = format!("{working_dir}/real/../real/nesting");
+ let junction = format!("{working_dir}/junction");
+
+ // Override non-broken junction
+ fs.junction(&old_target, &junction).unwrap();
+ fs.junction(&target, &junction).unwrap();
+
+ assert!(fs.is_junction(&junction), "{junction}: is a junction");
+ assert!(
+ fs.is_junction(&format!("{target}/../../junction")),
+ "{target}/../../junction: is a junction"
+ );
+
+ // Remove junction
+ assert!(
+ fs.remove_junction(&junction).unwrap(),
+ "{junction} has been removed"
+ );
+
+ // Override broken junction
+ fs.junction(&old_target, &junction).unwrap();
+ fs.remove_directory(&old_target).unwrap();
+ fs.junction(&target, &junction).unwrap();
+
+ assert!(fs.is_junction(&junction), "{junction}: is a junction");
+ assert!(
+ fs.is_junction(&format!("{target}/../../junction")),
+ "{target}/../../junction: is a junction"
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_copy() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+ let unique_tmp = tempfile::TempDir::new().unwrap();
+ let test_file = format!("{}/composer_test_file", unique_tmp.path().to_str().unwrap());
+
+ mkdir(&format!("{working_dir}/foo/bar"), 0o777, true);
+ mkdir(&format!("{working_dir}/foo/baz"), 0o777, true);
+ file_put_contents(&format!("{working_dir}/foo/foo.file"), b"foo");
+ file_put_contents(&format!("{working_dir}/foo/bar/foobar.file"), b"foobar");
+ file_put_contents(&format!("{working_dir}/foo/baz/foobaz.file"), b"foobaz");
+ file_put_contents(&test_file, b"testfile");
+
+ let mut fs = Filesystem::new(None);
+
+ let result1 = fs
+ .copy(
+ &format!("{working_dir}/foo"),
+ &format!("{working_dir}/foop"),
+ )
+ .unwrap();
+ assert!(result1, "Copying directory failed.");
+ assert!(
+ is_dir(format!("{working_dir}/foop")),
+ "Not a directory: {working_dir}/foop"
+ );
+ assert!(
+ is_dir(format!("{working_dir}/foop/bar")),
+ "Not a directory: {working_dir}/foop/bar"
+ );
+ assert!(
+ is_dir(format!("{working_dir}/foop/baz")),
+ "Not a directory: {working_dir}/foop/baz"
+ );
+ assert!(
+ file_exists(format!("{working_dir}/foop/foo.file")),
+ "Not a file: {working_dir}/foop/foo.file"
+ );
+ assert!(
+ file_exists(format!("{working_dir}/foop/bar/foobar.file")),
+ "Not a file: {working_dir}/foop/bar/foobar.file"
+ );
+ assert!(
+ file_exists(format!("{working_dir}/foop/baz/foobaz.file")),
+ "Not a file: {working_dir}/foop/baz/foobaz.file"
+ );
+
+ let result2 = fs
+ .copy(&test_file, &format!("{working_dir}/testfile.file"))
+ .unwrap();
+ assert!(result2);
+ assert!(file_exists(format!("{working_dir}/testfile.file")));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_copy_then_remove() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+ let unique_tmp = tempfile::TempDir::new().unwrap();
+ let test_file = format!("{}/composer_test_file", unique_tmp.path().to_str().unwrap());
+
+ mkdir(&format!("{working_dir}/foo/bar"), 0o777, true);
+ mkdir(&format!("{working_dir}/foo/baz"), 0o777, true);
+ file_put_contents(&format!("{working_dir}/foo/foo.file"), b"foo");
+ file_put_contents(&format!("{working_dir}/foo/bar/foobar.file"), b"foobar");
+ file_put_contents(&format!("{working_dir}/foo/baz/foobaz.file"), b"foobaz");
+ file_put_contents(&test_file, b"testfile");
+
+ let mut fs = Filesystem::new(None);
+
+ fs.copy_then_remove(&test_file, &format!("{working_dir}/testfile.file"))
+ .unwrap();
+ assert!(!file_exists(&test_file), "Still a file: {test_file}");
+
+ fs.copy_then_remove(
+ &format!("{working_dir}/foo"),
+ &format!("{working_dir}/foop"),
+ )
+ .unwrap();
+ assert!(
+ !file_exists(format!("{working_dir}/foo/baz/foobaz.file")),
+ "Still a file: {working_dir}/foo/baz/foobaz.file"
+ );
+ assert!(
+ !file_exists(format!("{working_dir}/foo/bar/foobar.file")),
+ "Still a file: {working_dir}/foo/bar/foobar.file"
+ );
+ assert!(
+ !file_exists(format!("{working_dir}/foo/foo.file")),
+ "Still a file: {working_dir}/foo/foo.file"
+ );
+ assert!(
+ !is_dir(format!("{working_dir}/foo/baz")),
+ "Still a directory: {working_dir}/foo/baz"
+ );
+ assert!(
+ !is_dir(format!("{working_dir}/foo/bar")),
+ "Still a directory: {working_dir}/foo/bar"
+ );
+ assert!(
+ !is_dir(format!("{working_dir}/foo")),
+ "Still a directory: {working_dir}/foo"
+ );
}
diff --git a/crates/shirabe/tests/util/forgejo_test.rs b/crates/shirabe/tests/util/forgejo_test.rs
index 2cae2ac..e8bf766 100644
--- a/crates/shirabe/tests/util/forgejo_test.rs
+++ b/crates/shirabe/tests/util/forgejo_test.rs
@@ -5,13 +5,13 @@
// available, and a real HttpDownloader reaches curl_multi_init (todo!()).
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
+#[ignore = "requires getIOMock/getHttpDownloaderMock and getMockBuilder mocks of Config/JsonConfigSource with expects()/willReturn(); no mocking infrastructure exists"]
fn test_username_password_authentication_flow() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
+#[ignore = "requires getIOMock/getHttpDownloaderMock and getMockBuilder mocks of Config/JsonConfigSource with expects()/willReturn(); no mocking infrastructure exists"]
fn test_username_password_failure() {
todo!()
}
diff --git a/crates/shirabe/tests/util/git_test.rs b/crates/shirabe/tests/util/git_test.rs
index a78ae88..40ca9da 100644
--- a/crates/shirabe/tests/util/git_test.rs
+++ b/crates/shirabe/tests/util/git_test.rs
@@ -10,46 +10,46 @@ fn set_up() {
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires mocked Config (getMockBuilder Config) and getProcessExecutorMock with expects() command expectations; no mocking infrastructure exists"]
fn test_run_command_public_git_hub_repository_not_initial_clone() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires mocked Config and getProcessExecutorMock with expects() command expectations; no mocking infrastructure exists"]
fn test_run_command_private_git_hub_repository_not_initial_clone_not_interactive_without_authentication()
{
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock and mocked IO (getMockBuilder IOInterface with hasAuthentication/getAuthentication/isInteractive expectations); no mocking infrastructure exists"]
fn test_run_command_private_git_hub_repository_not_initial_clone_not_interactive_with_authentication()
{
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock and mocked IO/Config (getMockBuilder with hasAuthentication/getAuthentication/isInteractive expectations); no mocking infrastructure exists"]
fn test_run_command_private_bitbucket_repository_not_initial_clone_not_interactive_with_authentication()
{
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock, getHttpDownloaderMock and mocked IO/Config with askConfirmation/askAndHideAnswer/setAuthentication expectations; no mocking infrastructure exists"]
fn test_run_command_private_bitbucket_repository_not_initial_clone_interactive_with_oauth() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and mocked Config/Filesystem (getMockBuilder removeDirectory); no mocking infrastructure exists"]
fn test_sync_mirror_sanitizes_url_after_initial_clone() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and mocked Config; no mocking infrastructure exists"]
fn test_sync_mirror_sanitizes_url_even_after_failed_update() {
todo!()
}
diff --git a/crates/shirabe/tests/util/github_test.rs b/crates/shirabe/tests/util/github_test.rs
index 019b858..5caf5c7 100644
--- a/crates/shirabe/tests/util/github_test.rs
+++ b/crates/shirabe/tests/util/github_test.rs
@@ -5,13 +5,13 @@
// available, and a real HttpDownloader reaches curl_multi_init (todo!()).
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
+#[ignore = "requires getIOMock/getHttpDownloaderMock and getMockBuilder mocks of Config/JsonConfigSource with expects()/willReturn(); no mocking infrastructure exists"]
fn test_username_password_authentication_flow() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
+#[ignore = "requires getIOMock/getHttpDownloaderMock and getMockBuilder mocks of Config/JsonConfigSource with expects()/willReturn(); no mocking infrastructure exists"]
fn test_username_password_failure() {
todo!()
}
diff --git a/crates/shirabe/tests/util/gitlab_test.rs b/crates/shirabe/tests/util/gitlab_test.rs
index 27b7258..e7c8bf4 100644
--- a/crates/shirabe/tests/util/gitlab_test.rs
+++ b/crates/shirabe/tests/util/gitlab_test.rs
@@ -4,14 +4,14 @@
// HttpDownloader to drive the username/password authentication flow. Mocking is not
// available, and a real HttpDownloader reaches curl_multi_init (todo!()).
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config/JsonConfigSource (no mock infrastructure)"]
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
fn test_username_password_authentication_flow() {
todo!()
}
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config/JsonConfigSource (no mock infrastructure)"]
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
fn test_username_password_failure() {
todo!()
}
diff --git a/crates/shirabe/tests/util/http/proxy_manager_test.rs b/crates/shirabe/tests/util/http/proxy_manager_test.rs
index 0c177f7..dede524 100644
--- a/crates/shirabe/tests/util/http/proxy_manager_test.rs
+++ b/crates/shirabe/tests/util/http/proxy_manager_test.rs
@@ -38,7 +38,7 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore = "ProxyManager::get_instance returns a shared &'static Mutex, so instance identity (=== / after reset) cannot be expressed through the public API"]
fn test_instantiation() {
let _tear_down = TearDown;
set_up();
@@ -46,49 +46,225 @@ fn test_instantiation() {
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_get_proxy_for_request_throws_on_bad_proxy_url() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ Platform::put_env("http_proxy", "localhost");
+ ProxyManager::reset();
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy_manager = guard.as_ref().unwrap();
+
+ assert!(
+ proxy_manager
+ .get_proxy_for_request("http://example.com")
+ .is_err()
+ );
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_lowercase_overrides_uppercase() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ // server, url, expectedUrl
+ let cases: Vec<(Vec<(&str, &str)>, &str, &str)> = vec![
+ (
+ vec![
+ ("HTTP_PROXY", "http://upper.com"),
+ ("http_proxy", "http://lower.com"),
+ ],
+ "http://repo.org",
+ "http://lower.com:80",
+ ),
+ (
+ vec![
+ ("CGI_HTTP_PROXY", "http://upper.com"),
+ ("cgi_http_proxy", "http://lower.com"),
+ ],
+ "http://repo.org",
+ "http://lower.com:80",
+ ),
+ (
+ vec![
+ ("HTTPS_PROXY", "http://upper.com"),
+ ("https_proxy", "http://lower.com"),
+ ],
+ "https://repo.org",
+ "http://lower.com:80",
+ ),
+ ];
+
+ for (server, url, expected_url) in cases {
+ set_up();
+ for (name, value) in &server {
+ Platform::put_env(name, value);
+ }
+ ProxyManager::reset();
+
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard.as_ref().unwrap().get_proxy_for_request(url).unwrap();
+ assert_eq!(expected_url, proxy.get_status(None).unwrap());
+ }
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_cgi_proxy_is_only_used_when_no_http_proxy() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ // server, expectedUrl
+ let cases: Vec<(Vec<(&str, &str)>, &str)> = vec![
+ (
+ vec![("CGI_HTTP_PROXY", "http://cgi.com:80")],
+ "http://cgi.com:80",
+ ),
+ (
+ vec![
+ ("http_proxy", "http://http.com:80"),
+ ("CGI_HTTP_PROXY", "http://cgi.com:80"),
+ ],
+ "http://http.com:80",
+ ),
+ ];
+
+ for (server, expected_url) in cases {
+ set_up();
+ for (name, value) in &server {
+ Platform::put_env(name, value);
+ }
+ ProxyManager::reset();
+
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard
+ .as_ref()
+ .unwrap()
+ .get_proxy_for_request("http://repo.org")
+ .unwrap();
+ assert_eq!(expected_url, proxy.get_status(None).unwrap());
+ }
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_no_http_proxy_does_not_use_https_proxy() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ Platform::put_env("https_proxy", "https://proxy.com:443");
+ ProxyManager::reset();
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard
+ .as_ref()
+ .unwrap()
+ .get_proxy_for_request("http://repo.org")
+ .unwrap();
+ assert_eq!("", proxy.get_status(None).unwrap());
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_no_https_proxy_does_not_use_http_proxy() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ Platform::put_env("http_proxy", "http://proxy.com:80");
+ ProxyManager::reset();
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard
+ .as_ref()
+ .unwrap()
+ .get_proxy_for_request("https://repo.org")
+ .unwrap();
+ assert_eq!("", proxy.get_status(None).unwrap());
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_get_proxy_for_request() {
+ use indexmap::IndexMap;
+ use shirabe_php_shim::PhpMixed;
+
let _tear_down = TearDown;
set_up();
- todo!()
+
+ let server = vec![
+ ("http_proxy", "http://user:p%40ss@proxy.com"),
+ ("https_proxy", "https://proxy.com:443"),
+ ("no_proxy", "other.repo.org"),
+ ];
+
+ let http_options =
+ |pairs: &[(&str, PhpMixed)]| -> Option<IndexMap<String, IndexMap<String, PhpMixed>>> {
+ let mut http: IndexMap<String, PhpMixed> = IndexMap::new();
+ for (k, v) in pairs {
+ http.insert((*k).to_string(), v.clone());
+ }
+ let mut options: IndexMap<String, IndexMap<String, PhpMixed>> = IndexMap::new();
+ options.insert("http".to_string(), http);
+ Some(options)
+ };
+
+ // server, url, options, status, excluded
+ let cases: Vec<(
+ Vec<(&str, &str)>,
+ &str,
+ Option<IndexMap<String, IndexMap<String, PhpMixed>>>,
+ &str,
+ bool,
+ )> = vec![
+ (vec![], "http://repo.org", None, "", false),
+ (
+ server.clone(),
+ "http://repo.org",
+ http_options(&[
+ ("proxy", PhpMixed::String("tcp://proxy.com:80".to_string())),
+ (
+ "header",
+ PhpMixed::String("Proxy-Authorization: Basic dXNlcjpwQHNz".to_string()),
+ ),
+ ("request_fulluri", PhpMixed::Bool(true)),
+ ]),
+ "http://***:***@proxy.com:80",
+ false,
+ ),
+ (
+ server.clone(),
+ "https://repo.org",
+ http_options(&[("proxy", PhpMixed::String("ssl://proxy.com:443".to_string()))]),
+ "https://proxy.com:443",
+ false,
+ ),
+ (
+ server.clone(),
+ "https://other.repo.org",
+ None,
+ "excluded by no_proxy",
+ true,
+ ),
+ ];
+
+ for (srv, url, options, status, excluded) in cases {
+ set_up();
+ for (name, value) in &srv {
+ Platform::put_env(name, value);
+ }
+ ProxyManager::reset();
+
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard.as_ref().unwrap().get_proxy_for_request(url).unwrap();
+
+ assert_eq!(options.as_ref(), proxy.get_context_options());
+ assert_eq!(status, proxy.get_status(None).unwrap());
+ assert_eq!(excluded, proxy.is_excluded_by_no_proxy());
+ }
}
diff --git a/crates/shirabe/tests/util/http_downloader_test.rs b/crates/shirabe/tests/util/http_downloader_test.rs
index 238fe83..5c34e19 100644
--- a/crates/shirabe/tests/util/http_downloader_test.rs
+++ b/crates/shirabe/tests/util/http_downloader_test.rs
@@ -1,13 +1,107 @@
//! ref: composer/tests/Composer/Test/Util/HttpDownloaderTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::io::IOInterface;
+use shirabe::io::buffer_io::BufferIO;
+use shirabe::util::http_downloader::HttpDownloader;
+use shirabe_external_packages::symfony::console::output::output_interface::VERBOSITY_NORMAL;
+use shirabe_php_shim::{PHP_EOL, PhpMixed};
+
#[test]
-#[ignore = "constructs a real HttpDownloader (curl_multi_init is todo!()) and mocks a Config; performs a network request"]
+#[ignore = "asserts IOInterface mock ->expects()->method('setAuthentication')->with(...) and performs a live HTTP get; no mock infrastructure exists"]
fn test_capture_authentication_params_from_url() {
todo!()
}
#[test]
-#[ignore = "constructs a real HttpDownloader (curl_multi_init is todo!()) and mocks a Config; performs a network request"]
+#[ignore]
fn test_output_warnings() {
- todo!()
+ let io: Rc<RefCell<BufferIO>> = Rc::new(RefCell::new(
+ BufferIO::new(String::new(), VERBOSITY_NORMAL, None).unwrap(),
+ ));
+ let io_dyn: Rc<RefCell<dyn IOInterface>> = io.clone();
+
+ HttpDownloader::output_warnings(io_dyn.clone(), "$URL", &IndexMap::new()).unwrap();
+ assert_eq!("", io.borrow().get_output());
+
+ let mut data: IndexMap<String, PhpMixed> = IndexMap::new();
+ data.insert(
+ "warning".to_string(),
+ PhpMixed::String("old warning msg".to_string()),
+ );
+ data.insert(
+ "warning-versions".to_string(),
+ PhpMixed::String(">=2.0".to_string()),
+ );
+ data.insert(
+ "info".to_string(),
+ PhpMixed::String("old info msg".to_string()),
+ );
+ data.insert(
+ "info-versions".to_string(),
+ PhpMixed::String(">=2.0".to_string()),
+ );
+
+ let mut warning_should_not = IndexMap::new();
+ warning_should_not.insert(
+ "message".to_string(),
+ PhpMixed::String("should not appear".to_string()),
+ );
+ warning_should_not.insert("versions".to_string(), PhpMixed::String("<2.2".to_string()));
+ let mut warning_visible = IndexMap::new();
+ warning_visible.insert(
+ "message".to_string(),
+ PhpMixed::String("visible warning".to_string()),
+ );
+ warning_visible.insert(
+ "versions".to_string(),
+ PhpMixed::String(">=2.2-dev".to_string()),
+ );
+ data.insert(
+ "warnings".to_string(),
+ PhpMixed::List(vec![
+ PhpMixed::Array(warning_should_not),
+ PhpMixed::Array(warning_visible),
+ ]),
+ );
+
+ let mut info_should_not = IndexMap::new();
+ info_should_not.insert(
+ "message".to_string(),
+ PhpMixed::String("should not appear".to_string()),
+ );
+ info_should_not.insert("versions".to_string(), PhpMixed::String("<2.2".to_string()));
+ let mut info_visible = IndexMap::new();
+ info_visible.insert(
+ "message".to_string(),
+ PhpMixed::String("visible info".to_string()),
+ );
+ info_visible.insert(
+ "versions".to_string(),
+ PhpMixed::String(">=2.2-dev".to_string()),
+ );
+ data.insert(
+ "infos".to_string(),
+ PhpMixed::List(vec![
+ PhpMixed::Array(info_should_not),
+ PhpMixed::Array(info_visible),
+ ]),
+ );
+
+ HttpDownloader::output_warnings(io_dyn.clone(), "$URL", &data).unwrap();
+
+ // the <info> tag are consumed by the OutputFormatter, but not <warning> as that is not a default output format
+ assert_eq!(
+ format!(
+ "<warning>Warning from $URL: old warning msg</warning>{eol}\
+ Info from $URL: old info msg{eol}\
+ <warning>Warning from $URL: visible warning</warning>{eol}\
+ Info from $URL: visible info{eol}",
+ eol = PHP_EOL
+ ),
+ io.borrow().get_output()
+ );
}
diff --git a/crates/shirabe/tests/util/metadata_minifier_test.rs b/crates/shirabe/tests/util/metadata_minifier_test.rs
index 03bee8e..85ed507 100644
--- a/crates/shirabe/tests/util/metadata_minifier_test.rs
+++ b/crates/shirabe/tests/util/metadata_minifier_test.rs
@@ -1,7 +1,7 @@
//! ref: composer/tests/Composer/Test/Util/MetadataMinifierTest.php
#[test]
-#[ignore = "MetadataMinifier::minify is intentionally not ported in shirabe_external_packages (unused by Composer itself)"]
+#[ignore = "MetadataMinifier::minify is not ported (intentionally absent in metadata_minifier.rs)"]
fn test_minify_expand() {
todo!()
}
diff --git a/crates/shirabe/tests/util/perforce_test.rs b/crates/shirabe/tests/util/perforce_test.rs
index fb517ba..0a62ebb 100644
--- a/crates/shirabe/tests/util/perforce_test.rs
+++ b/crates/shirabe/tests/util/perforce_test.rs
@@ -3,6 +3,55 @@
// These mock IO and a ProcessExecutor to drive Perforce client/stream/command behaviour;
// mocking is not available here.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::io::{IOInterface, NullIO};
+use shirabe::util::{Perforce, ProcessExecutor};
+use shirabe_php_shim::PhpMixed;
+
+const TEST_DEPOT: &str = "depot";
+const TEST_BRANCH: &str = "branch";
+const TEST_P4USER: &str = "user";
+const TEST_CLIENT_NAME: &str = "TEST";
+const TEST_PORT: &str = "port";
+const TEST_PATH: &str = "path";
+
+fn get_test_repo_config() -> IndexMap<String, PhpMixed> {
+ let mut config = IndexMap::new();
+ config.insert(
+ "depot".to_string(),
+ PhpMixed::String(TEST_DEPOT.to_string()),
+ );
+ config.insert(
+ "branch".to_string(),
+ PhpMixed::String(TEST_BRANCH.to_string()),
+ );
+ config.insert(
+ "p4user".to_string(),
+ PhpMixed::String(TEST_P4USER.to_string()),
+ );
+ config.insert(
+ "unique_perforce_client_name".to_string(),
+ PhpMixed::String(TEST_CLIENT_NAME.to_string()),
+ );
+ config
+}
+
+fn create_new_perforce_with_windows_flag(flag: bool) -> Perforce {
+ let process = Rc::new(RefCell::new(ProcessExecutor::new(None)));
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ Perforce::new(
+ get_test_repo_config(),
+ TEST_PORT.to_string(),
+ TEST_PATH.to_string(),
+ process,
+ flag,
+ io,
+ )
+}
+
#[allow(dead_code)]
fn set_up() {
// Builds mocked ProcessExecutor/IO, the test repo config, and a Windows-flagged Perforce;
@@ -10,230 +59,296 @@ fn set_up() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_client_without_stream() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ let client = perforce.get_client();
+
+ let expected = "composer_perforce_TEST_depot";
+ assert_eq!(expected, client);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_client_from_stream() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+ perforce.set_stream("//depot/branch");
+
+ let client = perforce.get_client();
+
+ let expected = "composer_perforce_TEST_depot_branch";
+ assert_eq!(expected, client);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_stream_without_stream() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ let stream = perforce.get_stream();
+ assert_eq!("//depot", stream);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_stream_with_stream() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+ perforce.set_stream("//depot/branch");
+
+ let stream = perforce.get_stream();
+ assert_eq!("//depot/branch", stream);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_stream_without_label_with_stream_without_label() {
- todo!()
+ let perforce = create_new_perforce_with_windows_flag(true);
+
+ let stream = perforce.get_stream_without_label("//depot/branch");
+ assert_eq!("//depot/branch", stream);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_stream_without_label_with_stream_with_label() {
- todo!()
+ let perforce = create_new_perforce_with_windows_flag(true);
+
+ let stream = perforce.get_stream_without_label("//depot/branching@label");
+ assert_eq!("//depot/branching", stream);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_client_spec() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ let client_spec = perforce.get_p4_client_spec();
+ let expected = "path/composer_perforce_TEST_depot.p4.spec";
+ assert_eq!(expected, client_spec);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_generate_p4_command() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ let p4_command =
+ perforce.generate_p4_command(vec!["do".to_string(), "something".to_string()], true);
+ let expected = vec![
+ "p4".to_string(),
+ "-u".to_string(),
+ "user".to_string(),
+ "-c".to_string(),
+ "composer_perforce_TEST_depot".to_string(),
+ "-p".to_string(),
+ "port".to_string(),
+ "do".to_string(),
+ "something".to_string(),
+ ];
+ assert_eq!(expected, p4_command);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_query_p4_user_with_user_already_set() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ perforce.query_p4_user();
+ assert_eq!(Some(TEST_P4USER.to_string()), perforce.get_user());
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command stdout stubbing (p4 set => P4USER=...); no mocking infrastructure exists"]
fn test_query_p4_user_with_user_set_in_p4_variables_with_windows_os() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command stdout stubbing (echo $P4USER => ...); no mocking infrastructure exists"]
fn test_query_p4_user_with_user_set_in_p4_variables_not_windows_os() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock; no mocking infrastructure exists"]
fn test_query_p4_user_queries_for_user() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock expects() command verification; no mocking infrastructure exists"]
fn test_query_p4_user_stores_response_to_query_for_user_with_windows() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock expects() command verification; no mocking infrastructure exists"]
fn test_query_p4_user_stores_response_to_query_for_user_without_windows() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock expects() command verification; no mocking infrastructure exists"]
fn test_query_p4_user_escapes_injection_on_windows() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock expects() command verification; no mocking infrastructure exists"]
fn test_query_p4_user_escapes_injection_on_unix() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_query_p4_password_with_password_already_set() {
- todo!()
+ let mut repo_config = IndexMap::new();
+ repo_config.insert("depot".to_string(), PhpMixed::String("depot".to_string()));
+ repo_config.insert("branch".to_string(), PhpMixed::String("branch".to_string()));
+ repo_config.insert("p4user".to_string(), PhpMixed::String("user".to_string()));
+ repo_config.insert(
+ "p4password".to_string(),
+ PhpMixed::String("TEST_PASSWORD".to_string()),
+ );
+ let process = Rc::new(RefCell::new(ProcessExecutor::new(None)));
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let mut perforce = Perforce::new(
+ repo_config,
+ "port".to_string(),
+ "path".to_string(),
+ process,
+ false,
+ io,
+ );
+
+ let password = perforce.query_p4_password();
+ assert_eq!(Some("TEST_PASSWORD".to_string()), password);
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command stdout stubbing (p4 set => P4PASSWD=...); no mocking infrastructure exists"]
fn test_query_p4_password_with_password_set_in_p4_variables_with_windows_os() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command stdout stubbing (echo $P4PASSWD => ...); no mocking infrastructure exists"]
fn test_query_p4_password_with_password_set_in_p4_variables_not_windows_os() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface askAndHideAnswer()->willReturn; no mocking infrastructure exists"]
fn test_query_p4_password_queries_for_password() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for the p4 client spec write; no mocking infrastructure exists"]
fn test_write_p4_client_spec_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for the p4 client spec write; no mocking infrastructure exists"]
fn test_write_p4_client_spec_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 login -s; no mocking infrastructure exists"]
fn test_is_logged_in() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 streams; no mocking infrastructure exists"]
fn test_get_branches_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 changes; no mocking infrastructure exists"]
fn test_get_branches_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 changes; no mocking infrastructure exists"]
fn test_get_tags_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 changes; no mocking infrastructure exists"]
fn test_get_tags_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 streams; no mocking infrastructure exists"]
fn test_check_stream_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 streams; no mocking infrastructure exists"]
fn test_check_stream_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 print composer.json; no mocking infrastructure exists"]
fn test_get_composer_information_without_label_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 print composer.json; no mocking infrastructure exists"]
fn test_get_composer_information_with_label_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 print composer.json; no mocking infrastructure exists"]
fn test_get_composer_information_without_label_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 print composer.json; no mocking infrastructure exists"]
fn test_get_composer_information_with_label_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for p4 sync; no mocking infrastructure exists"]
fn test_sync_code_base_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for p4 sync; no mocking infrastructure exists"]
fn test_sync_code_base_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 info -s; no mocking infrastructure exists"]
fn test_check_server_exists() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 info -s; no mocking infrastructure exists"]
fn test_check_server_client_error() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for p4 client -d; no mocking infrastructure exists"]
fn test_cleanup_client_spec_should_delete_client() {
todo!()
}
diff --git a/crates/shirabe/tests/util/process_executor_test.rs b/crates/shirabe/tests/util/process_executor_test.rs
index 88449f1..f17f162 100644
--- a/crates/shirabe/tests/util/process_executor_test.rs
+++ b/crates/shirabe/tests/util/process_executor_test.rs
@@ -3,68 +3,206 @@
// These run real subprocesses (capturing output/stderr/timeout) and assert ProcessExecutor's
// password hiding, line splitting and argument escaping; the subprocess execution and mocked
// IO are not ported.
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use shirabe::io::ConsoleIO;
+use shirabe::io::IOInterface;
+use shirabe::io::buffer_io::BufferIO;
+use shirabe::util::process_executor::ProcessExecutor;
+use shirabe_external_packages::symfony::console::helper::HelperSet;
+use shirabe_external_packages::symfony::console::input::array_input::ArrayInput;
+use shirabe_external_packages::symfony::console::input::input_interface::InputInterface;
+use shirabe_external_packages::symfony::console::output::buffered_output::BufferedOutput;
+use shirabe_external_packages::symfony::console::output::output_interface::{
+ OutputInterface, VERBOSITY_DEBUG, VERBOSITY_NORMAL,
+};
+use shirabe_php_shim::{PHP_EOL, trim};
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_execute_captures_output() {
- todo!()
+ let mut process = ProcessExecutor::new(None);
+ let mut output = String::new();
+ process.execute("echo foo", &mut output, ()).unwrap();
+ assert_eq!(format!("foo{}", PHP_EOL), output);
}
+#[ignore = "requires PHP output buffering (ob_start/ob_get_clean) to capture stdout; no equivalent symbol"]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_execute_outputs_if_not_captured() {
todo!()
}
+#[ignore = "requires getMockBuilder('IOInterface') with expects()->once()->method('writeRaw')->with() expectation verification; no mocking framework"]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_use_io_is_not_null_and_if_not_captured() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_execute_captures_stderr() {
- todo!()
+ let mut process = ProcessExecutor::new(None);
+ let mut output = String::new();
+ process.execute("cat foo", &mut output, ()).unwrap();
+ assert!(
+ process
+ .get_error_output()
+ .contains("foo: No such file or directory")
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_timeout() {
- todo!()
+ ProcessExecutor::set_timeout(1_i64);
+ let process = ProcessExecutor::new(None);
+ assert_eq!(1, ProcessExecutor::get_timeout());
+ let _ = &process;
+ ProcessExecutor::set_timeout(60_i64);
+}
+
+fn hide_password_provider() -> Vec<(&'static str, &'static str)> {
+ vec![
+ (
+ "echo https://foo:bar@example.org/",
+ "echo https://foo:***@example.org/",
+ ),
+ ("echo http://foo@example.org", "echo http://foo@example.org"),
+ (
+ "echo http://abcdef1234567890234578:x-oauth-token@github.com/",
+ "echo http://***:***@github.com/",
+ ),
+ (
+ "echo http://github_pat_1234567890abcdefghijkl_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW:x-oauth-token@github.com/",
+ "echo http://***:***@github.com/",
+ ),
+ (
+ "svn ls --verbose --non-interactive --username 'foo' --password 'bar' 'https://foo.example.org/svn/'",
+ "svn ls --verbose --non-interactive --username 'foo' --password '***' 'https://foo.example.org/svn/'",
+ ),
+ (
+ "svn ls --verbose --non-interactive --username 'foo' --password 'bar 'bar' 'https://foo.example.org/svn/'",
+ "svn ls --verbose --non-interactive --username 'foo' --password '***' 'https://foo.example.org/svn/'",
+ ),
+ ]
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_hide_passwords() {
- todo!()
+ for (command, expected_command_output) in hide_password_provider() {
+ let buffer = Rc::new(RefCell::new(
+ BufferIO::new(String::new(), VERBOSITY_DEBUG, None).unwrap(),
+ ));
+ let mut process =
+ ProcessExecutor::new(Some(buffer.clone() as Rc<RefCell<dyn IOInterface>>));
+ let mut output = String::new();
+ process.execute(command, &mut output, ()).unwrap();
+ assert_eq!(
+ format!("Executing command (CWD): {}", expected_command_output),
+ trim(&buffer.borrow().get_output(), None)
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_doesnt_hide_ports() {
- todo!()
+ let buffer = Rc::new(RefCell::new(
+ BufferIO::new(String::new(), VERBOSITY_DEBUG, None).unwrap(),
+ ));
+ let mut process = ProcessExecutor::new(Some(buffer.clone() as Rc<RefCell<dyn IOInterface>>));
+ let mut output = String::new();
+ process
+ .execute("echo https://localhost:1234/", &mut output, ())
+ .unwrap();
+ assert_eq!(
+ "Executing command (CWD): echo https://localhost:1234/",
+ trim(&buffer.borrow().get_output(), None)
+ );
}
+#[ignore = "splitLines is called with null in the PHP test, but split_lines accepts only &str (no ?string/Option overload)"]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_split_lines() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_console_io_does_not_format_symfony_console_style() {
- todo!()
+ let output = Rc::new(RefCell::new(BufferedOutput::new(
+ Some(VERBOSITY_NORMAL),
+ true,
+ None,
+ )));
+ let input: Rc<RefCell<dyn InputInterface>> =
+ Rc::new(RefCell::new(ArrayInput::new(vec![], None).unwrap()));
+ let console_io = ConsoleIO::new(
+ input,
+ output.clone() as Rc<RefCell<dyn OutputInterface>>,
+ HelperSet::default(),
+ );
+ let mut process = ProcessExecutor::new(Some(
+ Rc::new(RefCell::new(console_io)) as Rc<RefCell<dyn IOInterface>>
+ ));
+
+ process
+ .execute(
+ r#"php -ddisplay_errors=0 -derror_reporting=0 -r "echo '<error>foo</error>'.PHP_EOL;""#,
+ (),
+ (),
+ )
+ .unwrap();
+ assert_eq!(
+ format!("<error>foo</error>{}", PHP_EOL),
+ output.borrow().fetch()
+ );
}
+#[ignore = "executeAsync returns a Process, not a cancelable promise; no promise/cancel symbol exists"]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_execute_async_cancel() {
todo!()
}
+fn data_escape_arguments() -> Vec<(&'static str, &'static str)> {
+ // (argument, unix-expected). Not on Windows, so the unix column is used.
+ // null and false arguments are coerced to the empty string.
+ vec![
+ ("", "''"),
+ ("", "''"),
+ ("", "''"),
+ ("a'bc", "'a'\\''bc'"),
+ ("a\nb\nc", "'a\nb\nc'"),
+ ("a b c", "'a b c'"),
+ ("a\tb\tc", "'a\tb\tc'"),
+ ("abc", "'abc'"),
+ ("a,bc", "'a,bc'"),
+ ("a\"bc", "'a\"bc'"),
+ ("a\\\"bc", "'a\\\"bc'"),
+ ("ab\\\\c\\", "'ab\\\\c\\'"),
+ ("a b c\\\\", "'a b c\\\\'"),
+ ("a \"b\" c", "'a \"b\" c'"),
+ ("%path%", "'%path%'"),
+ ("%path", "'%path'"),
+ ("%%path", "'%%path'"),
+ ("!path!", "'!path!'"),
+ ("!path", "'!path'"),
+ ("!!path", "'!!path'"),
+ ("<>\"&|()^", "'<>\"&|()^'"),
+ ("<> &| ()^", "'<> &| ()^'"),
+ ("<>&|()^", "'<>&|()^'"),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_escape_argument() {
- todo!()
+ for (argument, unix) in data_escape_arguments() {
+ assert_eq!(unix, ProcessExecutor::escape(argument));
+ }
}
diff --git a/crates/shirabe/tests/util/remote_filesystem_test.rs b/crates/shirabe/tests/util/remote_filesystem_test.rs
index 1fc9f7e..b39a2dd 100644
--- a/crates/shirabe/tests/util/remote_filesystem_test.rs
+++ b/crates/shirabe/tests/util/remote_filesystem_test.rs
@@ -4,79 +4,79 @@
// building and downloads; mocking/reflection are not available and a real HttpDownloader
// reaches curl_multi_init (todo!()).
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->hasAuthentication) and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->hasAuthentication/getAuthentication) and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url_with_authorization() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->hasAuthentication/getAuthentication) and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url_with_stream_options() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->hasAuthentication/getAuthentication) and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url_with_call_options_keeps_header() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and ReflectionMethod to invoke private callback_get plus ReflectionProperty to read private bytes_max; no mocking/reflection infrastructure exists"]
fn test_callback_get_file_size() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->overwriteError) and ReflectionProperty to set private bytes_max/progress and read private last_progress; no mocking/reflection infrastructure exists"]
fn test_callback_get_notify_progress() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and ReflectionMethod to invoke private callback_get; no mocking/reflection infrastructure exists"]
fn test_callback_get_passes_through404() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and a real get_contents which bottoms at curl_multi_init (todo!()); no mocking infrastructure exists"]
fn test_get_contents() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and a real copy which bottoms at curl_multi_init (todo!()); no mocking infrastructure exists"]
fn test_copy() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a MockObject subclass of RemoteFilesystem overriding private get_remote_contents; no mocking infrastructure exists"]
fn test_copy_with_no_retry_on_failure() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires MockObject subclasses overriding RemoteFilesystem::get_remote_contents and AuthHelper::prompt_auth_if_needed; no mocking infrastructure exists"]
fn test_copy_with_success_on_retry() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url_creates_secure_tls_defaults() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked ConsoleIO (getMockBuilder disableOriginalConstructor) and a real getContents network download reaching curl_multi_init (todo!()); no mocking infrastructure exists"]
fn test_bit_bucket_public_download() {
todo!()
}
diff --git a/crates/shirabe/tests/util/stream_context_factory_test.rs b/crates/shirabe/tests/util/stream_context_factory_test.rs
index f58ee75..23d4392 100644
--- a/crates/shirabe/tests/util/stream_context_factory_test.rs
+++ b/crates/shirabe/tests/util/stream_context_factory_test.rs
@@ -3,8 +3,11 @@
// These build a stream context and assert proxy/option handling driven by HTTP(S)_PROXY /
// no_proxy environment variables; the env-dependent setup (without its setUp/tearDown
// isolation) is not ported.
+use indexmap::IndexMap;
use shirabe::util::http::proxy_manager::ProxyManager;
use shirabe::util::platform::Platform;
+use shirabe::util::stream_context_factory::StreamContextFactory;
+use shirabe_php_shim::{PhpMixed, implode, stripos};
fn set_up() {
Platform::clear_env("HTTP_PROXY");
@@ -35,7 +38,7 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options/stream_context_get_params shim functions do not exist; cannot read back created context to assert"]
fn test_get_context() {
let _tear_down = TearDown;
set_up();
@@ -43,7 +46,7 @@ fn test_get_context() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_http_proxy() {
let _tear_down = TearDown;
set_up();
@@ -51,7 +54,7 @@ fn test_http_proxy() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_http_proxy_with_no_proxy() {
let _tear_down = TearDown;
set_up();
@@ -59,7 +62,7 @@ fn test_http_proxy_with_no_proxy() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_http_proxy_with_no_proxy_wildcard() {
let _tear_down = TearDown;
set_up();
@@ -67,7 +70,7 @@ fn test_http_proxy_with_no_proxy_wildcard() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_options_are_preserved() {
let _tear_down = TearDown;
set_up();
@@ -75,7 +78,7 @@ fn test_options_are_preserved() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_http_proxy_without_port() {
let _tear_down = TearDown;
set_up();
@@ -83,7 +86,7 @@ fn test_http_proxy_without_port() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_https_proxy_override() {
let _tear_down = TearDown;
set_up();
@@ -91,7 +94,7 @@ fn test_https_proxy_override() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_ssl_proxy() {
let _tear_down = TearDown;
set_up();
@@ -99,7 +102,7 @@ fn test_ssl_proxy() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_ensure_thatfix_http_header_field_moves_content_type_to_end_of_options() {
let _tear_down = TearDown;
set_up();
@@ -107,17 +110,54 @@ fn test_ensure_thatfix_http_header_field_moves_content_type_to_end_of_options()
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore]
fn test_init_options_does_include_proxy_auth_headers() {
let _tear_down = TearDown;
set_up();
- todo!()
+ Platform::put_env(
+ "https_proxy",
+ "http://username:password@proxyserver.net:3128/",
+ );
+
+ let options: IndexMap<String, PhpMixed> = IndexMap::new();
+ let options =
+ StreamContextFactory::init_options("https://example.org", options, false).unwrap();
+ let header_list: Vec<String> = options
+ .get("http")
+ .and_then(|v| v.as_array())
+ .and_then(|a| a.get("header"))
+ .and_then(|v| v.as_list())
+ .unwrap()
+ .iter()
+ .filter_map(|item| item.as_string().map(|s| s.to_string()))
+ .collect();
+ let headers = implode(" ", &header_list);
+
+ assert!(stripos(&headers, "Proxy-Authorization").is_some());
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore]
fn test_init_options_for_curl_does_not_include_proxy_auth_headers() {
let _tear_down = TearDown;
set_up();
- todo!()
+ Platform::put_env(
+ "http_proxy",
+ "http://username:password@proxyserver.net:3128/",
+ );
+
+ let options: IndexMap<String, PhpMixed> = IndexMap::new();
+ let options = StreamContextFactory::init_options("https://example.org", options, true).unwrap();
+ let header_list: Vec<String> = options
+ .get("http")
+ .and_then(|v| v.as_array())
+ .and_then(|a| a.get("header"))
+ .and_then(|v| v.as_list())
+ .unwrap()
+ .iter()
+ .filter_map(|item| item.as_string().map(|s| s.to_string()))
+ .collect();
+ let headers = implode(" ", &header_list);
+
+ assert!(stripos(&headers, "Proxy-Authorization").is_none());
}
diff --git a/crates/shirabe/tests/util/svn_test.rs b/crates/shirabe/tests/util/svn_test.rs
index 5e2775f..90a6b45 100644
--- a/crates/shirabe/tests/util/svn_test.rs
+++ b/crates/shirabe/tests/util/svn_test.rs
@@ -1,33 +1,31 @@
//! ref: composer/tests/Composer/Test/Util/SvnTest.php
-// These mock IO/Config and use reflection to drive Svn's credential handling; mocking and
-// reflection are not available here.
+#[ignore = "Svn::get_credential_args is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_credentials() {
todo!()
}
+#[ignore = "Svn::get_command is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_interactive_string() {
todo!()
}
+#[ignore = "Svn::get_credential_args is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_credentials_from_config() {
todo!()
}
+#[ignore = "Svn::get_credential_args is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_credentials_from_config_with_cache_credentials_true() {
todo!()
}
+#[ignore = "Svn::get_credential_args is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_credentials_from_config_with_cache_credentials_false() {
todo!()
}
diff --git a/crates/shirabe/tests/util/tls_helper_test.rs b/crates/shirabe/tests/util/tls_helper_test.rs
index 260ff47..4717282 100644
--- a/crates/shirabe/tests/util/tls_helper_test.rs
+++ b/crates/shirabe/tests/util/tls_helper_test.rs
@@ -1,13 +1,13 @@
//! ref: composer/tests/Composer/Test/Util/TlsHelperTest.php
#[test]
-#[ignore = "Composer\\Util\\TlsHelper is not yet ported"]
+#[ignore = "TlsHelper::check_certificate_host not implemented in crates/shirabe/src"]
fn test_check_certificate_host() {
todo!()
}
#[test]
-#[ignore = "Composer\\Util\\TlsHelper is not yet ported"]
+#[ignore = "TlsHelper::get_certificate_names not implemented in crates/shirabe/src"]
fn test_get_certificate_names() {
todo!()
}