Skip to content

Commit

Permalink
Rewrite TestDox buffering logic
Browse files Browse the repository at this point in the history
  • Loading branch information
epdenouden authored and sebastianbergmann committed Nov 26, 2018
1 parent c655a5d commit c56c431
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 57 deletions.
117 changes: 78 additions & 39 deletions src/Util/TestDox/CliTestDoxPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -28,7 +27,7 @@
class CliTestDoxPrinter extends ResultPrinter
{
/**
* @var TestDoxTestResult[]
* @var int[]
*/
private $nonSuccessfulTestResults = [];

Expand All @@ -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()
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -236,21 +221,62 @@ 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
{
if ($lastClassName === null || $className !== $lastClassName) {
return \sprintf(
"%s%s\n%s",
($this->testFlushCount > 0) ? "\n" : '',
($this->testFlushIndex > 0) ? "\n" : '',
$className,
$msg
);
Expand Down Expand Up @@ -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' => '',
];
}
}
37 changes: 19 additions & 18 deletions src/Util/TestResultCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}

0 comments on commit c56c431

Please sign in to comment.