diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-22 23:42:07 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-22 23:42:07 +0900 |
| commit | 5ab5f3b316798c1411ce8e6a7f5b091fda93589c (patch) | |
| tree | c7669f94f5d9bd9adc07bc1aab3f14cfdec1ae5f /crates/shirabe/tests/repository | |
| parent | b291e714bc739262140323e08fe2fb9e91e00ee7 (diff) | |
| download | php-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.tar.gz php-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.tar.zst php-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.zip | |
test: port previously-ignored Composer tests via __ test hatches
Re-evaluate the reason'd #[ignore] tests under the Phase D criterion:
a test is unportable ONLY if the APIs/types needed to WRITE it do not
exist. A test that compiles but panics at runtime (todo!() body, a
regex the regex crate cannot compile) or fails at runtime (incomplete
or incorrect impl behavior) is portable -- it is written in full and
marked with a reason-less #[ignore].
About 120 test functions move from reason'd #[ignore] to reason-less
#[ignore] (the ported-but-not-yet-passing signal). Impl crates gain
only additive __ test hatches (init_command, pool, file_downloader,
package handle link setters, artifact/path repository, repository
manager, svn); no existing logic changes. Tests whose required APIs
genuinely do not exist (mock/reflection harness, ApplicationTester,
solve() discarding SolverProblemsException, a script::Event that
cannot be passed as an originating event) keep their reason'd
#[ignore].
cargo check -p shirabe --tests passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/repository')
9 files changed, 365 insertions, 38 deletions
diff --git a/crates/shirabe/tests/repository/array_repository_test.rs b/crates/shirabe/tests/repository/array_repository_test.rs index ee6dfb9..60bea16 100644 --- a/crates/shirabe/tests/repository/array_repository_test.rs +++ b/crates/shirabe/tests/repository/array_repository_test.rs @@ -100,7 +100,7 @@ fn test_find_packages() { } #[test] -#[ignore = "AliasPackage::get_unique_name returns the aliased package's name, so has_package misses the alias version"] +#[ignore] fn test_automatically_add_aliased_package_but_not_remove() { let mut repo = ArrayRepository::new(vec![]).unwrap(); diff --git a/crates/shirabe/tests/repository/artifact_repository_test.rs b/crates/shirabe/tests/repository/artifact_repository_test.rs index 14475da..765bdac 100644 --- a/crates/shirabe/tests/repository/artifact_repository_test.rs +++ b/crates/shirabe/tests/repository/artifact_repository_test.rs @@ -1,9 +1,12 @@ //! ref: composer/tests/Composer/Test/Repository/ArtifactRepositoryTest.php -// ArtifactRepository::getPackages scans the fixture directory and opens each archive via -// ZipArchive / PharData, both of which are todo!() in the php-shim. +use std::cell::RefCell; +use std::rc::Rc; -use shirabe_php_shim::extension_loaded; +use indexmap::IndexMap; +use shirabe::io::{IOInterface, NullIO}; +use shirabe::repository::ArtifactRepository; +use shirabe_php_shim::{PhpMixed, extension_loaded}; fn set_up() { if !extension_loaded("zip") { @@ -12,23 +15,104 @@ fn set_up() { } } +fn artifacts_dir() -> String { + format!( + "{}/../../composer/tests/Composer/Test/Repository/Fixtures/artifacts", + env!("CARGO_MANIFEST_DIR") + ) +} + +fn create_repo(url: &str) -> ArtifactRepository { + let mut coordinates: IndexMap<String, PhpMixed> = IndexMap::new(); + coordinates.insert("type".to_string(), PhpMixed::String("artifact".to_string())); + coordinates.insert("url".to_string(), PhpMixed::String(url.to_string())); + + let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new())); + ArtifactRepository::new(coordinates, io).unwrap() +} + #[test] -#[ignore = "ArtifactRepository exposes no public get_packages(); it does not impl RepositoryInterface and initialize/scan_directory are private"] +#[ignore] fn test_extracts_configs_from_zip_archives() { set_up(); - todo!() + + let mut expected_packages = vec![ + "vendor0/package0-0.0.1".to_string(), + "composer/composer-1.0.0-alpha6".to_string(), + "vendor1/package2-4.3.2".to_string(), + "vendor3/package1-5.4.3".to_string(), + "test/jsonInRoot-1.0.0".to_string(), + "test/jsonInRootTarFile-1.0.0".to_string(), + "test/jsonInFirstLevel-1.0.0".to_string(), + // The files not-an-artifact.zip and jsonSecondLevel are not valid + // artifacts and do not get detected. + ]; + + let mut repo = create_repo(&artifacts_dir()); + + let mut found_packages: Vec<String> = repo + .__get_packages() + .unwrap() + .iter() + .map(|package| { + format!( + "{}-{}", + package.get_pretty_name(), + package.get_pretty_version() + ) + }) + .collect(); + + expected_packages.sort(); + found_packages.sort(); + + assert_eq!(expected_packages, found_packages); + + let tar_package: Vec<_> = repo + .__get_packages() + .unwrap() + .into_iter() + .filter(|package| package.get_pretty_name() == "test/jsonInRootTarFile") + .collect(); + assert_eq!(1, tar_package.len()); + let tar_package = tar_package.into_iter().next_back().unwrap(); + assert_eq!(Some("tar".to_string()), tar_package.get_dist_type()); } #[test] -#[ignore = "ArtifactRepository exposes no public get_packages(); it does not impl RepositoryInterface and initialize/scan_directory are private"] +#[ignore] fn test_absolute_repo_url_creates_absolute_url_packages() { set_up(); - todo!() + + let absolute_path = artifacts_dir(); + let mut repo = create_repo(&absolute_path); + + for package in repo.__get_packages().unwrap() { + assert_eq!( + package + .get_dist_url() + .unwrap_or_default() + .find(&absolute_path.replace('\\', "/")), + Some(0) + ); + } } #[test] -#[ignore = "ArtifactRepository exposes no public get_packages(); it does not impl RepositoryInterface and initialize/scan_directory are private"] +#[ignore] fn test_relative_repo_url_creates_relative_url_packages() { set_up(); - todo!() + + let relative_path = "tests/Composer/Test/Repository/Fixtures/artifacts"; + let mut repo = create_repo(relative_path); + + for package in repo.__get_packages().unwrap() { + assert_eq!( + package + .get_dist_url() + .unwrap_or_default() + .find(relative_path), + Some(0) + ); + } } diff --git a/crates/shirabe/tests/repository/composite_repository_test.rs b/crates/shirabe/tests/repository/composite_repository_test.rs index e21ac65..f01a3fd 100644 --- a/crates/shirabe/tests/repository/composite_repository_test.rs +++ b/crates/shirabe/tests/repository/composite_repository_test.rs @@ -27,7 +27,7 @@ fn test_has_package() { } #[test] -#[ignore = "constraint parsing uses a look-around regex the regex crate does not support"] +#[ignore] fn test_find_package() { let mut repo = CompositeRepository::new(vec![ array_repo(vec![get_package("foo", "1")]), diff --git a/crates/shirabe/tests/repository/installed_repository_test.rs b/crates/shirabe/tests/repository/installed_repository_test.rs index b2c88a6..6720260 100644 --- a/crates/shirabe/tests/repository/installed_repository_test.rs +++ b/crates/shirabe/tests/repository/installed_repository_test.rs @@ -34,7 +34,7 @@ fn provided_link() -> PhpMixed { } #[test] -#[ignore = "InstalledRepository::add_repository asserts on a fixed set of repo types that omits InstalledRepositoryInterface, so adding an InstalledArrayRepository panics"] +#[ignore] fn test_find_packages_with_replacers_and_providers() { let foo = loaded("foo", "1", vec![("replace", provided_link())]); let foo2 = get_package("foo", "2"); diff --git a/crates/shirabe/tests/repository/path_repository_test.rs b/crates/shirabe/tests/repository/path_repository_test.rs index c2cf892..cea6a85 100644 --- a/crates/shirabe/tests/repository/path_repository_test.rs +++ b/crates/shirabe/tests/repository/path_repository_test.rs @@ -1,54 +1,253 @@ //! ref: composer/tests/Composer/Test/Repository/PathRepositoryTest.php -// PathRepository does not implement RepositoryInterface and exposes no public -// getPackages/count/hasPackage; the delegation to its inner ArrayRepository is not yet -// ported, so there is no way to drive these tests. The unversioned cases additionally -// require the VersionGuesser (git). +use std::cell::RefCell; +use std::rc::Rc; -#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"] +use indexmap::IndexMap; +use shirabe::config::Config; +use shirabe::io::{IOInterface, NullIO}; +use shirabe::repository::PathRepository; +use shirabe::util::{Platform, ProcessExecutor}; +use shirabe_php_shim::{ + DIRECTORY_SEPARATOR, PhpMixed, file_get_contents, hash, realpath, serialize, +}; + +use crate::test_case::get_package; + +fn fixtures_dir() -> String { + format!( + "{}/../../composer/tests/Composer/Test/Repository/Fixtures", + env!("CARGO_MANIFEST_DIR") + ) +} + +/// ref: PathRepositoryTest::createPathRepo +fn create_path_repo(options: IndexMap<String, PhpMixed>) -> PathRepository { + let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new())); + + let config = Rc::new(RefCell::new(Config::new(true, None))); + let proc = Rc::new(RefCell::new(ProcessExecutor::new(None))); + + PathRepository::new(options, io, config, None, None, Some(proc)).unwrap() +} + +fn coordinates(pairs: Vec<(&str, PhpMixed)>) -> IndexMap<String, PhpMixed> { + let mut map: IndexMap<String, PhpMixed> = IndexMap::new(); + for (key, value) in pairs { + map.insert(key.to_string(), value); + } + map +} + +#[ignore] #[test] fn test_load_package_from_file_system_with_incorrect_path() { - todo!() + let repository_url = + [fixtures_dir(), "path".to_string(), "missing".to_string()].join(DIRECTORY_SEPARATOR); + let mut repository = + create_path_repo(coordinates(vec![("url", PhpMixed::String(repository_url))])); + assert!(repository.__get_packages().is_err()); } -#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"] +#[ignore] #[test] fn test_load_package_from_file_system_with_version() { - todo!() + let repository_url = [ + fixtures_dir(), + "path".to_string(), + "with-version".to_string(), + ] + .join(DIRECTORY_SEPARATOR); + let mut repository = + create_path_repo(coordinates(vec![("url", PhpMixed::String(repository_url))])); + repository.__get_packages().unwrap(); + + assert_eq!(1, repository.__count().unwrap()); + assert!( + repository + .__has_package(get_package("test/path-versioned", "0.0.2")) + .unwrap() + ); } -#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"] +#[ignore] #[test] fn test_load_package_from_file_system_without_version() { - todo!() + let repository_url = [ + fixtures_dir(), + "path".to_string(), + "without-version".to_string(), + ] + .join(DIRECTORY_SEPARATOR); + let mut repository = + create_path_repo(coordinates(vec![("url", PhpMixed::String(repository_url))])); + let packages = repository.__get_packages().unwrap(); + + assert!(repository.__count().unwrap() >= 1); + + let package = &packages[0]; + assert_eq!("test/path-unversioned", package.get_name()); + + let package_version = package.get_version(); + assert!(!package_version.is_empty()); } -#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"] +#[ignore] #[test] fn test_load_package_from_file_system_with_wildcard() { - todo!() + let repository_url = + [fixtures_dir(), "path".to_string(), "*".to_string()].join(DIRECTORY_SEPARATOR); + let mut repository = + create_path_repo(coordinates(vec![("url", PhpMixed::String(repository_url))])); + let packages = repository.__get_packages().unwrap(); + let mut names: Vec<String> = Vec::new(); + + assert!(repository.__count().unwrap() >= 2); + + let package = &packages[0]; + names.push(package.get_name()); + + let package = &packages[1]; + names.push(package.get_name()); + + names.sort(); + assert_eq!( + vec![ + "test/path-unversioned".to_string(), + "test/path-versioned".to_string() + ], + names + ); } -#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"] +#[ignore] #[test] fn test_load_package_with_explicit_versions() { - todo!() + let mut versions: IndexMap<String, PhpMixed> = IndexMap::new(); + versions.insert( + "test/path-unversioned".to_string(), + PhpMixed::String("4.3.2.1".to_string()), + ); + versions.insert( + "test/path-versioned".to_string(), + PhpMixed::String("3.2.1.0".to_string()), + ); + let options = coordinates(vec![("versions", PhpMixed::Array(versions))]); + + let repository_url = + [fixtures_dir(), "path".to_string(), "*".to_string()].join(DIRECTORY_SEPARATOR); + let mut repository = create_path_repo(coordinates(vec![ + ("url", PhpMixed::String(repository_url)), + ("options", PhpMixed::Array(options)), + ])); + let packages = repository.__get_packages().unwrap(); + + let mut versions: IndexMap<String, String> = IndexMap::new(); + + assert_eq!(2, repository.__count().unwrap()); + + let package = &packages[0]; + versions.insert(package.get_name(), package.get_version()); + + let package = &packages[1]; + versions.insert(package.get_name(), package.get_version()); + + versions.sort_keys(); + let expected: IndexMap<String, String> = [ + ("test/path-unversioned".to_string(), "4.3.2.1".to_string()), + ("test/path-versioned".to_string(), "3.2.1.0".to_string()), + ] + .into_iter() + .collect(); + assert_eq!(expected, versions); } -#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"] +/// Verify relative repository URLs remain relative, see #4439 +#[ignore] #[test] fn test_url_remains_relative() { - todo!() + // realpath() does not fully expand the paths + // PHP Bug https://bugs.php.net/bug.php?id=72642 + let repository_url = [ + realpath(&realpath(&fixtures_dir().replace("/Fixtures", "")).unwrap_or_default()) + .unwrap_or_default(), + "Fixtures".to_string(), + "path".to_string(), + "with-version".to_string(), + ] + .join(DIRECTORY_SEPARATOR); + // getcwd() not necessarily match __DIR__ + // PHP Bug https://bugs.php.net/bug.php?id=73797 + let cwd = realpath(&realpath(&Platform::get_cwd(false).unwrap()).unwrap_or_default()) + .unwrap_or_default(); + let relative_url = repository_url[cwd.len().min(repository_url.len())..] + .trim_start_matches(DIRECTORY_SEPARATOR) + .to_string(); + + let mut repository = create_path_repo(coordinates(vec![( + "url", + PhpMixed::String(relative_url.clone()), + )])); + let packages = repository.__get_packages().unwrap(); + + assert_eq!(1, repository.__count().unwrap()); + + let package = &packages[0]; + assert_eq!("test/path-versioned", package.get_name()); + + // Convert platform specific separators back to generic URL slashes + let relative_url = relative_url.replace(DIRECTORY_SEPARATOR, "/"); + assert_eq!(Some(relative_url), package.get_dist_url()); } -#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"] +#[ignore] #[test] fn test_reference_none() { - todo!() + let options = coordinates(vec![("reference", PhpMixed::String("none".to_string()))]); + let repository_url = + [fixtures_dir(), "path".to_string(), "*".to_string()].join(DIRECTORY_SEPARATOR); + let mut repository = create_path_repo(coordinates(vec![ + ("url", PhpMixed::String(repository_url)), + ("options", PhpMixed::Array(options)), + ])); + let packages = repository.__get_packages().unwrap(); + + assert!(repository.__count().unwrap() >= 2); + + for package in &packages { + assert_eq!(package.get_dist_reference(), None); + } } -#[ignore = "PathRepository exposes no public RepositoryInterface::get_packages/count/has_package; the inner ArrayRepository delegation is not ported"] +#[ignore] #[test] fn test_reference_config() { - todo!() + let options = coordinates(vec![ + ("reference", PhpMixed::String("config".to_string())), + ("relative", PhpMixed::Bool(true)), + ]); + let repository_url = + [fixtures_dir(), "path".to_string(), "*".to_string()].join(DIRECTORY_SEPARATOR); + let mut repository = create_path_repo(coordinates(vec![ + ("url", PhpMixed::String(repository_url)), + ("options", PhpMixed::Array(options.clone())), + ])); + let packages = repository.__get_packages().unwrap(); + + assert!(repository.__count().unwrap() >= 2); + + for package in &packages { + let dist_url = package.get_dist_url().unwrap_or_default(); + assert_eq!( + package.get_dist_reference(), + Some(hash( + "sha1", + &format!( + "{}{}", + file_get_contents(format!("{}/composer.json", dist_url)).unwrap_or_default(), + serialize(&PhpMixed::Array(options.clone())) + ) + )) + ); + } } diff --git a/crates/shirabe/tests/repository/repository_factory_test.rs b/crates/shirabe/tests/repository/repository_factory_test.rs index a0eb81f..c018c45 100644 --- a/crates/shirabe/tests/repository/repository_factory_test.rs +++ b/crates/shirabe/tests/repository/repository_factory_test.rs @@ -1,13 +1,57 @@ //! ref: composer/tests/Composer/Test/Repository/RepositoryFactoryTest.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::repository::RepositoryFactory; +use shirabe::util::http_downloader::HttpDownloader; use shirabe_php_shim::PhpMixed; #[test] -#[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"] +#[ignore] fn test_manager_with_all_repository_types() { - todo!() + let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new())); + let config = Rc::new(RefCell::new(Config::new(false, None))); + let http_downloader = Rc::new(RefCell::new(HttpDownloader::new( + io.clone(), + config.clone(), + IndexMap::new(), + true, + ))); + + let manager = + RepositoryFactory::manager(io, &config, Some(http_downloader), None, None).unwrap(); + + let repository_classes: Vec<&str> = manager + .__repository_classes() + .keys() + .map(|k| k.as_str()) + .collect(); + + assert_eq!( + vec![ + "composer", + "vcs", + "package", + "pear", + "git", + "bitbucket", + "git-bitbucket", + "github", + "gitlab", + "svn", + "fossil", + "perforce", + "hg", + "artifact", + "path", + ], + repository_classes + ); } fn generate_repository_name_provider() -> Vec<( @@ -53,7 +97,7 @@ fn generate_repository_name_provider() -> Vec<( } #[test] -#[ignore = "generate_repository_name does not stringify an integer index (PhpMixed::as_string returns None for Int), so a numeric index with no url yields \"\" instead of e.g. \"0\""] +#[ignore] fn test_generate_repository_name() { for (index, repo_pairs, existing_keys, expected) in generate_repository_name_provider() { let repo: IndexMap<String, PhpMixed> = repo_pairs diff --git a/crates/shirabe/tests/repository/repository_utils_test.rs b/crates/shirabe/tests/repository/repository_utils_test.rs index 3f55bfd..3ea1439 100644 --- a/crates/shirabe/tests/repository/repository_utils_test.rs +++ b/crates/shirabe/tests/repository/repository_utils_test.rs @@ -153,7 +153,7 @@ fn provide_filter_require_tests() -> Vec<FilterCase> { } #[test] -#[ignore = "building packages with links via ArrayLoader parses constraints with a look-around regex the regex crate cannot compile"] +#[ignore] fn test_filter_required_packages() { for case in provide_filter_require_tests() { let pkgs = build_packages(); diff --git a/crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs b/crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs index 0836fc5..ea130ea 100644 --- a/crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs +++ b/crates/shirabe/tests/repository/vcs/forgejo_driver_test.rs @@ -76,7 +76,7 @@ fn supports_provider() -> Vec<(bool, &'static str)> { } #[test] -#[ignore = "ForgejoDriver::supports uses a regex with a character class the regex crate cannot compile (unclosed character class)"] +#[ignore] fn test_supports() { for (expected, repo_url) in supports_provider() { let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new())); diff --git a/crates/shirabe/tests/repository/vcs/github_driver_test.rs b/crates/shirabe/tests/repository/vcs/github_driver_test.rs index 5313c0b..f5958a4 100644 --- a/crates/shirabe/tests/repository/vcs/github_driver_test.rs +++ b/crates/shirabe/tests/repository/vcs/github_driver_test.rs @@ -64,7 +64,7 @@ fn supports_provider() -> Vec<(bool, &'static str)> { } #[test] -#[ignore = "GitHubDriver::supports reaches non-strict in_array, which is todo!() in the php-shim"] +#[ignore] fn test_supports() { let SetUp { home, config: _ } = set_up(); let _tear_down = TearDown::new(home.path().to_path_buf()); |
