aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/shirabe/tests/autoload/autoload_generator_test.rs535
1 files changed, 508 insertions, 27 deletions
diff --git a/crates/shirabe/tests/autoload/autoload_generator_test.rs b/crates/shirabe/tests/autoload/autoload_generator_test.rs
index 73182a2..a79bba0 100644
--- a/crates/shirabe/tests/autoload/autoload_generator_test.rs
+++ b/crates/shirabe/tests/autoload/autoload_generator_test.rs
@@ -7,6 +7,7 @@ use shirabe::autoload::AutoloadGenerator;
use shirabe::composer::{ComposerHandle, PartialOrFullComposer};
use shirabe::config::Config;
use shirabe::event_dispatcher::EventDispatcher;
+use shirabe::filter::platform_requirement_filter::PlatformRequirementFilterFactory;
use shirabe::installer::{InstallationManager, InstallerInterface};
use shirabe::io::{BufferIO, IOInterface};
use shirabe::package::handle::{AliasPackageHandle, PackageHandle, RootPackageHandle};
@@ -18,6 +19,7 @@ use shirabe::util::http_downloader::HttpDownloader;
use shirabe::util::r#loop::Loop;
use shirabe_external_packages::symfony::console::output::output_interface;
use shirabe_php_shim::PhpMixed;
+use shirabe_semver::VersionParser;
use shirabe_semver::constraint::{AnyConstraint, MatchAllConstraint, SimpleConstraint};
use std::cell::RefCell;
use std::rc::Rc;
@@ -141,6 +143,27 @@ fn null_path(s: &str) -> String {
s.to_string()
}
+/// Builds an InstallationManager whose single installer routes `getInstallPath` through
+/// `InstallPathStubInstaller`. The PHP loop mock has its constructor disabled and is never
+/// exercised here, so a mock HttpDownloader (no real curl backend) stands in for the loop.
+fn make_installation_manager(
+ vendor_dir: &str,
+ io: Rc<RefCell<dyn IOInterface>>,
+) -> InstallationManager {
+ let config_for_downloader = Rc::new(RefCell::new(Config::new(false, None)));
+ let http_downloader = Rc::new(RefCell::new(HttpDownloader::__new_mock(
+ io.clone(),
+ config_for_downloader,
+ )));
+ let loop_ = Rc::new(RefCell::new(Loop::new(http_downloader, None)));
+
+ let mut im = InstallationManager::new(loop_, io, None);
+ im.add_installer(Box::new(InstallPathStubInstaller {
+ vendor_dir: vendor_dir.to_string(),
+ }));
+ im
+}
+
fn set_up() -> SetUp {
let temp_dir = TempDir::new().unwrap();
let working_dir = temp_dir.path().to_str().unwrap().to_string();
@@ -154,20 +177,8 @@ fn set_up() -> SetUp {
BufferIO::new(String::new(), output_interface::VERBOSITY_NORMAL, None).unwrap(),
));
- // The PHP loop mock has its constructor disabled and is never exercised here, so a mock
- // HttpDownloader (no real curl backend) stands in for the InstallationManager's loop.
let dispatcher_io: Rc<RefCell<dyn IOInterface>> = io.clone();
- let config_for_downloader = Rc::new(RefCell::new(Config::new(false, None)));
- let http_downloader = Rc::new(RefCell::new(HttpDownloader::__new_mock(
- dispatcher_io.clone(),
- config_for_downloader,
- )));
- let loop_ = Rc::new(RefCell::new(Loop::new(http_downloader, None)));
-
- let mut im = InstallationManager::new(loop_, dispatcher_io.clone(), None);
- im.add_installer(Box::new(InstallPathStubInstaller {
- vendor_dir: vendor_dir.clone(),
- }));
+ let im = make_installation_manager(&vendor_dir, dispatcher_io.clone());
let repository = InstalledArrayRepository::new().unwrap();
@@ -253,6 +264,15 @@ fn assert_file_content_equals(expected: &str, actual: &str) {
assert_eq!(exp, act, "{} equals {}", expected, actual);
}
+/// ref: PHPUnit `assertStringEqualsFile`
+#[track_caller]
+fn assert_str_equals_file(expected: &str, actual_path: &str) {
+ let act = std::fs::read_to_string(actual_path)
+ .unwrap_or_else(|e| panic!("read {}: {}", actual_path, e))
+ .replace('\r', "");
+ assert_eq!(expected, act, "content of {}", actual_path);
+}
+
fn match_all() -> AnyConstraint {
AnyConstraint::MatchAll(MatchAllConstraint::new(None))
}
@@ -1721,12 +1741,8 @@ fn test_exclude_from_classmap() {
// - testIncludePathsArePrependedInAutoloadFile / testIncludePathsInRootPackage /
// testUseGlobalIncludePath: assert PHP's get_include_path() after `require autoload.php`.
// - testPreAndPostEventsAreDispatchedDuringAutoloadDump: EventDispatcher::dispatchScript spy.
-// - testVendorDirExcludedFromWorkingDir / testUpLevelRelativePaths: chdir into a nested working dir
-// with a custom getInstallPath using a different vendor dir.
// - testAutoloadRulesInPackageThatDoesNotExistOnDisk: exercises buildPackageMap/parseAutoloads
// directly plus a CompletePackage; multi-dump with mutation.
-// - testGeneratesPlatformCheck: data-provider over many platform-requirement scenarios.
-// - testAbsoluteSymlinkWith*: create real filesystem symlinks.
#[test]
#[ignore = "require autoload.php + function_exists() assertions are unportable (composer_require todo!())"]
@@ -1765,15 +1781,196 @@ fn test_use_global_include_path() {
}
#[test]
-#[ignore = "needs nested working dir + custom getInstallPath vendor dir"]
+#[serial]
fn test_vendor_dir_excluded_from_working_dir() {
- todo!()
+ let mut s = set_up();
+ let working_dir = format!("{}/working-dir", s.vendor_dir);
+ let vendor_dir = format!("{}/../vendor", working_dir);
+
+ s.ensure_dir(&working_dir);
+ std::env::set_current_dir(&working_dir).unwrap();
+
+ let package = new_root_pkg("root/a");
+ package.set_autoload(autoload(vec![
+ ("psr-0", str_map(&[("Foo", pstr("src"))])),
+ ("psr-4", str_map(&[("Acme\\Foo\\", pstr("src-psr4"))])),
+ ("classmap", str_list(&["classmap"])),
+ ("files", str_list(&["test.php"])),
+ ]));
+ package.set_requires(requires(vec![("b/b", link("a", "b/b", match_all(), None))]));
+
+ let vendor_package = new_pkg("b/b");
+ vendor_package.__set_autoload(autoload(vec![
+ ("psr-0", str_map(&[("Bar", pstr("lib"))])),
+ ("psr-4", str_map(&[("Acme\\Bar\\", pstr("lib-psr4"))])),
+ ("classmap", str_list(&["classmaps"])),
+ ("files", str_list(&["bootstrap.php"])),
+ ]));
+
+ s.set_canonical_packages(vec![vendor_package.into()]);
+
+ let mut im = make_installation_manager(&vendor_dir, s.io.clone());
+
+ s.ensure_dir(&format!("{}/src/Foo", working_dir));
+ s.ensure_dir(&format!("{}/classmap", working_dir));
+ s.ensure_dir(&format!("{}/composer", vendor_dir));
+ s.ensure_dir(&format!("{}/b/b/lib/Bar", vendor_dir));
+ s.ensure_dir(&format!("{}/b/b/classmaps", vendor_dir));
+ s.put(
+ &format!("{}/src/Foo/Bar.php", working_dir),
+ "<?php namespace Foo; class Bar {}",
+ );
+ s.put(
+ &format!("{}/classmap/classes.php", working_dir),
+ "<?php namespace Foo; class Foo {}",
+ );
+ s.put(&format!("{}/test.php", working_dir), "<?php class Foo {}");
+ s.put(
+ &format!("{}/b/b/lib/Bar/Foo.php", vendor_dir),
+ "<?php namespace Bar; class Foo {}",
+ );
+ s.put(
+ &format!("{}/b/b/classmaps/classes.php", vendor_dir),
+ "<?php namespace Bar; class Bar {}",
+ );
+ s.put(
+ &format!("{}/b/b/bootstrap.php", vendor_dir),
+ "<?php class Bar {}",
+ );
+
+ s.vendor_dir = vendor_dir.clone();
+ let config = s.config();
+ s.generator
+ .dump(
+ &config,
+ &mut s.repository,
+ package.into(),
+ &mut im,
+ "composer",
+ true,
+ Some("_13".to_string()),
+ None,
+ false,
+ )
+ .unwrap();
+
+ let expected_namespace = "<?php\n\n// autoload_namespaces.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname($vendorDir).'/working-dir';\n\nreturn array(\n 'Foo' => array($baseDir . '/src'),\n 'Bar' => array($vendorDir . '/b/b/lib'),\n);\n";
+
+ let expected_psr4 = "<?php\n\n// autoload_psr4.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname($vendorDir).'/working-dir';\n\nreturn array(\n 'Acme\\\\Foo\\\\' => array($baseDir . '/src-psr4'),\n 'Acme\\\\Bar\\\\' => array($vendorDir . '/b/b/lib-psr4'),\n);\n";
+
+ let expected_classmap = "<?php\n\n// autoload_classmap.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname($vendorDir).'/working-dir';\n\nreturn array(\n 'Bar\\\\Bar' => $vendorDir . '/b/b/classmaps/classes.php',\n 'Bar\\\\Foo' => $vendorDir . '/b/b/lib/Bar/Foo.php',\n 'Composer\\\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',\n 'Foo\\\\Bar' => $baseDir . '/src/Foo/Bar.php',\n 'Foo\\\\Foo' => $baseDir . '/classmap/classes.php',\n);\n";
+
+ assert_str_equals_file(
+ expected_namespace,
+ &format!("{}/composer/autoload_namespaces.php", vendor_dir),
+ );
+ assert_str_equals_file(
+ expected_psr4,
+ &format!("{}/composer/autoload_psr4.php", vendor_dir),
+ );
+ assert_str_equals_file(
+ expected_classmap,
+ &format!("{}/composer/autoload_classmap.php", vendor_dir),
+ );
+ let files = std::fs::read_to_string(format!("{}/composer/autoload_files.php", vendor_dir))
+ .unwrap()
+ .replace('\r', "");
+ assert!(files.contains("$vendorDir . '/b/b/bootstrap.php',\n"));
+ assert!(files.contains("$baseDir . '/test.php',\n"));
}
#[test]
-#[ignore = "needs nested working dir chdir + up-level relative path fixtures"]
+#[serial]
+#[ignore = "classmap generation does not apply exclude-from-classmap rules that use up-level (../) relative paths or wildcards, so excluded classes (Boo/Boo2/Boo3/Boo4) still appear"]
fn test_up_level_relative_paths() {
- todo!()
+ let mut s = set_up();
+ let working_dir = format!("{}/working-dir", s.working_dir);
+ std::fs::create_dir_all(&working_dir).unwrap();
+ std::env::set_current_dir(&working_dir).unwrap();
+
+ let package = new_root_pkg("root/a");
+ package.set_autoload(autoload(vec![
+ ("psr-0", str_map(&[("Foo", pstr("../path/../src"))])),
+ (
+ "psr-4",
+ str_map(&[("Acme\\Foo\\", pstr("../path/../src-psr4"))]),
+ ),
+ (
+ "classmap",
+ str_list(&[
+ "../classmap",
+ "../classmap2/subdir",
+ "classmap3",
+ "classmap4",
+ ]),
+ ),
+ ("files", str_list(&["../test.php"])),
+ (
+ "exclude-from-classmap",
+ str_list(&[
+ "./../classmap/excluded",
+ "../classmap2",
+ "classmap3/classes.php",
+ "classmap4/*/classes.php",
+ ]),
+ ),
+ ]));
+
+ s.ensure_dir(&format!("{}/src/Foo", s.working_dir));
+ s.ensure_dir(&format!("{}/classmap/excluded", s.working_dir));
+ s.ensure_dir(&format!("{}/classmap2/subdir", s.working_dir));
+ s.ensure_dir(&format!("{}/working-dir/classmap3", s.working_dir));
+ s.ensure_dir(&format!("{}/working-dir/classmap4/foo/", s.working_dir));
+ s.put(
+ &format!("{}/src/Foo/Bar.php", s.working_dir),
+ "<?php namespace Foo; class Bar {}",
+ );
+ s.put(
+ &format!("{}/classmap/classes.php", s.working_dir),
+ "<?php namespace Foo; class Foo {}",
+ );
+ s.put(
+ &format!("{}/classmap/excluded/classes.php", s.working_dir),
+ "<?php namespace Foo; class Boo {}",
+ );
+ s.put(
+ &format!("{}/classmap2/subdir/classes.php", s.working_dir),
+ "<?php namespace Foo; class Boo2 {}",
+ );
+ s.put(
+ &format!("{}/working-dir/classmap3/classes.php", s.working_dir),
+ "<?php namespace Foo; class Boo3 {}",
+ );
+ s.put(
+ &format!("{}/working-dir/classmap4/foo/classes.php", s.working_dir),
+ "<?php namespace Foo; class Boo4 {}",
+ );
+ s.put(&format!("{}/test.php", s.working_dir), "<?php class Foo {}");
+
+ dump(&mut s, package.into(), true, "_14").unwrap();
+
+ let expected_namespace = "<?php\n\n// autoload_namespaces.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname($vendorDir).'/working-dir';\n\nreturn array(\n 'Foo' => array($baseDir . '/../src'),\n);\n";
+
+ let expected_psr4 = "<?php\n\n// autoload_psr4.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname($vendorDir).'/working-dir';\n\nreturn array(\n 'Acme\\\\Foo\\\\' => array($baseDir . '/../src-psr4'),\n);\n";
+
+ let expected_classmap = "<?php\n\n// autoload_classmap.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname($vendorDir).'/working-dir';\n\nreturn array(\n 'Composer\\\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',\n 'Foo\\\\Bar' => $baseDir . '/../src/Foo/Bar.php',\n 'Foo\\\\Foo' => $baseDir . '/../classmap/classes.php',\n);\n";
+
+ assert_str_equals_file(
+ expected_namespace,
+ &format!("{}/composer/autoload_namespaces.php", s.vendor_dir),
+ );
+ assert_str_equals_file(
+ expected_psr4,
+ &format!("{}/composer/autoload_psr4.php", s.vendor_dir),
+ );
+ assert_str_equals_file(
+ expected_classmap,
+ &format!("{}/composer/autoload_classmap.php", s.vendor_dir),
+ );
+ let files = std::fs::read_to_string(format!("{}/composer/autoload_files.php", s.vendor_dir))
+ .unwrap()
+ .replace('\r', "");
+ assert!(files.contains("$baseDir . '/../test.php',\n"));
}
#[test]
@@ -1782,20 +1979,304 @@ fn test_autoload_rules_in_package_that_does_not_exist_on_disk() {
todo!()
}
+/// ref: AutoloadGeneratorTest::platformCheckProvider — builds the link map for a requires/provides/
+/// replaces entry. Each tuple is `(key, target, constraint)` mirroring `new Link('a', target, parse)`.
+fn platform_links(vp: &VersionParser, entries: &[(&str, &str, &str)]) -> IndexMap<String, Link> {
+ requires(
+ entries
+ .iter()
+ .map(|(key, target, c)| {
+ (
+ *key,
+ link("a", target, vp.parse_constraints(c).unwrap(), None),
+ )
+ })
+ .collect(),
+ )
+}
+
#[test]
-#[ignore = "data-provider over platform-requirement scenarios"]
+#[serial]
+#[ignore = "get_platform_check: an extension whose provider/replacer constraint does NOT satisfy the requirement (ext-pdo 7.1.* vs ^7.2) is still skipped, so platform_check.php is not generated where Composer generates it"]
fn test_generates_platform_check() {
- todo!()
+ let vp = VersionParser;
+
+ // ref: AutoloadGeneratorTest::platformCheckProvider (all 13 scenarios).
+ struct Scenario {
+ name: &'static str,
+ requires: Vec<(&'static str, &'static str, &'static str)>,
+ expected_fixture: Option<&'static str>,
+ provides: Vec<(&'static str, &'static str, &'static str)>,
+ replaces: Vec<(&'static str, &'static str, &'static str)>,
+ ignore_platform_reqs: PhpMixed,
+ }
+
+ let scenarios = vec![
+ Scenario {
+ name: "Typical project requirements",
+ requires: vec![
+ ("php", "php", "^7.2"),
+ ("ext-xml", "ext-xml", "*"),
+ ("ext-json", "ext-json", "*"),
+ ],
+ expected_fixture: Some("typical"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ Scenario {
+ name: "No PHP lower bound",
+ requires: vec![("php", "php", "< 8")],
+ expected_fixture: None,
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ Scenario {
+ name: "No PHP upper bound",
+ requires: vec![("php", "php", ">= 7.2")],
+ expected_fixture: Some("no_php_upper_bound"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ Scenario {
+ name: "Specific PHP release version",
+ requires: vec![("php", "php", "^7.2.8")],
+ expected_fixture: Some("specific_php_release"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ Scenario {
+ name: "Specific 64-bit PHP version",
+ requires: vec![("php-64bit", "php-64bit", "^7.2.8")],
+ expected_fixture: Some("specific_php_64bit_required"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ Scenario {
+ name: "64-bit PHP required",
+ requires: vec![("php-64bit", "php-64bit", "*")],
+ expected_fixture: Some("php_64bit_required"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ Scenario {
+ name: "No PHP required",
+ requires: vec![("ext-xml", "ext-xml", "*"), ("ext-json", "ext-json", "*")],
+ expected_fixture: Some("no_php_required"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ Scenario {
+ name: "Ignoring all platform requirements skips check completely",
+ requires: vec![
+ ("php", "php", "^7.2"),
+ ("ext-xml", "ext-xml", "*"),
+ ("ext-json", "ext-json", "*"),
+ ],
+ expected_fixture: None,
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(true),
+ },
+ Scenario {
+ name: "Ignored platform requirements are not checked for",
+ requires: vec![
+ ("php", "php", "^7.2.8"),
+ ("ext-xml", "ext-xml", "*"),
+ ("ext-json", "ext-json", "*"),
+ ("ext-pdo", "ext-pdo", "*"),
+ ],
+ expected_fixture: Some("no_php_required"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: str_list(&["php", "ext-pdo"]),
+ },
+ Scenario {
+ name: "Via wildcard ignored platform requirements are not checked for",
+ requires: vec![
+ ("php", "php", "^7.2.8"),
+ ("ext-xml", "ext-xml", "*"),
+ ("ext-json", "ext-json", "*"),
+ ("ext-fileinfo", "ext-fileinfo", "*"),
+ ("ext-filesystem", "ext-filesystem", "*"),
+ ("ext-filter", "ext-filter", "*"),
+ ],
+ expected_fixture: Some("no_php_required"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: str_list(&["php", "ext-fil*"]),
+ },
+ Scenario {
+ name: "No extensions required",
+ requires: vec![("php", "php", "^7.2")],
+ expected_fixture: Some("no_extensions_required"),
+ provides: vec![],
+ replaces: vec![],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ Scenario {
+ name: "Replaced/provided extensions are not checked for + checking case insensitivity",
+ requires: vec![
+ ("ext-xml", "ext-xml", "^7.2"),
+ ("ext-pdo", "ext-Pdo", "^7.2"),
+ ("ext-bcmath", "ext-bcMath", "^7.2"),
+ ],
+ expected_fixture: Some("replaced_provided_exts"),
+ // constraint does not satisfy all the ^7.2 requirement so we do not accept ext-pdo as being replaced;
+ // valid replace of bcmath so no need to check for it
+ replaces: vec![
+ ("ext-pdo", "ext-PDO", "7.1.*"),
+ ("ext-bcmath", "ext-BCMath", "^7.1"),
+ ],
+ // valid provide of ext-xml so no need to check for it
+ provides: vec![("ext-xml", "ext-XML", "*")],
+ ignore_platform_reqs: PhpMixed::Bool(false),
+ },
+ ];
+
+ for scenario in scenarios {
+ let mut s = set_up();
+ let package = new_root_pkg("root/a");
+ package.set_requires(platform_links(&vp, &scenario.requires));
+
+ if !scenario.provides.is_empty() {
+ package.set_provides(platform_links(&vp, &scenario.provides));
+ }
+
+ if !scenario.replaces.is_empty() {
+ package.set_replaces(platform_links(&vp, &scenario.replaces));
+ }
+
+ s.generator.set_platform_requirement_filter(
+ PlatformRequirementFilterFactory::from_bool_or_list(
+ scenario.ignore_platform_reqs.clone(),
+ )
+ .unwrap(),
+ );
+ dump(&mut s, package.into(), true, "_1").unwrap();
+
+ let platform_check = format!("{}/composer/platform_check.php", s.vendor_dir);
+ let autoload_real =
+ std::fs::read_to_string(format!("{}/composer/autoload_real.php", s.vendor_dir))
+ .unwrap()
+ .replace('\r', "");
+ match scenario.expected_fixture {
+ None => {
+ assert!(
+ !std::path::Path::new(&platform_check).exists(),
+ "[{}] platform_check.php should not exist",
+ scenario.name
+ );
+ assert!(
+ !autoload_real.contains("require __DIR__ . '/platform_check.php';"),
+ "[{}] autoload_real.php should not require platform_check.php",
+ scenario.name
+ );
+ }
+ Some(fixture) => {
+ assert_file_content_equals(
+ fixtures_dir()
+ .join("platform")
+ .join(format!("{}.php", fixture))
+ .to_str()
+ .unwrap(),
+ &platform_check,
+ );
+ assert!(
+ autoload_real.contains("require __DIR__ . '/platform_check.php';"),
+ "[{}] autoload_real.php should require platform_check.php",
+ scenario.name
+ );
+ }
+ }
+ }
}
#[test]
-#[ignore = "creates real filesystem symlinks"]
+#[serial]
+#[ignore = "psr-4 compliance warning is emitted for files reached through an absolute symlink; Composer does not warn here"]
fn test_absolute_symlink_with_psr4_does_not_generate_warnings() {
- todo!()
+ let mut s = set_up();
+ let package = new_root_pkg("test/package");
+
+ // Create a directory structure with PSR-4 autoloading
+ s.ensure_dir(&format!(
+ "{}/tools-real/vendor/phpunit/phpunit/src/Framework/Exception",
+ s.working_dir
+ ));
+ s.put(
+ &format!(
+ "{}/tools-real/vendor/phpunit/phpunit/src/Framework/Exception/Exception.php",
+ s.working_dir
+ ),
+ "<?php namespace PHPUnit\\Framework; class Exception extends \\Exception {}",
+ );
+
+ // Create an absolute symlink
+ let target = format!("{}/tools-real", s.working_dir);
+ let r#link = format!("{}/tools", s.working_dir);
+ assert!(shirabe_php_shim::symlink(&target, &r#link));
+
+ package.set_autoload(autoload(vec![
+ ("psr-4", str_map(&[("MyTools\\", pstr("tools/"))])),
+ ("exclude-from-classmap", str_list(&["**/vendor/"])),
+ ]));
+
+ dump(&mut s, package.into(), true, "_9").unwrap();
+
+ let output = s.io.borrow().get_output();
+
+ // Should not contain PSR-4 violation warnings
+ assert!(!output.contains("does not comply with psr-4 autoloading standard"));
}
#[test]
-#[ignore = "creates real filesystem symlinks"]
+#[serial]
+#[ignore = "exclude-from-classmap '**/vendor/' is not applied to paths reached through an absolute symlink, so PHPUnit\\Framework\\Exception is not excluded"]
fn test_absolute_symlink_with_classmap_exclude_from_classmap() {
- todo!()
+ let mut s = set_up();
+ let package = new_root_pkg("test/package");
+
+ // Create a directory structure with files
+ s.ensure_dir(&format!(
+ "{}/tools-real/vendor/phpunit/phpunit/src/Framework",
+ s.working_dir
+ ));
+ s.put(
+ &format!(
+ "{}/tools-real/vendor/phpunit/phpunit/src/Framework/Exception.php",
+ s.working_dir
+ ),
+ "<?php namespace PHPUnit\\Framework; class Exception extends \\Exception {}",
+ );
+ s.put(
+ &format!("{}/tools-real/MyClass.php", s.working_dir),
+ "<?php class MyClass {}",
+ );
+
+ // Create an absolute symlink
+ let target = format!("{}/tools-real", s.working_dir);
+ let r#link = format!("{}/tools", s.working_dir);
+ assert!(shirabe_php_shim::symlink(&target, &r#link));
+
+ package.set_autoload(autoload(vec![
+ ("classmap", str_list(&["tools/"])),
+ ("exclude-from-classmap", str_list(&["**/vendor/"])),
+ ]));
+
+ let class_map = dump(&mut s, package.into(), false, "_9").unwrap();
+
+ // Check that MyClass is included but vendor files are excluded
+ assert!(class_map.get_map().contains_key("MyClass"));
+ assert!(
+ !class_map
+ .get_map()
+ .contains_key("PHPUnit\\Framework\\Exception")
+ );
}