From ed8694f89eb7702eb7e617af29f8f444f32b8d3c Mon Sep 17 00:00:00 2001 From: nsfisis Date: Wed, 12 Aug 2026 02:05:03 +0900 Subject: test(installed-versions): verify the PHP class the worker loads InstalledVersions has no Rust port, so the skeletons left behind asserted nothing about compatibility. The tests now require the Composer checkout's vendor/autoload.php into the PHP worker and drive the real class there, which puts $selfDir, the registered ClassLoader and Composer\Semver\VersionParser in the same state as the upstream PHPUnit run. The upstream setUp reflection and the installed_relative.php require stay in PHP; the expected values are Rust. The class Composer's own vendor directory autoloads and the one FilesystemRepository::write dumps from include_str! are separate files, so an added test asserts they hold the same bytes. FilesystemRepositoryTest::testSafelyLoadInstalledVersions moves to the worker too, against the php/stubs FilesystemRepository, whose safelyLoadInstalledVersions runs the PCRE recursive grammar natively. The shared worker helpers live in tests/common/php_worker.rs. Co-Authored-By: Claude Opus 5 (1M context) --- .../tests/repository/filesystem_repository_test.rs | 104 ++++++++++++++++++++- crates/shirabe/tests/repository/main.rs | 2 + 2 files changed, 102 insertions(+), 4 deletions(-) (limited to 'crates/shirabe/tests/repository') diff --git a/crates/shirabe/tests/repository/filesystem_repository_test.rs b/crates/shirabe/tests/repository/filesystem_repository_test.rs index 59901072..4fc968cc 100644 --- a/crates/shirabe/tests/repository/filesystem_repository_test.rs +++ b/crates/shirabe/tests/repository/filesystem_repository_test.rs @@ -1,5 +1,6 @@ //! ref: composer/tests/Composer/Test/Repository/FilesystemRepositoryTest.php +use crate::php_worker::{load_composer_php_runtime, php_call_static, php_runtime_available}; use crate::test_case::{get_alias_package, get_package}; use indexmap::IndexMap; use serial_test::serial; @@ -12,6 +13,7 @@ use shirabe::package::{Link, PackageInterfaceHandle, RootAliasPackageHandle, Roo use shirabe::repository::RepositoryInterface; use shirabe::repository::filesystem_repository::FilesystemRepository; use shirabe::util::filesystem::Filesystem; +use shirabe_php_rpc::PluginValue; use shirabe_php_shim::Catch as _; use shirabe_php_shim::PhpMixed; use shirabe_semver::VersionParser; @@ -325,10 +327,104 @@ fn test_repository_writes_installed_php() { assert_eq!(expected, actual); } -#[ignore = "safely_load_installed_versions's pattern uses a PCRE (?(DEFINE)...) recursive grammar the regex crate cannot compile, and InstalledVersions::getAllRawData has no Rust counterpart"] +/// The Rust `FilesystemRepository::safely_load_installed_versions` is a no-op stub, and +/// `InstalledVersions` has no Rust port at all; both live in the PHP worker, which is where the +/// upstream assertions are checked. See `crates/shirabe/tests/installed_versions_test.rs`. #[test] +// Serialized because test_repository_writes_installed_php pushes InstalledVersions::reload into +// the same worker, which would replace the state asserted here. +#[serial] fn test_safely_load_installed_versions() { - // TODO(pcre): needs a regex-crate expression equivalent to the PCRE recursive grammar, and - // InstalledVersions::get_all_raw_data. - todo!() + if !php_runtime_available() { + return; + } + load_composer_php_runtime(); + + let fixtures_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../composer/tests/Composer/Test/Repository/Fixtures") + .canonicalize() + .expect("the Composer checkout must provide the repository fixtures") + .to_str() + .unwrap() + .to_string(); + + let result = php_call_static( + "Composer\\Repository\\FilesystemRepository", + "safelyLoadInstalledVersions", + vec![PluginValue::string(format!( + "{}/installed_complex.php", + fixtures_dir + ))], + ); + assert_eq!( + PluginValue::Bool(true), + result, + "The file should be considered valid" + ); + + let raw_data = php_call_static("Composer\\InstalledVersions", "getAllRawData", vec![]); + let PluginValue::List(datasets) = raw_data else { + panic!("getAllRawData must return a list, got {raw_data:?}") + }; + let raw_data = datasets.last().cloned().unwrap(); + + let root = PhpMixed::Array(IndexMap::from([ + ( + "install_path".to_string(), + PhpMixed::String(format!("{}/./", fixtures_dir)), + ), + ( + "aliases".to_string(), + PhpMixed::List(vec![ + PhpMixed::String("1.10.x-dev".to_string()), + PhpMixed::String("2.10.x-dev".to_string()), + ]), + ), + ("name".to_string(), PhpMixed::String("__root__".to_string())), + ("true".to_string(), PhpMixed::Bool(true)), + ("false".to_string(), PhpMixed::Bool(false)), + ("null".to_string(), PhpMixed::Null), + ])); + + let a_provider = PhpMixed::Array(IndexMap::from([ + ( + "foo".to_string(), + PhpMixed::String("simple string/no backslash".to_string()), + ), + ( + "install_path".to_string(), + PhpMixed::String(format!( + "{}/vendor/{{${{passthru('bash -i')}}}}", + fixtures_dir + )), + ), + ("empty array".to_string(), PhpMixed::List(vec![])), + ])); + + let c_c = PhpMixed::Array(IndexMap::from([ + ( + "install_path".to_string(), + PhpMixed::String("/foo/bar/ven/do{}r/c/c${}".to_string()), + ), + ("aliases".to_string(), PhpMixed::List(vec![])), + ( + "reference".to_string(), + PhpMixed::String( + "{${passthru('bash -i')}} Foo\\Bar\n\ttab\u{0b}verticaltab\0".to_string(), + ), + ), + ])); + + let expected = PhpMixed::Array(IndexMap::from([ + ("root".to_string(), root), + ( + "versions".to_string(), + PhpMixed::Array(IndexMap::from([ + ("a/provider".to_string(), a_provider), + ("c/c".to_string(), c_c), + ])), + ), + ])); + + assert_eq!(PluginValue::from_php_mixed(&expected), raw_data); } diff --git a/crates/shirabe/tests/repository/main.rs b/crates/shirabe/tests/repository/main.rs index e86772e7..cf15d27b 100644 --- a/crates/shirabe/tests/repository/main.rs +++ b/crates/shirabe/tests/repository/main.rs @@ -6,6 +6,8 @@ mod config_stub; mod http_downloader_mock; #[path = "../common/io_stub.rs"] mod io_stub; +#[path = "../common/php_worker.rs"] +mod php_worker; #[path = "../common/process_executor_mock.rs"] mod process_executor_mock; #[path = "../common/test_case.rs"] -- cgit v1.3.1-4-g156e