diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-25 15:37:21 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-26 00:20:05 +0900 |
| commit | 3a883e6912e642a1bcfe68336007eae018207308 (patch) | |
| tree | 2750519e1bbaaf8caa493bcf1eb15efb143280d9 /crates/shirabe/tests/downloader | |
| parent | d4cdccb8de8758bd46a12283f8df90e020327b99 (diff) | |
| download | php-shirabe-3a883e6912e642a1bcfe68336007eae018207308.tar.gz php-shirabe-3a883e6912e642a1bcfe68336007eae018207308.tar.zst php-shirabe-3a883e6912e642a1bcfe68336007eae018207308.zip | |
test: port 35 auth/installer/io/zip/bitbucket tests; implement date_create
Port auth_helper (14), library_installer (8), console_io (7), zip_downloader (3),
git_bitbucket_driver (3) tests. Implement date_create/strtotime for the ISO8601/
RFC3339/relative formats Composer uses (unknown input -> None, no silent guess).
Fix production bugs: Question::is_assoc list-vs-assoc, auth_helper gitlab-domains
list handling, LibraryInstaller RefCell double-borrow, ZipArchive::extract_to
ErrorException propagation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/downloader')
| -rw-r--r-- | crates/shirabe/tests/downloader/zip_downloader_test.rs | 186 |
1 files changed, 146 insertions, 40 deletions
diff --git a/crates/shirabe/tests/downloader/zip_downloader_test.rs b/crates/shirabe/tests/downloader/zip_downloader_test.rs index 0bffa89..055e98f 100644 --- a/crates/shirabe/tests/downloader/zip_downloader_test.rs +++ b/crates/shirabe/tests/downloader/zip_downloader_test.rs @@ -1,32 +1,79 @@ //! ref: composer/tests/Composer/Test/Downloader/ZipDownloaderTest.php +use std::cell::RefCell; +use std::rc::Rc; + +use serial_test::serial; +use shirabe::config::Config; +use shirabe::downloader::ArchiveDownloader; +use shirabe::downloader::zip_downloader::ZipDownloader; +use shirabe::io::IOInterface; +use shirabe::package::handle::{CompletePackageHandle, PackageInterfaceHandle}; +use shirabe::util::HttpDownloader; +use shirabe::util::ProcessExecutor; use shirabe::util::filesystem::Filesystem; +use shirabe_php_shim::{ZipArchive, ZipArchiveMock}; +use shirabe_semver::VersionParser; use tempfile::TempDir; +use crate::io_stub::IOStub; + +fn run<F: std::future::Future>(future: F) -> F::Output { + tokio::runtime::Builder::new_current_thread() + .build() + .unwrap() + .block_on(future) +} + struct SetUp { test_dir: TempDir, + io: Rc<RefCell<dyn IOInterface>>, + config: Rc<RefCell<Config>>, + http_downloader: Rc<RefCell<HttpDownloader>>, + package: PackageInterfaceHandle, filename: std::path::PathBuf, } +/// ref: ZipDownloaderTest::setUp. +/// +/// The PHP test mocks IOInterface/Config/HttpDownloader/PackageInterface via PHPUnit. Here the +/// IO/Config use the existing stubs, the HttpDownloader is built as a mock (no network is touched on +/// the `extract` path exercised by the ported tests), and the package is a real CompletePackage whose +/// `getName()` is `test/pkg`, matching the PHP mock's `->method('getName')->willReturn('test/pkg')`. fn set_up() -> SetUp { let test_dir = TempDir::new().unwrap(); - // The IO/Config/HttpDownloader/Package mocks are not ported; HttpDownloader construction - // additionally reaches curl_multi_init (todo!()). - let () = todo!(); - #[allow(unreachable_code)] - { - let filename = test_dir.path().join("composer-test.zip"); - std::fs::write(&filename, "zip").unwrap(); - SetUp { test_dir, filename } + + let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(IOStub::new())); + let config = Rc::new(RefCell::new(Config::new(false, None))); + let dl_config = Rc::new(RefCell::new(Config::new(false, None))); + let http_downloader = Rc::new(RefCell::new(HttpDownloader::__new_mock( + io.clone(), + dl_config, + ))); + + let norm_version = VersionParser.normalize("1.0.0", None).unwrap(); + let package: PackageInterfaceHandle = + CompletePackageHandle::new("test/pkg".to_string(), norm_version, "1.0.0".to_string()) + .into(); + + let filename = test_dir.path().join("composer-test.zip"); + std::fs::write(&filename, "zip").unwrap(); + + SetUp { + test_dir, + io, + config, + http_downloader, + package, + filename, } } fn tear_down(test_dir: &std::path::Path) { let mut fs = Filesystem::new(None); fs.remove_directory(test_dir).unwrap(); - // setPrivateProperty('hasZipArchive', null) resets a ZipDownloader static via reflection; - // the static is not reachable from a test here. - todo!() + // setPrivateProperty('hasZipArchive', null) + ZipDownloader::__set_has_zip_archive(None); } struct TearDown { @@ -45,76 +92,135 @@ 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"] +fn make_downloader(set_up: &SetUp) -> ZipDownloader { + let filesystem = Rc::new(RefCell::new(Filesystem::new(None))); + let process = Rc::new(RefCell::new(ProcessExecutor::new(Some(set_up.io.clone())))); + ZipDownloader::new( + set_up.io.clone(), + set_up.config.clone(), + set_up.http_downloader.clone(), + None, + None, + filesystem, + process, + ) +} + +// The system-unzip / non-windows-fallback paths route through ProcessExecutor::execute_async, whose +// mock branch is an unimplemented todo!() (no Process mock seam exists in the external-packages +// crate). The PHP tests below mock Process/ProcessExecutor::executeAsync, which is not reproducible +// here, so they remain ignored. +// +// testErrorMessages drives a real HttpDownloader + Loop (curl_multi_init todo!()), also out of reach. + +#[ignore = "drives a real HttpDownloader + Loop (download/install), which reaches curl_multi_init todo!()"] #[test] fn test_error_messages() { let set_up = set_up(); let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf()); - let _ = (&set_up.test_dir, &set_up.filename); + let _ = (&set_up.io, &set_up.config, &set_up.http_downloader); todo!() } -#[ignore = "requires setPrivateProperty reflection on hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and a getMockBuilder('ZipArchive') mock; no mocking/reflection framework"] #[test] +#[serial] fn test_zip_archive_only_failed() { let set_up = set_up(); let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf()); - let _ = (&set_up.test_dir, &set_up.filename); - todo!() + + ZipDownloader::__set_has_zip_archive(Some(true)); + let mut downloader = make_downloader(&set_up); + let zip_archive = ZipArchive::__mock(ZipArchiveMock { + open: Ok(()), + count: 0, + extract_to: Ok(false), + }); + downloader.__set_zip_archive_object(Some(zip_archive)); + + let filename = set_up.filename.to_string_lossy().into_owned(); + let result = run(downloader.extract(set_up.package.clone(), &filename, "vendor/dir")); + + let e = result.expect_err("expected RuntimeException"); + assert!( + e.to_string() + .contains("There was an error extracting the ZIP file"), + "got: {e}" + ); } -#[ignore = "requires setPrivateProperty reflection on hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and a getMockBuilder('ZipArchive') mock throwing ErrorException; no mocking/reflection framework"] #[test] +#[serial] 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()); - let _ = (&set_up.test_dir, &set_up.filename); - todo!() + + ZipDownloader::__set_has_zip_archive(Some(true)); + let mut downloader = make_downloader(&set_up); + let zip_archive = ZipArchive::__mock(ZipArchiveMock { + open: Ok(()), + count: 0, + extract_to: Err("Not a directory".to_string()), + }); + downloader.__set_zip_archive_object(Some(zip_archive)); + + let filename = set_up.filename.to_string_lossy().into_owned(); + let result = run(downloader.extract(set_up.package.clone(), &filename, "vendor/dir")); + + let e = result.expect_err("expected RuntimeException"); + assert!( + e.to_string().contains( + "The archive for \"test/pkg\" may contain identical file names with different \ + capitalization (which fails on case insensitive filesystems): Not a directory" + ), + "got: {e}" + ); } -#[ignore = "requires setPrivateProperty reflection on hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and a getMockBuilder('ZipArchive') mock; no mocking/reflection framework"] #[test] +#[serial] fn test_zip_archive_only_good() { let set_up = set_up(); let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf()); - let _ = (&set_up.test_dir, &set_up.filename); - todo!() + + ZipDownloader::__set_has_zip_archive(Some(true)); + let mut downloader = make_downloader(&set_up); + let zip_archive = ZipArchive::__mock(ZipArchiveMock { + open: Ok(()), + count: 0, + extract_to: Ok(true), + }); + downloader.__set_zip_archive_object(Some(zip_archive)); + + let filename = set_up.filename.to_string_lossy().into_owned(); + let result = run(downloader.extract(set_up.package.clone(), &filename, "vendor/dir")); + + result.expect("extract should succeed"); } -#[ignore = "requires setPrivateProperty reflection on isWindows/hasZipArchive/unzipCommands, a MockedZipDownloader subclass, and getMockBuilder mocks of Process/ProcessExecutor::executeAsync; no mocking/reflection framework"] +#[ignore = "routes through ProcessExecutor::execute_async whose mock branch is todo!() (no Process mock seam in external-packages)"] #[test] fn test_system_unzip_only_failed() { - let set_up = set_up(); - let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf()); - let _ = (&set_up.test_dir, &set_up.filename); + let _ = set_up(); todo!() } -#[ignore = "requires setPrivateProperty reflection on isWindows/hasZipArchive/unzipCommands, a MockedZipDownloader subclass, and getMockBuilder mocks of Process/ProcessExecutor::executeAsync; no mocking/reflection framework"] +#[ignore = "routes through ProcessExecutor::execute_async whose mock branch is todo!() (no Process mock seam in external-packages)"] #[test] fn test_system_unzip_only_good() { - let set_up = set_up(); - let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf()); - let _ = (&set_up.test_dir, &set_up.filename); + let _ = set_up(); todo!() } -#[ignore = "requires setPrivateProperty reflection on isWindows/hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and getMockBuilder mocks of Process/ProcessExecutor/ZipArchive; no mocking/reflection framework"] +#[ignore = "routes through ProcessExecutor::execute_async whose mock branch is todo!() (no Process mock seam in external-packages)"] #[test] fn test_non_windows_fallback_good() { - let set_up = set_up(); - let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf()); - let _ = (&set_up.test_dir, &set_up.filename); + let _ = set_up(); todo!() } -#[ignore = "requires setPrivateProperty reflection on isWindows/hasZipArchive/zipArchiveObject, a MockedZipDownloader subclass, and getMockBuilder mocks of Process/ProcessExecutor/ZipArchive; no mocking/reflection framework"] +#[ignore = "routes through ProcessExecutor::execute_async whose mock branch is todo!() (no Process mock seam in external-packages)"] #[test] fn test_non_windows_fallback_failed() { - let set_up = set_up(); - let _tear_down = TearDown::new(set_up.test_dir.path().to_path_buf()); - let _ = (&set_up.test_dir, &set_up.filename); + let _ = set_up(); todo!() } |
