%PDF- %PDF-
Direktori : /home/silvzytp/crm-ind-code/vendor/phpunit/phpunit/src/Util/TestDox/ |
Current File : //home/silvzytp/crm-ind-code/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php |
<?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * 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 ceil; use function count; use function explode; use function get_class; use function implode; use function preg_match; use function sprintf; use function strlen; use function strpos; use function trim; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestResult; use PHPUnit\Runner\BaseTestRunner; use PHPUnit\Runner\PhptTestCase; use PHPUnit\Util\Color; use SebastianBergmann\Timer\ResourceUsageFormatter; use SebastianBergmann\Timer\Timer; use Throwable; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ class CliTestDoxPrinter extends TestDoxPrinter { /** * The default Testdox left margin for messages is a vertical line. */ private const PREFIX_SIMPLE = [ 'default' => '│', 'start' => '│', 'message' => '│', 'diff' => '│', 'trace' => '│', 'last' => '│', ]; /** * Colored Testdox use box-drawing for a more textured map of the message. */ private const PREFIX_DECORATED = [ 'default' => '│', 'start' => '┐', 'message' => '├', 'diff' => '┊', 'trace' => '╵', 'last' => '┴', ]; private const SPINNER_ICONS = [ " \e[36m◐\e[0m running tests", " \e[36m◓\e[0m running tests", " \e[36m◑\e[0m running tests", " \e[36m◒\e[0m running tests", ]; private const STATUS_STYLES = [ BaseTestRunner::STATUS_PASSED => [ 'symbol' => '✔', 'color' => 'fg-green', ], BaseTestRunner::STATUS_ERROR => [ 'symbol' => '✘', 'color' => 'fg-yellow', 'message' => 'bg-yellow,fg-black', ], BaseTestRunner::STATUS_FAILURE => [ 'symbol' => '✘', 'color' => 'fg-red', 'message' => 'bg-red,fg-white', ], BaseTestRunner::STATUS_SKIPPED => [ 'symbol' => '↩', 'color' => 'fg-cyan', 'message' => 'fg-cyan', ], BaseTestRunner::STATUS_RISKY => [ 'symbol' => '☢', 'color' => 'fg-yellow', 'message' => 'fg-yellow', ], BaseTestRunner::STATUS_INCOMPLETE => [ 'symbol' => '∅', 'color' => 'fg-yellow', 'message' => 'fg-yellow', ], BaseTestRunner::STATUS_WARNING => [ 'symbol' => '⚠', 'color' => 'fg-yellow', 'message' => 'fg-yellow', ], BaseTestRunner::STATUS_UNKNOWN => [ 'symbol' => '?', 'color' => 'fg-blue', 'message' => 'fg-white,bg-blue', ], ]; /** * @var int[] */ private $nonSuccessfulTestResults = []; /** * @var Timer */ private $timer; /** * @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->timer = new Timer; $this->timer->start(); } public function printResult(TestResult $result): void { $this->printHeader($result); $this->printNonSuccessfulTestsSummary($result->count()); $this->printFooter($result); } protected function printHeader(TestResult $result): void { $this->write("\n" . (new ResourceUsageFormatter)->resourceUsage($this->timer->stop()) . "\n\n"); } protected function formatClassName(Test $test): string { if ($test instanceof TestCase) { return $this->prettifier->prettifyTestClass(get_class($test)); } return get_class($test); } /** * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException */ protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void { if ($status !== BaseTestRunner::STATUS_PASSED) { $this->nonSuccessfulTestResults[] = $this->testIndex; } parent::registerTestResult($test, $t, $status, $time, $verbose); } /** * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException */ protected function formatTestName(Test $test): string { if ($test instanceof TestCase) { return $this->prettifier->prettifyTestCase($test); } return parent::formatTestName($test); } protected function writeTestResult(array $prevResult, array $result): void { // spacer line for new suite headers and after verbose messages if ($prevResult['testName'] !== '' && (!empty($prevResult['message']) || $prevResult['className'] !== $result['className'])) { $this->write(PHP_EOL); } // suite header if ($prevResult['className'] !== $result['className']) { $this->write($this->colorizeTextBox('underlined', $result['className']) . PHP_EOL); } // test result line if ($this->colors && $result['className'] === PhptTestCase::class) { $testName = Color::colorizePath($result['testName'], $prevResult['testName'], true); } else { $testName = $result['testMethod']; } $style = self::STATUS_STYLES[$result['status']]; $line = sprintf( ' %s %s%s' . PHP_EOL, $this->colorizeTextBox($style['color'], $style['symbol']), $testName, $this->verbose ? ' ' . $this->formatRuntime($result['time'], $style['color']) : '' ); $this->write($line); // additional information when verbose $this->write($result['message']); } protected function formatThrowable(Throwable $t, ?int $status = null): string { return trim(\PHPUnit\Framework\TestFailure::exceptionToString($t)); } protected function colorizeMessageAndDiff(string $style, string $buffer): array { $lines = $buffer ? array_map('\rtrim', explode(PHP_EOL, $buffer)) : []; $message = []; $diff = []; $insideDiff = false; foreach ($lines as $line) { if ($line === '--- Expected') { $insideDiff = true; } if (!$insideDiff) { $message[] = $line; } else { if (strpos($line, '-') === 0) { $line = Color::colorize('fg-red', Color::visualizeWhitespace($line, true)); } elseif (strpos($line, '+') === 0) { $line = Color::colorize('fg-green', Color::visualizeWhitespace($line, true)); } elseif ($line === '@@ @@') { $line = Color::colorize('fg-cyan', $line); } $diff[] = $line; } } $diff = implode(PHP_EOL, $diff); if (!empty($message)) { $message = $this->colorizeTextBox($style, implode(PHP_EOL, $message)); } return [$message, $diff]; } protected function formatStacktrace(Throwable $t): string { $trace = \PHPUnit\Util\Filter::getFilteredStacktrace($t); if (!$this->colors) { return $trace; } $lines = []; $prevPath = ''; foreach (explode(PHP_EOL, $trace) as $line) { if (preg_match('/^(.*):(\d+)$/', $line, $matches)) { $lines[] = Color::colorizePath($matches[1], $prevPath) . Color::dim(':') . Color::colorize('fg-blue', $matches[2]) . "\n"; $prevPath = $matches[1]; } else { $lines[] = $line; $prevPath = ''; } } return implode('', $lines); } protected function formatTestResultMessage(Throwable $t, array $result, ?string $prefix = null): string { $message = $this->formatThrowable($t, $result['status']); $diff = ''; if (!($this->verbose || $result['verbose'])) { return ''; } if ($message && $this->colors) { $style = self::STATUS_STYLES[$result['status']]['message'] ?? ''; [$message, $diff] = $this->colorizeMessageAndDiff($style, $message); } if ($prefix === null || !$this->colors) { $prefix = self::PREFIX_SIMPLE; } if ($this->colors) { $color = self::STATUS_STYLES[$result['status']]['color'] ?? ''; $prefix = array_map(static function ($p) use ($color) { return Color::colorize($color, $p); }, self::PREFIX_DECORATED); } $trace = $this->formatStacktrace($t); $out = $this->prefixLines($prefix['start'], PHP_EOL) . PHP_EOL; if ($message) { $out .= $this->prefixLines($prefix['message'], $message . PHP_EOL) . PHP_EOL; } if ($diff) { $out .= $this->prefixLines($prefix['diff'], $diff . PHP_EOL) . PHP_EOL; } if ($trace) { if ($message || $diff) { $out .= $this->prefixLines($prefix['default'], PHP_EOL) . PHP_EOL; } $out .= $this->prefixLines($prefix['trace'], $trace . PHP_EOL) . PHP_EOL; } $out .= $this->prefixLines($prefix['last'], PHP_EOL) . PHP_EOL; return $out; } protected function drawSpinner(): void { if ($this->colors) { $id = $this->spinState % count(self::SPINNER_ICONS); $this->write(self::SPINNER_ICONS[$id]); } } protected function undrawSpinner(): void { if ($this->colors) { $id = $this->spinState % count(self::SPINNER_ICONS); $this->write("\e[1K\e[" . strlen(self::SPINNER_ICONS[$id]) . 'D'); } } private function formatRuntime(float $time, string $color = ''): string { if (!$this->colors) { return sprintf('[%.2f ms]', $time * 1000); } if ($time > 1) { $color = 'fg-magenta'; } return Color::colorize($color, ' ' . (int) ceil($time * 1000) . ' ' . Color::dim('ms')); } private function printNonSuccessfulTestsSummary(int $numberOfExecutedTests): void { if (empty($this->nonSuccessfulTestResults)) { return; } if ((count($this->nonSuccessfulTestResults) / $numberOfExecutedTests) >= 0.7) { return; } $this->write("Summary of non-successful tests:\n\n"); $prevResult = $this->getEmptyTestResult(); foreach ($this->nonSuccessfulTestResults as $testIndex) { $result = $this->testResults[$testIndex]; $this->writeTestResult($prevResult, $result); $prevResult = $result; } } }