diff --git a/src/Render/TerminalInterceptor.php b/src/Render/TerminalInterceptor.php index 3720e85..bcbb687 100644 --- a/src/Render/TerminalInterceptor.php +++ b/src/Render/TerminalInterceptor.php @@ -4,18 +4,22 @@ namespace Testo\Render; -use Testo\Interceptor\TestCaseRunInterceptor; -use Testo\Interceptor\TestRunInterceptor; -use Testo\Interceptor\TestSuiteRunInterceptor; +use Testo\Common\Container; +use Testo\Config\EventListenerCollector; +use Testo\Config\PluginConfigurator; use Testo\Render\Terminal\ColorMode; use Testo\Render\Terminal\Style; use Testo\Render\Terminal\TerminalLogger; -use Testo\Test\Dto\CaseInfo; -use Testo\Test\Dto\CaseResult; -use Testo\Test\Dto\SuiteInfo; -use Testo\Test\Dto\SuiteResult; use Testo\Test\Dto\TestInfo; -use Testo\Test\Dto\TestResult; +use Testo\Test\Event\Test\TestBatchFinished; +use Testo\Test\Event\Test\TestBatchStarting; +use Testo\Test\Event\Test\TestDataSetFinished; +use Testo\Test\Event\Test\TestDataSetStarting; +use Testo\Test\Event\Test\TestPipelineFinished; +use Testo\Test\Event\TestCase\TestCaseFinished; +use Testo\Test\Event\TestCase\TestCaseStarting; +use Testo\Test\Event\TestSuite\TestSuiteFinished; +use Testo\Test\Event\TestSuite\TestSuiteStarting; /** * Terminal interceptor for rendering test results with configurable output. @@ -23,11 +27,15 @@ * Implements StdoutRenderer to ensure only one stdout renderer is active. * Supports multiple output formats (Compact, Verbose, Dots) and color modes. */ -final class TerminalInterceptor implements - TestRunInterceptor, - TestCaseRunInterceptor, - TestSuiteRunInterceptor +final class TerminalInterceptor implements PluginConfigurator { + /** + * Tracks whether we're inside a DataProvider batch. + * + * @var array + */ + private array $isBatch = []; + public function __construct( private readonly TerminalLogger $logger, ColorMode $colorMode = ColorMode::Always, @@ -36,48 +44,96 @@ public function __construct( Style::setColorsEnabled($colorMode->shouldUseColors()); } - public function runTest(TestInfo $info, callable $next): TestResult + public function configure(Container $container): void { - $this->logger->testStartedFromInfo($info); + $listeners = $container->get(EventListenerCollector::class); + + // Test Pipeline events (lifecycle of entire test through all interceptors) + $listeners->addListener(TestPipelineFinished::class, $this->onTestPipelineFinished(...)); + + // Test Batch events (for DataProvider) + $listeners->addListener(TestBatchStarting::class, $this->onTestBatchStarting(...)); + $listeners->addListener(TestBatchFinished::class, $this->onTestBatchFinished(...)); + + // DataSet events (for individual datasets within DataProvider) + $listeners->addListener(TestDataSetStarting::class, $this->onTestDataSetStarting(...)); + $listeners->addListener(TestDataSetFinished::class, $this->onTestDataSetFinished(...)); + + // TestCase events + $listeners->addListener(TestCaseStarting::class, $this->onTestCaseStarting(...)); + $listeners->addListener(TestCaseFinished::class, $this->onTestCaseFinished(...)); - $start = \microtime(true); - /** @var TestResult $result */ - $result = $next($info); - $duration = (int) \round((\microtime(true) - $start) * 1000); + // TestSuite events + $listeners->addListener(TestSuiteStarting::class, $this->onTestSuiteStarting(...)); + $listeners->addListener(TestSuiteFinished::class, $this->onTestSuiteFinished(...)); + } + + private static function getId(TestInfo $testInfo): string + { + return \spl_object_hash($testInfo->testDefinition); + } + + private function onTestPipelineFinished(TestPipelineFinished $event): void + { + // Check if this test was inside a DataProvider batch + $id = self::getId($event->testInfo); + if (isset($this->isBatch[$id])) { + // DataProvider test - already handled in dataset events + unset($this->isBatch[$id]); + return; + } - $this->logger->handleTestResult($result, $duration); - return $result; + // Regular test without DataProvider - log it now + $this->logger->testStartedFromInfo($event->testInfo); + $duration = (int) $event->testResult->getAttribute('duration'); + $this->logger->handleTestResult($event->testResult, $duration); } - public function runTestCase(CaseInfo $info, callable $next): CaseResult + private function onTestBatchStarting(TestBatchStarting $event): void { - $this->logger->caseStartedFromInfo($info); + // Mark that we're inside a batch + $id = self::getId($event->testInfo); + $this->isBatch[$id] = true; + } - /** @var CaseResult $result */ - $result = $next($info); + private function onTestBatchFinished(TestBatchFinished $event): void + { + // Batch finished - cleanup is done in TestPipelineFinished + } - $this->logger->handleCaseResult($info, $result); - return $result; + private function onTestDataSetStarting(TestDataSetStarting $event): void + { + // Log individual dataset start + $this->logger->testStartedFromInfo($event->testInfo); } - public function runTestSuite(SuiteInfo $info, callable $next): SuiteResult + private function onTestDataSetFinished(TestDataSetFinished $event): void { - $this->logger->suiteStartedFromInfo($info); + // Handle individual dataset result + $duration = (int) $event->testResult->getAttribute('duration'); + $this->logger->handleTestResult($event->testResult, $duration); + } - /** @var SuiteResult $result */ - $result = $next($info); + private function onTestCaseStarting(TestCaseStarting $event): void + { + $this->logger->caseStartedFromInfo($event->caseInfo); + } - $this->logger->handleSuiteResult($info, $result); + private function onTestCaseFinished(TestCaseFinished $event): void + { + $this->logger->handleCaseResult($event->caseInfo, $event->caseResult); + } - return $result; + private function onTestSuiteStarting(TestSuiteStarting $event): void + { + $this->logger->suiteStartedFromInfo($event->suiteInfo); } - /** - * Prints final summary after all tests complete. - * Should be called after test execution finishes. - */ - public function printSummary(): void + private function onTestSuiteFinished(TestSuiteFinished $event): void { + $this->logger->handleSuiteResult($event->suiteInfo, $event->suiteResult); + + // Print final summary after all tests in suite complete $this->logger->printSummary(); } }