Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
LiveCodeTest.php
Go to the documentation of this file.
1 <?php
7 namespace Magento\Test\Php;
8 
15 use PHPMD\TextUI\Command;
16 
20 class LiveCodeTest extends \PHPUnit\Framework\TestCase
21 {
25  protected static $reportDir = '';
26 
30  protected static $pathToSource = '';
31 
37  public static function setUpBeforeClass()
38  {
39  self::$pathToSource = BP;
40  self::$reportDir = self::$pathToSource . '/dev/tests/static/report';
41  if (!is_dir(self::$reportDir)) {
42  mkdir(self::$reportDir);
43  }
44  }
45 
51  private static function getBaseFilesFolder()
52  {
53  return __DIR__;
54  }
55 
61  private static function getChangedFilesBaseDir()
62  {
63  return __DIR__ . '/..';
64  }
65 
75  public static function getWhitelist(
76  $fileTypes = ['php'],
77  $changedFilesBaseDir = '',
78  $baseFilesFolder = '',
79  $whitelistFile = '/_files/whitelist/common.txt'
80  ) {
81  $changedFiles = self::getChangedFilesList($changedFilesBaseDir);
82  if (empty($changedFiles)) {
83  return [];
84  }
85 
86  $globPatternsFolder = ('' !== $baseFilesFolder) ? $baseFilesFolder : self::getBaseFilesFolder();
87  try {
88  $directoriesToCheck = Files::init()->readLists($globPatternsFolder . $whitelistFile);
89  } catch (\Exception $e) {
90  // no directories matched white list
91  return [];
92  }
93  $targetFiles = self::filterFiles($changedFiles, $fileTypes, $directoriesToCheck);
94  return $targetFiles;
95  }
96 
112  private static function getChangedFilesList($changedFilesBaseDir)
113  {
114  return self::getFilesFromListFile(
115  $changedFilesBaseDir,
116  'changed_files*',
117  function () {
118  // if no list files, probably, this is the dev environment
119  @exec('git diff --name-only', $changedFiles);
120  @exec('git diff --cached --name-only', $addedFiles);
121  $changedFiles = array_unique(array_merge($changedFiles, $addedFiles));
122  return $changedFiles;
123  }
124  );
125  }
126 
133  private static function getAddedFilesList($changedFilesBaseDir)
134  {
135  return self::getFilesFromListFile(
136  $changedFilesBaseDir,
137  'changed_files*.added.*',
138  function () {
139  // if no list files, probably, this is the dev environment
140  @exec('git diff --cached --name-only', $addedFiles);
141  return $addedFiles;
142  }
143  );
144  }
145 
154  private static function getFilesFromListFile($listsBaseDir, $listFilePattern, $noListCallback)
155  {
156  $filesDefinedInList = [];
157 
158  $globFilesListPattern = ($listsBaseDir ?: self::getChangedFilesBaseDir())
159  . '/_files/' . $listFilePattern;
160  $listFiles = glob($globFilesListPattern);
161  if (count($listFiles)) {
162  foreach ($listFiles as $listFile) {
163  $filesDefinedInList = array_merge(
164  $filesDefinedInList,
165  file($listFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
166  );
167  }
168  } else {
169  $filesDefinedInList = call_user_func($noListCallback);
170  }
171 
172  array_walk(
173  $filesDefinedInList,
174  function (&$file) {
175  $file = BP . '/' . $file;
176  }
177  );
178 
179  $filesDefinedInList = array_values(array_unique($filesDefinedInList));
180 
181  return $filesDefinedInList;
182  }
183 
199  private static function filterFiles(array $files, array $allowedFileTypes, array $allowedDirectories)
200  {
201  if (empty($allowedFileTypes)) {
202  $fileHasAllowedType = function () {
203  return true;
204  };
205  } else {
206  $fileHasAllowedType = function ($file) use ($allowedFileTypes) {
207  return in_array(pathinfo($file, PATHINFO_EXTENSION), $allowedFileTypes);
208  };
209  }
210 
211  if (empty($allowedDirectories)) {
212  $fileIsInAllowedDirectory = function () {
213  return true;
214  };
215  } else {
216  $allowedDirectories = array_map('realpath', $allowedDirectories);
217  usort($allowedDirectories, function ($dir1, $dir2) {
218  return strlen($dir1) - strlen($dir2);
219  });
220  $fileIsInAllowedDirectory = function ($file) use ($allowedDirectories) {
221  foreach ($allowedDirectories as $directory) {
222  if (strpos($file, $directory) === 0) {
223  return true;
224  }
225  }
226  return false;
227  };
228  }
229 
230  $filtered = array_filter(
231  $files,
232  function ($file) use ($fileHasAllowedType, $fileIsInAllowedDirectory) {
233  $file = realpath($file);
234  if (false === $file) {
235  return false;
236  }
237  return $fileHasAllowedType($file) && $fileIsInAllowedDirectory($file);
238  }
239  );
240 
241  return $filtered;
242  }
243 
249  private function getFullWhitelist()
250  {
251  try {
252  return Files::init()->readLists(__DIR__ . '/_files/whitelist/common.txt');
253  } catch (\Exception $e) {
254  // nothing is whitelisted
255  return [];
256  }
257  }
258 
262  public function testCodeStyle()
263  {
264  $isFullScan = defined('TESTCODESTYLE_IS_FULL_SCAN') && TESTCODESTYLE_IS_FULL_SCAN === '1';
265  $reportFile = self::$reportDir . '/phpcs_report.txt';
266  if (!file_exists($reportFile)) {
267  touch($reportFile);
268  }
269  $codeSniffer = new CodeSniffer('Magento', $reportFile, new Wrapper());
270  $result = $codeSniffer->run($isFullScan ? $this->getFullWhitelist() : self::getWhitelist(['php', 'phtml']));
271  $report = file_get_contents($reportFile);
272  $this->assertEquals(
273  0,
274  $result,
275  "PHP Code Sniffer detected {$result} violation(s): " . PHP_EOL . $report
276  );
277  }
278 
282  public function testCodeMess()
283  {
284  $reportFile = self::$reportDir . '/phpmd_report.txt';
285  $codeMessDetector = new CodeMessDetector(realpath(__DIR__ . '/_files/phpmd/ruleset.xml'), $reportFile);
286 
287  if (!$codeMessDetector->canRun()) {
288  $this->markTestSkipped('PHP Mess Detector is not available.');
289  }
290 
291  $result = $codeMessDetector->run(self::getWhitelist(['php']));
292 
293  $output = "";
294  if (file_exists($reportFile)) {
295  $output = file_get_contents($reportFile);
296  }
297 
298  $this->assertEquals(
299  Command::EXIT_SUCCESS,
300  $result,
301  "PHP Code Mess has found error(s):" . PHP_EOL . $output
302  );
303 
304  // delete empty reports
305  if (file_exists($reportFile)) {
306  unlink($reportFile);
307  }
308  }
309 
313  public function testCopyPaste()
314  {
315  $reportFile = self::$reportDir . '/phpcpd_report.xml';
316  $copyPasteDetector = new CopyPasteDetector($reportFile);
317 
318  if (!$copyPasteDetector->canRun()) {
319  $this->markTestSkipped('PHP Copy/Paste Detector is not available.');
320  }
321 
322  $blackList = [];
323  foreach (glob(__DIR__ . '/_files/phpcpd/blacklist/*.txt') as $list) {
324  $blackList = array_merge($blackList, file($list, FILE_IGNORE_NEW_LINES));
325  }
326 
327  $copyPasteDetector->setBlackList($blackList);
328 
329  $result = $copyPasteDetector->run([BP]);
330 
331  $output = "";
332  if (file_exists($reportFile)) {
333  $output = file_get_contents($reportFile);
334  }
335 
336  $this->assertTrue(
337  $result,
338  "PHP Copy/Paste Detector has found error(s):" . PHP_EOL . $output
339  );
340  }
341 
345  public function testStrictTypes()
346  {
347  $changedFiles = self::getAddedFilesList('');
348 
349  try {
350  $blackList = Files::init()->readLists(
351  self::getBaseFilesFolder() . '/_files/blacklist/strict_type.txt'
352  );
353  } catch (\Exception $e) {
354  // nothing matched black list
355  $blackList = [];
356  }
357 
358  $toBeTestedFiles = array_diff(
359  self::filterFiles($changedFiles, ['php'], []),
360  $blackList
361  );
362 
363  $filesMissingStrictTyping = [];
364  foreach ($toBeTestedFiles as $fileName) {
365  $file = file_get_contents($fileName);
366  if (strstr($file, 'strict_types=1') === false) {
367  $filesMissingStrictTyping[] = $fileName;
368  }
369  }
370 
371  $this->assertEquals(
372  0,
373  count($filesMissingStrictTyping),
374  "Following files are missing strict type declaration:"
375  . PHP_EOL
376  . implode(PHP_EOL, $filesMissingStrictTyping)
377  );
378  }
379 }
exec($command, array &$output=null, &$return_var=null)
defined('TESTS_BP')||define('TESTS_BP' __DIR__
Definition: _bootstrap.php:60
$fileName
Definition: translate.phtml:15
static getWhitelist( $fileTypes=['php'], $changedFilesBaseDir='', $baseFilesFolder='', $whitelistFile='/_files/whitelist/common.txt')
const BP
Definition: autoload.php:14
mkdir($pathname, $mode=0777, $recursive=false, $context=null)
Definition: ioMock.php:25
foreach($appDirs as $dir) $files