PageRenderTime 42ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php

https://gitlab.com/madwanz64/laravel
PHP | 388 lines | 253 code | 63 blank | 72 comment | 33 complexity | 8b778799a53befed71a00a58f985160d MD5 | raw file
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of PHPUnit.
  4. *
  5. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace PHPUnit\Util\TestDox;
  11. use const PHP_EOL;
  12. use function array_map;
  13. use function get_class;
  14. use function implode;
  15. use function method_exists;
  16. use function preg_split;
  17. use function trim;
  18. use PHPUnit\Framework\AssertionFailedError;
  19. use PHPUnit\Framework\Reorderable;
  20. use PHPUnit\Framework\Test;
  21. use PHPUnit\Framework\TestCase;
  22. use PHPUnit\Framework\TestResult;
  23. use PHPUnit\Framework\TestSuite;
  24. use PHPUnit\Framework\Warning;
  25. use PHPUnit\Runner\BaseTestRunner;
  26. use PHPUnit\Runner\PhptTestCase;
  27. use PHPUnit\TextUI\DefaultResultPrinter;
  28. use Throwable;
  29. /**
  30. * @internal This class is not covered by the backward compatibility promise for PHPUnit
  31. */
  32. class TestDoxPrinter extends DefaultResultPrinter
  33. {
  34. /**
  35. * @var NamePrettifier
  36. */
  37. protected $prettifier;
  38. /**
  39. * @var int The number of test results received from the TestRunner
  40. */
  41. protected $testIndex = 0;
  42. /**
  43. * @var int The number of test results already sent to the output
  44. */
  45. protected $testFlushIndex = 0;
  46. /**
  47. * @var array<int, array> Buffer for test results
  48. */
  49. protected $testResults = [];
  50. /**
  51. * @var array<string, int> Lookup table for testname to testResults[index]
  52. */
  53. protected $testNameResultIndex = [];
  54. /**
  55. * @var bool
  56. */
  57. protected $enableOutputBuffer = false;
  58. /**
  59. * @var array array<string>
  60. */
  61. protected $originalExecutionOrder = [];
  62. /**
  63. * @var int
  64. */
  65. protected $spinState = 0;
  66. /**
  67. * @var bool
  68. */
  69. protected $showProgress = true;
  70. /**
  71. * @param null|resource|string $out
  72. * @param int|string $numberOfColumns
  73. *
  74. * @throws \PHPUnit\Framework\Exception
  75. */
  76. public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
  77. {
  78. parent::__construct($out, $verbose, $colors, $debug, $numberOfColumns, $reverse);
  79. $this->prettifier = new NamePrettifier($this->colors);
  80. }
  81. public function setOriginalExecutionOrder(array $order): void
  82. {
  83. $this->originalExecutionOrder = $order;
  84. $this->enableOutputBuffer = !empty($order);
  85. }
  86. public function setShowProgressAnimation(bool $showProgress): void
  87. {
  88. $this->showProgress = $showProgress;
  89. }
  90. public function printResult(TestResult $result): void
  91. {
  92. }
  93. /**
  94. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  95. */
  96. public function endTest(Test $test, float $time): void
  97. {
  98. if (!$test instanceof TestCase && !$test instanceof PhptTestCase && !$test instanceof TestSuite) {
  99. return;
  100. }
  101. if ($this->testHasPassed()) {
  102. $this->registerTestResult($test, null, BaseTestRunner::STATUS_PASSED, $time, false);
  103. }
  104. if ($test instanceof TestCase || $test instanceof PhptTestCase) {
  105. $this->testIndex++;
  106. }
  107. parent::endTest($test, $time);
  108. }
  109. /**
  110. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  111. */
  112. public function addError(Test $test, Throwable $t, float $time): void
  113. {
  114. $this->registerTestResult($test, $t, BaseTestRunner::STATUS_ERROR, $time, true);
  115. }
  116. /**
  117. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  118. */
  119. public function addWarning(Test $test, Warning $e, float $time): void
  120. {
  121. $this->registerTestResult($test, $e, BaseTestRunner::STATUS_WARNING, $time, true);
  122. }
  123. /**
  124. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  125. */
  126. public function addFailure(Test $test, AssertionFailedError $e, float $time): void
  127. {
  128. $this->registerTestResult($test, $e, BaseTestRunner::STATUS_FAILURE, $time, true);
  129. }
  130. /**
  131. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  132. */
  133. public function addIncompleteTest(Test $test, Throwable $t, float $time): void
  134. {
  135. $this->registerTestResult($test, $t, BaseTestRunner::STATUS_INCOMPLETE, $time, false);
  136. }
  137. /**
  138. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  139. */
  140. public function addRiskyTest(Test $test, Throwable $t, float $time): void
  141. {
  142. $this->registerTestResult($test, $t, BaseTestRunner::STATUS_RISKY, $time, false);
  143. }
  144. /**
  145. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  146. */
  147. public function addSkippedTest(Test $test, Throwable $t, float $time): void
  148. {
  149. $this->registerTestResult($test, $t, BaseTestRunner::STATUS_SKIPPED, $time, false);
  150. }
  151. public function writeProgress(string $progress): void
  152. {
  153. $this->flushOutputBuffer();
  154. }
  155. public function flush(): void
  156. {
  157. $this->flushOutputBuffer(true);
  158. }
  159. /**
  160. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  161. */
  162. protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void
  163. {
  164. $testName = $test instanceof Reorderable ? $test->sortId() : $test->getName();
  165. $result = [
  166. 'className' => $this->formatClassName($test),
  167. 'testName' => $testName,
  168. 'testMethod' => $this->formatTestName($test),
  169. 'message' => '',
  170. 'status' => $status,
  171. 'time' => $time,
  172. 'verbose' => $verbose,
  173. ];
  174. if ($t !== null) {
  175. $result['message'] = $this->formatTestResultMessage($t, $result);
  176. }
  177. $this->testResults[$this->testIndex] = $result;
  178. $this->testNameResultIndex[$testName] = $this->testIndex;
  179. }
  180. protected function formatTestName(Test $test): string
  181. {
  182. return method_exists($test, 'getName') ? $test->getName() : '';
  183. }
  184. protected function formatClassName(Test $test): string
  185. {
  186. return get_class($test);
  187. }
  188. protected function testHasPassed(): bool
  189. {
  190. if (!isset($this->testResults[$this->testIndex]['status'])) {
  191. return true;
  192. }
  193. if ($this->testResults[$this->testIndex]['status'] === BaseTestRunner::STATUS_PASSED) {
  194. return true;
  195. }
  196. return false;
  197. }
  198. protected function flushOutputBuffer(bool $forceFlush = false): void
  199. {
  200. if ($this->testFlushIndex === $this->testIndex) {
  201. return;
  202. }
  203. if ($this->testFlushIndex > 0) {
  204. if ($this->enableOutputBuffer &&
  205. isset($this->originalExecutionOrder[$this->testFlushIndex - 1])) {
  206. $prevResult = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex - 1]);
  207. } else {
  208. $prevResult = $this->testResults[$this->testFlushIndex - 1];
  209. }
  210. } else {
  211. $prevResult = $this->getEmptyTestResult();
  212. }
  213. if (!$this->enableOutputBuffer) {
  214. $this->writeTestResult($prevResult, $this->testResults[$this->testFlushIndex++]);
  215. } else {
  216. do {
  217. $flushed = false;
  218. if (!$forceFlush && isset($this->originalExecutionOrder[$this->testFlushIndex])) {
  219. $result = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex]);
  220. } else {
  221. // This test(name) cannot found in original execution order,
  222. // flush result to output stream right away
  223. $result = $this->testResults[$this->testFlushIndex];
  224. }
  225. if (!empty($result)) {
  226. $this->hideSpinner();
  227. $this->writeTestResult($prevResult, $result);
  228. $this->testFlushIndex++;
  229. $prevResult = $result;
  230. $flushed = true;
  231. } else {
  232. $this->showSpinner();
  233. }
  234. } while ($flushed && $this->testFlushIndex < $this->testIndex);
  235. }
  236. }
  237. protected function showSpinner(): void
  238. {
  239. if (!$this->showProgress) {
  240. return;
  241. }
  242. if ($this->spinState) {
  243. $this->undrawSpinner();
  244. }
  245. $this->spinState++;
  246. $this->drawSpinner();
  247. }
  248. protected function hideSpinner(): void
  249. {
  250. if (!$this->showProgress) {
  251. return;
  252. }
  253. if ($this->spinState) {
  254. $this->undrawSpinner();
  255. }
  256. $this->spinState = 0;
  257. }
  258. protected function drawSpinner(): void
  259. {
  260. // optional for CLI printers: show the user a 'buffering output' spinner
  261. }
  262. protected function undrawSpinner(): void
  263. {
  264. // remove the spinner from the current line
  265. }
  266. protected function writeTestResult(array $prevResult, array $result): void
  267. {
  268. }
  269. protected function getEmptyTestResult(): array
  270. {
  271. return [
  272. 'className' => '',
  273. 'testName' => '',
  274. 'message' => '',
  275. 'failed' => '',
  276. 'verbose' => '',
  277. ];
  278. }
  279. protected function getTestResultByName(?string $testName): array
  280. {
  281. if (isset($this->testNameResultIndex[$testName])) {
  282. return $this->testResults[$this->testNameResultIndex[$testName]];
  283. }
  284. return [];
  285. }
  286. protected function formatThrowable(Throwable $t, ?int $status = null): string
  287. {
  288. $message = trim(\PHPUnit\Framework\TestFailure::exceptionToString($t));
  289. if ($message) {
  290. $message .= PHP_EOL . PHP_EOL . $this->formatStacktrace($t);
  291. } else {
  292. $message = $this->formatStacktrace($t);
  293. }
  294. return $message;
  295. }
  296. protected function formatStacktrace(Throwable $t): string
  297. {
  298. return \PHPUnit\Util\Filter::getFilteredStacktrace($t);
  299. }
  300. protected function formatTestResultMessage(Throwable $t, array $result, string $prefix = '│'): string
  301. {
  302. $message = $this->formatThrowable($t, $result['status']);
  303. if ($message === '') {
  304. return '';
  305. }
  306. if (!($this->verbose || $result['verbose'])) {
  307. return '';
  308. }
  309. return $this->prefixLines($prefix, $message);
  310. }
  311. protected function prefixLines(string $prefix, string $message): string
  312. {
  313. $message = trim($message);
  314. return implode(
  315. PHP_EOL,
  316. array_map(
  317. static function (string $text) use ($prefix)
  318. {
  319. return ' ' . $prefix . ($text ? ' ' . $text : '');
  320. },
  321. preg_split('/\r\n|\r|\n/', $message)
  322. )
  323. );
  324. }
  325. }