diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-22 02:09:59 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-22 02:09:59 +0900 |
| commit | 822d9a872807a92a5337ee8b7bab96dc9845cdbb (patch) | |
| tree | 4931365df5978caffade69cad2154718a9076f66 /crates/shirabe/tests/installer | |
| parent | f691b864b687f251c3b266e8cff2774d730567ba (diff) | |
| download | php-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/installer')
4 files changed, 210 insertions, 51 deletions
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!() } |
