aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests/package
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-22 02:09:59 +0900
committernsfisis <nsfisis@gmail.com>2026-06-22 02:09:59 +0900
commit822d9a872807a92a5337ee8b7bab96dc9845cdbb (patch)
tree4931365df5978caffade69cad2154718a9076f66 /crates/shirabe/tests/package
parentf691b864b687f251c3b266e8cff2774d730567ba (diff)
downloadphp-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/package')
-rw-r--r--crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs6
-rw-r--r--crates/shirabe/tests/package/archiver/archive_manager_test.rs10
-rw-r--r--crates/shirabe/tests/package/archiver/phar_archiver_test.rs4
-rw-r--r--crates/shirabe/tests/package/archiver/zip_archiver_test.rs6
-rw-r--r--crates/shirabe/tests/package/base_package_test.rs2
-rw-r--r--crates/shirabe/tests/package/dumper/array_dumper_test.rs2
-rw-r--r--crates/shirabe/tests/package/loader/array_loader_test.rs621
-rw-r--r--crates/shirabe/tests/package/loader/root_package_loader_test.rs137
-rw-r--r--crates/shirabe/tests/package/loader/validating_array_loader_test.rs1022
-rw-r--r--crates/shirabe/tests/package/locker_test.rs20
-rw-r--r--crates/shirabe/tests/package/version/version_guesser_test.rs59
-rw-r--r--crates/shirabe/tests/package/version/version_selector_test.rs26
12 files changed, 1773 insertions, 142 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 5454074..48f0fc5 100644
--- a/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs
+++ b/crates/shirabe/tests/package/archiver/archivable_files_finder_test.rs
@@ -26,20 +26,20 @@ impl Drop for TearDown {
// 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"]
#[test]
-#[ignore = "needs a temp directory tree and git-backed fixtures to drive ArchivableFilesFinder; not ported"]
fn test_manual_excludes() {
todo!()
}
+#[ignore = "setUp needs TestCase::getUniqueTmpDirectory plus skipIfNotExecutable/Process::fromShellCommandline/PharData/RecursiveIteratorIterator; none ported"]
#[test]
-#[ignore = "needs a temp directory tree and git-backed fixtures to drive ArchivableFilesFinder; not ported"]
fn test_git_excludes() {
todo!()
}
+#[ignore = "setUp needs TestCase::getUniqueTmpDirectory to build the on-disk fixture tree; not ported"]
#[test]
-#[ignore = "needs a temp directory tree and git-backed fixtures to drive ArchivableFilesFinder; not ported"]
fn test_skip_excludes() {
todo!()
}
diff --git a/crates/shirabe/tests/package/archiver/archive_manager_test.rs b/crates/shirabe/tests/package/archiver/archive_manager_test.rs
index b3b61f8..2712da6 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 = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (set_up) which is unported"]
fn test_unknown_format() {
todo!()
}
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[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"]
fn test_archive_tar() {
todo!()
}
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[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"]
fn test_archive_custom_file_name() {
todo!()
}
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (set_up) which is unported"]
fn test_get_package_filename_parts() {
todo!()
}
#[test]
-#[ignore = "ArchiveManager builds archives via PharData (todo!()) over fixtures; not ported"]
+#[ignore = "setupPackage requires CompletePackage::setSourceType, not exposed on the package handle API; also needs Factory-built ArchiveManager (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 414aa36..385177b 100644
--- a/crates/shirabe/tests/package/archiver/phar_archiver_test.rs
+++ b/crates/shirabe/tests/package/archiver/phar_archiver_test.rs
@@ -1,13 +1,13 @@
//! 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"]
#[test]
-#[ignore = "PharArchiver::archive builds a tar via PharData, which is todo!() in the php-shim"]
fn test_tar_archive() {
todo!()
}
+#[ignore = "setUp/setupDummyRepo need TestCase::getUniqueTmpDirectory plus Filesystem to build the on-disk fixture tree; not ported"]
#[test]
-#[ignore = "PharArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim"]
fn test_zip_archive() {
todo!()
}
diff --git a/crates/shirabe/tests/package/archiver/zip_archiver_test.rs b/crates/shirabe/tests/package/archiver/zip_archiver_test.rs
index 5f41c78..5b51ce9 100644
--- a/crates/shirabe/tests/package/archiver/zip_archiver_test.rs
+++ b/crates/shirabe/tests/package/archiver/zip_archiver_test.rs
@@ -28,19 +28,19 @@ impl Drop for TearDown {
// ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim.
#[test]
-#[ignore = "ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim"]
+#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"]
fn test_simple_files() {
todo!()
}
#[test]
-#[ignore = "ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim"]
+#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"]
fn test_gitignore_exclude_negation() {
todo!()
}
#[test]
-#[ignore = "ZipArchiver::archive builds a zip via ZipArchive, which is todo!() in the php-shim"]
+#[ignore = "ArchiverTestCase infrastructure (setup_package/setup_dummy_repo/test_dir) not ported; ZipArchive shim lacks get_from_name"]
fn test_folder_with_backslashes() {
todo!()
}
diff --git a/crates/shirabe/tests/package/base_package_test.rs b/crates/shirabe/tests/package/base_package_test.rs
index 0d77f49..1056de1 100644
--- a/crates/shirabe/tests/package/base_package_test.rs
+++ b/crates/shirabe/tests/package/base_package_test.rs
@@ -35,8 +35,8 @@ fn test_set_another_repository() {
// 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"]
#[test]
-#[ignore = "mocks isDev/getSourceType/getPrettyVersion/getSourceReference on an abstract BasePackage; not reproducible with a real package"]
fn test_format_version_for_dev_package() {
todo!()
}
diff --git a/crates/shirabe/tests/package/dumper/array_dumper_test.rs b/crates/shirabe/tests/package/dumper/array_dumper_test.rs
index 6ed12fe..64880f1 100644
--- a/crates/shirabe/tests/package/dumper/array_dumper_test.rs
+++ b/crates/shirabe/tests/package/dumper/array_dumper_test.rs
@@ -83,7 +83,7 @@ fn test_dump_abandoned_replacement() {
// 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.
#[test]
-#[ignore = "exercises ~25 dynamic set<Property> calls over heterogeneous value types; not reproduced here"]
+#[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"]
fn test_keys() {
todo!()
}
diff --git a/crates/shirabe/tests/package/loader/array_loader_test.rs b/crates/shirabe/tests/package/loader/array_loader_test.rs
index 2dc4f3e..d35f671 100644
--- a/crates/shirabe/tests/package/loader/array_loader_test.rs
+++ b/crates/shirabe/tests/package/loader/array_loader_test.rs
@@ -1,170 +1,647 @@
//! ref: composer/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php
-use shirabe::package::loader::ArrayLoader;
+use indexmap::IndexMap;
+use shirabe::package::ArrayDumper;
+use shirabe::package::Link;
+use shirabe::package::loader::{ArrayLoader, LoaderInterface};
+use shirabe::package::version::VersionParser;
+use shirabe_php_shim::PhpMixed;
fn set_up() -> ArrayLoader {
ArrayLoader::new(None, false)
}
-// ArrayLoader::load parses version/link constraints through a look-around regex the regex
-// crate cannot compile.
+fn s(value: &str) -> PhpMixed {
+ PhpMixed::String(value.to_string())
+}
+
+fn map(entries: Vec<(&str, PhpMixed)>) -> PhpMixed {
+ let mut m: IndexMap<String, PhpMixed> = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ PhpMixed::Array(m)
+}
+
+fn make_config(entries: Vec<(&str, PhpMixed)>) -> IndexMap<String, PhpMixed> {
+ let mut m: IndexMap<String, PhpMixed> = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ m
+}
+
+fn list(items: Vec<PhpMixed>) -> PhpMixed {
+ PhpMixed::List(items)
+}
+
+/// ref: ArrayLoaderTest::parseDumpProvider valid config
+fn valid_config() -> IndexMap<String, PhpMixed> {
+ make_config(vec![
+ ("name", s("A/B")),
+ ("version", s("1.2.3")),
+ ("version_normalized", s("1.2.3.0")),
+ ("description", s("Foo bar")),
+ ("type", s("library")),
+ ("keywords", list(vec![s("a"), s("b"), s("c")])),
+ ("homepage", s("http://example.com")),
+ ("license", list(vec![s("MIT"), s("GPLv3")])),
+ (
+ "authors",
+ list(vec![map(vec![
+ ("name", s("Bob")),
+ ("email", s("bob@example.org")),
+ ("homepage", s("example.org")),
+ ("role", s("Developer")),
+ ])]),
+ ),
+ (
+ "funding",
+ list(vec![map(vec![
+ ("type", s("example")),
+ ("url", s("https://example.org/fund")),
+ ])]),
+ ),
+ ("require", map(vec![("foo/bar", s("1.0"))])),
+ ("require-dev", map(vec![("foo/baz", s("1.0"))])),
+ ("replace", map(vec![("foo/qux", s("1.0"))])),
+ ("conflict", map(vec![("foo/quux", s("1.0"))])),
+ ("provide", map(vec![("foo/quuux", s("1.0"))])),
+ (
+ "autoload",
+ map(vec![
+ ("psr-0", map(vec![("Ns\\Prefix", s("path"))])),
+ ("classmap", list(vec![s("path"), s("path2")])),
+ ]),
+ ),
+ ("include-path", list(vec![s("path3"), s("path4")])),
+ ("target-dir", s("some/prefix")),
+ (
+ "extra",
+ map(vec![(
+ "random",
+ map(vec![("things", s("of")), ("any", s("shape"))]),
+ )]),
+ ),
+ ("bin", list(vec![s("bin1"), s("bin/foo")])),
+ (
+ "archive",
+ map(vec![(
+ "exclude",
+ list(vec![s("/foo/bar"), s("baz"), s("!/foo/bar/baz")]),
+ )]),
+ ),
+ (
+ "transport-options",
+ map(vec![(
+ "ssl",
+ map(vec![("local_cert", s("/opt/certs/test.pem"))]),
+ )]),
+ ),
+ ("abandoned", s("foo/bar")),
+ ])
+}
+
+/// ref: ArrayLoaderTest::fixConfigWhenLoadConfigIsFalse
+fn fix_config_when_load_config_is_false(
+ config: &IndexMap<String, PhpMixed>,
+) -> IndexMap<String, PhpMixed> {
+ let mut expected_config = config.clone();
+ expected_config.shift_remove("transport-options");
+ expected_config
+}
+
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_self_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("1.2.3.4")),
+ ("replace", map(vec![("foo", s("self.version"))])),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ let replaces = package.get_replaces();
+ assert_eq!(
+ "== 1.2.3.4",
+ replaces.get("foo").unwrap().get_constraint().to_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_type_default() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![("name", s("A")), ("version", s("1.0"))]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("library", package.get_type());
+
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("1.0")),
+ ("type", s("foo")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("foo", package.get_type());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_normalized_version_optimization() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![("name", s("A")), ("version", s("1.2.3"))]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("1.2.3.0", package.get_version());
+
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("1.2.3")),
+ ("version_normalized", s("1.2.3.4")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("1.2.3.4", package.get_version());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_dump_default_load_config() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = valid_config();
+ let package = loader.load(config.clone(), None).unwrap();
+ let dumper = ArrayDumper::new();
+ let expected_config = fix_config_when_load_config_is_false(&config);
+ assert_eq!(expected_config, dumper.dump(package));
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_dump_true_load_config() {
- let _loader = set_up();
- todo!()
+ let config = valid_config();
+ let loader = ArrayLoader::new(None, true);
+ let package = loader.load(config.clone(), None).unwrap();
+ let dumper = ArrayDumper::new();
+ let expected_config = config;
+ assert_eq!(expected_config, dumper.dump(package));
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_dump_false_load_config() {
- let _loader = set_up();
- todo!()
+ let config = valid_config();
+ let loader = ArrayLoader::new(None, false);
+ let package = loader.load(config.clone(), None).unwrap();
+ let dumper = ArrayDumper::new();
+ let expected_config = fix_config_when_load_config_is_false(&config);
+ assert_eq!(expected_config, dumper.dump(package));
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_with_branch_alias() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("dev-master")),
+ (
+ "extra",
+ map(vec![(
+ "branch-alias",
+ map(vec![("dev-master", s("1.0.x-dev"))]),
+ )]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!("1.0.x-dev", package.get_pretty_version());
+
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("dev-master")),
+ (
+ "extra",
+ map(vec![(
+ "branch-alias",
+ map(vec![("dev-master", s("1.0-dev"))]),
+ )]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!("1.0.x-dev", package.get_pretty_version());
+
+ let config = make_config(vec![
+ ("name", s("B")),
+ ("version", s("4.x-dev")),
+ (
+ "extra",
+ map(vec![(
+ "branch-alias",
+ map(vec![("4.x-dev", s("4.0.x-dev"))]),
+ )]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!("4.0.x-dev", package.get_pretty_version());
+
+ let config = make_config(vec![
+ ("name", s("B")),
+ ("version", s("4.x-dev")),
+ (
+ "extra",
+ map(vec![("branch-alias", map(vec![("4.x-dev", s("4.0-dev"))]))]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!("4.0.x-dev", package.get_pretty_version());
+
+ let config = make_config(vec![
+ ("name", s("C")),
+ ("version", s("4.x-dev")),
+ (
+ "extra",
+ map(vec![(
+ "branch-alias",
+ map(vec![("4.x-dev", s("3.4.x-dev"))]),
+ )]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_package().is_some());
+ assert_eq!("4.x-dev", package.get_pretty_version());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_aliasing_without_branch_alias() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ // non-numeric gets a default alias
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("dev-main")),
+ ("default-branch", PhpMixed::Bool(true)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_alias_package().is_some());
+ assert_eq!(
+ VersionParser::DEFAULT_BRANCH_ALIAS,
+ package.get_pretty_version()
+ );
+
+ // non-default branch gets no alias even if non-numeric
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("dev-main")),
+ ("default-branch", PhpMixed::Bool(false)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_package().is_some());
+ assert_eq!("dev-main", package.get_pretty_version());
+
+ // default branch gets no alias if already numeric
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("2.x-dev")),
+ ("default-branch", PhpMixed::Bool(true)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_package().is_some());
+ assert_eq!("2.9999999.9999999.9999999-dev", package.get_version());
+
+ // default branch gets no alias if already numeric, with v prefix
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("v2.x-dev")),
+ ("default-branch", PhpMixed::Bool(true)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+
+ assert!(package.as_complete_package().is_some());
+ assert_eq!("2.9999999.9999999.9999999-dev", package.get_version());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_abandoned() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("A")),
+ ("version", s("1.2.3.4")),
+ ("abandoned", s("foo/bar")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ let package = package.as_complete().unwrap();
+ assert!(package.is_abandoned());
+ assert_eq!(
+ Some("foo/bar".to_string()),
+ package.get_replacement_package()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_not_abandoned() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![("name", s("A")), ("version", s("1.2.3.4"))]);
+
+ let package = loader.load(config, None).unwrap();
+ let package = package.as_complete().unwrap();
+ assert!(!package.is_abandoned());
+}
+
+/// ref: ArrayLoaderTest::providePluginApiVersions
+fn provide_plugin_api_versions() -> Vec<&'static str> {
+ vec![
+ "1.0",
+ "1.0.0",
+ "1.0.0.0",
+ "1",
+ "=1.0.0",
+ "==1.0",
+ "~1.0.0",
+ "*",
+ "3.0.*",
+ "@stable",
+ "1.0.0@stable",
+ "^5.1",
+ ">=1.0.0 <2.5",
+ "x",
+ "1.0.0-dev",
+ ]
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_plugin_api_version_are_kept_as_declared() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ for api_version in provide_plugin_api_versions() {
+ let links = loader
+ .parse_links(
+ "Plugin",
+ "9.9.9",
+ Link::TYPE_REQUIRE,
+ make_config(vec![("composer-plugin-api", s(api_version))]),
+ )
+ .unwrap();
+
+ assert!(links.contains_key("composer-plugin-api"));
+ assert_eq!(
+ api_version,
+ links
+ .get("composer-plugin-api")
+ .unwrap()
+ .get_constraint()
+ .get_pretty_string()
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_plugin_api_version_does_support_self_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let links = loader
+ .parse_links(
+ "Plugin",
+ "6.6.6",
+ Link::TYPE_REQUIRE,
+ make_config(vec![("composer-plugin-api", s("self.version"))]),
+ )
+ .unwrap();
+
+ assert!(links.contains_key("composer-plugin-api"));
+ assert_eq!(
+ "6.6.6",
+ links
+ .get("composer-plugin-api")
+ .unwrap()
+ .get_constraint()
+ .get_pretty_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_links_integer_target() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let links = loader
+ .parse_links(
+ "Plugin",
+ "9.9.9",
+ Link::TYPE_REQUIRE,
+ make_config(vec![("1", s("dev-main"))]),
+ )
+ .unwrap();
+
+ assert!(links.contains_key("1"));
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_parse_links_invalid_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let err = loader
+ .parse_links(
+ "Plugin",
+ "9.9.9",
+ Link::TYPE_REQUIRE,
+ make_config(vec![("composer-plugin-api", s("^^^"))]),
+ )
+ .unwrap_err();
+ assert_eq!(
+ "Link constraint in Plugin requires > composer-plugin-api should be a valid version constraint, got \"^^^\"",
+ err.to_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_none_string_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", PhpMixed::Int(1)),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!("1", package.get_pretty_version());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_none_string_source_dist_reference() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-main")),
+ (
+ "source",
+ map(vec![
+ ("type", s("svn")),
+ ("url", s("https://example.org/")),
+ ("reference", PhpMixed::Int(2019)),
+ ]),
+ ),
+ (
+ "dist",
+ map(vec![
+ ("type", s("zip")),
+ ("url", s("https://example.org/")),
+ ("reference", PhpMixed::Int(2019)),
+ ]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!(Some("2019".to_string()), package.get_source_reference());
+ assert_eq!(Some("2019".to_string()), package.get_dist_reference());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_branch_alias_integer_index() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ (
+ "extra",
+ map(vec![("branch-alias", map(vec![("1", s("1.3-dev"))]))]),
+ ),
+ (
+ "dist",
+ map(vec![("type", s("zip")), ("url", s("https://example.org/"))]),
+ ),
+ ]);
+
+ assert_eq!(None, loader.get_branch_alias(&config).unwrap());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_links_require() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ ("require", map(vec![("foo/bar", s("1.0"))])),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert!(package.get_requires().contains_key("foo/bar"));
+ assert_eq!(
+ "1.0",
+ package
+ .get_requires()
+ .get("foo/bar")
+ .unwrap()
+ .get_constraint()
+ .get_pretty_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_links_require_invalid() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ (
+ "require",
+ map(vec![("foo/bar", map(vec![("random-string", s("1.0"))]))]),
+ ),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!(0, package.get_requires().len());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_links_replace() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ ("replace", map(vec![("coyote/package", s("self.version"))])),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert!(package.get_replaces().contains_key("coyote/package"));
+ assert_eq!(
+ "dev-1",
+ package
+ .get_replaces()
+ .get("coyote/package")
+ .unwrap()
+ .get_constraint()
+ .get_pretty_string()
+ );
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_package_links_replace_invalid() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ ("replace", s("coyote/package")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ assert_eq!(0, package.get_replaces().len());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_support_string_value() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![
+ ("name", s("acme/package")),
+ ("version", s("dev-1")),
+ ("support", s("https://example.org")),
+ ]);
+
+ let package = loader.load(config, None).unwrap();
+ let package = package.as_complete().unwrap();
+ assert_eq!(0, package.get_support().len());
}
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load parses constraints via a look-around regex the regex crate cannot compile"]
fn test_invalid_version() {
- let _loader = set_up();
- todo!()
+ let loader = set_up();
+ let config = make_config(vec![("name", s("acme/package")), ("version", s("AA"))]);
+
+ let err = loader.load(config, None).unwrap_err();
+ assert_eq!(
+ "Failed to normalize version for package \"acme/package\": Invalid version string \"AA\"",
+ err.to_string()
+ );
}
diff --git a/crates/shirabe/tests/package/loader/root_package_loader_test.rs b/crates/shirabe/tests/package/loader/root_package_loader_test.rs
index 82d60ba..e78967e 100644
--- a/crates/shirabe/tests/package/loader/root_package_loader_test.rs
+++ b/crates/shirabe/tests/package/loader/root_package_loader_test.rs
@@ -4,32 +4,157 @@
// ProcessExecutor / VersionGuesser or require constraints whose parsing goes through a
// look-around regex the regex crate cannot compile.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::config::Config;
+use shirabe::io::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::package::loader::RootPackageLoader;
+use shirabe::package::version::{VersionGuesser, VersionParser};
+use shirabe::package::{STABILITY_ALPHA, STABILITY_DEV, STABILITY_RC};
+use shirabe::repository::RepositoryManager;
+use shirabe::util::http_downloader::HttpDownloader;
+use shirabe::util::process_executor::ProcessExecutor;
+use shirabe_php_shim::PhpMixed;
+
+fn null_io() -> Rc<RefCell<dyn IOInterface>> {
+ Rc::new(RefCell::new(NullIO::new()))
+}
+
+fn http_downloader(
+ io: &Rc<RefCell<dyn IOInterface>>,
+ config: &Rc<RefCell<Config>>,
+) -> Rc<RefCell<HttpDownloader>> {
+ Rc::new(RefCell::new(HttpDownloader::new(
+ io.clone(),
+ config.clone(),
+ IndexMap::new(),
+ true,
+ )))
+}
+
#[test]
-#[ignore = "RootPackageLoader::load parses require constraints via a look-around regex; mocks RepositoryManager"]
+#[ignore]
fn test_stability_flags_parsing() {
- todo!()
+ let io = null_io();
+ let config = Rc::new(RefCell::new(Config::new(true, None)));
+ {
+ let mut cfg = IndexMap::new();
+ cfg.insert(
+ "repositories".to_string(),
+ PhpMixed::Array({
+ let mut m = IndexMap::new();
+ m.insert("packagist".to_string(), PhpMixed::Bool(false));
+ m
+ }),
+ );
+ config.borrow_mut().merge(&cfg, "test");
+ }
+
+ let manager = Rc::new(RefCell::new(RepositoryManager::new(
+ io.clone(),
+ config.clone(),
+ http_downloader(&io, &config),
+ None,
+ None,
+ )));
+
+ let mut process_executor = ProcessExecutor::new(Some(io.clone()));
+ process_executor.enable_async();
+ let guesser = VersionGuesser::new(
+ config.clone(),
+ Rc::new(RefCell::new(process_executor)),
+ VersionParser::new(),
+ Some(io.clone()),
+ );
+
+ let mut loader = RootPackageLoader::new(manager, config.clone(), None, Some(guesser), None);
+
+ let mut data = IndexMap::new();
+ data.insert(
+ "require".to_string(),
+ PhpMixed::Array({
+ let mut m = IndexMap::new();
+ m.insert(
+ "foo/bar".to_string(),
+ PhpMixed::String("~2.1.0-beta2".to_string()),
+ );
+ m.insert(
+ "bar/baz".to_string(),
+ PhpMixed::String("1.0.x-dev as 1.2.0".to_string()),
+ );
+ m.insert(
+ "qux/quux".to_string(),
+ PhpMixed::String("1.0.*@rc".to_string()),
+ );
+ m.insert(
+ "zux/complex".to_string(),
+ PhpMixed::String("~1.0,>=1.0.2@dev".to_string()),
+ );
+ m.insert(
+ "or/op".to_string(),
+ PhpMixed::String("^2.0@dev || ^2.0@dev".to_string()),
+ );
+ m.insert(
+ "multi/lowest-wins".to_string(),
+ PhpMixed::String("^2.0@rc || >=3.0@dev , ~3.5@alpha".to_string()),
+ );
+ m.insert(
+ "or/op-without-flags".to_string(),
+ PhpMixed::String("dev-master || 2.0 , ~3.5-alpha".to_string()),
+ );
+ m.insert(
+ "or/op-without-flags2".to_string(),
+ PhpMixed::String("3.0-beta || 2.0 , ~3.5-alpha".to_string()),
+ );
+ m
+ }),
+ );
+ data.insert(
+ "minimum-stability".to_string(),
+ PhpMixed::String("alpha".to_string()),
+ );
+
+ let package = loader
+ .load(data, "Composer\\Package\\RootPackage", None)
+ .unwrap();
+ let package = package.as_root().unwrap();
+
+ assert_eq!("alpha", package.get_minimum_stability());
+
+ let mut expected = IndexMap::new();
+ expected.insert("bar/baz".to_string(), STABILITY_DEV);
+ expected.insert("qux/quux".to_string(), STABILITY_RC);
+ expected.insert("zux/complex".to_string(), STABILITY_DEV);
+ expected.insert("or/op".to_string(), STABILITY_DEV);
+ expected.insert("multi/lowest-wins".to_string(), STABILITY_DEV);
+ expected.insert("or/op-without-flags".to_string(), STABILITY_DEV);
+ expected.insert("or/op-without-flags2".to_string(), STABILITY_ALPHA);
+ assert_eq!(expected, package.get_stability_flags());
}
#[test]
-#[ignore = "mocks RepositoryManager and a ProcessExecutor returning a non-zero git result"]
+#[ignore = "requires getProcessExecutorMock with expects(['return' => 1]); no ProcessExecutorMock mocking infrastructure exists"]
fn test_no_version_is_visible_in_pretty_version() {
todo!()
}
#[test]
-#[ignore = "mocks RepositoryManager and a VersionGuesser returning a fixed guessed version"]
+#[ignore = "requires getMockBuilder VersionGuesser mock with guessVersion expectation; no VersionGuesser mocking infrastructure exists"]
fn test_pretty_version_for_root_package_in_version_branch() {
todo!()
}
#[test]
-#[ignore = "mocks RepositoryManager and a ProcessExecutor feeding git branch output"]
+#[ignore = "requires getProcessExecutorMock with expects() git command expectations; no ProcessExecutorMock mocking infrastructure exists"]
fn test_feature_branch_pretty_version() {
todo!()
}
#[test]
-#[ignore = "mocks RepositoryManager and a ProcessExecutor feeding git branch output"]
+#[ignore = "requires getProcessExecutorMock with expects() git command expectations; no ProcessExecutorMock mocking infrastructure exists"]
fn test_non_feature_branch_pretty_version() {
todo!()
}
diff --git a/crates/shirabe/tests/package/loader/validating_array_loader_test.rs b/crates/shirabe/tests/package/loader/validating_array_loader_test.rs
index 9858df1..db5ff07 100644
--- a/crates/shirabe/tests/package/loader/validating_array_loader_test.rs
+++ b/crates/shirabe/tests/package/loader/validating_array_loader_test.rs
@@ -1,27 +1,1029 @@
//! ref: composer/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php
-// ValidatingArrayLoader wraps ArrayLoader, whose constraint parsing uses a look-around
-// regex the regex crate cannot compile; the success/warning data sets are large.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::package::handle::PackageInterfaceHandle;
+use shirabe::package::loader::{InvalidPackageException, LoaderInterface, ValidatingArrayLoader};
+use shirabe_php_shim::PhpMixed;
+
+#[path = "../../common/test_case.rs"]
+mod test_case;
+
+fn s(v: &str) -> PhpMixed {
+ PhpMixed::String(v.to_string())
+}
+
+fn i(v: i64) -> PhpMixed {
+ PhpMixed::Int(v)
+}
+
+fn b(v: bool) -> PhpMixed {
+ PhpMixed::Bool(v)
+}
+
+/// Build a PHP assoc array (string-keyed). The impl reads every PHP `array`,
+/// list or assoc, via `PhpMixed::as_array`, so both shapes are `PhpMixed::Array`.
+fn arr(entries: Vec<(&str, PhpMixed)>) -> PhpMixed {
+ let mut m = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ PhpMixed::Array(m)
+}
+
+/// Build a PHP list array as a `PhpMixed::Array` with sequential string keys.
+fn list(items: Vec<PhpMixed>) -> PhpMixed {
+ let mut m = IndexMap::new();
+ for (idx, v) in items.into_iter().enumerate() {
+ m.insert(idx.to_string(), v);
+ }
+ PhpMixed::Array(m)
+}
+
+fn config(entries: Vec<(&str, PhpMixed)>) -> IndexMap<String, PhpMixed> {
+ let mut m = IndexMap::new();
+ for (k, v) in entries {
+ m.insert(k.to_string(), v);
+ }
+ m
+}
+
+type Calls = Rc<RefCell<Vec<IndexMap<String, PhpMixed>>>>;
+
+/// Mock LoaderInterface recording every `load` invocation, mirroring PHPUnit's
+/// `expects($this->once())->method('load')->with(...)`.
+#[derive(Debug)]
+struct MockLoader {
+ calls: Calls,
+}
+
+impl MockLoader {
+ fn new() -> (Self, Calls) {
+ let calls: Calls = Rc::new(RefCell::new(Vec::new()));
+ (
+ MockLoader {
+ calls: calls.clone(),
+ },
+ calls,
+ )
+ }
+}
+
+impl LoaderInterface for MockLoader {
+ fn load(
+ &self,
+ config: IndexMap<String, PhpMixed>,
+ _class: Option<String>,
+ ) -> anyhow::Result<PackageInterfaceHandle> {
+ self.calls.borrow_mut().push(config);
+ Ok(test_case::get_package("mock/mock", "1.0.0"))
+ }
+
+ fn as_any(&self) -> &dyn std::any::Any {
+ self
+ }
+}
+
+fn invalid_naming_error(name: &str) -> Vec<String> {
+ vec![format!(
+ "name : {} is invalid, it should have a vendor name, a forward slash, and a package name. The vendor and package name can be words separated by -, . or _. The complete name should match \"^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]?|-{{0,2}})[a-z0-9]+)*$\".",
+ name
+ )]
+}
+
+/// ref: ValidatingArrayLoaderTest::successProvider
+fn success_provider() -> Vec<IndexMap<String, PhpMixed>> {
+ vec![
+ // minimal
+ config(vec![("name", s("foo/bar"))]),
+ // complete
+ config(vec![
+ ("name", s("foo/bar")),
+ ("description", s("Foo bar")),
+ ("version", s("1.0.0")),
+ ("type", s("library")),
+ (
+ "keywords",
+ list(vec![s("a"), s("b_c"), s("D E"), s("éîüø"), s("微信")]),
+ ),
+ ("homepage", s("https://foo.com")),
+ ("time", s("2010-10-10T10:10:10+00:00")),
+ ("license", list(vec![s("MIT"), s("WTFPL")])),
+ (
+ "authors",
+ list(vec![
+ arr(vec![
+ ("name", s("Alice")),
+ ("email", s("alice@example.org")),
+ ("role", s("Lead")),
+ ("homepage", s("http://example.org")),
+ ]),
+ arr(vec![("name", s("Bob")), ("homepage", s(""))]),
+ ]),
+ ),
+ (
+ "support",
+ arr(vec![
+ ("email", s("mail@example.org")),
+ ("issues", s("http://example.org/")),
+ ("forum", s("http://example.org/")),
+ ("wiki", s("http://example.org/")),
+ ("source", s("http://example.org/")),
+ ("irc", s("irc://example.org/example")),
+ ("rss", s("http://example.org/rss")),
+ ("chat", s("http://example.org/chat")),
+ ("security", s("https://example.org/security")),
+ ]),
+ ),
+ (
+ "funding",
+ list(vec![
+ arr(vec![
+ ("type", s("example")),
+ ("url", s("https://example.org/fund")),
+ ]),
+ arr(vec![("url", s("https://example.org/fund"))]),
+ ]),
+ ),
+ (
+ "require",
+ arr(vec![
+ ("a/b", s("1.*")),
+ ("b/c", s("~2")),
+ ("example/pkg", s(">2.0-dev,<2.4-dev")),
+ ("composer-runtime-api", s("*")),
+ ]),
+ ),
+ (
+ "require-dev",
+ arr(vec![
+ ("a/b", s("1.*")),
+ ("b/c", s("*")),
+ ("example/pkg", s(">2.0-dev,<2.4-dev")),
+ ]),
+ ),
+ (
+ "conflict",
+ arr(vec![
+ ("a/bx", s("1.*")),
+ ("b/cx", s(">2.7")),
+ ("example/pkgx", s(">2.0-dev,<2.4-dev")),
+ ]),
+ ),
+ (
+ "replace",
+ arr(vec![
+ ("a/b", s("1.*")),
+ ("example/pkg", s(">2.0-dev,<2.4-dev")),
+ ]),
+ ),
+ (
+ "provide",
+ arr(vec![
+ ("a/b", s("1.*")),
+ ("example/pkg", s(">2.0-dev,<2.4-dev")),
+ ]),
+ ),
+ (
+ "suggest",
+ arr(vec![("foo/bar", s("Foo bar is very useful"))]),
+ ),
+ (
+ "autoload",
+ arr(vec![
+ (
+ "psr-0",
+ arr(vec![("Foo\\Bar", s("src/")), ("", s("fallback/libs/"))]),
+ ),
+ ("classmap", list(vec![s("dir/"), s("dir2/file.php")])),
+ ("files", list(vec![s("functions.php")])),
+ ]),
+ ),
+ ("include-path", list(vec![s("lib/")])),
+ ("target-dir", s("Foo/Bar")),
+ ("minimum-stability", s("dev")),
+ (
+ "repositories",
+ list(vec![arr(vec![
+ ("type", s("composer")),
+ ("url", s("https://repo.packagist.org/")),
+ ])]),
+ ),
+ (
+ "config",
+ arr(vec![
+ ("bin-dir", s("bin")),
+ ("vendor-dir", s("vendor")),
+ ("process-timeout", i(10000)),
+ ]),
+ ),
+ (
+ "archive",
+ arr(vec![(
+ "exclude",
+ list(vec![s("/foo/bar"), s("baz"), s("!/foo/bar/baz")]),
+ )]),
+ ),
+ (
+ "scripts",
+ arr(vec![
+ ("post-update-cmd", s("Foo\\Bar\\Baz::doSomething")),
+ (
+ "post-install-cmd",
+ list(vec![s("Foo\\Bar\\Baz::doSomething")]),
+ ),
+ ]),
+ ),
+ (
+ "extra",
+ arr(vec![
+ (
+ "random",
+ arr(vec![("stuff", arr(vec![("deeply", s("nested"))]))]),
+ ),
+ (
+ "branch-alias",
+ arr(vec![
+ ("dev-master", s("2.0-dev")),
+ ("dev-old", s("1.0.x-dev")),
+ ("3.x-dev", s("3.1.x-dev")),
+ ]),
+ ),
+ ]),
+ ),
+ ("bin", list(vec![s("bin/foo"), s("bin/bar")])),
+ (
+ "transport-options",
+ arr(vec![(
+ "ssl",
+ arr(vec![("local_cert", s("/opt/certs/test.pem"))]),
+ )]),
+ ),
+ ]),
+ // test bin as string
+ config(vec![("name", s("foo/bar")), ("bin", s("bin1"))]),
+ // package name with dashes
+ config(vec![("name", s("foo/bar-baz"))]),
+ config(vec![("name", s("foo/bar--baz"))]),
+ config(vec![("name", s("foo/b-ar--ba-z"))]),
+ config(vec![("name", s("npm-asset/angular--core"))]),
+ // refs as int or string
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "source",
+ arr(vec![
+ ("url", s("https://example.org")),
+ ("reference", i(1234)),
+ ("type", s("baz")),
+ ]),
+ ),
+ (
+ "dist",
+ arr(vec![
+ ("url", s("https://example.org")),
+ ("reference", s("foobar")),
+ ("type", s("baz")),
+ ]),
+ ),
+ ]),
+ // valid php-ext configuration
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![
+ ("extension-name", s("ext-xdebug")),
+ ("priority", i(80)),
+ ("support-zts", b(true)),
+ ("support-nts", b(false)),
+ ("build-path", s("my-extension-source")),
+ ("download-url-method", s("composer-default")),
+ ("os-families", list(vec![s("linux"), s("darwin")])),
+ (
+ "configure-options",
+ list(vec![
+ arr(vec![
+ ("name", s("enable-xdebug")),
+ ("needs-value", b(false)),
+ ("description", s("Enable xdebug support")),
+ ]),
+ arr(vec![
+ ("name", s("with-xdebug-path")),
+ ("needs-value", b(true)),
+ ]),
+ ]),
+ ),
+ ]),
+ ),
+ ]),
+ // valid php-ext with os-families-exclude
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext-zend")),
+ (
+ "php-ext",
+ arr(vec![("os-families-exclude", list(vec![s("windows")]))]),
+ ),
+ ]),
+ // valid php-ext with null build-path
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("build-path", PhpMixed::Null)])),
+ ]),
+ // valid php-ext with one download-url-method in a list
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![s("pre-packaged-binary")]),
+ )]),
+ ),
+ ]),
+ // valid php-ext with multiple download-url-methods
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![
+ s("pre-packaged-binary"),
+ s("pre-packaged-source"),
+ s("composer-default"),
+ ]),
+ )]),
+ ),
+ ]),
+ ]
+}
+
+/// ref: ValidatingArrayLoaderTest::testLoadSuccess
+#[ignore]
#[test]
-#[ignore = "ValidatingArrayLoader -> ArrayLoader parses constraints via a look-around regex the regex crate cannot compile"]
fn test_load_success() {
- todo!()
+ for cfg in success_provider() {
+ let (internal_loader, _calls) = MockLoader::new();
+ let mut loader = ValidatingArrayLoader::new(
+ Box::new(internal_loader),
+ true,
+ None,
+ ValidatingArrayLoader::CHECK_ALL,
+ );
+ loader
+ .load(cfg, "Composer\\Package\\CompletePackage")
+ .unwrap();
+ }
}
+/// ref: ValidatingArrayLoaderTest::errorProvider
+fn error_provider() -> Vec<(IndexMap<String, PhpMixed>, Vec<String>)> {
+ let mut data: Vec<(IndexMap<String, PhpMixed>, Vec<String>)> = Vec::new();
+
+ for invalid_name in ["foo", "foo/-bar-", "foo/-bar"] {
+ data.push((
+ config(vec![("name", s(invalid_name))]),
+ invalid_naming_error(invalid_name),
+ ));
+ }
+ for invalid_name in [
+ "fo--oo/bar",
+ "fo-oo/bar__baz",
+ "fo-oo/bar_.baz",
+ "foo/bar---baz",
+ ] {
+ data.push((
+ config(vec![("name", s(invalid_name))]),
+ invalid_naming_error(invalid_name),
+ ));
+ }
+
+ data.push((
+ config(vec![("name", s("foo/bar")), ("homepage", i(43))]),
+ vec!["homepage : should be a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("support", arr(vec![("source", list(vec![]))])),
+ ]),
+ vec!["support.source : invalid value, must be a string".to_string()],
+ ));
+ data.push((
+ config(vec![("name", s("foo/bar.json"))]),
+ vec!["name : foo/bar.json is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.".to_string()],
+ ));
+ data.push((
+ config(vec![("name", s("com1/foo"))]),
+ vec!["name : com1/foo is reserved, package and vendor names can not match any of: nul, con, prn, aux, com1, com2, com3, com4, com5, com6, com7, com8, com9, lpt1, lpt2, lpt3, lpt4, lpt5, lpt6, lpt7, lpt8, lpt9.".to_string()],
+ ));
+ data.push((
+ config(vec![("name", s("Foo/Bar"))]),
+ vec!["name : Foo/Bar is invalid, it should not contain uppercase characters. We suggest using foo/bar instead.".to_string()],
+ ));
+ data.push((
+ config(vec![("name", s("foo/bar")), ("autoload", s("strings"))]),
+ vec!["autoload : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("autoload", arr(vec![("psr0", arr(vec![("foo", s("src"))]))])),
+ ]),
+ vec!["autoload : invalid value (psr0), must be one of psr-0, psr-4, classmap, files, exclude-from-classmap".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("transport-options", s("test")),
+ ]),
+ vec!["transport-options : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "source",
+ arr(vec![
+ ("url", s("--foo")),
+ ("reference", s(" --bar")),
+ ("type", s("baz")),
+ ]),
+ ),
+ (
+ "dist",
+ arr(vec![
+ ("url", s(" --foox")),
+ ("reference", s("--barx")),
+ ("type", s("baz")),
+ ]),
+ ),
+ ]),
+ vec![
+ "dist.reference : must not start with a \"-\", \"--barx\" given".to_string(),
+ "dist.url : must not start with a \"-\", \" --foox\" given".to_string(),
+ "source.reference : must not start with a \"-\", \" --bar\" given".to_string(),
+ "source.url : must not start with a \"-\", \"--foo\" given".to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("require", arr(vec![("foo/Bar", s("1.*"))])),
+ ]),
+ vec!["require.foo/Bar : a package cannot set a require on itself".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("source", arr(vec![("url", i(1))])),
+ ("dist", arr(vec![("url", PhpMixed::Null)])),
+ ]),
+ vec![
+ "source.type : must be present".to_string(),
+ "source.url : should be a string, int given".to_string(),
+ "source.reference : must be present".to_string(),
+ "dist.type : must be present".to_string(),
+ "dist.url : must be present".to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("replace", list(vec![s("acme/bar")])),
+ ]),
+ vec!["replace.0 : invalid version constraint (Could not parse version constraint acme/bar: Invalid version string \"acme/bar\")".to_string()],
+ ));
+ data.push((
+ config(vec![("require", arr(vec![("acme/bar", s("^1.0"))]))]),
+ vec!["name : must be present".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("library")),
+ ("php-ext", arr(vec![("extension-name", s("ext-foobar"))])),
+ ]),
+ vec!["php-ext can only be set by packages of type \"php-ext\" or \"php-ext-zend\" which must be C extensions".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("extension-name", i(123))])),
+ ]),
+ vec!["php-ext.extension-name : should be a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("priority", s("invalid"))])),
+ ]),
+ vec!["php-ext.priority : should be an integer, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("support-zts", s("yes"))])),
+ ]),
+ vec!["php-ext.support-zts : should be a boolean, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("support-nts", i(1))])),
+ ]),
+ vec!["php-ext.support-nts : should be a boolean, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("build-path", i(123))])),
+ ]),
+ vec!["php-ext.build-path : should be a string or null, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("download-url-method", i(123))])),
+ ]),
+ vec!["php-ext.download-url-method : should be an array or a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![("download-url-method", s("invalid-method"))]),
+ ),
+ ]),
+ vec!["php-ext.download-url-method.0 : invalid value (invalid-method), must be one of composer-default, pre-packaged-source, pre-packaged-binary".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("download-url-method", list(vec![]))])),
+ ]),
+ vec!["php-ext.download-url-method : must contain at least one element".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![i(1), b(true), list(vec![])]),
+ )]),
+ ),
+ ]),
+ vec![
+ "php-ext.download-url-method.0 : should be a string, int given".to_string(),
+ "php-ext.download-url-method.1 : should be a string, bool given".to_string(),
+ "php-ext.download-url-method.2 : should be a string, array given".to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![s("invalid-method"), s("composer-default")]),
+ )]),
+ ),
+ ]),
+ vec!["php-ext.download-url-method.0 : invalid value (invalid-method), must be one of composer-default, pre-packaged-source, pre-packaged-binary".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "download-url-method",
+ list(vec![s("invalid-method"), s("another-invalid-method")]),
+ )]),
+ ),
+ ]),
+ vec![
+ "php-ext.download-url-method.0 : invalid value (invalid-method), must be one of composer-default, pre-packaged-source, pre-packaged-binary".to_string(),
+ "php-ext.download-url-method.1 : invalid value (another-invalid-method), must be one of composer-default, pre-packaged-source, pre-packaged-binary".to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![
+ ("os-families", list(vec![s("linux")])),
+ ("os-families-exclude", list(vec![s("windows")])),
+ ]),
+ ),
+ ]),
+ vec!["php-ext : os-families and os-families-exclude cannot both be specified".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families", s("linux"))])),
+ ]),
+ vec!["php-ext.os-families : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families", list(vec![]))])),
+ ]),
+ vec!["php-ext.os-families : must contain at least one element".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![("os-families", list(vec![s("invalid-os"), s("linux")]))]),
+ ),
+ ]),
+ vec!["php-ext.os-families.0 : invalid value (invalid-os), must be one of windows, bsd, darwin, solaris, linux, unknown".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families", list(vec![i(123)]))])),
+ ]),
+ vec!["php-ext.os-families.0 : should be a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families-exclude", s("windows"))])),
+ ]),
+ vec!["php-ext.os-families-exclude : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("os-families-exclude", list(vec![]))])),
+ ]),
+ vec!["php-ext.os-families-exclude : must contain at least one element".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![("os-families-exclude", list(vec![s("invalid")]))]),
+ ),
+ ]),
+ vec!["php-ext.os-families-exclude.0 : invalid value (invalid), must be one of windows, bsd, darwin, solaris, linux, unknown".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ ("php-ext", arr(vec![("configure-options", s("invalid"))])),
+ ]),
+ vec!["php-ext.configure-options : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![("configure-options", list(vec![s("invalid")]))]),
+ ),
+ ]),
+ vec!["php-ext.configure-options.0 : should be an array, string given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "configure-options",
+ list(vec![arr(vec![("description", s("test"))])]),
+ )]),
+ ),
+ ]),
+ vec!["php-ext.configure-options.0.name : must be present".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "configure-options",
+ list(vec![arr(vec![("name", i(123))])]),
+ )]),
+ ),
+ ]),
+ vec!["php-ext.configure-options.0.name : should be a string, int given".to_string()],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "configure-options",
+ list(vec![arr(vec![
+ ("name", s("valid-name")),
+ ("needs-value", s("yes")),
+ ])]),
+ )]),
+ ),
+ ]),
+ vec![
+ "php-ext.configure-options.0.needs-value : should be a boolean, string given"
+ .to_string(),
+ ],
+ ));
+ data.push((
+ config(vec![
+ ("name", s("foo/bar")),
+ ("type", s("php-ext")),
+ (
+ "php-ext",
+ arr(vec![(
+ "configure-options",
+ list(vec![arr(vec![
+ ("name", s("valid-name")),
+ ("description", i(123)),
+ ])]),
+ )]),
+ ),
+ ]),
+ vec!["php-ext.configure-options.0.description : should be a string, int given".to_string()],
+ ));
+
+ data
+}
+
+/// ref: ValidatingArrayLoaderTest::testLoadFailureThrowsException
+#[ignore]
#[test]
-#[ignore = "ValidatingArrayLoader -> ArrayLoader parses constraints via a look-around regex the regex crate cannot compile"]
fn test_load_failure_throws_exception() {
- todo!()
+ for (cfg, mut expected_errors) in error_provider() {
+ let (internal_loader, _calls) = MockLoader::new();
+ let mut loader = ValidatingArrayLoader::new(
+ Box::new(internal_loader),
+ true,
+ None,
+ ValidatingArrayLoader::CHECK_ALL,
+ );
+ match loader.load(cfg, "Composer\\Package\\CompletePackage") {
+ Ok(_) => panic!("Expected exception to be thrown"),
+ Err(e) => {
+ let exception = e
+ .downcast_ref::<InvalidPackageException>()
+ .expect("Expected InvalidPackageException");
+ let mut errors: Vec<String> = exception.get_errors().to_vec();
+ expected_errors.sort();
+ errors.sort();
+ assert_eq!(expected_errors, errors);
+ }
+ }
+ }
}
+/// ref: ValidatingArrayLoaderTest::warningProvider
+/// Returns (config, expected_warnings, must_check, expected_array).
+fn warning_provider() -> Vec<(
+ IndexMap<String, PhpMixed>,
+ Vec<String>,
+ bool,
+ Option<IndexMap<String, PhpMixed>>,
+)> {
+ vec![
+ (
+ config(vec![("name", s("foo/bar")), ("homepage", s("foo:bar"))]),
+ vec!["homepage : invalid value (foo:bar), must be an http/https URL".to_string()],
+ true,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "support",
+ arr(vec![
+ ("source", s("foo:bar")),
+ ("forum", s("foo:bar")),
+ ("issues", s("foo:bar")),
+ ("wiki", s("foo:bar")),
+ ("chat", s("foo:bar")),
+ ("security", s("foo:bar")),
+ ]),
+ ),
+ ]),
+ vec![
+ "support.source : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.forum : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.issues : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.wiki : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.chat : invalid value (foo:bar), must be an http/https URL".to_string(),
+ "support.security : invalid value (foo:bar), must be an http/https URL".to_string(),
+ ],
+ true,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "require",
+ arr(vec![
+ ("foo/baz", s("*")),
+ ("bar/baz", s(">=1.0")),
+ ("bar/hacked", s("@stable")),
+ ("bar/woo", s("1.0.0")),
+ ]),
+ ),
+ ]),
+ vec![
+ "require.foo/baz : unbound version constraints (*) should be avoided".to_string(),
+ "require.bar/baz : unbound version constraints (>=1.0) should be avoided"
+ .to_string(),
+ "require.bar/hacked : unbound version constraints (@stable) should be avoided"
+ .to_string(),
+ "require.bar/woo : exact version constraints (1.0.0) should be avoided if the package follows semantic versioning".to_string(),
+ ],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "require",
+ arr(vec![
+ ("foo/baz", s(">1, <0.5")),
+ ("bar/baz", s("dev-main, >0.5")),
+ ]),
+ ),
+ ]),
+ vec![
+ "require.foo/baz : this version constraint cannot possibly match anything (>1, <0.5)".to_string(),
+ "require.bar/baz : this version constraint cannot possibly match anything (dev-main, >0.5)".to_string(),
+ ],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ ("require", arr(vec![("bar/unstable", s("0.3.0"))])),
+ ]),
+ vec![],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "extra",
+ arr(vec![(
+ "branch-alias",
+ arr(vec![("5.x-dev", s("3.1.x-dev"))]),
+ )]),
+ ),
+ ]),
+ vec!["extra.branch-alias.5.x-dev : the target branch (3.1.x-dev) is not a valid numeric alias for this version".to_string()],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ (
+ "extra",
+ arr(vec![("branch-alias", arr(vec![("5.x-dev", s("3.1-dev"))]))]),
+ ),
+ ]),
+ vec!["extra.branch-alias.5.x-dev : the target branch (3.1-dev) is not a valid numeric alias for this version".to_string()],
+ false,
+ None,
+ ),
+ (
+ config(vec![
+ ("name", s("foo/bar")),
+ ("require", arr(vec![("Foo/Baz", s("^1.0"))])),
+ ]),
+ vec!["require.Foo/Baz is invalid, it should not contain uppercase characters. Please use foo/baz instead.".to_string()],
+ false,
+ None,
+ ),
+ (
+ config(vec![("name", s("a/b")), ("license", s("XXXXX"))]),
+ vec![format!(
+ "License \"XXXXX\" is not a valid SPDX license identifier, see https://spdx.org/licenses/ if you use an open license.{}If the software is closed-source, you may use \"proprietary\" as license.",
+ shirabe_php_shim::PHP_EOL
+ )],
+ true,
+ Some(config(vec![
+ ("name", s("a/b")),
+ ("license", list(vec![s("XXXXX")])),
+ ])),
+ ),
+ (
+ config(vec![
+ ("name", s("a/b")),
+ ("license", list(vec![arr(vec![("author", s("bar"))]), s("MIT")])),
+ ]),
+ vec!["License {\"author\":\"bar\"} should be a string.".to_string()],
+ true,
+ Some(config(vec![
+ ("name", s("a/b")),
+ ("license", list(vec![s("MIT")])),
+ ])),
+ ),
+ ]
+}
+
+/// ref: ValidatingArrayLoaderTest::testLoadWarnings
+#[ignore]
#[test]
-#[ignore = "ValidatingArrayLoader -> ArrayLoader parses constraints via a look-around regex the regex crate cannot compile"]
fn test_load_warnings() {
- todo!()
+ for (cfg, mut expected_warnings, _must_check, _expected_array) in warning_provider() {
+ let (internal_loader, _calls) = MockLoader::new();
+ let mut loader = ValidatingArrayLoader::new(
+ Box::new(internal_loader),
+ true,
+ None,
+ ValidatingArrayLoader::CHECK_ALL,
+ );
+ loader
+ .load(cfg, "Composer\\Package\\CompletePackage")
+ .unwrap();
+ let mut warnings: Vec<String> = loader.get_warnings().to_vec();
+ expected_warnings.sort();
+ warnings.sort();
+ assert_eq!(expected_warnings, warnings);
+ }
}
+/// ref: ValidatingArrayLoaderTest::testLoadSkipsWarningDataWhenIgnoringErrors
+#[ignore]
#[test]
-#[ignore = "ValidatingArrayLoader -> ArrayLoader parses constraints via a look-around regex the regex crate cannot compile"]
fn test_load_skips_warning_data_when_ignoring_errors() {
- todo!()
+ for (mut cfg, _expected_warnings, must_check, expected_array) in warning_provider() {
+ if !must_check {
+ assert!(true);
+ continue;
+ }
+ let (internal_loader, calls) = MockLoader::new();
+ let expected = expected_array.unwrap_or_else(|| config(vec![("name", s("a/b"))]));
+
+ let mut loader = ValidatingArrayLoader::new(
+ Box::new(internal_loader),
+ true,
+ None,
+ ValidatingArrayLoader::CHECK_ALL,
+ );
+ cfg.insert("name".to_string(), s("a/b"));
+ loader
+ .load(cfg, "Composer\\Package\\CompletePackage")
+ .unwrap();
+
+ // The mock recorded exactly the (post-validation) config passed to the inner loader.
+ let recorded = calls.borrow();
+ assert_eq!(recorded.len(), 1);
+ assert_eq!(recorded[0], expected);
+ }
}
diff --git a/crates/shirabe/tests/package/locker_test.rs b/crates/shirabe/tests/package/locker_test.rs
index 7b5d39f..c793a8a 100644
--- a/crates/shirabe/tests/package/locker_test.rs
+++ b/crates/shirabe/tests/package/locker_test.rs
@@ -4,61 +4,61 @@
// mocked ProcessExecutor to drive lock read/write and freshness checks; mocking is not
// available here.
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (exists/read) which is not available"]
fn test_is_locked() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (exists) which is not available"]
fn test_get_not_locked_packages() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (exists/read) which is not available"]
fn test_get_locked_packages() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (write) which is not available"]
fn test_set_lock_data() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile and PackageInterface (createPackageMock) which is not available"]
fn test_lock_bad_packages() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh_false() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh_with_content_hash() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh_with_content_hash_and_no_hash() {
todo!()
}
#[test]
-#[ignore = "mocks JsonFile/InstallationManager/repository/ProcessExecutor to drive Locker; mocking is not available"]
+#[ignore = "requires PHPUnit mock of JsonFile (read) which is not available"]
fn test_is_fresh_false_with_content_hash() {
todo!()
}
diff --git a/crates/shirabe/tests/package/version/version_guesser_test.rs b/crates/shirabe/tests/package/version/version_guesser_test.rs
index 75d4ae0..76cd672 100644
--- a/crates/shirabe/tests/package/version/version_guesser_test.rs
+++ b/crates/shirabe/tests/package/version/version_guesser_test.rs
@@ -1,5 +1,13 @@
//! ref: composer/tests/Composer/Test/Package/Version/VersionGuesserTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use shirabe::config::Config;
+use shirabe::package::version::{VersionGuesser, VersionParser};
+use shirabe::util::platform::Platform;
+use shirabe::util::process_executor::ProcessExecutor;
+
#[allow(dead_code)]
fn set_up() {
// Resets GitUtil's cached `version` static via ReflectionProperty; the static is not
@@ -23,94 +31,113 @@ impl Drop for TearDown {
// These drive VersionGuesser with a mocked ProcessExecutor feeding git/hg command output;
// mocking is not available here.
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_hg_guess_version_returns_data() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_returns_data() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_does_not_see_custom_default_branch_as_non_feature_branch() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_reads_and_respects_non_feature_branches_configuration_for_arbitrary_naming() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_reads_and_respects_non_feature_branches_configuration_for_arbitrary_naming_regex()
{
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_guess_version_reads_and_respects_non_feature_branches_configuration_for_arbitrary_naming_when_on_non_feature_branch()
{
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_detached_head_becomes_dev_hash() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_detached_fetch_head_becomes_dev_hash_git2() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_detached_commit_head_becomes_dev_hash_git2() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_tag_becomes_version() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_tag_becomes_pretty_version() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_invalid_tag_becomes_version() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_numeric_branches_show_nicely() {
todo!()
}
+#[ignore = "requires getProcessExecutorMock with expects() command expectations; no ProcessExecutorMock mocking infrastructure exists"]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_remote_branches_are_selected() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks a ProcessExecutor feeding git/hg output to drive VersionGuesser; mocking is not available"]
fn test_get_root_version_from_env() {
- todo!()
+ // @dataProvider rootEnvVersionsProvider
+ let root_env_versions: Vec<(&str, &str)> = vec![
+ ("1.0-dev", "1.0.x-dev"),
+ ("1.0.x-dev", "1.0.x-dev"),
+ ("1-dev", "1.x-dev"),
+ ("1.x-dev", "1.x-dev"),
+ ("1.0.0", "1.0.0"),
+ ];
+
+ for (env, expected_version) in root_env_versions {
+ Platform::put_env("COMPOSER_ROOT_VERSION", env);
+ let config = Rc::new(RefCell::new(Config::new(true, None)));
+ let process = Rc::new(RefCell::new(ProcessExecutor::new(None)));
+ let guesser = VersionGuesser::new(config, process, VersionParser::new(), None);
+ assert_eq!(
+ expected_version,
+ guesser.get_root_version_from_env().unwrap()
+ );
+ Platform::clear_env("COMPOSER_ROOT_VERSION");
+ }
}
diff --git a/crates/shirabe/tests/package/version/version_selector_test.rs b/crates/shirabe/tests/package/version/version_selector_test.rs
index fd426ce..fa288cd 100644
--- a/crates/shirabe/tests/package/version/version_selector_test.rs
+++ b/crates/shirabe/tests/package/version/version_selector_test.rs
@@ -3,79 +3,79 @@
// VersionSelector ranks candidate packages whose versions/constraints are parsed through a
// look-around regex the regex crate cannot compile; the setup also mocks a repository.
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned_that_matches_php_requirements() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned_that_matches_ext_requirements() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned_that_matches_platform_ext() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_latest_version_is_returned_that_matches_composer_requirements() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_most_stable_version_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages with willReturnOnConsecutiveCalls; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_most_stable_version_is_returned_regardless_of_order() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_highest_version_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_highest_version_matching_stability_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_most_stable_unstable_version_is_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_default_branch_alias_is_never_returned() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "requires mocking RepositorySet::find_packages to return an empty list; RepositorySet is a concrete struct with no injectable/overridable find_packages"]
fn test_false_returned_on_no_packages() {
todo!()
}
#[test]
-#[ignore = "not yet ported (VersionSelector over a mocked repository; constraint parsing uses a look-around regex)"]
+#[ignore = "branch-alias cases need Package::set_extra, exposed only on RootPackageHandle, not on the PackageHandle/PackageInterfaceHandle passed to find_recommended_require_version"]
fn test_find_recommended_require_version() {
todo!()
}