From 340164c64e90d44b1bdf620b514166db1f76cc98 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Wed, 24 Jun 2026 00:47:20 +0900 Subject: test: port more unimplemented tests Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/shirabe/src/installed_versions.rs | 14 ++++ .../package/archiver/archivable_files_finder.rs | 2 +- crates/shirabe/src/package/handle.rs | 9 +++ .../src/question/strict_confirmation_question.rs | 4 + .../shirabe/src/repository/package_repository.rs | 87 +++++++++++++++++++++- crates/shirabe/src/util/http/proxy_manager.rs | 13 ++++ 6 files changed, 127 insertions(+), 2 deletions(-) (limited to 'crates/shirabe/src') diff --git a/crates/shirabe/src/installed_versions.rs b/crates/shirabe/src/installed_versions.rs index c4ef526..33286ad 100644 --- a/crates/shirabe/src/installed_versions.rs +++ b/crates/shirabe/src/installed_versions.rs @@ -352,6 +352,20 @@ impl InstalledVersions { /// Returns the raw data of all installed.php which are currently loaded for custom implementations /// /// @return array[] + /// Returns the first dataset loaded, which may not be what you expect. Use get_all_raw_data + /// instead, which returns all datasets for all autoloaders present in the process. + pub fn get_raw_data() -> IndexMap { + // PHP emits an E_USER_DEPRECATED notice here; there is no Rust equivalent. + let mut installed = INSTALLED.lock().unwrap(); + if installed.is_none() { + // PHP only includes __DIR__/installed.php when loaded from its dumped location; the + // shim is always the source location (PHP's `else` branch), so the data is empty. + *installed = Some(IndexMap::new()); + } + + installed.clone().unwrap() + } + pub fn get_all_raw_data() -> Vec> { Self::get_installed() } diff --git a/crates/shirabe/src/package/archiver/archivable_files_finder.rs b/crates/shirabe/src/package/archiver/archivable_files_finder.rs index 08f8df1..67f2fda 100644 --- a/crates/shirabe/src/package/archiver/archivable_files_finder.rs +++ b/crates/shirabe/src/package/archiver/archivable_files_finder.rs @@ -57,7 +57,7 @@ impl ArchivableFilesFinder { } let relative_path = Preg::replace( - &format!("^{}", preg_quote(&sources_clone, Some('#'))), + &format!("#^{}#", preg_quote(&sources_clone, Some('#'))), "", &fs.normalize_path(&realpath.to_string_lossy()), ); diff --git a/crates/shirabe/src/package/handle.rs b/crates/shirabe/src/package/handle.rs index 303983a..665efb6 100644 --- a/crates/shirabe/src/package/handle.rs +++ b/crates/shirabe/src/package/handle.rs @@ -1213,6 +1213,15 @@ macro_rules! impl_real_package_test_setters { .expect("real package handle invariant") .set_type(r#type); } + + /// For testing only: mirrors PHP `Package::setSourceType`. + pub fn __set_source_type(&self, r#type: Option) { + self.0 + .borrow_mut() + .as_package_mut() + .expect("real package handle invariant") + .set_source_type(r#type); + } } }; } diff --git a/crates/shirabe/src/question/strict_confirmation_question.rs b/crates/shirabe/src/question/strict_confirmation_question.rs index 87290ac..8d4239b 100644 --- a/crates/shirabe/src/question/strict_confirmation_question.rs +++ b/crates/shirabe/src/question/strict_confirmation_question.rs @@ -35,6 +35,10 @@ impl StrictConfirmationQuestion { &self.inner } + pub fn inner_mut(&mut self) -> &mut Question { + &mut self.inner + } + fn get_default_normalizer(&self) -> Box PhpMixed> { let default = self.inner.get_default(); let true_regex = self.true_answer_regex.clone(); diff --git a/crates/shirabe/src/repository/package_repository.rs b/crates/shirabe/src/repository/package_repository.rs index 554e24a..e19d04c 100644 --- a/crates/shirabe/src/repository/package_repository.rs +++ b/crates/shirabe/src/repository/package_repository.rs @@ -2,12 +2,18 @@ use crate::advisory::SecurityAdvisory; use crate::advisory::{AnySecurityAdvisory, PartialSecurityAdvisory}; +use crate::package::BasePackageHandle; +use crate::package::PackageInterfaceHandle; use crate::package::loader::ArrayLoader; use crate::package::loader::ValidatingArrayLoader; use crate::package::version::VersionParser; use crate::repository::ArrayRepository; use crate::repository::InvalidRepositoryException; -use crate::repository::{AdvisoryProviderInterface, SecurityAdvisoryResult}; +use crate::repository::RepositoryInterfaceWeakHandle; +use crate::repository::{ + AdvisoryProviderInterface, FindPackageConstraint, LoadPackagesResult, ProviderInfo, + RepositoryInterface, SearchResult, SecurityAdvisoryResult, +}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::Preg; use shirabe_php_shim::{Exception, PhpMixed, RuntimeException, var_export}; @@ -80,6 +86,85 @@ impl PackageRepository { } } +impl RepositoryInterface for PackageRepository { + // The structural methods are inherited from ArrayRepository in PHP, where they trigger the + // overridden initialize() that loads packages from config. Wiring that virtual dispatch is a + // Phase C concern; the advisory paths below are what is exercised so far. + fn count(&self) -> anyhow::Result { + todo!() + } + + fn has_package(&self, _package: PackageInterfaceHandle) -> bool { + todo!() + } + + fn find_package( + &mut self, + _name: &str, + _constraint: FindPackageConstraint, + ) -> anyhow::Result> { + todo!() + } + + fn find_packages( + &mut self, + _name: &str, + _constraint: Option, + ) -> anyhow::Result> { + todo!() + } + + fn get_packages(&mut self) -> anyhow::Result> { + todo!() + } + + fn load_packages( + &mut self, + _package_name_map: IndexMap>, + _acceptable_stabilities: IndexMap, + _stability_flags: IndexMap, + _already_loaded: IndexMap>, + ) -> anyhow::Result { + todo!() + } + + fn search( + &mut self, + _query: String, + _mode: i64, + _type: Option, + ) -> anyhow::Result> { + todo!() + } + + fn get_providers( + &mut self, + _package_name: String, + ) -> anyhow::Result> { + todo!() + } + + fn get_repo_name(&self) -> String { + PackageRepository::get_repo_name(self) + } + + fn as_advisory_provider(&self) -> Option<&dyn AdvisoryProviderInterface> { + Some(self) + } + + fn as_advisory_provider_mut(&mut self) -> Option<&mut dyn AdvisoryProviderInterface> { + Some(self) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn set_self_handle(&self, weak: RepositoryInterfaceWeakHandle) { + self.inner.set_self_handle(weak); + } +} + impl AdvisoryProviderInterface for PackageRepository { fn has_security_advisories(&mut self) -> anyhow::Result { Ok(!self.security_advisories.is_empty()) diff --git a/crates/shirabe/src/util/http/proxy_manager.rs b/crates/shirabe/src/util/http/proxy_manager.rs index 37d73c0..d0ff9d9 100644 --- a/crates/shirabe/src/util/http/proxy_manager.rs +++ b/crates/shirabe/src/util/http/proxy_manager.rs @@ -1,5 +1,6 @@ //! ref: composer/src/Composer/Util/Http/ProxyManager.php +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Mutex, OnceLock}; use crate::downloader::TransportException; @@ -9,12 +10,17 @@ use crate::util::http::RequestProxy; static INSTANCE: OnceLock>> = OnceLock::new(); +// Distinguishes ProxyManager instances so tests can mirror PHP `===` identity of the singleton, +// which the Rust value-based singleton does not otherwise expose. +static NEXT_GENERATION: AtomicU64 = AtomicU64::new(0); + #[derive(Debug)] pub struct ProxyManager { error: Option, http_proxy: Option, https_proxy: Option, no_proxy_handler: std::cell::RefCell>, + generation: u64, } impl ProxyManager { @@ -24,6 +30,7 @@ impl ProxyManager { http_proxy: None, https_proxy: None, no_proxy_handler: std::cell::RefCell::new(None), + generation: NEXT_GENERATION.fetch_add(1, Ordering::Relaxed), }; if let Err(e) = instance.get_proxy_data() { instance.error = Some(e.to_string()); @@ -41,6 +48,12 @@ impl ProxyManager { } } + /// For testing only: a unique id per constructed instance, used to mirror PHP `===` identity + /// comparison of the ProxyManager singleton across `get_instance`/`reset`. + pub fn __generation(&self) -> u64 { + self.generation + } + pub fn has_proxy(&self) -> bool { self.http_proxy.is_some() || self.https_proxy.is_some() } -- cgit v1.3.1