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) --- crates/shirabe/tests/common/php_worker.rs | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 crates/shirabe/tests/common/php_worker.rs (limited to 'crates/shirabe/tests/common') diff --git a/crates/shirabe/tests/common/php_worker.rs b/crates/shirabe/tests/common/php_worker.rs new file mode 100644 index 00000000..4be064e4 --- /dev/null +++ b/crates/shirabe/tests/common/php_worker.rs @@ -0,0 +1,55 @@ +//! Shared access to the PHP worker for integration tests. +//! +//! Included into an integration-test binary via +//! `#[path = "../common/php_worker.rs"] mod php_worker;`. +#![allow(dead_code)] + +use shirabe_php_rpc::PluginValue; +use shirabe_symfony_process::PhpExecutableFinder; + +/// Whether a PHP binary is available. Without one the worker cannot start, so tests that need it +/// return early instead of failing. +pub fn php_runtime_available() -> bool { + PhpExecutableFinder::new().find(false).is_some() +} + +/// All tests in one binary share the single PHP worker, whose loaded-class table and class statics +/// persist across tests just like PHPUnit's single-process runs. Interleaving two tests would let +/// one test's state race the other's, so the worker-touching tests run serialized. +static PHP_WORKER_TESTS: std::sync::Mutex<()> = std::sync::Mutex::new(()); + +pub fn lock_php_worker() -> std::sync::MutexGuard<'static, ()> { + PHP_WORKER_TESTS + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) +} + +/// Requires the Composer PHP runtime (`composer/vendor/autoload.php`) into the worker, which is +/// what makes the real `Composer\` classes autoloadable there. +pub fn load_composer_php_runtime() { + shirabe::event_dispatcher::EventDispatcher::__ensure_composer_php_runtime().unwrap(); +} + +/// Calls a static method in the worker, panicking on either failure lane. +pub fn php_call_static(class: &str, method: &str, args: Vec) -> PluginValue { + shirabe_php_rpc::call_static_method(class, method, args, None) + .unwrap_or_else(|error| panic!("{class}::{method} request failed: {error}")) + .unwrap_or_else(|throw| { + panic!( + "{class}::{method} threw {}: {}", + throw.exception_class, throw.message + ) + }) +} + +/// Runs a PHP snippet in the worker and returns its `return` value. +pub fn php_eval(code: &str) -> PluginValue { + shirabe_php_rpc::call_function("__shirabe_eval", vec![PluginValue::string(code)]) + .expect("eval request failed") + .expect("eval threw") +} + +/// Quotes a string as a PHP single-quoted literal for a generated snippet. +pub fn php_single_quote(value: &str) -> String { + format!("'{}'", value.replace('\\', "\\\\").replace('\'', "\\'")) +} -- cgit v1.3.1-4-g156e