aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests
AgeCommit message (Collapse)Author
2026-07-24fix(composer-repository): initialize wrapper before delegating loadPackagesnsfisis
For a simple, non-lazy composer repository (no providers-url/ metadata-url/providers-lazy-url), load_packages() delegates to self.inner.load_packages() (PHP: parent::loadPackages()). PHP's ArrayRepository::loadPackages() calls $this->getPackages(), which virtual-dispatches through ComposerRepository::getPackages() down to ComposerRepository::initialize() (the real HTTP/file fetch). Composition doesn't get that dispatch for free: self.inner is a bare ArrayRepository, so self.inner.load_packages() ends up calling ArrayRepository::initialize() — a no-op stub that just sets an empty package list — instead of ComposerRepository::initialize(). The repository's packages.json fetched and parsed successfully, but the result was silently discarded, so the repo always looked empty. get_packages() already carries the identical guard with the same diagnosis in its own comment; load_packages() was just missing it. Documented the same latent gap in find_package/find_packages/count/ has_package, which call into ArrayRepository the same unguarded way but aren't known to be exercised by any test yet.
2026-07-24fix(installer-test): port InstallerTest::setUp's chdir(__DIR__)nsfisis
PHP's InstallerTest::setUp() does chdir(__DIR__) before every test so relative "type": "path" repository URLs in fixtures resolve against composer/tests/Composer/Test; tearDown() restores the previous cwd. This was never ported, only the env-var clears were, so any fixture declaring a relative path repo failed at PathRepository::initialize() with "the `url` supplied for the path (...) repository does not exist" — not a missing PathRepository feature, just an unset cwd. Turned TearDown into a real guard that captures and chdirs on construction and restores on Drop. Since set_current_dir is process-wide state and tests run concurrently by default, added #[serial] to test_installer (the only call site not already inside a #[serial] macro-generated fn) so no two TearDown-holding tests can race on cwd; serial_test's plain #[serial] shares one unnamed lock across the whole binary, so this is sufficient.
2026-07-24fix(pool-builder): use plain getPackages() on locked repositorynsfisis
PoolBuilder::build_pool() and warn_about_non_matching_update_allow_list() called get_canonical_packages() on the locked repository during a partial update, but PHP's PoolBuilder uses the plain getPackages(). get_canonical_packages() unwraps AliasPackage down to its base package, discarding the alias's own version identity. Locker::get_locked_repository() wraps a lock entry with extra.branch-alias in a single CompleteAliasPackage rather than adding a separate base object, so canonicalizing it silently dropped the locked branch-alias version (e.g. 2.2.x-dev), leaving only the raw dev-master version behind. For a package excluded from the partial update's allow-list, that meant its locked branch-alias version could no longer satisfy the root's constraint, producing a spurious solver conflict instead of keeping the package pinned exactly as locked. Fixed the same bug in AuditCommand's --locked package listing, which had the identical get_canonical_packages()/getPackages() mismatch against AuditCommand.php.
2026-07-24fix(dependency-resolver): query real PHP for ext-* version/loaded checksnsfisis
Two shim gaps made the extension-related branches of solver-problem messages wrong: - phpversion($ext) with a non-empty extension can't be known statically (it's shirabe-php-shim's todo!()); Problem::get_missing_package_reason now calls shirabe_php_rpc::phpversion, the same RPC bridge platform::runtime::Runtime::get_extension_version already uses. - extension_loaded's hardcoded allowlist was missing "pcre", a mandatory always-compiled-in PHP extension, so ext-pcre was misreported as "missing from your system" instead of "disabled by your platform config" whenever a platform override disabled it. Also fix XdebugHandler::getAllIniFiles() always returning `[""]` (a php-runtime stub): create_extension_hint()'s early-return guard (`paths[0] empty && len==1`) fired unconditionally, silently dropping the entire "To enable extensions..." hint from every solver-problem message that mentions missing extensions. shirabe-external-packages can't depend on shirabe-php-rpc (shirabe-php-rpc already depends on shirabe-external-packages), so IniHelper::get_all() queries a new get_all_ini_files RPC command directly instead of going through the stub. This exposed that XdebugHandler is never constructed with a name because bin/composer's restart-without-Xdebug bootstrap was never ported to main.rs, making COMPOSER_ORIGINAL_INIS-driven behavior unreachable; documented with a TODO(phase-c) and updated ini_helper_test.rs's ignore reasons (and ignored test_with_no_ini, which only passed before by coincidence with the old stub's constant output) to match.
2026-07-24fix(installer-test): classify EXPECT-LOCK by PHP truthiness, not string matchnsfisis
PHP's readTestFile splits sections with a regex that leaves a section's own trailing newline attached when it is the file's last section (verified against real PHP); for install-without-lock.test and update-without-lock.test, --EXPECT-LOCK-- is that last section, so its raw content is "false\n", not "false". PHP's `$expectLock === 'false'` check therefore also misses, but PHP falls through to JsonFile::parseJson("false\n"), which json_decodes to boolean false anyway, and every downstream check in doTestIntegration branches on PHP truthiness of $expectLock, so the outcome is unaffected either way. The Rust port only mirrored the literal string comparison, so the same "false\n" produced ExpectLock::Json(Value::Bool(false)) instead of ExpectLock::Never, and do_test_integration's Json arm unconditionally read composer.lock, panicking because config.lock=false means no lock file is ever written. Parse EXPECT-LOCK as JSON first and classify by PHP truthiness of the result, matching what doTestIntegration actually checks instead of the raw string.
2026-07-24fix(php-shim): keep literal '>' outside tags in strip_tagsnsfisis
The b'>' match arm in strip_tags's state machine never pushed the character to the output buffer when encountered outside a tag (state 0), unlike every other special-character arm (!, ?, -, and the catch-all) which does push in that state. Every literal '>' not part of an HTML-like tag was silently dropped. This corrupted "=>" into "=" in Composer's operation trace strings (e.g. "Upgrading foo/bar (1.0.0 => 1.1.0)"), which go through strip_tags to remove the <info>/<comment> markup before comparison, un-ignoring 82 integration tests that were asserting on that exact arrow.
2026-07-24fix(locker): return stability-flags as int, not stringnsfisis
Locker::get_stability_flags returned IndexMap<String, String>, converting each value via PhpMixed::as_string(), which only matches the String variant. composer.lock's "stability-flags" values are always JSON integers (BasePackage::STABILITIES), so every flag silently decoded to "" and installer.rs's downstream .parse::<i64>() defaulted it to 0 (stable). This made any locked package pinned via a non-stable stability-flags entry look "unacceptable" during `composer install`, silently dropping it from the solver's pool instead of fixing/requiring it — turning a real dependency conflict into a spurious "lock file needs changes" result. Return i64 directly, matching RootPackageInterface::get_stability_flags and set_lock_data's existing convention for this same PHP array shape.
2026-07-24fix(installer-test): match Locker content-hash encoding to lock hashnsfisis
do_test_integration built the Locker's composer.json content string with serde_json::to_string, which doesn't escape slashes, while the fixture's auto-computed lock "hash" field used JsonFile::encode_with_options with slashes escaped (mirroring PHP's json_encode default). Since virtually every package name contains a "/", this made Locker::isFresh() spuriously report every such lock as stale, unignoring 12 fixtures that depended on the lock being recognized as fresh during `install`.
2026-07-24test(installer): split integration tests into one #[test] per fixturensfisis
Replace the three loop-based test functions (each iterating all fixtures with a shared SKIP_INSTALLER_* skip list) with macro-generated per-fixture test functions, so a single failing or panicking fixture no longer hides the pass/fail status of the rest. Known-failing fixtures keep their TODO(phase-d) reasons via #[ignore] on their own test instead of a shared skip list. All generated tests are #[serial] since they mutate global env vars (COMPOSER_POOL_OPTIMIZER, COMPOSER_FUND) that would otherwise race across parallel test threads. This is an interim structure for triaging the ~131 ignored fixtures one at a time; it should be reverted to a single loop-based test per group (matching Composer's directory-scanned fixtures) once they are resolved.
2026-07-20fix(json-file): forward detected indent into write's encode optionsnsfisis
JsonFile::write_with_options() used the caller-supplied JsonEncodeOptions verbatim, ignoring self.indent (set by read()'s detect_indenting), unlike PHP's write() which always passes $this->indent to encode() regardless of the $options argument. Un-ignore test_preserve_indentation_after_read.
2026-07-20fix(pool-builder): fix three build_pool bugs found by un-ignoring ↵nsfisis
test_pool_builder build_pool never populated skipped_load for locked packages skipped due to the update allow list (nor their replace targets), so load_package's skipped_load-driven transitive-unlock branch never fired. load_packages_marked_for_loading never recorded loaded packages into loaded_per_repo, so repositories had no way to dedupe already-loaded versions when a constraint got re-expanded, producing duplicate pool entries. unlock_package looked up a locked package's removal index via the position in a Vec snapshot of self.packages.values() instead of its actual IndexMap key, so after earlier removals the wrong entry (or none) got removed, leaving stale locked packages in the pool. Fixing all three lets test_pool_builder run un-ignored.
2026-07-20fix(no-proxy-pattern): stop chr() corrupting IP bytes as lossy UTF-8nsfisis
shirabe_php_shim::chr() returned a Rust String, which lossily re-encodes bytes >= 0x80 as UTF-8 replacement characters. ip_get_mask, ip_get_network, and ip_map_to_6 relied on chr() to build raw in_addr and netmask byte arrays, corrupting IPv4-in-IPv6 mappings and CIDR netmasks. Build the Vec<u8> byte arrays directly instead of round-tripping through String, and un-ignore test_ip_address and test_ip_range now that the underlying bug is fixed. chr()'s only other caller (http_downloader.rs, an ASCII ESC byte in a regex pattern) didn't need the indirection either, so remove the shim function entirely. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20test(proxy-manager): un-ignore tests by serializing env-var accessnsfisis
The ignored tests raced on the process-wide HTTP_PROXY/etc env vars and the ProxyManager::INSTANCE mutex, causing spurious PoisonError panics when run in parallel. Adding #[serial_test::serial], the same annotation test_instantiation already used, fixes the race with no other changes needed.
2026-07-20fix(php-shim): use PhpMixed::to_bool() for PHP truthy castsnsfisis
Several call sites coerced PhpMixed to bool via `.as_bool()` (which only matches a literal Bool variant) where the corresponding PHP code does a plain `(bool)` cast or truthy check (isset()/array_key_exists() + implicit bool conversion). This silently dropped truthy non-bool values (e.g. String("true"), String("1"), Int(1)) to their unwrap_or default instead of PHP's actual truthy result. Switched these sites to PhpMixed::to_bool(), which implements PHP's full truthy-cast rules.
2026-07-20test(ignore): document root causes for unannotated #[ignore] testsnsfisis
74 tests carried a bare #[ignore] with no explanation. Re-ran each: 25 now pass and had the attribute removed; the remaining 49 got a concise reason (todo!() stubs, regex-crate PCRE gaps, PhpMixed type mismatches, config bool-coercion bugs, missing skipped_load wiring in PoolBuilder, etc.) so future work can find and fix them by grep. No production code or test logic/assertions were changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20fix(advisory): treat int-keyed ignore entries as plain IDsnsfisis
parseIgnoreWithApply distinguishes ['CVE-123' => 'reason'] from [0 => 'CVE-123'] by checking is_int($key) in PHP. AuditConfig only matched on the value's type, so a canonical-int-keyed string value was mistaken for an id => reason pair. Expose canonical_int_key from the php-shim to replicate PHP's key-canonicalization rule and unignore test_mixed_formats.
2026-07-20fix(diagnose-command): stop holding a Config borrow across http callsnsfisis
execute() held &config.borrow() across check_http/check_composer_repo/ check_composer_audit, which reach HttpDownloader -> CurlDownloader:: download; that method does self.config.borrow_mut() on the same Config RefCell, panicking with "RefCell already borrowed" once the phpinfo panic that previously masked this was fixed. Switch those three helpers to take the Rc<RefCell<Config>> handle (matching check_version's existing pattern) and borrow only where a field is actually read, so no borrow spans the downstream network call. Un-ignore the now-passing run_diagnose smoke test and test_cmd_fail; test_cmd_success stays ignored, now for two separate reasons: it needs real network access (as the PHP original does), and shirabe_php_shim::OPENSSL_VERSION_NUMBER is a hardcoded stub (0) that always trips check_platform's TLSv1.1/1.2 support check regardless of the real linked OpenSSL, forcing a non-zero exit code.
2026-07-20feat(php-rpc): implement phpinfo() capture over RPCnsfisis
DiagnoseCommand::check_platform needed phpinfo() output but shirabe-php-shim's ob_start()/phpinfo()/ob_get_clean() are unmodeled todo!()s. Add a phpinfo dispatch entry to the PHP worker (capturing output the same way extension_info already does) and a get_phpinfo() wrapper, then switch check_platform to call it directly. This unblocks the phpinfo-related panic in diagnose; the ignored tests now hit a separate RefCell double-borrow bug in check_http, so their ignore reasons are updated to point at that instead.
2026-07-20test(fund-command): match PHP tester options for deterministic displaynsfisis
capture_stderr_separately routed the tester through ConsoleOutput, which detects color/hyperlink support from the real process STDOUT before the stream is swapped to the memory buffer. When STDOUT is a real tty, decoration leaks into the captured output. The PHP original never passes this option and get_error_output() was unused here, so drop it to match and keep the assertion deterministic.
2026-07-20test(show-command): ignore test_self over UTC-only date() timezone gapnsfisis
The shim date() renders in UTC only (no timezone database) while PHP's date() uses the system default timezone, so get_relative_time misses the "today" match and prints "this week" whenever the local date differs from the UTC date (daily 00:00-09:00 JST on this machine). Verified by running the test with and without TZ=UTC at 07:40 JST. Mark the gap with a TODO(phase-c) in the shim; fixing it needs a timezone database (a new crate), which is a user decision. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(zip): detail why the zip-extension test stays ignorednsfisis
PHP only runs this test when the zip extension is not loaded; the Rust port has unconditional zip support, so that precondition cannot exist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(repository-manager): un-ignore test_repo_creationnsfisis
The ignore reason was stale: create_repository_by_class now dispatches every repository class this test registers, and the test passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(github-driver): defer get_branches until tags search missesnsfisis
PHP's `?:` chain in getComposerInformation short-circuits, so getBranches() only runs when the tags search is falsy. The eager port issued an extra git/refs/heads API request that PHP never makes. Un-ignore test_public_repository_archived, which this fixes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(platform-repository): name real test_library_information blockersnsfisis
The previous ignore reason blamed unmodeled extension info; the actual blockers are the TODO(plugin) stubs resource_bundle_get (returns Null, dropping lib-icu-cldr) and imagick_get_version_string (returns "", dropping lib-imagick-imagemagick), both pending dynamic method dispatch on PHP objects via the plugin RPC mechanism. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(composer-repository): un-ignore test_what_providesnsfisis
The ignore reason went stale: AliasPackage::get_source_type is implemented (delegates to alias_of) and the test passes as-is. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(semver): stop classical pattern matching 6+ digit versionsnsfisis
The regex crate parses PCRE's possessive \d{1,5}+ as a stacked repetition (?:\d{1,5})+, i.e. \d+, so date versions like 20121020 matched the classical pattern and normalized to 20121020.0.0.0 instead of falling through to the date(time) pattern like PHP. The plain \d{1,5} is equivalent to the possessive form here per the regex-porting rules. Un-ignore test_find_recommended_require_version which this had blocked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(config): drop insecure git protocol under secure-httpnsfisis
Config::get("github-protocols") ported PHP's array_search over the protocol list via a string-keyed map, but array_search_mixed returns the matched index as PhpMixed::Int, which the as_string() read never matched, so the git protocol was never removed (Config.php:447-449 removes it whenever secure-http is on). Search the list directly and read the index as an Int. Un-ignore test_update_throws_runtime_exception_if_git_command_fails which this had blocked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(config): restore PHP (int) cast for ttl and timeout valuesnsfisis
PHP's Config::get() applies an (int) cast to cache-files-ttl, cache-ttl, and the process-timeout env override (Config.php:326,367,398), so string values like '99999999' become integers. The strict PhpMixed::as_int returned None for strings, collapsing them to 0. Use the intval shim, which implements the PHP cast, and un-ignore test_cache_garbage_collection_is_called which this had blocked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(update-command): un-ignore test_interactive_tmp via assoc select choicesnsfisis
PHP's UpdateCommand::getPackagesInteractively passes $autocompleterValues keyed by package name to $io->select, so the selection resolves to package names. The port passed only the keys as a list, making select resolve to a numeric index that the update then treated as an unknown package. The old ignore reason (non-interactive terminal error) no longer applied. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(io): widen IOInterface::select choices to PhpMixed for assoc arraysnsfisis
PHP's IOInterface::select accepts an associative choices array whose keys are the selectable values, but the port narrowed it to Vec<String>, making key-based selection unrepresentable. Accept PhpMixed (List or Array) like PHP's array $choices; ConsoleIO already branched on both shapes internally. Also mirror PHP in the single-select array_search fallback for numeric-keyed arrays. All call sites keep their previous list-based behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(path-repository): un-ignore test_url_remains_relativensfisis
The PHP test implicitly requires the process cwd to be an ancestor of the Fixtures dir (phpunit runs inside the composer checkout); cargo runs tests from the crate manifest dir, which is not. Replicate the phpunit precondition with a drop-restoring CwdGuard chdir'ing to the __DIR__ equivalent, and serialize it (together with the only other cwd-mutating test in the repository binary, test_repository_writes_installed_php) via #[serial] so the process-global cwd cannot race. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(installation-manager): un-ignore test_add_remove_installernsfisis
Add the __add_installer test seam that registers an installer as a pre-built Rc handle, so the test can reproduce PHP's object-identity semantics (assertSame / removeInstaller) via Rc::ptr_eq; add_installer cannot serve because Rc::from(Box) reallocates, losing the caller's pointer identity. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(run-script-command): detail dev-mode test ignore blockersnsfisis
Re-verified the reason: besides the missing as_any seam on EventInterface (a cross-cutting trait change over every event type), the mocked dispatchScript call expectation is also inexpressible since dispatch_script is a concrete method with no call-recording seam. Record both blockers in the ignore string and TODO(phase-d) comment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(console-io): un-ignore test_write_error via setErrorOutputnsfisis
The ignore reason had rotted: ConsoleOutputInterface::set_error_output is already ported, so a BufferedOutput error sink can be injected into a real ConsoleOutput and the error-routed write read back, matching the file's convention of replacing PHPUnit mock expectations with BufferedOutput assertions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(event-dispatcher): un-ignore test_dispatcher_support_for_additional_argsnsfisis
The only missing seam was the PHP test's ReflectionMethod(getPhpExecCommand) access; add the test-only __get_php_exec_command wrapper and port the test on the existing get_listeners override and process-executor mock infrastructure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(auditor): restore instanceof ConsoleIO semantics for BufferIOnsfisis
PHP's BufferIO extends ConsoleIO, so $io instanceof ConsoleIO matches it; the port models that inheritance as composition, making the plain ConsoleIO downcast reject BufferIO and throw where PHP renders tables. Also try a BufferIO downcast and unwrap its inner ConsoleIO, which unblocks the two FORMAT_TABLE cases and un-ignores test_audit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(installation-manager): detail test_execute ignore reasonnsfisis
Spell out why the existing __new_mock seam cannot serve: it replaces execute() wholesale (skipping the download step, ref InstallationManagerMock), while the PHP test runs the real execute() and spies only on the three per-operation methods it dispatches to. A per-method spy on the real path would be a production design change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(event-dispatcher): correct dev-mode test ignore reasonnsfisis
The old reason blamed missing mock infrastructure, but a spy against dyn AutoloadGeneratorInterface is perfectly writable. The actual blocker is that make_autoloader (PHP makeAutoloader, called from doDispatch's script branches, where setDevMode is invoked) is an intentional no-op in the port, so set_dev_mode is never reached and a spy would observe nothing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(completion-functional): detail test_complete ignore blockersnsfisis
Beyond the missing CommandCompletionTester harness, the PHP test's expected suggestions depend on the Composer dev checkout environment (its own composer.json/lock, installed vendor packages) and live Packagist queries, which the port cannot reproduce without a fixture environment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(event-dispatcher): un-ignore test_dispatcher_outputs_commandnsfisis
The ignore reason went stale: the getListeners override seam and a real ProcessExecutor wired to the IO already cover the PHP setup, and IOStub is the PHPUnit IOInterface-mock equivalent. IOStub now records writeError calls (writeRaw was already recorded) so the expects(once)->with(...) spies on writeError/writeRaw can be reproduced as call-list equality assertions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(git-downloader): un-ignore test_remove via FilesystemMock path seamnsfisis
The ignore reason went stale: the FilesystemMock seam added for FileDownloaderTest already intercepts removeDirectoryAsync, and the sibling fossil/hg testRemove ports use it. The seam now records the removed directories instead of a bare call count so the PHP ->with($this->equalTo($this->workingDir)) argument assertion can be reproduced faithfully. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(diagnose-command): detail ignore reasons with the actual blockernsfisis
The tests fail before any network access: DiagnoseCommand::check_platform captures phpinfo() via ob_start()/ob_get_clean(), which are todo!() in shirabe-php-shim, so the command panics before producing output. Record that as the primary blocker alongside the live-network requirement. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(remote-filesystem): read scheme-less local paths in get_remote_contentsnsfisis
PHP's getRemoteContents calls file_get_contents unconditionally: the same stream wrapper reads file:// URLs, plain local paths and network schemes. The Rust port only handled the explicit "file" scheme, so a scheme-less local packages.json repository failed with "file could not be downloaded". Extend the local branch to empty schemes; the http(s) stub is unchanged. This clears the first blocker of the create-project functional test; its ignore reason now documents the remaining ones (live network and Glob::to_regex emitting PCRE lookaheads the regex crate cannot compile), which need a user decision. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(version-guesser): un-ignore test_hg_guess_version_returns_datansfisis
The ignore reason went stale: HttpDownloader is reqwest-based now, so building it for HgDriver no longer reaches curl_multi_init() (todo!() in shirabe-php-shim::curl). Test content unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20test(zip-downloader): un-ignore test_error_messages, reason went stalensfisis
The file:// branch of RemoteFilesystem::get_remote_contents is now implemented, so the dist download reaches the ZipArchive "is not a zip archive" path the test asserts. Test content unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(validating-array-loader): un-ignore test_fund_command by fixing empty checknsfisis
validate_array judged emptiness via as_array(), which only matches PhpMixed::Array, so a non-empty PhpMixed::List (e.g. a funding array) was misjudged as empty and dropped, diverging from PHP's !count() check. Match both Array and List. The stale ignore reason on test_fund_command no longer applies: init_temp_composer injects packagist:false so no network is reached, and the downloader stack is reqwest-based (no curl shim todo!()). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20fix(process-executor): un-ignore 11 tests by implementing execute_async mock ↵nsfisis
support ProcessExecutor::execute_async's mock branch was an unimplemented todo!(), blocking every test whose code path calls it (feature-branch git diffing, system-unzip/7z fallback extraction). Implement it by: - Adding Process::__mock (mirroring the existing ZipArchive::__mock pattern) so execute_async can resolve with a fabricated, already- terminated Process instead of spawning a real subprocess. - Extracting the sync mock's expectation-matching logic into a shared ProcessExecutor::mock_match, wrapping the mock state in a RefCell so it works from execute_async's &self/&mut self receivers. - Setting error_output/capture_output from the mock branch, matching PHP's ProcessExecutorMock::executeAsync sharing doExecute with the sync path; execute_async now takes &mut self for this (safe, since the borrow only needs to live through the synchronous setup, not across the .await). - Turning a strict-mode expectation mismatch from a panic!() into a shirabe_php_shim::RuntimeException Err, mirroring PHPUnit's AssertionFailedError extending \RuntimeException: PHP call sites that catch (\RuntimeException $e) around a mocked git/hg/svn call (e.g. Git::get_mirror_default_branch, GitDriver::supports) treat a mismatch as an ordinary recoverable failure, and now so does the port. The RefMut is dropped before firing an expectation's optional callback so a re-entrant callback doesn't panic on double-borrow. Also fixes two real bugs found while porting test_private_repository_ no_interaction: GitHub::authorize_oauth and GitLab::authorize_oauth checked their domains config via PhpMixed::as_array(), which only matches the Array (map) variant, but github-domains/gitlab-domains default to PhpMixed::List, so the check always returned false and OAuth token lookup was silently skipped. Use the in_array shim instead, matching PHP's in_array() semantics. Also fix Git::run_command's "capture credentials from git remote -v" call, which used the panic- swallowing execute_args wrapper instead of a fallible execute(), so a mock mismatch there couldn't reach get_mirror_default_branch's catch. Un-ignores: - zip_downloader_test::test_system_unzip_only_{good,failed} - zip_downloader_test::test_non_windows_fallback_{good,failed} - event_dispatcher_test::test_dispatcher_outputs_error_on_failed_command - root_package_loader_test::test_feature_branch_pretty_version - version_guesser_test::test_guess_version_reads_and_respects_non_feature_branches_configuration_for_arbitrary_naming{,_regex} - version_guesser_test::test_remote_branches_are_selected - github_driver_test::test_private_repository_no_interaction (also adds the missing #[serial], since it seeds the shared Git::VERSION static that vcs_repository_test::test_load_versions depends on for real) - init_command_test::test_get_git_config, made deterministic by pointing HOME at a throwaway dir with its own .gitconfig instead of depending on the host's global git config Deduplicates the GitVersionGuard/RestoreEnv test-drop-guard idioms into tests/common/test_case.rs instead of reimplementing them per file. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19fix(root-package-loader): un-ignore 4 tests by fixing stability-flag isset() ↵nsfisis
port extract_stability_flags ported PHP's `isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability` as `unwrap_or(i64::MAX) > stability`, so the check always short-circuited to "already more unstable" and no flag (e.g. from an explicit `*@dev` requirement) was ever recorded. Fixed using Option::is_some_and, a direct translation of PHP's isset() && ... check. Also fixes tests/common/test_case.rs's shared installation_manager() helper, which built a real InstallationManager::new instead of the __new_mock constructor (mirroring PHP's FactoryMock::createInstallationManager()), so it always had zero installers registered and wrote install-path: null into fixture installed.json files. Un-ignores test_reinstall_command, test_locally_modified_packages_from_source/ _from_dist, and test_package_still_present_error_when_no_install_flag_used — the first three were already passing (their #[ignore] reasons were stale), the last is fixed by the test_case.rs change above. Updates the #[ignore] reasons on installer_test.rs's three fixture-driven integration tests to reflect their current state: the install pipeline now runs end-to-end, but the ~189-fixture installer/ set still hits several independent, unrelated bugs/gaps that need case-by-case triage rather than a single fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19fix(show-command): un-ignore 10 tests by fixing show-warnings typing and ↵nsfisis
repo bugs Replace the PhpMixed-based `$showWarnings` hack in VersionSelector:: findBestCandidate with a typed ShowWarnings enum (Always / Predicate), letting ShowCommand::findLatestPackage pass its real closure instead of hardcoding `true`. Fix the --no-dev branch in ShowCommand::execute, which built `repos` from an empty package list instead of sharing the same InstalledRepository as `installed_repo`. Pass repository handles instead of pre-borrowed `&dyn RepositoryInterface` refs into get_package/ generate_package_tree/add_tree to stop a RefCell double-borrow panic on --all/--locked. Add the missing CompletePackage/RootPackage set_release_date setter so the outdated sorting-by-age test can set fixture dates. Resolve OutputFormatterStyleStack::pop's empty-style todo!() via clone_box(), and fix FileDownloader's cache-GC log call to pass the VERY_VERBOSE verbosity PHP uses. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19fix(search-command): un-ignore test_search by fixing JSON output and ↵nsfisis
abandoned propagation The json format branch ignored search results entirely and always wrote null. Encode results into the same name/description/abandoned/url shape Composer's array-backed repositories produce. Also fix ComposerRepository's RepositoryInterface::search adapter, which dropped the abandoned field from raw API results even when present.