$body) { $path = $dir . DIRECTORY_SEPARATOR . $name; file_put_contents($path, $body); chmod($path, 0755); } $originalPath = getenv('PATH') ?: ''; putenv("PATH={$dir}"); $_ENV['PATH'] = $dir; $_SERVER['PATH'] = $dir; try { $callback($dir); } finally { putenv("PATH={$originalPath}"); $_ENV['PATH'] = $originalPath; $_SERVER['PATH'] = $originalPath; if (is_dir($dir)) { $items = scandir($dir); if (is_array($items)) { foreach ($items as $item) { if ($item === '.' || $item === '..') { continue; } $path = $dir . DIRECTORY_SEPARATOR . $item; if (is_file($path)) { unlink($path); } } } rmdir($dir); } } } it('returns system status for admins', function (): void { withFakeBinForStatus([ 'php' => "#!/bin/sh\nif [ \"$1\" = \"-r\" ]; then echo \"8.4.0\"; exit 0; fi\necho \"php\"\n", 'composer' => "#!/bin/sh\necho \"composer 2.0.0\"\n", 'node' => "#!/bin/sh\necho \"v20.0.0\"\n", 'npm' => "#!/bin/sh\necho \"9.0.0\"\n", 'tar' => "#!/bin/sh\necho \"tar 1.2.3\"\n", 'rsync' => "#!/bin/sh\necho \"rsync 3.2.0\"\n", ], function (string $dir): void { $admin = User::factory()->create(); $role = Role::firstOrCreate(['name' => 'ROLE_ADMIN'], ['color' => '#111111']); $admin->roles()->attach($role); $request = Request::create('/api/system/status', 'GET'); $request->setUserResolver(fn () => $admin); $controller = new SystemStatusController(); $response = $controller->__invoke($request); expect($response->getStatusCode())->toBe(200); $payload = $response->getData(true); expect($payload)->toHaveKeys([ 'php', 'php_default', 'composer', 'composer_version', 'node', 'node_version', 'npm', 'npm_version', 'tar', 'tar_version', 'rsync', 'rsync_version', 'proc_functions', 'storage_writable', 'updates_writable', ]); }); }); it('covers binary resolution edge cases', function (): void { withFakeBinForStatus([ 'sh' => "#!/bin/sh\nexit 0\n", ], function (string $dir): void { $controller = new SystemStatusController(); $refBinary = new ReflectionMethod($controller, 'resolveBinary'); $refBinary->setAccessible(true); expect($refBinary->invoke($controller, 'php'))->toBeNull(); }); }); it('returns php version when available', function (): void { withFakeBinForStatus([ 'phpfake' => "#!/bin/sh\nif [ \"$1\" = \"-r\" ]; then echo \"8.4.1\"; exit 0; fi\nexit 0\n", ], function (string $dir): void { $controller = new SystemStatusController(); $refPhp = new ReflectionMethod($controller, 'resolvePhpVersion'); $refPhp->setAccessible(true); $path = $dir . '/phpfake'; expect($refPhp->invoke($controller, $path))->toBe('8.4.1'); }); }); it('returns null php version when command fails', function (): void { withFakeBinForStatus([ 'phpfail' => "#!/bin/sh\nexit 1\n", ], function (string $dir): void { $controller = new SystemStatusController(); $refPhp = new ReflectionMethod($controller, 'resolvePhpVersion'); $refPhp->setAccessible(true); $path = $dir . '/phpfail'; expect($refPhp->invoke($controller, $path))->toBeNull(); }); }); it('returns binary version when regex matches', function (): void { withFakeBinForStatus([ 'tool' => "#!/bin/sh\necho \"tool v1.2.3\"\n", ], function (string $dir): void { $controller = new SystemStatusController(); $refVer = new ReflectionMethod($controller, 'resolveBinaryVersion'); $refVer->setAccessible(true); $path = $dir . '/tool'; expect($refVer->invoke($controller, $path, ['--version']))->toBe('1.2.3'); }); }); it('returns null when binary version output is empty', function (): void { withFakeBinForStatus([ 'empty' => "#!/bin/sh\nexit 0\n", ], function (string $dir): void { $controller = new SystemStatusController(); $refVer = new ReflectionMethod($controller, 'resolveBinaryVersion'); $refVer->setAccessible(true); $path = $dir . '/empty'; expect($refVer->invoke($controller, $path, ['--version']))->toBeNull(); }); }); it('returns null when binary version output has no version', function (): void { withFakeBinForStatus([ 'noversion' => "#!/bin/sh\necho \"tool version unknown\"\n", ], function (string $dir): void { $controller = new SystemStatusController(); $refVer = new ReflectionMethod($controller, 'resolveBinaryVersion'); $refVer->setAccessible(true); $path = $dir . '/noversion'; expect($refVer->invoke($controller, $path, ['--version']))->toBeNull(); }); }); it('returns null when binary version command fails', function (): void { withFakeBinForStatus([ 'fail' => "#!/bin/sh\nexit 1\n", ], function (string $dir): void { $controller = new SystemStatusController(); $refVer = new ReflectionMethod($controller, 'resolveBinaryVersion'); $refVer->setAccessible(true); $path = $dir . '/fail'; expect($refVer->invoke($controller, $path, ['--version']))->toBeNull(); }); }); it('returns empty array when readJson cannot read file', function (): void { $controller = new SystemStatusController(); $ref = new ReflectionMethod($controller, 'readJson'); $ref->setAccessible(true); $path = sys_get_temp_dir() . '/missing.json'; $result = $ref->invoke($controller, $path); expect($result)->toBe([]); }); it('returns empty array when readJson invalid', function (): void { $controller = new SystemStatusController(); $ref = new ReflectionMethod($controller, 'readJson'); $ref->setAccessible(true); $path = sys_get_temp_dir() . '/invalid.json'; file_put_contents($path, 'not-json'); $result = $ref->invoke($controller, $path); unlink($path); expect($result)->toBe([]); }); it('returns empty array when readJson cannot read contents', function (): void { $controller = new SystemStatusController(); $ref = new ReflectionMethod($controller, 'readJson'); $ref->setAccessible(true); $path = storage_path('app/unreadable.json'); file_put_contents($path, '{"a":1}'); chmod($path, 0000); $prev = set_error_handler(static fn () => true); $result = $ref->invoke($controller, $path); restore_error_handler(); chmod($path, 0644); unlink($path); expect($result)->toBe([]); });