aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-22 23:42:07 +0900
committernsfisis <nsfisis@gmail.com>2026-06-22 23:42:07 +0900
commit5ab5f3b316798c1411ce8e6a7f5b091fda93589c (patch)
treec7669f94f5d9bd9adc07bc1aab3f14cfdec1ae5f /crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
parentb291e714bc739262140323e08fe2fb9e91e00ee7 (diff)
downloadphp-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.tar.gz
php-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.tar.zst
php-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.zip
test: port previously-ignored Composer tests via __ test hatches
Re-evaluate the reason'd #[ignore] tests under the Phase D criterion: a test is unportable ONLY if the APIs/types needed to WRITE it do not exist. A test that compiles but panics at runtime (todo!() body, a regex the regex crate cannot compile) or fails at runtime (incomplete or incorrect impl behavior) is portable -- it is written in full and marked with a reason-less #[ignore]. About 120 test functions move from reason'd #[ignore] to reason-less #[ignore] (the ported-but-not-yet-passing signal). Impl crates gain only additive __ test hatches (init_command, pool, file_downloader, package handle link setters, artifact/path repository, repository manager, svn); no existing logic changes. Tests whose required APIs genuinely do not exist (mock/reflection harness, ApplicationTester, solve() discarding SolverProblemsException, a script::Event that cannot be passed as an originating event) keep their reason'd #[ignore]. cargo check -p shirabe --tests passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/dependency_resolver/pool_builder_test.rs')
-rw-r--r--crates/shirabe/tests/dependency_resolver/pool_builder_test.rs646
1 files changed, 642 insertions, 4 deletions
diff --git a/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs b/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
index 4c72091..87f02aa 100644
--- a/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
@@ -1,9 +1,647 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/PoolBuilderTest.php
-// testPoolBuilder is a large fixture-driven case that loads packages from test inputs and
-// builds a Pool; constraint parsing uses a look-around regex the regex crate cannot compile.
+use std::cell::RefCell;
+use std::path::PathBuf;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::config::Config;
+use shirabe::dependency_resolver::default_policy::DefaultPolicy;
+use shirabe::dependency_resolver::pool::Pool;
+use shirabe::dependency_resolver::pool_optimizer::PoolOptimizer;
+use shirabe::dependency_resolver::request::{Request, UpdateAllowTransitiveDeps};
+use shirabe::io::io_interface::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::json::JsonFile;
+use shirabe::package::BasePackageHandle;
+use shirabe::package::STABILITIES;
+use shirabe::package::loader::{ArrayLoader, LoaderInterface};
+use shirabe::package::version::version_parser::VersionParser;
+use shirabe::repository::array_repository::ArrayRepository;
+use shirabe::repository::filter_repository::FilterRepository;
+use shirabe::repository::handle::{LockArrayRepositoryHandle, RepositoryInterfaceHandle};
+use shirabe::repository::lock_array_repository::LockArrayRepository;
+use shirabe::repository::repository_factory::RepositoryFactory;
+use shirabe::repository::repository_set::{RepositorySet, RootAliasInput};
+use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_php_shim::PREG_SPLIT_DELIM_CAPTURE;
+use shirabe_php_shim::PhpMixed;
+
+/// Maps the PHP `$loadPackage` closure: pops the optional `id` from the data, loads the
+/// package and records it in `package_ids` keyed by that id (erroring on duplicates).
+fn load_package(
+ loader: &ArrayLoader,
+ package_ids: &mut IndexMap<i64, BasePackageHandle>,
+ data: &IndexMap<String, PhpMixed>,
+) -> BasePackageHandle {
+ let mut data = data.clone();
+
+ let mut id: Option<i64> = None;
+ // PHP: !empty($data['id'])
+ if let Some(id_val) = data.get("id") {
+ if let Some(i) = id_val.as_int() {
+ if i != 0 {
+ id = Some(i);
+ data.shift_remove("id");
+ }
+ }
+ }
+
+ let pkg = loader.load(data, None).unwrap();
+
+ if let Some(id) = id {
+ if package_ids.contains_key(&id) {
+ panic!("Duplicate package id {} defined", id);
+ }
+ package_ids.insert(id, pkg.clone());
+ }
+
+ pkg
+}
+
+fn read_test_file(file: &str, fixtures_dir: &str) -> IndexMap<String, String> {
+ let contents = shirabe_php_shim::file_get_contents(file).unwrap();
+ let tokens = Preg::split4(
+ r"#(?:^|\n*)--([A-Z-]+)--\n#",
+ &contents,
+ -1,
+ PREG_SPLIT_DELIM_CAPTURE,
+ );
+
+ // PHP section_info is a map of name => required flag.
+ let section_info: Vec<(&str, bool)> = vec![
+ ("TEST", true),
+ ("ROOT", false),
+ ("REQUEST", true),
+ ("FIXED", false),
+ ("PACKAGE-REPOS", true),
+ ("EXPECT", true),
+ ("EXPECT-OPTIMIZED", false),
+ ];
+
+ let mut section: Option<String> = None;
+ let mut data: IndexMap<String, String> = IndexMap::new();
+ for token in tokens {
+ if section.is_none() && token.is_empty() {
+ continue;
+ }
+
+ if section.is_none() {
+ if !section_info.iter().any(|(name, _)| *name == token.as_str()) {
+ panic!(
+ "The test file \"{}\" must not contain a section named \"{}\".",
+ file.replace(&format!("{}/", fixtures_dir), ""),
+ token
+ );
+ }
+ section = Some(token);
+ continue;
+ }
+
+ let section_data = token;
+ data.insert(section.take().unwrap(), section_data);
+ }
+
+ for (section, required) in &section_info {
+ if *required && !data.contains_key(*section) {
+ panic!(
+ "The test file \"{}\" must have a section named \"{}\".",
+ file.replace(&format!("{}/", fixtures_dir), ""),
+ section
+ );
+ }
+ }
+
+ data
+}
+
+fn collect_test_files(dir: &std::path::Path, out: &mut Vec<PathBuf>) {
+ for entry in std::fs::read_dir(dir).unwrap() {
+ let entry = entry.unwrap();
+ let path = entry.path();
+ if path.is_dir() {
+ collect_test_files(&path, out);
+ } else {
+ out.push(path);
+ }
+ }
+}
+
+struct IntegrationTest {
+ file: String,
+ message: String,
+ expect: PhpMixed,
+ expect_optimized: PhpMixed,
+ root: PhpMixed,
+ request: PhpMixed,
+ package_repos: PhpMixed,
+ fixed: PhpMixed,
+}
+
+fn get_integration_tests(fixtures_dir: &std::path::Path) -> IndexMap<String, IntegrationTest> {
+ let fixtures_dir_str = fixtures_dir.to_str().unwrap().to_string();
+
+ let mut files: Vec<PathBuf> = Vec::new();
+ collect_test_files(fixtures_dir, &mut files);
+
+ let mut tests: IndexMap<String, IntegrationTest> = IndexMap::new();
+ for file in files {
+ let file = file.to_str().unwrap().to_string();
+
+ if !Preg::is_match(r"/\.test$/", &file) {
+ continue;
+ }
+
+ let test_data = read_test_file(&file, &fixtures_dir_str);
+
+ let message = test_data["TEST"].clone();
+
+ let request = JsonFile::parse_json(Some(&test_data["REQUEST"]), None).unwrap();
+ // PHP: !empty($testData['ROOT']) ? parseJson(...) : []
+ let root = match test_data.get("ROOT") {
+ Some(s) if !s.is_empty() => JsonFile::parse_json(Some(s), None).unwrap(),
+ _ => PhpMixed::List(vec![]),
+ };
+
+ let package_repos = JsonFile::parse_json(Some(&test_data["PACKAGE-REPOS"]), None).unwrap();
+ let fixed = match test_data.get("FIXED") {
+ Some(s) if !s.is_empty() => JsonFile::parse_json(Some(s), None).unwrap(),
+ _ => PhpMixed::List(vec![]),
+ };
+ let expect = JsonFile::parse_json(Some(&test_data["EXPECT"]), None).unwrap();
+ let expect_optimized = match test_data.get("EXPECT-OPTIMIZED") {
+ Some(s) if !s.is_empty() => JsonFile::parse_json(Some(s), None).unwrap(),
+ _ => expect.clone(),
+ };
+
+ let basename = std::path::Path::new(&file)
+ .file_name()
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .to_string();
+ tests.insert(
+ basename,
+ IntegrationTest {
+ file: file.replace(&format!("{}/", fixtures_dir_str), ""),
+ message,
+ expect,
+ expect_optimized,
+ root,
+ request,
+ package_repos,
+ fixed,
+ },
+ );
+ }
+
+ tests
+}
+
+/// PHP `sort()` with SORT_REGULAR over a mixed int/string list. Mirrors PHP 8 loose
+/// comparison: two ints compare numerically; a string and an int that looks numeric
+/// compare numerically; otherwise both are compared as strings.
+fn php_sort_mixed(values: &mut [PhpMixed]) {
+ fn cmp(a: &PhpMixed, b: &PhpMixed) -> std::cmp::Ordering {
+ use std::cmp::Ordering;
+ let num = |m: &PhpMixed| -> Option<f64> {
+ match m {
+ PhpMixed::Int(i) => Some(*i as f64),
+ PhpMixed::Float(f) => Some(*f),
+ PhpMixed::String(s) => s.trim().parse::<f64>().ok(),
+ _ => None,
+ }
+ };
+ let str_of = |m: &PhpMixed| -> String {
+ match m {
+ PhpMixed::Int(i) => i.to_string(),
+ PhpMixed::Float(f) => f.to_string(),
+ PhpMixed::String(s) => s.clone(),
+ _ => String::new(),
+ }
+ };
+ match (a, b) {
+ (PhpMixed::Int(x), PhpMixed::Int(y)) => x.cmp(y),
+ _ => match (num(a), num(b)) {
+ (Some(x), Some(y)) => x.partial_cmp(&y).unwrap_or(Ordering::Equal),
+ _ => str_of(a).cmp(&str_of(b)),
+ },
+ }
+ }
+ values.sort_by(cmp);
+}
+
+/// ref: PoolBuilderTest::getPackageResultSet
+fn get_package_result_set(
+ pool: &Pool,
+ package_ids: &IndexMap<i64, BasePackageHandle>,
+) -> Vec<PhpMixed> {
+ let mut result: Vec<BasePackageHandle> = Vec::new();
+ let count = pool.__count();
+ // PHP: for ($i = 1; $i <= $count; $i++)
+ let mut i = 1;
+ while i <= count {
+ result.push(pool.package_by_id(i));
+ i += 1;
+ }
+
+ // PHP: array_search($package, $packageIds, true) — identity lookup.
+ let find_id = |package: &BasePackageHandle| -> Option<i64> {
+ for (id, candidate) in package_ids {
+ if candidate.ptr_id() == package.ptr_id() {
+ return Some(*id);
+ }
+ }
+ None
+ };
+
+ result
+ .into_iter()
+ .map(|package| {
+ // PHP: if ($id = array_search(...)) — id keys start at 1 so always truthy when found.
+ if let Some(id) = find_id(&package) {
+ return PhpMixed::Int(id);
+ }
+
+ let mut suffix = String::new();
+ if let Some(source_reference) = package.get_source_reference() {
+ suffix = format!("#{}", source_reference);
+ }
+ if let Some(repo) = package.get_repository() {
+ if repo.is::<LockArrayRepository>() {
+ suffix.push_str(" (locked)");
+ }
+ }
+
+ if let Some(alias) = package.as_alias() {
+ let alias_of = alias.get_alias_of();
+ // PHP: array_search($package->getAliasOf(), $packageIds, true)
+ let mut matched: Option<i64> = None;
+ for (id, candidate) in package_ids {
+ if candidate.ptr_id() == alias_of.ptr_id() {
+ matched = Some(*id);
+ break;
+ }
+ }
+ if let Some(id) = matched {
+ return PhpMixed::String(format!(
+ "{}-{}{} (alias of {})",
+ package.get_name(),
+ package.get_version(),
+ suffix,
+ id
+ ));
+ }
+
+ return PhpMixed::String(format!(
+ "{}-{}{} (alias of {})",
+ package.get_name(),
+ package.get_version(),
+ suffix,
+ alias_of.get_version()
+ ));
+ }
+
+ PhpMixed::String(format!(
+ "{}-{}{}",
+ package.get_name(),
+ package.get_version(),
+ suffix
+ ))
+ })
+ .collect()
+}
+
+/// ref: PoolBuilderTest::testPoolBuilder
+#[allow(clippy::too_many_arguments)]
+fn run_test_pool_builder(
+ fixtures_dir: &std::path::Path,
+ _file: &str,
+ message: &str,
+ expect: &PhpMixed,
+ expect_optimized: &PhpMixed,
+ root: &PhpMixed,
+ request_data: &PhpMixed,
+ package_repos: &PhpMixed,
+ fixed: &PhpMixed,
+) {
+ // PHP: $root is array; empty checks against keys.
+ let root_map = root.as_array();
+ let get_root = |key: &str| -> Option<&PhpMixed> { root_map.and_then(|m| m.get(key)) };
+ let is_empty = |v: Option<&PhpMixed>| -> bool {
+ match v {
+ None => true,
+ Some(PhpMixed::Null) => true,
+ Some(PhpMixed::Bool(false)) => true,
+ Some(PhpMixed::Int(0)) => true,
+ Some(PhpMixed::String(s)) => s.is_empty(),
+ Some(PhpMixed::List(l)) => l.is_empty(),
+ Some(PhpMixed::Array(a)) => a.is_empty(),
+ Some(PhpMixed::Object(a)) => a.is_empty(),
+ _ => false,
+ }
+ };
+
+ // PHP: $rootAliases = !empty($root['aliases']) ? $root['aliases'] : [];
+ let root_aliases_data: Vec<IndexMap<String, PhpMixed>> = if !is_empty(get_root("aliases")) {
+ get_root("aliases")
+ .and_then(|v| v.as_list())
+ .map(|l| {
+ l.iter()
+ .filter_map(|v| v.as_array().cloned())
+ .collect::<Vec<_>>()
+ })
+ .unwrap_or_default()
+ } else {
+ vec![]
+ };
+
+ let minimum_stability: String = if !is_empty(get_root("minimum-stability")) {
+ get_root("minimum-stability")
+ .and_then(|v| v.as_string())
+ .unwrap_or("stable")
+ .to_string()
+ } else {
+ "stable".to_string()
+ };
+
+ // PHP: $stabilityFlags map of name => stability string.
+ let stability_flags_data: IndexMap<String, String> = if !is_empty(get_root("stability-flags")) {
+ get_root("stability-flags")
+ .and_then(|v| v.as_array())
+ .map(|m| {
+ m.iter()
+ .filter_map(|(k, v)| v.as_string().map(|s| (k.clone(), s.to_string())))
+ .collect()
+ })
+ .unwrap_or_default()
+ } else {
+ IndexMap::new()
+ };
+
+ let root_references: IndexMap<String, String> = if !is_empty(get_root("references")) {
+ get_root("references")
+ .and_then(|v| v.as_array())
+ .map(|m| {
+ m.iter()
+ .filter_map(|(k, v)| v.as_string().map(|s| (k.clone(), s.to_string())))
+ .collect()
+ })
+ .unwrap_or_default()
+ } else {
+ IndexMap::new()
+ };
+
+ // PHP: array_map over stability flags, mapping to BasePackage::STABILITIES[$stability].
+ let mut stability_flags: IndexMap<String, i64> = IndexMap::new();
+ for (name, stability) in &stability_flags_data {
+ let Some(value) = STABILITIES.get(stability.as_str()) else {
+ panic!("Invalid stability given: {}", stability);
+ };
+ stability_flags.insert(name.clone(), *value);
+ }
+
+ let parser = VersionParser::new();
+ // PHP: foreach ($rootAliases as $index => $alias) { normalize version + alias }
+ let mut root_aliases: Vec<RootAliasInput> = Vec::new();
+ for alias in &root_aliases_data {
+ let package = alias
+ .get("package")
+ .and_then(|v| v.as_string())
+ .unwrap_or("")
+ .to_string();
+ let version = parser
+ .normalize(
+ alias
+ .get("version")
+ .and_then(|v| v.as_string())
+ .unwrap_or(""),
+ None,
+ )
+ .unwrap();
+ let alias_str = alias
+ .get("alias")
+ .and_then(|v| v.as_string())
+ .unwrap_or("")
+ .to_string();
+ let alias_normalized = parser
+ .normalize(
+ alias.get("alias").and_then(|v| v.as_string()).unwrap_or(""),
+ None,
+ )
+ .unwrap();
+ root_aliases.push(RootAliasInput {
+ package,
+ version,
+ alias: alias_str,
+ alias_normalized,
+ });
+ }
+
+ let loader = ArrayLoader::new(None, true);
+ let mut package_ids: IndexMap<i64, BasePackageHandle> = IndexMap::new();
+
+ // PHP: $oldCwd = Platform::getCwd(); chdir(__DIR__.'/Fixtures/poolbuilder/');
+ let old_cwd = std::env::current_dir().unwrap();
+ std::env::set_current_dir(fixtures_dir).unwrap();
+
+ let mut repository_set = RepositorySet::new(
+ &minimum_stability,
+ stability_flags,
+ root_aliases,
+ root_references,
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let config = Rc::new(RefCell::new(Config::new(false, None)));
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let mut rm = RepositoryFactory::manager(io.clone(), &config, None, None, None).unwrap();
+
+ // PHP: foreach ($packageRepos as $packages)
+ for repo_entry in package_repos.as_list().unwrap() {
+ // PHP: isset($packages['type'])
+ if let Some(repo_map) = repo_entry.as_array() {
+ if repo_map.contains_key("type") {
+ let repo = RepositoryFactory::create_repo(
+ io.clone(),
+ &config,
+ repo_map.clone(),
+ Some(&mut rm),
+ )
+ .unwrap();
+ repository_set.add_repository(repo).unwrap();
+ continue;
+ }
+ }
+
+ let repo = ArrayRepository::new(vec![]).unwrap();
+ let repo_handle = RepositoryInterfaceHandle::new(repo);
+
+ // PHP: isset($packages['canonical']) || isset($packages['only']) || isset($packages['exclude'])
+ let packages_list: Vec<IndexMap<String, PhpMixed>>;
+ if let Some(repo_map) = repo_entry.as_array() {
+ if repo_map.contains_key("canonical")
+ || repo_map.contains_key("only")
+ || repo_map.contains_key("exclude")
+ {
+ let mut options = repo_map.clone();
+ let packages = options
+ .shift_remove("packages")
+ .unwrap_or(PhpMixed::List(vec![]));
+ repository_set
+ .add_repository(RepositoryInterfaceHandle::new(
+ FilterRepository::new(repo_handle.clone(), options).unwrap(),
+ ))
+ .unwrap();
+ packages_list = packages
+ .as_list()
+ .map(|l| l.iter().filter_map(|v| v.as_array().cloned()).collect())
+ .unwrap_or_default();
+ } else {
+ repository_set.add_repository(repo_handle.clone()).unwrap();
+ packages_list = repo_map
+ .values()
+ .filter_map(|v| v.as_array().cloned())
+ .collect();
+ }
+ } else {
+ repository_set.add_repository(repo_handle.clone()).unwrap();
+ packages_list = repo_entry
+ .as_list()
+ .map(|l| l.iter().filter_map(|v| v.as_array().cloned()).collect())
+ .unwrap_or_default();
+ }
+
+ let array_repo = repo_handle.downcast_rc::<ArrayRepository>().unwrap();
+ for package in &packages_list {
+ array_repo
+ .borrow()
+ .add_package(load_package(&loader, &mut package_ids, package))
+ .unwrap();
+ }
+ }
+
+ let locked_repo = LockArrayRepositoryHandle::new(LockArrayRepository::new(vec![]).unwrap());
+ repository_set
+ .add_repository(locked_repo.clone().into())
+ .unwrap();
+
+ let request_map = request_data.as_array().unwrap();
+
+ // PHP: if (isset($requestData['locked']))
+ if let Some(locked) = request_map.get("locked") {
+ for package in locked.as_list().unwrap() {
+ locked_repo
+ .borrow()
+ .add_package(load_package(
+ &loader,
+ &mut package_ids,
+ package.as_array().unwrap(),
+ ))
+ .unwrap();
+ }
+ }
+
+ let mut request = Request::new(Some(locked_repo.clone()));
+ for (package, constraint) in request_map["require"].as_array().unwrap() {
+ request
+ .require_name(
+ package,
+ Some(
+ parser
+ .parse_constraints(constraint.as_string().unwrap())
+ .unwrap(),
+ ),
+ )
+ .unwrap();
+ }
+
+ // PHP: if (isset($requestData['allowList']))
+ if let Some(allow_list) = request_map.get("allowList") {
+ let mut transitive_deps = UpdateAllowTransitiveDeps::UpdateOnlyListed;
+ if request_map
+ .get("allowTransitiveDepsNoRootRequire")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false)
+ {
+ transitive_deps =
+ UpdateAllowTransitiveDeps::UpdateListedWithTransitiveDepsNoRootRequire;
+ }
+ if request_map
+ .get("allowTransitiveDeps")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false)
+ {
+ transitive_deps = UpdateAllowTransitiveDeps::UpdateListedWithTransitiveDeps;
+ }
+ let allow_list_names: Vec<String> = allow_list
+ .as_list()
+ .unwrap()
+ .iter()
+ .filter_map(|v| v.as_string().map(|s| s.to_string()))
+ .collect();
+ request.set_update_allow_list(allow_list_names, transitive_deps);
+ }
+
+ // PHP: foreach ($fixed as $fixedPackage)
+ for fixed_package in fixed.as_list().unwrap() {
+ request.fix_package(load_package(
+ &loader,
+ &mut package_ids,
+ fixed_package.as_array().unwrap(),
+ ));
+ }
+
+ let pool = repository_set
+ .create_pool(&mut request, io.clone(), None, None, vec![], None, None)
+ .unwrap();
+
+ let mut result = get_package_result_set(&pool, &package_ids);
+
+ let mut expect = expect.as_list().unwrap().clone();
+ php_sort_mixed(&mut expect);
+ php_sort_mixed(&mut result);
+ assert_eq!(
+ expect, result,
+ "Unoptimized pool does not match expected package set ({})",
+ message
+ );
+
+ let mut optimizer = PoolOptimizer::new(Rc::new(DefaultPolicy::new(false, false, None)));
+ let optimized = optimizer.optimize(&request, &pool);
+ let mut result = get_package_result_set(&optimized, &package_ids);
+ let mut expect_optimized = expect_optimized.as_list().unwrap().clone();
+ php_sort_mixed(&mut expect_optimized);
+ php_sort_mixed(&mut result);
+ assert_eq!(
+ expect_optimized, result,
+ "Optimized pool does not match expected package set ({})",
+ message
+ );
+
+ // PHP: chdir($oldCwd);
+ std::env::set_current_dir(&old_cwd).unwrap();
+}
+
+#[ignore]
#[test]
-#[ignore = "ArrayLoader::load (single-package, pub) and Pool::count are not exposed: the loadPackage closure calls $loader->load($data) per package and getPackageResultSet uses count($pool)"]
fn test_pool_builder() {
- todo!()
+ let fixtures_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+ .join("../../composer/tests/Composer/Test/DependencyResolver/Fixtures/poolbuilder");
+ let fixtures_dir = std::fs::canonicalize(&fixtures_dir).unwrap();
+
+ let tests = get_integration_tests(&fixtures_dir);
+ for (_name, test) in tests {
+ run_test_pool_builder(
+ &fixtures_dir,
+ &test.file,
+ &test.message,
+ &test.expect,
+ &test.expect_optimized,
+ &test.root,
+ &test.request,
+ &test.package_repos,
+ &test.fixed,
+ );
+ }
}