From 5ab5f3b316798c1411ce8e6a7f5b091fda93589c Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 22 Jun 2026 23:42:07 +0900 Subject: 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) --- .../tests/repository/path_repository_test.rs | 239 +++++++++++++++++++-- 1 file changed, 219 insertions(+), 20 deletions(-) (limited to 'crates/shirabe/tests/repository/path_repository_test.rs') 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) -> PathRepository { + let io: Rc> = 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 { + let mut map: IndexMap = 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 = 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 = 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 = 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 = [ + ("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())) + ) + )) + ); + } } -- cgit v1.3.1