diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-24 00:47:20 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-24 00:47:53 +0900 |
| commit | 340164c64e90d44b1bdf620b514166db1f76cc98 (patch) | |
| tree | 86195fe5ff8582b64e0324e9f40619e36c04948f /crates/shirabe/tests/package | |
| parent | 8fe3390d064303b86133a1d2983144a4818a7121 (diff) | |
| download | php-shirabe-340164c64e90d44b1bdf620b514166db1f76cc98.tar.gz php-shirabe-340164c64e90d44b1bdf620b514166db1f76cc98.tar.zst php-shirabe-340164c64e90d44b1bdf620b514166db1f76cc98.zip | |
test: port more unimplemented tests
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/package')
6 files changed, 535 insertions, 66 deletions
diff --git a/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs b/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs index 48f0fc5..aed0dc3 100644 --- a/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs +++ b/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs @@ -1,45 +1,235 @@ //! ref: composer/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php -/// Builds a temp directory tree of fixture files under a unique tmp dir; the Filesystem and -/// getUniqueTmpDirectory infrastructure is not ported. -#[allow(dead_code)] -fn set_up() -> String { - todo!() -} +use shirabe::package::archiver::ArchivableFilesFinder; +use shirabe::util::Filesystem; +use shirabe_external_packages::composer::pcre::Preg; +use shirabe_php_shim::{dirname, file_put_contents, preg_quote}; +use tempfile::TempDir; -#[allow(dead_code)] -fn tear_down(_sources: &str) { - // Removes the temp directory tree created in set_up. - todo!() +struct SetUp { + _sources_dir: TempDir, + sources: String, + fs: Filesystem, } -#[allow(dead_code)] -struct TearDown { - sources: String, +fn set_up() -> SetUp { + let mut fs = Filesystem::new(None); + + let sources_dir = TempDir::new().unwrap(); + let sources = fs.normalize_path(&sources_dir.path().canonicalize().unwrap().to_string_lossy()); + + let file_tree = [ + ".foo", + "A/prefixA.foo", + "A/prefixB.foo", + "A/prefixC.foo", + "A/prefixD.foo", + "A/prefixE.foo", + "A/prefixF.foo", + "B/sub/prefixA.foo", + "B/sub/prefixB.foo", + "B/sub/prefixC.foo", + "B/sub/prefixD.foo", + "B/sub/prefixE.foo", + "B/sub/prefixF.foo", + "C/prefixA.foo", + "C/prefixB.foo", + "C/prefixC.foo", + "C/prefixD.foo", + "C/prefixE.foo", + "C/prefixF.foo", + "D/prefixA", + "D/prefixB", + "D/prefixC", + "D/prefixD", + "D/prefixE", + "D/prefixF", + "E/subtestA.foo", + "F/subtestA.foo", + "G/subtestA.foo", + "H/subtestA.foo", + "I/J/subtestA.foo", + "K/dirJ/subtestA.foo", + "toplevelA.foo", + "toplevelB.foo", + "prefixA.foo", + "prefixB.foo", + "prefixC.foo", + "prefixD.foo", + "prefixE.foo", + "prefixF.foo", + "parameters.yml", + "parameters.yml.dist", + "!important!.txt", + "!important_too!.txt", + "#weirdfile", + ]; + + for relative_path in file_tree { + let path = format!("{}/{}", sources, relative_path); + fs.ensure_directory_exists(&dirname(&path)).unwrap(); + file_put_contents(&path, b""); + } + + SetUp { + _sources_dir: sources_dir, + sources, + fs, + } } -impl Drop for TearDown { - fn drop(&mut self) { - tear_down(&self.sources); +fn get_archivable_files(set_up: &SetUp, finder: ArchivableFilesFinder) -> Vec<String> { + let mut files: Vec<String> = vec![]; + for file in finder { + if !file.is_dir() { + let real_path = file.canonicalize().unwrap(); + files.push(Preg::replace( + &format!("#^{}#", preg_quote(&set_up.sources, Some('#'))), + "", + &set_up.fs.normalize_path(&real_path.to_string_lossy()), + )); + } } + + files.sort(); + + files +} + +fn assert_archivable_files(set_up: &SetUp, finder: ArchivableFilesFinder, expected_files: &[&str]) { + let actual_files = get_archivable_files(set_up, finder); + + let expected_files: Vec<String> = expected_files.iter().map(|s| s.to_string()).collect(); + assert_eq!(expected_files, actual_files); } -// These set up a temp directory tree (including a git repo) and assert the files the finder -// selects with manual/git/skip excludes; the git-backed fixture setup is not ported. -#[ignore = "setUp needs TestCase::getUniqueTmpDirectory to build the on-disk fixture tree; not ported"] +// The manual exclude patterns (e.g. `.*`, `prefixC.*`) compile, via ComposerExcludeFilter, to +// look-ahead regexes like `(?=[^\.])...(?=$|/)`, which the regex crate cannot compile. +#[ignore = "ComposerExcludeFilter builds look-ahead regexes the regex crate does not support"] #[test] fn test_manual_excludes() { - todo!() + let set_up = set_up(); + + let excludes = vec![ + "prefixB.foo".to_string(), + "!/prefixB.foo".to_string(), + "/prefixA.foo".to_string(), + "prefixC.*".to_string(), + "!*/*/*/prefixC.foo".to_string(), + ".*".to_string(), + ]; + + let finder = ArchivableFilesFinder::new(&set_up.sources, excludes, false).unwrap(); + + assert_archivable_files( + &set_up, + finder, + &[ + "/!important!.txt", + "/!important_too!.txt", + "/#weirdfile", + "/A/prefixA.foo", + "/A/prefixD.foo", + "/A/prefixE.foo", + "/A/prefixF.foo", + "/B/sub/prefixA.foo", + "/B/sub/prefixC.foo", + "/B/sub/prefixD.foo", + "/B/sub/prefixE.foo", + "/B/sub/prefixF.foo", + "/C/prefixA.foo", + "/C/prefixD.foo", + "/C/prefixE.foo", + "/C/prefixF.foo", + "/D/prefixA", + "/D/prefixB", + "/D/prefixC", + "/D/prefixD", + "/D/prefixE", + "/D/prefixF", + "/E/subtestA.foo", + "/F/subtestA.foo", + "/G/subtestA.foo", + "/H/subtestA.foo", + "/I/J/subtestA.foo", + "/K/dirJ/subtestA.foo", + "/parameters.yml", + "/parameters.yml.dist", + "/prefixB.foo", + "/prefixD.foo", + "/prefixE.foo", + "/prefixF.foo", + "/toplevelA.foo", + "/toplevelB.foo", + ], + ); } -#[ignore = "setUp needs TestCase::getUniqueTmpDirectory plus skipIfNotExecutable/Process::fromShellCommandline/PharData/RecursiveIteratorIterator; none ported"] +// getArchivedFiles drives a git pipeline (Process::fromShellCommandline) and reads the produced +// zip back through PharData + RecursiveIteratorIterator; neither the process helper nor the zip +// archive reader is ported, so this case cannot run. +#[ignore = "getArchivedFiles needs a git process pipeline plus PharData/RecursiveIteratorIterator zip reading; not ported"] #[test] fn test_git_excludes() { todo!() } -#[ignore = "setUp needs TestCase::getUniqueTmpDirectory to build the on-disk fixture tree; not ported"] #[test] fn test_skip_excludes() { - todo!() + let set_up = set_up(); + + let excludes = vec!["prefixB.foo".to_string()]; + + let finder = ArchivableFilesFinder::new(&set_up.sources, excludes, true).unwrap(); + + assert_archivable_files( + &set_up, + finder, + &[ + "/!important!.txt", + "/!important_too!.txt", + "/#weirdfile", + "/.foo", + "/A/prefixA.foo", + "/A/prefixB.foo", + "/A/prefixC.foo", + "/A/prefixD.foo", + "/A/prefixE.foo", + "/A/prefixF.foo", + "/B/sub/prefixA.foo", + "/B/sub/prefixB.foo", + "/B/sub/prefixC.foo", + "/B/sub/prefixD.foo", + "/B/sub/prefixE.foo", + "/B/sub/prefixF.foo", + "/C/prefixA.foo", + "/C/prefixB.foo", + "/C/prefixC.foo", + "/C/prefixD.foo", + "/C/prefixE.foo", + "/C/prefixF.foo", + "/D/prefixA", + "/D/prefixB", + "/D/prefixC", + "/D/prefixD", + "/D/prefixE", + "/D/prefixF", + "/E/subtestA.foo", + "/F/subtestA.foo", + "/G/subtestA.foo", + "/H/subtestA.foo", + "/I/J/subtestA.foo", + "/K/dirJ/subtestA.foo", + "/parameters.yml", + "/parameters.yml.dist", + "/prefixA.foo", + "/prefixB.foo", + "/prefixC.foo", + "/prefixD.foo", + "/prefixE.foo", + "/prefixF.foo", + "/toplevelA.foo", + "/toplevelB.foo", + ], + ); } diff --git a/crates/shirabe/tests/package/archiver/archive_manager_test.rs b/crates/shirabe/tests/package/archiver/archive_manager_test.rs index 2712da6..fdc4bf0 100644 --- a/crates/shirabe/tests/package/archiver/archive_manager_test.rs +++ b/crates/shirabe/tests/package/archiver/archive_manager_test.rs @@ -29,31 +29,31 @@ impl Drop for TearDown { // the filename-derivation helpers over packages; the archiving and fixture setup are not // ported. #[test] -#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (set_up) which is unported"] +#[ignore = "needs the Factory/FactoryMock-built ArchiveManager (createDownloadManager/createHttpDownloader/FactoryMock::createConfig) in set_up, which is unported"] fn test_unknown_format() { todo!() } #[test] -#[ignore = "needs setupGitRepo + PharData tar archiving and Factory-built ArchiveManager (set_up), and setupPackage's setSourceType which is not exposed on the package handle API"] +#[ignore = "needs setupGitRepo + PharData tar archiving and the Factory/FactoryMock-built ArchiveManager (set_up), which is unported"] fn test_archive_tar() { todo!() } #[test] -#[ignore = "needs setupGitRepo + PharData tar archiving and Factory-built ArchiveManager (set_up), and setupPackage's setSourceType which is not exposed on the package handle API"] +#[ignore = "needs setupGitRepo + PharData tar archiving and the Factory/FactoryMock-built ArchiveManager (set_up), which is unported"] fn test_archive_custom_file_name() { todo!() } #[test] -#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (set_up) which is unported"] +#[ignore = "needs the Factory/FactoryMock-built ArchiveManager (createDownloadManager/createHttpDownloader/FactoryMock::createConfig) in set_up, which is unported"] fn test_get_package_filename_parts() { todo!() } #[test] -#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (set_up) which is unported"] +#[ignore = "needs the Factory/FactoryMock-built ArchiveManager (createDownloadManager/createHttpDownloader/FactoryMock::createConfig) in set_up, which is unported"] fn test_get_package_filename() { todo!() } diff --git a/crates/shirabe/tests/package/archiver/phar_archiver_test.rs b/crates/shirabe/tests/package/archiver/phar_archiver_test.rs index 385177b..fe6185d 100644 --- a/crates/shirabe/tests/package/archiver/phar_archiver_test.rs +++ b/crates/shirabe/tests/package/archiver/phar_archiver_test.rs @@ -1,13 +1,130 @@ //! ref: composer/tests/Composer/Test/Package/Archiver/PharArchiverTest.php -#[ignore = "setUp/setupDummyRepo need TestCase::getUniqueTmpDirectory plus Filesystem to build the on-disk fixture tree; not ported"] +use shirabe::package::archiver::{ArchiverInterface, PharArchiver}; +use shirabe::package::handle::CompletePackageHandle; +use shirabe::util::{Filesystem, Platform}; +use shirabe_php_shim::{dirname, file_exists, file_put_contents, mkdir, realpath}; +use tempfile::TempDir; + +// ref: ArchiverTestCase. +struct ArchiverTestCase { + filesystem: Filesystem, + test_dir: String, + _test_dir_guard: TempDir, +} + +impl ArchiverTestCase { + fn set_up() -> Self { + let guard = TempDir::new().unwrap(); + let test_dir = guard.path().to_string_lossy().to_string(); + Self { + filesystem: Filesystem::new(None), + test_dir, + _test_dir_guard: guard, + } + } + + fn setup_package(&self) -> CompletePackageHandle { + let package = CompletePackageHandle::new( + "archivertest/archivertest".to_string(), + "master".to_string(), + "master".to_string(), + ); + package.set_source_url(Some(realpath(&self.test_dir).unwrap_or_default())); + package.set_source_reference(Some("master".to_string())); + package.__set_source_type(Some("git".to_string())); + + package + } + + fn setup_dummy_repo(&self) { + let current_work_dir = Platform::get_cwd(false).unwrap(); + std::env::set_current_dir(&self.test_dir).unwrap(); + + self.write_file("file.txt", "content", ¤t_work_dir); + self.write_file("foo/bar/baz", "content", ¤t_work_dir); + self.write_file("foo/bar/ignoreme", "content", ¤t_work_dir); + self.write_file("x/baz", "content", ¤t_work_dir); + self.write_file("x/includeme", "content", ¤t_work_dir); + + std::env::set_current_dir(¤t_work_dir).unwrap(); + } + + fn write_file(&self, path: &str, content: &str, current_work_dir: &str) { + if !file_exists(dirname(path)) { + mkdir(&dirname(path), 0o777, true); + } + + let result = file_put_contents(path, content.as_bytes()); + if result.is_none() { + std::env::set_current_dir(current_work_dir).unwrap(); + panic!("Could not save file."); + } + } +} + +#[ignore = "PharArchiver::archive builds the archive via PharData, which is todo!() in the php-shim"] #[test] fn test_tar_archive() { - todo!() + let mut test_case = ArchiverTestCase::set_up(); + + test_case.setup_dummy_repo(); + let package = test_case.setup_package(); + let target_dir = TempDir::new().unwrap(); + let target = format!( + "{}/composer_archiver_test.tar", + target_dir.path().to_string_lossy() + ); + + let archiver = PharArchiver::new(); + archiver + .archive( + package.get_source_url().unwrap(), + target.clone(), + "tar".to_string(), + vec![ + "foo/bar".to_string(), + "baz".to_string(), + "!/foo/bar/baz".to_string(), + ], + false, + ) + .unwrap(); + assert!(file_exists(&target)); + + test_case + .filesystem + .remove_directory(dirname(&target)) + .unwrap(); } -#[ignore = "setUp/setupDummyRepo need TestCase::getUniqueTmpDirectory plus Filesystem to build the on-disk fixture tree; not ported"] +#[ignore = "PharArchiver::archive builds the archive via PharData, which is todo!() in the php-shim"] #[test] fn test_zip_archive() { - todo!() + let mut test_case = ArchiverTestCase::set_up(); + + test_case.setup_dummy_repo(); + let package = test_case.setup_package(); + let target_dir = TempDir::new().unwrap(); + let target = format!( + "{}/composer_archiver_test.zip", + target_dir.path().to_string_lossy() + ); + + let archiver = PharArchiver::new(); + archiver + .archive( + package.get_source_url().unwrap(), + target.clone(), + "zip".to_string(), + vec![], + false, + ) + .unwrap(); + assert!(file_exists(&target)); + + test_case + .filesystem + .remove_directory(dirname(&target)) + .unwrap(); } diff --git a/crates/shirabe/tests/package/archiver/zip_archiver_test.rs b/crates/shirabe/tests/package/archiver/zip_archiver_test.rs index 5b51ce9..7785976 100644 --- a/crates/shirabe/tests/package/archiver/zip_archiver_test.rs +++ b/crates/shirabe/tests/package/archiver/zip_archiver_test.rs @@ -1,46 +1,174 @@ //! ref: composer/tests/Composer/Test/Package/Archiver/ZipArchiverTest.php -/// Creates the Filesystem/ProcessExecutor and a unique tmp testDir; that infrastructure is -/// not ported. Returns testDir. -#[allow(dead_code)] -fn set_up() -> String { - todo!() -} - -/// Unlinks the zip files collected in filesToCleanup, then (parent) removes testDir. -#[allow(dead_code)] -fn tear_down(_files_to_cleanup: &[String], _test_dir: &str) { - todo!() -} +use indexmap::IndexMap; +use shirabe::package::archiver::{ArchiverInterface, ZipArchiver}; +use shirabe::package::handle::CompletePackageHandle; +use shirabe::util::Platform; +use shirabe_php_shim::{ + ZipArchive, class_exists, dirname, file_exists, file_put_contents, mkdir, realpath, + sys_get_temp_dir, unlink, +}; +use tempfile::TempDir; -#[allow(dead_code)] -struct TearDown { - files_to_cleanup: Vec<String>, +// ref: ArchiverTestCase. Holds the unique tmp testDir plus the ZipArchiverTest cleanup list. +struct ArchiverTestCase { test_dir: String, + _test_dir_guard: TempDir, + files_to_cleanup: Vec<String>, } -impl Drop for TearDown { +impl Drop for ArchiverTestCase { fn drop(&mut self) { - tear_down(&self.files_to_cleanup, &self.test_dir); + for file in &self.files_to_cleanup { + unlink(file); + } } } -// ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim. +impl ArchiverTestCase { + fn set_up() -> Self { + let guard = TempDir::new().unwrap(); + let test_dir = guard.path().to_string_lossy().to_string(); + Self { + test_dir, + _test_dir_guard: guard, + files_to_cleanup: vec![], + } + } + + fn setup_package(&self) -> CompletePackageHandle { + let package = CompletePackageHandle::new( + "archivertest/archivertest".to_string(), + "master".to_string(), + "master".to_string(), + ); + package.set_source_url(Some(realpath(&self.test_dir).unwrap_or_default())); + package.set_source_reference(Some("master".to_string())); + package.__set_source_type(Some("git".to_string())); + + package + } + fn assert_zip_archive(&mut self, mut files: IndexMap<String, Option<String>>) { + if !class_exists("ZipArchive") { + // markTestSkipped('Cannot run ZipArchiverTest, missing class "ZipArchive".') + return; + } + + self.setup_dummy_repo(&mut files); + let package = self.setup_package(); + let target = format!("{}/composer_archiver_test.zip", sys_get_temp_dir()); + self.files_to_cleanup.push(target.clone()); + + let archiver = ZipArchiver::new(); + archiver + .archive( + package.get_source_url().unwrap(), + target.clone(), + "zip".to_string(), + vec![], + false, + ) + .unwrap(); + assert!(file_exists(&target)); + let mut zip = ZipArchive::new(); + let res = zip.open(&target, 0); + assert!(res.is_ok(), "Failed asserting that Zip file can be opened"); + + let mut zip_contents: IndexMap<String, Option<String>> = IndexMap::new(); + for i in 0..zip.num_files { + let path = zip.get_name_index(i); + zip_contents.insert(path.clone(), zip.get_from_name(&path)); + } + zip.close(); + + let files: IndexMap<String, Option<String>> = files; + assert_eq!( + files, zip_contents, + "Failed asserting that Zip created with the ZipArchiver contains all files from the repository." + ); + } + + fn setup_dummy_repo(&self, files: &mut IndexMap<String, Option<String>>) { + let current_work_dir = Platform::get_cwd(false).unwrap(); + std::env::set_current_dir(&self.test_dir).unwrap(); + let paths: Vec<String> = files.keys().cloned().collect(); + for path in paths { + if files[&path].is_none() { + files.insert(path.clone(), Some("content".to_string())); + } + self.write_file(&path, files[&path].clone().unwrap(), ¤t_work_dir); + } + + std::env::set_current_dir(¤t_work_dir).unwrap(); + } + + fn write_file(&self, path: &str, content: String, current_work_dir: &str) { + if !file_exists(dirname(path)) { + mkdir(&dirname(path), 0o777, true); + } + + let result = file_put_contents(path, content.as_bytes()); + if result.is_none() { + std::env::set_current_dir(current_work_dir).unwrap(); + panic!("Could not save file."); + } + } +} + +#[ignore = "ZipArchiver::archive and the ZipArchive reader (open/get_from_name/...) are todo!() in the php-shim"] #[test] -#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"] fn test_simple_files() { - todo!() + let mut test_case = ArchiverTestCase::set_up(); + + let mut files: IndexMap<String, Option<String>> = IndexMap::new(); + files.insert("file.txt".to_string(), None); + files.insert("foo/bar/baz".to_string(), None); + files.insert("x/baz".to_string(), None); + files.insert("x/includeme".to_string(), None); + + if !Platform::is_windows() { + files.insert( + format!("zfoo{}/file.txt", Platform::get_cwd(false).unwrap()), + None, + ); + } + + test_case.assert_zip_archive(files); } +#[ignore = "ZipArchiver::archive and the ZipArchive reader (open/get_from_name/...) are todo!() in the php-shim"] #[test] -#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"] fn test_gitignore_exclude_negation() { - todo!() + for include in ["!/docs", "!/docs/"] { + let mut test_case = ArchiverTestCase::set_up(); + + let mut files: IndexMap<String, Option<String>> = IndexMap::new(); + files.insert( + ".gitignore".to_string(), + Some(format!("/*\n.*\n!.git*\n{}", include)), + ); + files.insert("docs/README.md".to_string(), Some("# The doc".to_string())); + + test_case.assert_zip_archive(files); + } } +#[ignore = "ZipArchiver::archive and the ZipArchive reader (open/get_from_name/...) are todo!() in the php-shim"] #[test] -#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"] fn test_folder_with_backslashes() { - todo!() + if Platform::is_windows() { + // markTestSkipped('Folder names cannot contain backslashes on Windows.') + return; + } + + let mut test_case = ArchiverTestCase::set_up(); + + let mut files: IndexMap<String, Option<String>> = IndexMap::new(); + files.insert( + "folder\\with\\backslashes/README.md".to_string(), + Some("# doc".to_string()), + ); + + test_case.assert_zip_archive(files); } diff --git a/crates/shirabe/tests/package/base_package_test.rs b/crates/shirabe/tests/package/base_package_test.rs index 1056de1..16d3a5b 100644 --- a/crates/shirabe/tests/package/base_package_test.rs +++ b/crates/shirabe/tests/package/base_package_test.rs @@ -1,7 +1,10 @@ //! ref: composer/tests/Composer/Test/Package/BasePackageTest.php +use shirabe::package::DisplayMode; use shirabe::package::base_package::package_names_to_regexp; +use shirabe::package::handle::PackageHandle; use shirabe::repository::{ArrayRepository, RepositoryInterfaceHandle}; +use shirabe_semver::version_parser::VersionParser; use crate::test_case::get_package; @@ -31,14 +34,40 @@ fn test_set_another_repository() { assert!(package.set_repository(repository2.clone()).is_err()); } -// In PHP this mocks isDev()/getSourceType()/getPrettyVersion()/getSourceReference() -// on an abstract BasePackage to drive getFullPrettyVersion(). Reproducing those exact -// getter values requires mocking; a real package cannot carry the pretty version -// "PrettyVersion" together with isDev() == true. -#[ignore = "requires mocking isDev/getSourceType/getPrettyVersion/getSourceReference on an abstract BasePackage; no mock infrastructure exists and a real package cannot carry prettyVersion \"PrettyVersion\" with isDev() == true"] +// PHP mocks isDev()/getSourceType()/getPrettyVersion()/getSourceReference() on an abstract +// BasePackage. A real Package reproduces the same observable getters: a "dev-master" version makes +// isDev() true, while the pretty version is an independent constructor argument. #[test] fn test_format_version_for_dev_package() { - todo!() + let cases: Vec<(&str, bool, &str)> = vec![ + ("v2.1.0-RC2", true, "PrettyVersion v2.1.0-RC2"), + ( + "bbf527a27356414bfa9bf520f018c5cb7af67c77", + true, + "PrettyVersion bbf527a", + ), + ("v1.0.0", false, "PrettyVersion v1.0.0"), + ( + "bbf527a27356414bfa9bf520f018c5cb7af67c77", + false, + "PrettyVersion bbf527a27356414bfa9bf520f018c5cb7af67c77", + ), + ]; + + for (source_reference, truncate, expected) in cases { + let package = PackageHandle::new( + "dummy/pkg".to_string(), + VersionParser.normalize("dev-master", None).unwrap(), + "PrettyVersion".to_string(), + ); + package.__set_source_type(Some("git".to_string())); + package.set_source_reference(Some(source_reference.to_string())); + + assert_eq!( + expected, + package.get_full_pretty_version(truncate, DisplayMode::SourceRefIfDev) + ); + } } #[test] diff --git a/crates/shirabe/tests/package/dumper/array_dumper_test.rs b/crates/shirabe/tests/package/dumper/array_dumper_test.rs index 64880f1..1e5fd05 100644 --- a/crates/shirabe/tests/package/dumper/array_dumper_test.rs +++ b/crates/shirabe/tests/package/dumper/array_dumper_test.rs @@ -79,11 +79,16 @@ fn test_dump_abandoned_replacement() { ); } -// PHP drives ~25 heterogeneous setters dynamically (set{ucfirst(method)}) across strings, -// arrays, a DateTime and Link maps, then checks the corresponding dumped key. Reproducing -// that dynamic dispatch faithfully would require per-case wiring for every property type. +// PHP drives 26 heterogeneous setters dynamically (set{ucfirst(method)}) across strings, +// arrays, a DateTime and Link maps, then checks the corresponding dumped key. Three of the +// data sets cannot be expressed faithfully because the ported production types were narrowed +// from PHP's loose `array`: the `authors` set passes plain strings (Rust set_authors wants +// Vec<IndexMap<String,String>>), `scripts` passes a bare string value (set_scripts wants +// IndexMap<String,Vec<String>>), and `funding` passes a single map (set_funding wants +// Vec<IndexMap<String,PhpMixed>>); the dumper additionally re-wraps each of these. Porting the +// remaining 23 would drop those three cases, so testKeys stays unported (all-or-nothing). #[test] -#[ignore = "RootPackageHandle lacks set_type/set_release_date/set_binaries/set_php_ext setters required by the data provider's type/time/bin/php-ext cases"] +#[ignore = "authors/scripts/funding data sets pass loosely-typed PHP arrays the narrowed Rust set_authors/set_scripts/set_funding types cannot represent, and the dumper re-wraps them; faithful all-or-nothing port blocked without loosening those production types"] fn test_keys() { todo!() } |
