summaryrefslogtreecommitdiff
path: root/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php')
-rw-r--r--vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php388
1 files changed, 388 insertions, 0 deletions
diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php b/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php
new file mode 100644
index 000000000..bd64785c9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php
@@ -0,0 +1,388 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\TestDox;
+
+use const PHP_EOL;
+use function array_map;
+use function get_class;
+use function implode;
+use function method_exists;
+use function preg_split;
+use function trim;
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Reorderable;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestResult;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Runner\BaseTestRunner;
+use PHPUnit\Runner\PhptTestCase;
+use PHPUnit\TextUI\DefaultResultPrinter;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class TestDoxPrinter extends DefaultResultPrinter
+{
+ /**
+ * @var NamePrettifier
+ */
+ protected $prettifier;
+
+ /**
+ * @var int The number of test results received from the TestRunner
+ */
+ protected $testIndex = 0;
+
+ /**
+ * @var int The number of test results already sent to the output
+ */
+ protected $testFlushIndex = 0;
+
+ /**
+ * @var array<int, array> Buffer for test results
+ */
+ protected $testResults = [];
+
+ /**
+ * @var array<string, int> Lookup table for testname to testResults[index]
+ */
+ protected $testNameResultIndex = [];
+
+ /**
+ * @var bool
+ */
+ protected $enableOutputBuffer = false;
+
+ /**
+ * @var array array<string>
+ */
+ protected $originalExecutionOrder = [];
+
+ /**
+ * @var int
+ */
+ protected $spinState = 0;
+
+ /**
+ * @var bool
+ */
+ protected $showProgress = true;
+
+ /**
+ * @param null|resource|string $out
+ * @param int|string $numberOfColumns
+ *
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
+ {
+ parent::__construct($out, $verbose, $colors, $debug, $numberOfColumns, $reverse);
+
+ $this->prettifier = new NamePrettifier($this->colors);
+ }
+
+ public function setOriginalExecutionOrder(array $order): void
+ {
+ $this->originalExecutionOrder = $order;
+ $this->enableOutputBuffer = !empty($order);
+ }
+
+ public function setShowProgressAnimation(bool $showProgress): void
+ {
+ $this->showProgress = $showProgress;
+ }
+
+ public function printResult(TestResult $result): void
+ {
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function endTest(Test $test, float $time): void
+ {
+ if (!$test instanceof TestCase && !$test instanceof PhptTestCase && !$test instanceof TestSuite) {
+ return;
+ }
+
+ if ($this->testHasPassed()) {
+ $this->registerTestResult($test, null, BaseTestRunner::STATUS_PASSED, $time, false);
+ }
+
+ if ($test instanceof TestCase || $test instanceof PhptTestCase) {
+ $this->testIndex++;
+ }
+
+ parent::endTest($test, $time);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ $this->registerTestResult($test, $t, BaseTestRunner::STATUS_ERROR, $time, true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ $this->registerTestResult($test, $e, BaseTestRunner::STATUS_WARNING, $time, true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ $this->registerTestResult($test, $e, BaseTestRunner::STATUS_FAILURE, $time, true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->registerTestResult($test, $t, BaseTestRunner::STATUS_INCOMPLETE, $time, false);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->registerTestResult($test, $t, BaseTestRunner::STATUS_RISKY, $time, false);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->registerTestResult($test, $t, BaseTestRunner::STATUS_SKIPPED, $time, false);
+ }
+
+ public function writeProgress(string $progress): void
+ {
+ $this->flushOutputBuffer();
+ }
+
+ public function flush(): void
+ {
+ $this->flushOutputBuffer(true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void
+ {
+ $testName = $test instanceof Reorderable ? $test->sortId() : $test->getName();
+
+ $result = [
+ 'className' => $this->formatClassName($test),
+ 'testName' => $testName,
+ 'testMethod' => $this->formatTestName($test),
+ 'message' => '',
+ 'status' => $status,
+ 'time' => $time,
+ 'verbose' => $verbose,
+ ];
+
+ if ($t !== null) {
+ $result['message'] = $this->formatTestResultMessage($t, $result);
+ }
+
+ $this->testResults[$this->testIndex] = $result;
+ $this->testNameResultIndex[$testName] = $this->testIndex;
+ }
+
+ protected function formatTestName(Test $test): string
+ {
+ return method_exists($test, 'getName') ? $test->getName() : '';
+ }
+
+ protected function formatClassName(Test $test): string
+ {
+ return get_class($test);
+ }
+
+ protected function testHasPassed(): bool
+ {
+ if (!isset($this->testResults[$this->testIndex]['status'])) {
+ return true;
+ }
+
+ if ($this->testResults[$this->testIndex]['status'] === BaseTestRunner::STATUS_PASSED) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function flushOutputBuffer(bool $forceFlush = false): void
+ {
+ if ($this->testFlushIndex === $this->testIndex) {
+ return;
+ }
+
+ if ($this->testFlushIndex > 0) {
+ if ($this->enableOutputBuffer &&
+ isset($this->originalExecutionOrder[$this->testFlushIndex - 1])) {
+ $prevResult = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex - 1]);
+ } else {
+ $prevResult = $this->testResults[$this->testFlushIndex - 1];
+ }
+ } else {
+ $prevResult = $this->getEmptyTestResult();
+ }
+
+ if (!$this->enableOutputBuffer) {
+ $this->writeTestResult($prevResult, $this->testResults[$this->testFlushIndex++]);
+ } else {
+ do {
+ $flushed = false;
+
+ if (!$forceFlush && isset($this->originalExecutionOrder[$this->testFlushIndex])) {
+ $result = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex]);
+ } else {
+ // This test(name) cannot found in original execution order,
+ // flush result to output stream right away
+ $result = $this->testResults[$this->testFlushIndex];
+ }
+
+ if (!empty($result)) {
+ $this->hideSpinner();
+ $this->writeTestResult($prevResult, $result);
+ $this->testFlushIndex++;
+ $prevResult = $result;
+ $flushed = true;
+ } else {
+ $this->showSpinner();
+ }
+ } while ($flushed && $this->testFlushIndex < $this->testIndex);
+ }
+ }
+
+ protected function showSpinner(): void
+ {
+ if (!$this->showProgress) {
+ return;
+ }
+
+ if ($this->spinState) {
+ $this->undrawSpinner();
+ }
+
+ $this->spinState++;
+ $this->drawSpinner();
+ }
+
+ protected function hideSpinner(): void
+ {
+ if (!$this->showProgress) {
+ return;
+ }
+
+ if ($this->spinState) {
+ $this->undrawSpinner();
+ }
+
+ $this->spinState = 0;
+ }
+
+ protected function drawSpinner(): void
+ {
+ // optional for CLI printers: show the user a 'buffering output' spinner
+ }
+
+ protected function undrawSpinner(): void
+ {
+ // remove the spinner from the current line
+ }
+
+ protected function writeTestResult(array $prevResult, array $result): void
+ {
+ }
+
+ protected function getEmptyTestResult(): array
+ {
+ return [
+ 'className' => '',
+ 'testName' => '',
+ 'message' => '',
+ 'failed' => '',
+ 'verbose' => '',
+ ];
+ }
+
+ protected function getTestResultByName(?string $testName): array
+ {
+ if (isset($this->testNameResultIndex[$testName])) {
+ return $this->testResults[$this->testNameResultIndex[$testName]];
+ }
+
+ return [];
+ }
+
+ protected function formatThrowable(Throwable $t, ?int $status = null): string
+ {
+ $message = trim(\PHPUnit\Framework\TestFailure::exceptionToString($t));
+
+ if ($message) {
+ $message .= PHP_EOL . PHP_EOL . $this->formatStacktrace($t);
+ } else {
+ $message = $this->formatStacktrace($t);
+ }
+
+ return $message;
+ }
+
+ protected function formatStacktrace(Throwable $t): string
+ {
+ return \PHPUnit\Util\Filter::getFilteredStacktrace($t);
+ }
+
+ protected function formatTestResultMessage(Throwable $t, array $result, string $prefix = '│'): string
+ {
+ $message = $this->formatThrowable($t, $result['status']);
+
+ if ($message === '') {
+ return '';
+ }
+
+ if (!($this->verbose || $result['verbose'])) {
+ return '';
+ }
+
+ return $this->prefixLines($prefix, $message);
+ }
+
+ protected function prefixLines(string $prefix, string $message): string
+ {
+ $message = trim($message);
+
+ return implode(
+ PHP_EOL,
+ array_map(
+ static function (string $text) use ($prefix)
+ {
+ return ' ' . $prefix . ($text ? ' ' . $text : '');
+ },
+ preg_split('/\r\n|\r|\n/', $message)
+ )
+ );
+ }
+}