ArgumentsTest.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Test\Integrity\Phrase;
  7. use Magento\Framework\Component\ComponentRegistrar;
  8. /**
  9. * Scan source code for detects invocations of __() function or Phrase object, analyzes placeholders with arguments
  10. * and see if they not equal
  11. */
  12. class ArgumentsTest extends \Magento\Test\Integrity\Phrase\AbstractTestCase
  13. {
  14. /**
  15. * @var \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
  16. */
  17. protected $_phraseCollector;
  18. /**
  19. * List of files that must be omitted
  20. *
  21. * @todo remove blacklist related logic when all files correspond to the standard
  22. * @var array
  23. */
  24. protected $blackList;
  25. protected function setUp()
  26. {
  27. $this->_phraseCollector = new \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector(
  28. new \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer(),
  29. true,
  30. \Magento\Framework\Phrase::class
  31. );
  32. $componentRegistrar = new ComponentRegistrar();
  33. $this->blackList = [
  34. // the file below is the only file where strings are translated without corresponding arguments
  35. $componentRegistrar->getPath(ComponentRegistrar::MODULE, 'Magento_Translation')
  36. . '/Model/Js/DataProvider.php',
  37. ];
  38. }
  39. public function testArguments()
  40. {
  41. $incorrectNumberOfArgumentsErrors = [];
  42. $missedPhraseErrors = [];
  43. foreach ($this->_getFiles() as $file) {
  44. if (in_array($file, $this->blackList)) {
  45. continue;
  46. }
  47. $this->_phraseCollector->parse($file);
  48. foreach ($this->_phraseCollector->getPhrases() as $phrase) {
  49. $this->checkEmptyPhrases($phrase, $missedPhraseErrors);
  50. $this->checkArgumentMismatch($phrase, $incorrectNumberOfArgumentsErrors);
  51. }
  52. }
  53. $this->assertEmpty(
  54. $missedPhraseErrors,
  55. sprintf(
  56. "\n%d missed phrases were discovered: \n%s",
  57. count($missedPhraseErrors),
  58. implode("\n\n", $missedPhraseErrors)
  59. )
  60. );
  61. $this->assertEmpty(
  62. $incorrectNumberOfArgumentsErrors,
  63. sprintf(
  64. "\n%d usages of inconsistency the number of arguments and placeholders were discovered: \n%s",
  65. count($incorrectNumberOfArgumentsErrors),
  66. implode("\n\n", $incorrectNumberOfArgumentsErrors)
  67. )
  68. );
  69. }
  70. /**
  71. * Will check if phrase is empty
  72. *
  73. * @param $phrase
  74. * @param $missedPhraseErrors
  75. */
  76. private function checkEmptyPhrases($phrase, &$missedPhraseErrors)
  77. {
  78. if (empty(trim($phrase['phrase'], "'\"\t\n\r\0\x0B"))) {
  79. $missedPhraseErrors[] = $this->_createMissedPhraseError($phrase);
  80. }
  81. }
  82. /**
  83. * Will check if the number of arguments does not match the number of placeholders
  84. *
  85. * @param $phrase
  86. * @param $incorrectNumberOfArgumentsErrors
  87. */
  88. private function checkArgumentMismatch($phrase, &$incorrectNumberOfArgumentsErrors)
  89. {
  90. if (preg_match_all('/%(\w+)/', $phrase['phrase'], $matches) || $phrase['arguments']) {
  91. $placeholderCount = count(array_unique($matches[1]));
  92. // Check for zend placeholders %placeholder% and sprintf placeholder %s
  93. if (preg_match_all('/%((s)|([A-Za-z]+)%)/', $phrase['phrase'], $placeHolders, PREG_OFFSET_CAPTURE)) {
  94. foreach ($placeHolders[0] as $ph) {
  95. // Check if char after placeholder is not a digit or letter
  96. $charAfterPh = $phrase['phrase'][$ph[1] + strlen($ph[0])];
  97. if (!preg_match('/[A-Za-z0-9]/', $charAfterPh)) {
  98. $placeholderCount--;
  99. }
  100. }
  101. }
  102. if ($placeholderCount != $phrase['arguments']) {
  103. $incorrectNumberOfArgumentsErrors[] = $this->_createPhraseError($phrase);
  104. }
  105. }
  106. }
  107. }