DependencyTest.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Test\Integrity\Library;
  7. use Magento\Framework\App\Utility\Files;
  8. use Magento\Framework\App\Utility\AggregateInvoker;
  9. use Magento\Framework\Component\ComponentRegistrar;
  10. use Magento\TestFramework\Integrity\Library\Injectable;
  11. use Magento\TestFramework\Integrity\Library\PhpParser\ParserFactory;
  12. use Magento\TestFramework\Integrity\Library\PhpParser\Tokens;
  13. use Zend\Code\Reflection\FileReflection;
  14. /**
  15. * Test check if Magento library components contain incorrect dependencies to application layer
  16. *
  17. */
  18. class DependencyTest extends \PHPUnit\Framework\TestCase
  19. {
  20. /**
  21. * Collect errors
  22. *
  23. * @var array
  24. */
  25. protected $errors = [];
  26. /**
  27. * Allowed sub namespaces
  28. *
  29. * @return array
  30. */
  31. protected function getAllowedNamespaces()
  32. {
  33. return [
  34. 'Framework',
  35. 'SomeModule',
  36. 'ModuleName',
  37. 'Setup\Console\CommandList',
  38. 'Setup\Console\CompilerPreparation',
  39. 'Setup\Model\ObjectManagerProvider',
  40. 'Setup\Mvc\Bootstrap\InitParamListener',
  41. 'Store\Model\ScopeInterface',
  42. 'Store\Model\StoreManagerInterface',
  43. 'Directory\Model\CurrencyFactory',
  44. 'PageCache\Model\Cache\Type',
  45. 'Backup\Model\ResourceModel\Db',
  46. 'Backend\Block\Widget\Button',
  47. 'Ui\Component\Container',
  48. 'SalesRule\Model\Rule',
  49. 'SalesRule\Api\Data\RuleInterface',
  50. 'SalesRule\Model\Rule\Interceptor',
  51. 'SalesRule\Model\Rule\Proxy',
  52. 'Theme\Model\View\Design'
  53. ];
  54. }
  55. public function testCheckDependencies()
  56. {
  57. $invoker = new \Magento\Framework\App\Utility\AggregateInvoker($this);
  58. $invoker(
  59. /**
  60. * @param string $file
  61. */
  62. function ($file) {
  63. $componentRegistrar = new ComponentRegistrar();
  64. $fileReflection = new FileReflection($file);
  65. $tokens = new Tokens($fileReflection->getContents(), new ParserFactory());
  66. $tokens->parseContent();
  67. $dependencies = array_merge(
  68. (new Injectable())->getDependencies($fileReflection),
  69. $tokens->getDependencies()
  70. );
  71. $allowedNamespaces = str_replace('\\', '\\\\', implode('|', $this->getAllowedNamespaces()));
  72. $pattern = '#Magento\\\\(?!' . $allowedNamespaces . ').*#';
  73. foreach ($dependencies as $dependency) {
  74. $dependencyPaths = explode('\\', $dependency);
  75. $dependencyPaths = array_slice($dependencyPaths, 2);
  76. $dependencyPath = implode('\\', $dependencyPaths);
  77. $libraryPaths = $componentRegistrar->getPaths(ComponentRegistrar::LIBRARY);
  78. foreach ($libraryPaths as $libraryPath) {
  79. $filePath = str_replace('\\', '/', $libraryPath . '/' . $dependencyPath . '.php');
  80. if (preg_match($pattern, $dependency) && !file_exists($filePath)) {
  81. $this->errors[$fileReflection->getFileName()][] = $dependency;
  82. }
  83. }
  84. }
  85. if (!empty($this->errors)) {
  86. $this->fail($this->getFailMessage());
  87. }
  88. },
  89. $this->libraryDataProvider()
  90. );
  91. }
  92. /**
  93. * @inheritdoc
  94. */
  95. public function tearDown()
  96. {
  97. $this->errors = [];
  98. }
  99. /**
  100. * Prepare failed message
  101. *
  102. * @return string
  103. */
  104. protected function getFailMessage()
  105. {
  106. $failMessage = '';
  107. foreach ($this->errors as $class => $dependencies) {
  108. $failMessage .= $class . ' depends for non-library ' . (count($dependencies) > 1 ? 'classes ' : 'class ');
  109. foreach ($dependencies as $dependency) {
  110. $failMessage .= $dependency . ' ';
  111. }
  112. $failMessage = trim($failMessage) . PHP_EOL;
  113. }
  114. return $failMessage;
  115. }
  116. /**
  117. * Contains all library files
  118. *
  119. * @return array
  120. */
  121. public function libraryDataProvider()
  122. {
  123. // @TODO: remove this code when class Magento\Framework\Data\Collection will fixed
  124. $componentRegistrar = new ComponentRegistrar();
  125. include_once $componentRegistrar->getPath(ComponentRegistrar::LIBRARY, 'magento/framework')
  126. . '/Option/ArrayInterface.php';
  127. $blackList = Files::init()->readLists(__DIR__ . '/_files/blacklist*.txt');
  128. $dataProvider = Files::init()->getPhpFiles(Files::INCLUDE_LIBS | Files::AS_DATA_SET);
  129. foreach ($dataProvider as $key => $data) {
  130. if (in_array($data[0], $blackList)) {
  131. unset($dataProvider[$key]);
  132. } else {
  133. include_once $data[0];
  134. }
  135. }
  136. return $dataProvider;
  137. }
  138. }