Viewing file: NamePrettifier.php (8.81 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?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 function array_key_exists; use function array_keys; use function array_map; use function array_pop; use function array_values; use function explode; use function get_class; use function gettype; use function implode; use function in_array; use function is_bool; use function is_float; use function is_int; use function is_numeric; use function is_object; use function is_scalar; use function is_string; use function ord; use function preg_quote; use function preg_replace; use function range; use function sprintf; use function str_replace; use function strlen; use function strpos; use function strtolower; use function strtoupper; use function substr; use function trim; use PHPUnit\Framework\TestCase; use PHPUnit\Util\Color; use PHPUnit\Util\Exception as UtilException; use PHPUnit\Util\Test; use ReflectionException; use ReflectionMethod; use ReflectionObject; use SebastianBergmann\Exporter\Exporter;
/** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NamePrettifier { /** * @var string[] */ private $strings = [];
/** * @var bool */ private $useColor;
public function __construct(bool $useColor = false) { $this->useColor = $useColor; }
/** * Prettifies the name of a test class. * * @psalm-param class-string $className */ public function prettifyTestClass(string $className): string { try { $annotations = Test::parseTestMethodAnnotations($className);
if (isset($annotations['class']['testdox'][0])) { return $annotations['class']['testdox'][0]; } } catch (UtilException $e) { // ignore, determine className by parsing the provided name }
$parts = explode('\\', $className); $className = array_pop($parts);
if (substr($className, -1 * strlen('Test')) === 'Test') { $className = substr($className, 0, strlen($className) - strlen('Test')); }
if (strpos($className, 'Tests') === 0) { $className = substr($className, strlen('Tests')); } elseif (strpos($className, 'Test') === 0) { $className = substr($className, strlen('Test')); }
if (empty($className)) { $className = 'UnnamedTests'; }
if (!empty($parts)) { $parts[] = $className; $fullyQualifiedName = implode('\\', $parts); } else { $fullyQualifiedName = $className; }
$result = preg_replace('/(?<=[[:lower:]])(?=[[:upper:]])/u', ' ', $className);
if ($fullyQualifiedName !== $className) { return $result . ' (' . $fullyQualifiedName . ')'; }
return $result; }
/** * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException */ public function prettifyTestCase(TestCase $test): string { $annotations = Test::parseTestMethodAnnotations( get_class($test), $test->getName(false), );
$annotationWithPlaceholders = false;
$callback = static function (string $variable): string { return sprintf('/%s(?=\b)/', preg_quote($variable, '/')); };
if (isset($annotations['method']['testdox'][0])) { $result = $annotations['method']['testdox'][0];
if (strpos($result, '$') !== false) { $annotation = $annotations['method']['testdox'][0]; $providedData = $this->mapTestMethodParameterNamesToProvidedDataValues($test); $variables = array_map($callback, array_keys($providedData));
$result = trim(preg_replace($variables, $providedData, $annotation));
$annotationWithPlaceholders = true; } } else { $result = $this->prettifyTestMethod($test->getName(false)); }
if (!$annotationWithPlaceholders && $test->usesDataProvider()) { $result .= $this->prettifyDataSet($test); }
return $result; }
public function prettifyDataSet(TestCase $test): string { if (!$this->useColor) { return $test->getDataSetAsString(false); }
if (is_int($test->dataName())) { $data = Color::dim(' with data set ') . Color::colorize('fg-cyan', (string) $test->dataName()); } else { $data = Color::dim(' with ') . Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $test->dataName())); }
return $data; }
/** * Prettifies the name of a test method. */ public function prettifyTestMethod(string $name): string { $buffer = '';
if ($name === '') { return $buffer; }
$string = (string) preg_replace('#\d+$#', '', $name, -1, $count);
if (in_array($string, $this->strings, true)) { $name = $string; } elseif ($count === 0) { $this->strings[] = $string; }
if (strpos($name, 'test_') === 0) { $name = substr($name, 5); } elseif (strpos($name, 'test') === 0) { $name = substr($name, 4); }
if ($name === '') { return $buffer; }
$name[0] = strtoupper($name[0]);
if (strpos($name, '_') !== false) { return trim(str_replace('_', ' ', $name)); }
$wasNumeric = false;
foreach (range(0, strlen($name) - 1) as $i) { if ($i > 0 && ord($name[$i]) >= 65 && ord($name[$i]) <= 90) { $buffer .= ' ' . strtolower($name[$i]); } else { $isNumeric = is_numeric($name[$i]);
if (!$wasNumeric && $isNumeric) { $buffer .= ' '; $wasNumeric = true; }
if ($wasNumeric && !$isNumeric) { $wasNumeric = false; }
$buffer .= $name[$i]; } }
return $buffer; }
/** * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException */ private function mapTestMethodParameterNamesToProvidedDataValues(TestCase $test): array { try { $reflector = new ReflectionMethod(get_class($test), $test->getName(false)); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new UtilException( $e->getMessage(), $e->getCode(), $e, ); } // @codeCoverageIgnoreEnd
$providedData = []; $providedDataValues = array_values($test->getProvidedData()); $i = 0;
$providedData['$_dataName'] = $test->dataName();
foreach ($reflector->getParameters() as $parameter) { if (!array_key_exists($i, $providedDataValues) && $parameter->isDefaultValueAvailable()) { try { $providedDataValues[$i] = $parameter->getDefaultValue(); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new UtilException( $e->getMessage(), $e->getCode(), $e, ); } // @codeCoverageIgnoreEnd }
$value = $providedDataValues[$i++] ?? null;
if (is_object($value)) { $reflector = new ReflectionObject($value);
if ($reflector->hasMethod('__toString')) { $value = (string) $value; } else { $value = get_class($value); } }
if (!is_scalar($value)) { $value = gettype($value); }
if (is_bool($value) || is_int($value) || is_float($value)) { $value = (new Exporter)->export($value); }
if (is_string($value) && $value === '') { if ($this->useColor) { $value = Color::colorize('dim,underlined', 'empty'); } else { $value = "''"; } }
$providedData['$' . $parameter->getName()] = $value; }
if ($this->useColor) { $providedData = array_map(static function ($value) { return Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $value, true)); }, $providedData); }
return $providedData; } }
|