From c56c431ed4e18551ec072d925cb7b45330accbcd Mon Sep 17 00:00:00 2001 From: Ewout Pieter den Ouden Date: Fri, 23 Nov 2018 20:20:08 +0100 Subject: [PATCH] Rewrite TestDox buffering logic --- src/Util/TestDox/CliTestDoxPrinter.php | 117 ++++++++++++++++--------- src/Util/TestResultCache.php | 37 ++++---- 2 files changed, 97 insertions(+), 57 deletions(-) diff --git a/src/Util/TestDox/CliTestDoxPrinter.php b/src/Util/TestDox/CliTestDoxPrinter.php index f86593edc44..b46f93da49f 100644 --- a/src/Util/TestDox/CliTestDoxPrinter.php +++ b/src/Util/TestDox/CliTestDoxPrinter.php @@ -18,7 +18,6 @@ use PHPUnit\Runner\PhptTestCase; use PHPUnit\Runner\TestResultCache; use PHPUnit\TextUI\ResultPrinter; -use PHPUnit\Util\TestDox\TestResult as TestDoxTestResult; use SebastianBergmann\Timer\Timer; /** @@ -28,7 +27,7 @@ class CliTestDoxPrinter extends ResultPrinter { /** - * @var TestDoxTestResult[] + * @var int[] */ private $nonSuccessfulTestResults = []; @@ -40,12 +39,12 @@ class CliTestDoxPrinter extends ResultPrinter /** * @var int The number of test results received from the TestRunner */ - private $testCount = 0; + private $testIndex = 0; /** * @var int The number of test results already sent to the output */ - private $testFlushCount = 0; + private $testFlushIndex = 0; /** * @var array Buffer for write() @@ -122,23 +121,25 @@ public function endTest(Test $test, float $time): void } if ($test instanceof TestCase || $test instanceof PhptTestCase) { - $this->testCount++; + $this->testIndex++; } if ($this->lastTestFailed) { $msg = $this->msg; - $this->nonSuccessfulTestResults[] = [ - 'className' => $this->className, - 'message' => $this->msg, - ]; + $this->nonSuccessfulTestResults[] = $this->testIndex; } else { $msg = $this->formatTestResultMessage($this->formatWithColor('fg-green', '✔'), '', $time, $this->verbose); } if ($this->bufferExecutionOrder) { $this->bufferTestResult($test, $msg); + $this->flushOutputBuffer(); } else { $this->writeTestResult($msg); + + if ($this->lastTestFailed) { + $this->bufferTestResult($test, $msg); + } } parent::endTest($test, $time); @@ -182,35 +183,19 @@ public function addSkippedTest(Test $test, \Throwable $t, float $time): void public function bufferTestResult(Test $test, string $msg): void { - $testName = TestResultCache::getTestSorterUID($test); - - if ($testName == $this->originalExecutionOrder[$this->testFlushCount]) { - $prevClassName = $this->lastFlushedClassName(); - $msg = $this->formatTestSuiteHeader($prevClassName, $this->className, $msg); - $this->write($msg); - $this->testFlushCount++; - - $prevClassName = $this->className; - - while ($this->testFlushCount < $this->testCount && isset($this->outputBuffer[$this->originalExecutionOrder[$this->testFlushCount]])) { - $result = $this->outputBuffer[$this->originalExecutionOrder[$this->testFlushCount++]]; -// print "** flush $prevClassName {$result['className']}\n"; - $msg = $this->formatTestSuiteHeader($prevClassName, $result['className'], $result['message']); - $this->write($msg); - $prevClassName = $result['className']; - } - } else { - $this->outputBuffer[$testName] = [ - 'className' => $this->className, - 'message' => $msg, - ]; - } + $this->outputBuffer[$this->testIndex] = [ + 'className' => $this->className, + 'testName' => TestResultCache::getTestSorterUID($test), + 'message' => $msg, + 'failed' => $this->lastTestFailed, + 'verbose' => $this->lastFlushedTestWasVerbose, + ]; } public function writeTestResult(string $msg): void { $msg = $this->formatTestSuiteHeader($this->lastClassName, $this->className, $msg); - parent::write($msg); + $this->write($msg); } public function writeProgress(string $progress): void @@ -236,13 +221,54 @@ protected function printHeader(): void $this->write("\n" . Timer::resourceUsage() . "\n\n"); } - private function lastFlushedClassName(): string + private function flushOutputBuffer(): void + { + if ($this->testFlushIndex === $this->testIndex) { + return; + } +// print "## flush fi={$this->testFlushIndex} / i={$this->testIndex}\n"; + + if ($this->testFlushIndex > 0) { + $prevResult = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex - 1]); + } else { + $prevResult = $this->getEmptyTestResult(); + } + + do { + $flushed = false; +// print "# next: {$this->originalExecutionOrder[$this->testFlushIndex]}\n"; + $result = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex]); + + if (!empty($result)) { + // Write spacer line for new suite headers and after verbose messages + if ($prevResult['testName'] !== '' && + ($prevResult['verbose'] === true || $prevResult['className'] !== $result['className'])) { + $this->write("\n"); + } + + // Write suite header + if ($prevResult['className'] !== $result['className']) { + $this->write($result['className'] . "\n"); + } + + // Write the test result itself + $this->write($result['message']); + $this->testFlushIndex++; + $prevResult = $result; + $flushed = true; + } + } while ($flushed && $this->testFlushIndex < $this->testIndex); + } + + private function getTestResultByName(string $testName): array { - if ($this->testFlushCount === 0) { - return '_'; + foreach ($this->outputBuffer as $result) { + if ($result['testName'] === $testName) { + return $result; + } } - return $this->outputBuffer[$this->originalExecutionOrder[$this->testFlushCount - 1]]['className'] ?? ''; + return []; } private function formatTestSuiteHeader(?string $lastClassName, string $className, string $msg): string @@ -250,7 +276,7 @@ private function formatTestSuiteHeader(?string $lastClassName, string $className if ($lastClassName === null || $className !== $lastClassName) { return \sprintf( "%s%s\n%s", - ($this->testFlushCount > 0) ? "\n" : '', + ($this->testFlushIndex > 0) ? "\n" : '', $className, $msg ); @@ -326,11 +352,24 @@ private function printNonSuccessfulTestsSummary(int $numberOfExecutedTests): voi $prevClassName = ''; - foreach ($this->nonSuccessfulTestResults as $result) { + foreach ($this->nonSuccessfulTestResults as $testIndex) { + $result = $this->outputBuffer[$testIndex]; + $msg = $this->formatTestSuiteHeader($prevClassName, $result['className'], $result['message']); $msg = \strpos($msg, "\n") === 0 ? $msg : "\n$msg"; $this->write($msg); $prevClassName = $result['className']; } } + + private function getEmptyTestResult(): array + { + return [ + 'className' => '', + 'testName' => '', + 'message' => '', + 'failed' => '', + 'verbose' => '', + ]; + } } diff --git a/src/Util/TestResultCache.php b/src/Util/TestResultCache.php index 077d5b44b3c..05bd4811a15 100644 --- a/src/Util/TestResultCache.php +++ b/src/Util/TestResultCache.php @@ -64,6 +64,25 @@ class TestResultCache implements \Serializable, TestResultCacheInterface */ private $times = []; + public static function getTestSorterUID(Test $test): string + { + if ($test instanceof PhptTestCase) { + return $test->getName(); + } + + if ($test instanceof TestCase) { + $testName = $test->getName(true); + + if (\strpos($testName, '::') === false) { + $testName = \get_class($test) . '::' . $testName; + } + + return $testName; + } + + return $test->getName(); + } + public function __construct($filename = null) { $this->cacheFilename = $filename ?? $_ENV['PHPUNIT_RESULT_CACHE'] ?? self::DEFAULT_RESULT_CACHE_FILENAME; @@ -193,22 +212,4 @@ private function createDirectory(string $directory): bool { return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory)); } - - public static function getTestSorterUID(Test $test): string - { - if ($test instanceof PhptTestCase) { - return $test->getName(); - } - - if ($test instanceof TestCase) { - $testName = $test->getName(true); - - if (\strpos($testName, '::') === false) { - $testName = \get_class($test) . '::' . $testName; - } - return $testName; - } - - return $test->getName(); - } }