PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://gitlab.com/madwanz64/laravel
PHP | 312 lines | 227 code | 49 blank | 36 comment | 38 complexity | eb5d80fd2edc743b6ee4ebf849e49c21 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 function array_key_exists;
  12. use function array_keys;
  13. use function array_map;
  14. use function array_pop;
  15. use function array_values;
  16. use function explode;
  17. use function get_class;
  18. use function gettype;
  19. use function implode;
  20. use function in_array;
  21. use function is_bool;
  22. use function is_float;
  23. use function is_int;
  24. use function is_numeric;
  25. use function is_object;
  26. use function is_scalar;
  27. use function is_string;
  28. use function ord;
  29. use function preg_quote;
  30. use function preg_replace;
  31. use function range;
  32. use function sprintf;
  33. use function str_replace;
  34. use function strlen;
  35. use function strpos;
  36. use function strtolower;
  37. use function strtoupper;
  38. use function substr;
  39. use function trim;
  40. use PHPUnit\Framework\TestCase;
  41. use PHPUnit\Util\Color;
  42. use PHPUnit\Util\Exception as UtilException;
  43. use PHPUnit\Util\Test;
  44. use ReflectionException;
  45. use ReflectionMethod;
  46. use ReflectionObject;
  47. use SebastianBergmann\Exporter\Exporter;
  48. /**
  49. * @internal This class is not covered by the backward compatibility promise for PHPUnit
  50. */
  51. final class NamePrettifier
  52. {
  53. /**
  54. * @var string[]
  55. */
  56. private $strings = [];
  57. /**
  58. * @var bool
  59. */
  60. private $useColor;
  61. public function __construct(bool $useColor = false)
  62. {
  63. $this->useColor = $useColor;
  64. }
  65. /**
  66. * Prettifies the name of a test class.
  67. *
  68. * @psalm-param class-string $className
  69. */
  70. public function prettifyTestClass(string $className): string
  71. {
  72. try {
  73. $annotations = Test::parseTestMethodAnnotations($className);
  74. if (isset($annotations['class']['testdox'][0])) {
  75. return $annotations['class']['testdox'][0];
  76. }
  77. } catch (UtilException $e) {
  78. // ignore, determine className by parsing the provided name
  79. }
  80. $parts = explode('\\', $className);
  81. $className = array_pop($parts);
  82. if (substr($className, -1 * strlen('Test')) === 'Test') {
  83. $className = substr($className, 0, strlen($className) - strlen('Test'));
  84. }
  85. if (strpos($className, 'Tests') === 0) {
  86. $className = substr($className, strlen('Tests'));
  87. } elseif (strpos($className, 'Test') === 0) {
  88. $className = substr($className, strlen('Test'));
  89. }
  90. if (empty($className)) {
  91. $className = 'UnnamedTests';
  92. }
  93. if (!empty($parts)) {
  94. $parts[] = $className;
  95. $fullyQualifiedName = implode('\\', $parts);
  96. } else {
  97. $fullyQualifiedName = $className;
  98. }
  99. $result = preg_replace('/(?<=[[:lower:]])(?=[[:upper:]])/u', ' ', $className);
  100. if ($fullyQualifiedName !== $className) {
  101. return $result . ' (' . $fullyQualifiedName . ')';
  102. }
  103. return $result;
  104. }
  105. /**
  106. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  107. */
  108. public function prettifyTestCase(TestCase $test): string
  109. {
  110. $annotations = Test::parseTestMethodAnnotations(
  111. get_class($test),
  112. $test->getName(false)
  113. );
  114. $annotationWithPlaceholders = false;
  115. $callback = static function (string $variable): string
  116. {
  117. return sprintf('/%s(?=\b)/', preg_quote($variable, '/'));
  118. };
  119. if (isset($annotations['method']['testdox'][0])) {
  120. $result = $annotations['method']['testdox'][0];
  121. if (strpos($result, '$') !== false) {
  122. $annotation = $annotations['method']['testdox'][0];
  123. $providedData = $this->mapTestMethodParameterNamesToProvidedDataValues($test);
  124. $variables = array_map($callback, array_keys($providedData));
  125. $result = trim(preg_replace($variables, $providedData, $annotation));
  126. $annotationWithPlaceholders = true;
  127. }
  128. } else {
  129. $result = $this->prettifyTestMethod($test->getName(false));
  130. }
  131. if (!$annotationWithPlaceholders && $test->usesDataProvider()) {
  132. $result .= $this->prettifyDataSet($test);
  133. }
  134. return $result;
  135. }
  136. public function prettifyDataSet(TestCase $test): string
  137. {
  138. if (!$this->useColor) {
  139. return $test->getDataSetAsString(false);
  140. }
  141. if (is_int($test->dataName())) {
  142. $data = Color::dim(' with data set ') . Color::colorize('fg-cyan', (string) $test->dataName());
  143. } else {
  144. $data = Color::dim(' with ') . Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $test->dataName()));
  145. }
  146. return $data;
  147. }
  148. /**
  149. * Prettifies the name of a test method.
  150. */
  151. public function prettifyTestMethod(string $name): string
  152. {
  153. $buffer = '';
  154. if ($name === '') {
  155. return $buffer;
  156. }
  157. $string = (string) preg_replace('#\d+$#', '', $name, -1, $count);
  158. if (in_array($string, $this->strings, true)) {
  159. $name = $string;
  160. } elseif ($count === 0) {
  161. $this->strings[] = $string;
  162. }
  163. if (strpos($name, 'test_') === 0) {
  164. $name = substr($name, 5);
  165. } elseif (strpos($name, 'test') === 0) {
  166. $name = substr($name, 4);
  167. }
  168. if ($name === '') {
  169. return $buffer;
  170. }
  171. $name[0] = strtoupper($name[0]);
  172. if (strpos($name, '_') !== false) {
  173. return trim(str_replace('_', ' ', $name));
  174. }
  175. $wasNumeric = false;
  176. foreach (range(0, strlen($name) - 1) as $i) {
  177. if ($i > 0 && ord($name[$i]) >= 65 && ord($name[$i]) <= 90) {
  178. $buffer .= ' ' . strtolower($name[$i]);
  179. } else {
  180. $isNumeric = is_numeric($name[$i]);
  181. if (!$wasNumeric && $isNumeric) {
  182. $buffer .= ' ';
  183. $wasNumeric = true;
  184. }
  185. if ($wasNumeric && !$isNumeric) {
  186. $wasNumeric = false;
  187. }
  188. $buffer .= $name[$i];
  189. }
  190. }
  191. return $buffer;
  192. }
  193. /**
  194. * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
  195. */
  196. private function mapTestMethodParameterNamesToProvidedDataValues(TestCase $test): array
  197. {
  198. try {
  199. $reflector = new ReflectionMethod(get_class($test), $test->getName(false));
  200. // @codeCoverageIgnoreStart
  201. } catch (ReflectionException $e) {
  202. throw new UtilException(
  203. $e->getMessage(),
  204. (int) $e->getCode(),
  205. $e
  206. );
  207. }
  208. // @codeCoverageIgnoreEnd
  209. $providedData = [];
  210. $providedDataValues = array_values($test->getProvidedData());
  211. $i = 0;
  212. $providedData['$_dataName'] = $test->dataName();
  213. foreach ($reflector->getParameters() as $parameter) {
  214. if (!array_key_exists($i, $providedDataValues) && $parameter->isDefaultValueAvailable()) {
  215. try {
  216. $providedDataValues[$i] = $parameter->getDefaultValue();
  217. // @codeCoverageIgnoreStart
  218. } catch (ReflectionException $e) {
  219. throw new UtilException(
  220. $e->getMessage(),
  221. (int) $e->getCode(),
  222. $e
  223. );
  224. }
  225. // @codeCoverageIgnoreEnd
  226. }
  227. $value = $providedDataValues[$i++] ?? null;
  228. if (is_object($value)) {
  229. $reflector = new ReflectionObject($value);
  230. if ($reflector->hasMethod('__toString')) {
  231. $value = (string) $value;
  232. } else {
  233. $value = get_class($value);
  234. }
  235. }
  236. if (!is_scalar($value)) {
  237. $value = gettype($value);
  238. }
  239. if (is_bool($value) || is_int($value) || is_float($value)) {
  240. $value = (new Exporter)->export($value);
  241. }
  242. if (is_string($value) && $value === '') {
  243. if ($this->useColor) {
  244. $value = Color::colorize('dim,underlined', 'empty');
  245. } else {
  246. $value = "''";
  247. }
  248. }
  249. $providedData['$' . $parameter->getName()] = $value;
  250. }
  251. if ($this->useColor) {
  252. $providedData = array_map(static function ($value)
  253. {
  254. return Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $value, true));
  255. }, $providedData);
  256. }
  257. return $providedData;
  258. }
  259. }