*/ private array $results = []; private ?string $currentTestId = null; private ?float $startTime = null; public function testPrepared(string $testId): void { $this->currentTestId = $testId; $this->startTime = microtime(true); } public function testPassed(): void { if ($this->currentTestId === null) { return; } $this->record(0, ''); } public function testFailed(string $message): void { if ($this->currentTestId === null) { return; } $this->record(7, $message); } public function testErrored(string $message): void { if ($this->currentTestId === null) { return; } $this->record(8, $message); } public function testSkipped(string $message): void { if ($this->currentTestId === null) { return; } $this->record(1, $message); } public function testIncomplete(string $message): void { if ($this->currentTestId === null) { return; } $this->record(2, $message); } public function testRisky(string $message): void { if ($this->currentTestId === null) { return; } $this->record(5, $message); } /** * @return array */ public function all(): array { return $this->results; } public function recordAssertions(string $testId, int $assertions): void { if (isset($this->results[$testId])) { $this->results[$testId]['assertions'] = $assertions; } } /** * Injects externally-collected results (e.g. partials flushed by parallel * workers) into this collector so the parent can persist them in the same * snapshot pass as non-parallel runs. * * @param array $results */ public function merge(array $results): void { foreach ($results as $testId => $result) { $this->results[$testId] = $result; } } public function reset(): void { $this->results = []; $this->currentTestId = null; $this->startTime = null; } /** * Called by the Finished subscriber after a test's outcome + assertion * events have all fired. Clears the "currently recording" pointer so * the next test's events don't get mis-attributed. */ public function finishTest(): void { $this->currentTestId = null; $this->startTime = null; } private function record(int $status, string $message): void { if ($this->currentTestId === null) { return; } $time = $this->startTime !== null ? round(microtime(true) - $this->startTime, 3) : 0.0; // PHPUnit can fire more than one outcome event per test — the // canonical case is a risky pass (`Passed` then `ConsideredRisky`). // Last-wins semantics preserve the most specific status; the // existing assertion count (if any) survives the overwrite. $existing = $this->results[$this->currentTestId] ?? null; $this->results[$this->currentTestId] = [ 'status' => $status, 'message' => $message, 'time' => $time, 'assertions' => $existing['assertions'] ?? 0, ]; } }