diff --git a/bin/phunkie b/bin/phunkie index b1e0b9a..21a5784 100755 --- a/bin/phunkie +++ b/bin/phunkie @@ -85,6 +85,7 @@ use function Phunkie\Console\Functions\{setColors, printBanner, loadHistory, sav if (isset($args[1]) && !str_starts_with($args[1], '-')) { $className = $args[1]; + if (class_exists($className) && is_subclass_of($className, IOApp::class)) { $app = new $className(); } diff --git a/tests/Acceptance/ReplSteps.php b/tests/Acceptance/ReplSteps.php index 7a3db2d..15cf9a0 100644 --- a/tests/Acceptance/ReplSteps.php +++ b/tests/Acceptance/ReplSteps.php @@ -44,24 +44,33 @@ public function __construct() private function startRepl(string $command = 'php bin/phunkie'): void { - if ($command !== 'php bin/phunkie' && $command !== 'php bin/phunkie -c') { + $isIOAppCommand = $command !== 'php bin/phunkie' && $command !== 'php bin/phunkie -c'; + + if ($isIOAppCommand) { // Non-standard command means we need to test the actual process $this->useProcessManager = true; } if ($this->useProcessManager) { $this->processManager->start($command); - $stdout = $this->processManager->getStdout(); - if ($stdout !== null) { - $newOutput = ReplOutputReader::readOutput($stdout); - $this->output .= $newOutput; - } - // Also capture stderr for debugging - $stderr = $this->processManager->getStderr(); - if ($stderr !== null) { - $errorOutput = ReplOutputReader::readOutput($stderr); - if ($errorOutput !== '') { - $this->output .= "\n[STDERR]: " . $errorOutput; + + if ($isIOAppCommand) { + // For IOApp commands, wait for the process to complete and capture all output + $this->waitForProcessAndCaptureOutput(); + } else { + // For REPL mode, read available output + $stdout = $this->processManager->getStdout(); + if ($stdout !== null) { + $newOutput = ReplOutputReader::readOutput($stdout); + $this->output .= $newOutput; + } + // Also capture stderr for debugging + $stderr = $this->processManager->getStderr(); + if ($stderr !== null) { + $errorOutput = ReplOutputReader::readOutput($stderr); + if ($errorOutput !== '') { + $this->output .= "\n[STDERR]: " . $errorOutput; + } } } } else { @@ -71,6 +80,66 @@ private function startRepl(string $command = 'php bin/phunkie'): void } } + private function waitForProcessAndCaptureOutput(): void + { + $stdout = $this->processManager->getStdout(); + $stderr = $this->processManager->getStderr(); + + // Wait for the process to complete (up to 5 seconds) + $maxWait = 5.0; + $startTime = microtime(true); + + while ((microtime(true) - $startTime) < $maxWait) { + // Read any available stdout + if ($stdout !== null) { + $read = [$stdout]; + $write = null; + $except = null; + if (stream_select($read, $write, $except, 0, 100000) > 0) { // 100ms timeout + $chunk = stream_get_contents($stdout); + if ($chunk !== false && $chunk !== '') { + $this->output .= $chunk; + } + } + } + + // Read any available stderr + if ($stderr !== null) { + $read = [$stderr]; + $write = null; + $except = null; + if (stream_select($read, $write, $except, 0, 10000) > 0) { // 10ms timeout + $chunk = stream_get_contents($stderr); + if ($chunk !== false && $chunk !== '') { + $this->output .= "\n[STDERR]: " . $chunk; + } + } + } + + // Check if process has exited + $status = $this->processManager->getStatus(); + if ($status !== null && !$status['running']) { + // Process has exited, read any remaining output + usleep(50000); // 50ms grace period for buffered output + if ($stdout !== null) { + $remaining = stream_get_contents($stdout); + if ($remaining !== false && $remaining !== '') { + $this->output .= $remaining; + } + } + if ($stderr !== null) { + $remaining = stream_get_contents($stderr); + if ($remaining !== false && $remaining !== '') { + $this->output .= "\n[STDERR]: " . $remaining; + } + } + break; + } + + usleep(10000); // 10ms sleep between checks + } + } + private function sendInput(string $input): void { // Check if input defines a class/function/trait/interface/enum diff --git a/tests/Acceptance/Support/ReplProcessManager.php b/tests/Acceptance/Support/ReplProcessManager.php index 640faca..024d5c7 100644 --- a/tests/Acceptance/Support/ReplProcessManager.php +++ b/tests/Acceptance/Support/ReplProcessManager.php @@ -80,6 +80,14 @@ public function isRunning(): bool return $this->process !== null; } + public function getStatus(): ?array + { + if ($this->process === null) { + return null; + } + return proc_get_status($this->process); + } + public function terminate(): void { if ($this->process !== null) {