diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-25 17:49:35 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-26 00:20:05 +0900 |
| commit | d4ec1dcb6fc04ff029ded35cc2fcc14f3bbc02ad (patch) | |
| tree | 0a85bd085961fcdfd5570cafc3b44ba5eb8cb152 /crates/shirabe/tests/downloader/fossil_downloader_test.rs | |
| parent | 22d0b327368e5f39de6f381046c081d08efdba15 (diff) | |
| download | php-shirabe-d4ec1dcb6fc04ff029ded35cc2fcc14f3bbc02ad.tar.gz php-shirabe-d4ec1dcb6fc04ff029ded35cc2fcc14f3bbc02ad.tar.zst php-shirabe-d4ec1dcb6fc04ff029ded35cc2fcc14f3bbc02ad.zip | |
test: port 32 command/repository/downloader tests
Add create_installed_json/create_composer_lock test helpers. Port command (8),
repository path/forgejo/perforce/vcs (11), and fossil/hg/download_manager (13)
tests. Fix production porting bugs: root_package_loader/forgejo_url/version_bumper
regex delimiters, repository_manager create_repository_by_class, array_loader
isset, licenses_command RefCell borrow; implement disk_free_space and
touch2/touch3 via libc.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/downloader/fossil_downloader_test.rs')
| -rw-r--r-- | crates/shirabe/tests/downloader/fossil_downloader_test.rs | 181 |
1 files changed, 163 insertions, 18 deletions
diff --git a/crates/shirabe/tests/downloader/fossil_downloader_test.rs b/crates/shirabe/tests/downloader/fossil_downloader_test.rs index 0c45d2c..e403229 100644 --- a/crates/shirabe/tests/downloader/fossil_downloader_test.rs +++ b/crates/shirabe/tests/downloader/fossil_downloader_test.rs @@ -1,8 +1,30 @@ //! ref: composer/tests/Composer/Test/Downloader/FossilDownloaderTest.php +use std::cell::RefCell; +use std::rc::Rc; + +use shirabe::config::Config; +use shirabe::downloader::VcsDownloader; +use shirabe::downloader::fossil_downloader::FossilDownloader; +use shirabe::io::IOInterface; +use shirabe::package::handle::{CompletePackageHandle, PackageInterfaceHandle}; +use shirabe::util::ProcessExecutor; use shirabe::util::filesystem::Filesystem; +use shirabe_php_shim::PhpMixed; +use shirabe_semver::VersionParser; use tempfile::TempDir; +use crate::config_stub::ConfigStubBuilder; +use crate::io_stub::IOStub; +use crate::process_executor_mock::get_process_executor_mock; + +fn run<F: std::future::Future>(future: F) -> F::Output { + tokio::runtime::Builder::new_current_thread() + .build() + .unwrap() + .block_on(future) +} + fn set_up() -> TempDir { TempDir::new().unwrap() } @@ -30,48 +52,168 @@ impl Drop for TearDown { } } -// Every case constructs a FossilDownloader with a mocked IO/Config and a mocked -// ProcessExecutor to feed fossil command output; a real HttpDownloader reaches -// curl_multi_init (todo!()), and ProcessExecutor mocking is not available. +/// ref: TestCase::getMockBuilder('Composer\Package\PackageInterface')->getMock() +/// +/// A real CompletePackage seeded with the stubbed values is a faithful stand-in +/// for a PackageInterface mock as long as `getSourceUrls()` equals +/// `[getSourceUrl()]`, which holds for every non-ignored case here. +fn get_package(source_reference: Option<&str>, source_url: Option<&str>) -> PackageInterfaceHandle { + let norm_version = VersionParser.normalize("1.0.0", None).unwrap(); + let package = + CompletePackageHandle::new("dummy/pkg".to_string(), norm_version, "1.0.0".to_string()); + package.__set_source_type(Some("fossil".to_string())); + package.set_source_reference(source_reference.map(|s| s.to_string())); + package.set_source_url(source_url.map(|s| s.to_string())); + package.into() +} + +/// ref: FossilDownloaderTest::getDownloaderMock +fn get_downloader_mock( + io: Option<Rc<RefCell<dyn IOInterface>>>, + config: Option<Config>, + process: Rc<RefCell<ProcessExecutor>>, +) -> FossilDownloader { + let io = + io.unwrap_or_else(|| Rc::new(RefCell::new(IOStub::new())) as Rc<RefCell<dyn IOInterface>>); + // ref: getConfig(['secure-http' => false]) + let config = Rc::new(RefCell::new(config.unwrap_or_else(|| { + ConfigStubBuilder::new() + .with("secure-http", PhpMixed::Bool(false)) + .build() + }))); + let fs = Rc::new(RefCell::new(Filesystem::new(None))); + FossilDownloader::new(io, config, process, fs) +} #[test] -#[ignore = "needs ProcessExecutorMock and PHPUnit mocks of IOInterface/PackageInterface/Filesystem for getDownloaderMock; not available"] fn test_install_for_package_without_source_reference() { let working_dir = set_up(); let _tear_down = TearDown::new(working_dir.path().to_path_buf()); - let _ = &working_dir; - todo!() + + let package = get_package(None, None); + + let (process, _guard) = get_process_executor_mock(vec![], false, Default::default()); + let mut downloader = get_downloader_mock(None, None, process); + + let path = format!("{}/path", working_dir.path().to_string_lossy()); + let result = run(downloader.install(package, &path)); + + let e = result.expect_err("missing source reference should throw"); + assert!(e.to_string().contains("missing reference information")); } #[test] -#[ignore = "needs ProcessExecutorMock with expects() command-sequence assertions and PHPUnit PackageInterface mock; not available"] fn test_install() { let working_dir = set_up(); let _tear_down = TearDown::new(working_dir.path().to_path_buf()); - let _ = &working_dir; - todo!() + + let working_dir_str = working_dir.path().to_string_lossy().into_owned(); + let package = get_package(Some("trunk"), Some("http://fossil.kd2.org/kd2fw/")); + + let repo_file = format!("{}.fossil", working_dir_str); + let (process, _guard) = get_process_executor_mock( + vec![ + crate::process_executor_mock::cmd(vec![ + "fossil", + "clone", + "--", + "http://fossil.kd2.org/kd2fw/", + &repo_file, + ]), + crate::process_executor_mock::cmd(vec!["fossil", "open", "--nested", "--", &repo_file]), + crate::process_executor_mock::cmd(vec!["fossil", "update", "--", "trunk"]), + ], + true, + Default::default(), + ); + + let mut downloader = get_downloader_mock(None, None, process); + run(downloader.install(package, &working_dir_str)).unwrap(); } #[test] -#[ignore = "needs ProcessExecutorMock and PHPUnit mocks of IOInterface/PackageInterface/Filesystem for getDownloaderMock; not available"] fn test_updatefor_package_without_source_reference() { let working_dir = set_up(); let _tear_down = TearDown::new(working_dir.path().to_path_buf()); - let _ = &working_dir; - todo!() + + let initial_package = get_package(Some("ref"), None); + let source_package = get_package(None, None); + + let (process, _guard) = get_process_executor_mock(vec![], false, Default::default()); + let mut downloader = get_downloader_mock(None, None, process); + + let result = run(async { + downloader + .prepare( + "update", + source_package.clone(), + "/path", + Some(initial_package.clone()), + ) + .await?; + downloader + .update(initial_package.clone(), source_package.clone(), "/path") + .await?; + downloader + .cleanup("update", source_package, "/path", Some(initial_package)) + .await + }); + + let e = result.expect_err("missing source reference should throw"); + assert!(e.to_string().contains("missing reference information")); } #[test] -#[ignore = "needs ProcessExecutorMock with expects() command-sequence assertions and PHPUnit PackageInterface mock; not available"] fn test_update() { let working_dir = set_up(); let _tear_down = TearDown::new(working_dir.path().to_path_buf()); - let _ = &working_dir; - todo!() + + let working_dir_str = working_dir.path().to_string_lossy().into_owned(); + + // Ensure the .fslckout metadata file exists. + let fslckout = format!("{}/.fslckout", working_dir_str); + if !std::path::Path::new(&fslckout).exists() { + std::fs::File::create(&fslckout).unwrap(); + } + + let package = get_package(Some("trunk"), Some("http://fossil.kd2.org/kd2fw/")); + + let (process, _guard) = get_process_executor_mock( + vec![ + crate::process_executor_mock::cmd(vec!["fossil", "changes"]), + crate::process_executor_mock::cmd(vec!["fossil", "pull"]), + crate::process_executor_mock::cmd(vec!["fossil", "up", "--", "trunk"]), + ], + true, + Default::default(), + ); + + let mut downloader = get_downloader_mock(None, None, process); + run(async { + downloader + .prepare( + "update", + package.clone(), + &working_dir_str, + Some(package.clone()), + ) + .await + .unwrap(); + downloader + .update(package.clone(), package.clone(), &working_dir_str) + .await + .unwrap(); + downloader + .cleanup("update", package.clone(), &working_dir_str, Some(package)) + .await + .unwrap(); + }); } +#[ignore = "PHP mocks Filesystem::removeDirectoryAsync; with a real Filesystem the actual \ + removeDirectoryAsync drives its own ProcessExecutor for `rm -rf` through the \ + unported execute_async mock seam"] #[test] -#[ignore = "needs ProcessExecutorMock and a PHPUnit Filesystem mock asserting removeDirectoryAsync; not available"] fn test_remove() { let working_dir = set_up(); let _tear_down = TearDown::new(working_dir.path().to_path_buf()); @@ -80,10 +222,13 @@ fn test_remove() { } #[test] -#[ignore = "needs ProcessExecutorMock and PHPUnit mocks of IOInterface/Filesystem for getDownloaderMock; not available"] fn test_get_installation_source() { let working_dir = set_up(); let _tear_down = TearDown::new(working_dir.path().to_path_buf()); let _ = &working_dir; - todo!() + + let (process, _guard) = get_process_executor_mock(vec![], false, Default::default()); + let downloader = get_downloader_mock(None, None, process); + + assert_eq!("source", downloader.get_installation_source()); } |
