PageRenderTime 39ms CodeModel.GetById 6ms RepoModel.GetById 0ms app.codeStats 0ms

/Symfony/CS/Fixer/Contrib/PhpUnitDedicateAssertFixer.php

http://github.com/fabpot/PHP-CS-Fixer
PHP | 264 lines | 185 code | 34 blank | 45 comment | 17 complexity | d61c3cd8420f194f27972dfdeca30ca2 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of PHP CS Fixer.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. namespace Symfony\CS\Fixer\Contrib;
  12. use Symfony\CS\AbstractFixer;
  13. use Symfony\CS\ConfigurationException\InvalidFixerConfigurationException;
  14. use Symfony\CS\Tokenizer\Token;
  15. use Symfony\CS\Tokenizer\Tokens;
  16. /**
  17. * @author SpacePossum
  18. */
  19. final class PhpUnitDedicateAssertFixer extends AbstractFixer
  20. {
  21. private $fixMap = array(
  22. 'array_key_exists' => array('assertArrayNotHasKey', 'assertArrayHasKey'),
  23. 'empty' => array('assertNotEmpty', 'assertEmpty'),
  24. 'file_exists' => array('assertFileNotExists', 'assertFileExists'),
  25. 'is_infinite' => array('assertFinite', 'assertInfinite'),
  26. 'is_nan' => array(false, 'assertNan'),
  27. 'is_null' => array('assertNotNull', 'assertNull'),
  28. 'is_array' => true,
  29. 'is_bool' => true,
  30. 'is_boolean' => true,
  31. 'is_callable' => true,
  32. 'is_double' => true,
  33. 'is_float' => true,
  34. 'is_int' => true,
  35. 'is_integer' => true,
  36. 'is_long' => true,
  37. 'is_​numeric' => true,
  38. 'is_object' => true,
  39. 'is_real' => true,
  40. 'is_​resource' => true,
  41. 'is_scalar' => true,
  42. 'is_string' => true,
  43. );
  44. private $configuration = array(
  45. 'array_key_exists',
  46. 'empty',
  47. 'file_exists',
  48. 'is_infinite',
  49. 'is_nan',
  50. 'is_null',
  51. 'is_array',
  52. 'is_bool',
  53. 'is_boolean',
  54. 'is_callable',
  55. 'is_double',
  56. 'is_float',
  57. 'is_int',
  58. 'is_integer',
  59. 'is_long',
  60. 'is_​numeric',
  61. 'is_object',
  62. 'is_real',
  63. 'is_​resource',
  64. 'is_scalar',
  65. 'is_string',
  66. );
  67. /**
  68. * @param array|null $configuration
  69. */
  70. public function configure(array $configuration = null)
  71. {
  72. if (null === $configuration) {
  73. return;
  74. }
  75. $this->configuration = array();
  76. foreach ($configuration as $method) {
  77. if (!array_key_exists($method, $this->fixMap)) {
  78. throw new InvalidFixerConfigurationException($this->getName(), sprintf('Unknown configuration method "%s".', $method));
  79. }
  80. $this->configuration[] = $method;
  81. }
  82. }
  83. /**
  84. * {@inheritdoc}
  85. */
  86. public function fix(\SplFileInfo $file, $content)
  87. {
  88. $tokens = Tokens::fromCode($content);
  89. static $searchSequence = array(
  90. array(T_VARIABLE, '$this'),
  91. array(T_OBJECT_OPERATOR, '->'),
  92. array(T_STRING),
  93. );
  94. $index = 1;
  95. $candidate = $tokens->findSequence($searchSequence, $index);
  96. while (null !== $candidate) {
  97. end($candidate);
  98. $index = $this->getAssertCandidate($tokens, key($candidate));
  99. if (is_array($index)) {
  100. $index = $this->fixAssert($tokens, $index);
  101. }
  102. ++$index;
  103. $candidate = $tokens->findSequence($searchSequence, $index);
  104. }
  105. return $tokens->generateCode();
  106. }
  107. /**
  108. * {@inheritdoc}
  109. */
  110. public function getDescription()
  111. {
  112. return 'PHPUnit assertions like "assertInternalType", "assertFileExists", should be used over "assertTrue". Warning! This could change code behavior.';
  113. }
  114. /**
  115. * {@inheritdoc}
  116. */
  117. public function getPriority()
  118. {
  119. // should be run after the PhpUnitConstructFixer.
  120. return -15;
  121. }
  122. /**
  123. * @param Tokens $tokens
  124. * @param int $assertCallIndex Token index of assert method call
  125. *
  126. * @return int|int[] indexes of assert call, test call and positive flag, or last index checked
  127. */
  128. private function getAssertCandidate(Tokens $tokens, $assertCallIndex)
  129. {
  130. $content = strtolower($tokens[$assertCallIndex]->getContent());
  131. if ('asserttrue' === $content) {
  132. $isPositive = 1;
  133. } elseif ('assertfalse' === $content) {
  134. $isPositive = 0;
  135. } else {
  136. return $assertCallIndex;
  137. }
  138. // test candidate for simple calls like: ([\]+'some fixable call'(...))
  139. $assertCallOpenIndex = $tokens->getNextMeaningfulToken($assertCallIndex);
  140. if (!$tokens[$assertCallOpenIndex]->equals('(')) {
  141. return $assertCallIndex;
  142. }
  143. $testDefaultNamespaceTokenIndex = false;
  144. $testIndex = $tokens->getNextMeaningfulToken($assertCallOpenIndex);
  145. if (!$tokens[$testIndex]->isGivenKind(array(T_EMPTY, T_STRING))) {
  146. if (!$tokens[$testIndex]->isGivenKind(T_NS_SEPARATOR)) {
  147. return $testIndex;
  148. }
  149. $testDefaultNamespaceTokenIndex = $testIndex;
  150. $testIndex = $tokens->getNextMeaningfulToken($testIndex);
  151. }
  152. $testOpenIndex = $tokens->getNextMeaningfulToken($testIndex);
  153. if (!$tokens[$testOpenIndex]->equals('(')) {
  154. return $testOpenIndex;
  155. }
  156. $testCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $testOpenIndex);
  157. $assertCallCloseIndex = $tokens->getNextMeaningfulToken($testCloseIndex);
  158. if (!$tokens[$assertCallCloseIndex]->equalsAny(array(')', ','))) {
  159. return $assertCallCloseIndex;
  160. }
  161. return array(
  162. $isPositive,
  163. $assertCallIndex,
  164. $assertCallOpenIndex,
  165. $testDefaultNamespaceTokenIndex,
  166. $testIndex,
  167. $testOpenIndex,
  168. $testCloseIndex,
  169. $assertCallCloseIndex,
  170. );
  171. }
  172. /**
  173. * @param Tokens $tokens
  174. * @param array $assertIndexes
  175. *
  176. * @return int index up till processed, number of tokens added
  177. */
  178. private function fixAssert(Tokens $tokens, array $assertIndexes)
  179. {
  180. list(
  181. $isPositive,
  182. $assertCallIndex,
  183. $assertCallOpenIndex,
  184. $testDefaultNamespaceTokenIndex,
  185. $testIndex,
  186. $testOpenIndex,
  187. $testCloseIndex,
  188. $assertCallCloseIndex
  189. ) = $assertIndexes;
  190. $content = strtolower($tokens[$testIndex]->getContent());
  191. if (!in_array($content, $this->configuration, true)) {
  192. return $assertCallCloseIndex;
  193. }
  194. if (is_array($this->fixMap[$content])) {
  195. if (false !== $this->fixMap[$content][$isPositive]) {
  196. $tokens[$assertCallIndex]->setContent($this->fixMap[$content][$isPositive]);
  197. $this->removeFunctionCall($tokens, $testDefaultNamespaceTokenIndex, $testIndex, $testOpenIndex, $testCloseIndex);
  198. }
  199. return $assertCallCloseIndex;
  200. }
  201. $type = substr($content, 3);
  202. $tokens[$assertCallIndex]->setContent($isPositive ? 'assertInternalType' : 'assertNotInternalType');
  203. $tokens->overrideAt($testIndex, array(T_CONSTANT_ENCAPSED_STRING, "'".$type."'", $tokens[$testIndex]->getLine()));
  204. $tokens->overrideAt($testOpenIndex, ',');
  205. $tokens->clearTokenAndMergeSurroundingWhitespace($testCloseIndex);
  206. if (!$tokens[$testOpenIndex + 1]->isWhitespace()) {
  207. $tokens->insertAt($testOpenIndex + 1, new Token(array(T_WHITESPACE, ' ')));
  208. }
  209. if (false !== $testDefaultNamespaceTokenIndex) {
  210. $tokens->clearTokenAndMergeSurroundingWhitespace($testDefaultNamespaceTokenIndex);
  211. }
  212. return $assertCallCloseIndex;
  213. }
  214. /**
  215. * @param Tokens $tokens
  216. * @param int|false $callNSIndex
  217. * @param int $callIndex
  218. * @param int $openIndex
  219. * @param int $closeIndex
  220. */
  221. private function removeFunctionCall(Tokens $tokens, $callNSIndex, $callIndex, $openIndex, $closeIndex)
  222. {
  223. $tokens->clearTokenAndMergeSurroundingWhitespace($callIndex);
  224. if (false !== $callNSIndex) {
  225. $tokens->clearTokenAndMergeSurroundingWhitespace($callNSIndex);
  226. }
  227. $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
  228. $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
  229. }
  230. }