View source
<?php
namespace Drupal\Test;
use PHP_CodeSniffer\Config;
use PHP_CodeSniffer\Ruleset;
use PHP_CodeSniffer\Files\LocalFile;
use PHP_CodeSniffer\Exceptions\RuntimeException;
use PHP_CodeSniffer\Util\Common;
use PHP_CodeSniffer\Util\Tokens;
use PHPUnit\Framework\TestCase;
abstract class CoderSniffUnitTest extends TestCase {
protected $backupGlobals = false;
private $rootDir = null;
public $standardsDir = null;
public $testsDir = null;
protected function setUp() {
$class = get_class($this);
$this->rootDir = __DIR__ . '/../../';
$this->testsDir = __DIR__ . '/';
$tokens = new Tokens();
if (defined('PHP_CODESNIFFER_VERBOSITY') === false) {
define('PHP_CODESNIFFER_VERBOSITY', 0);
}
if (defined('PHP_CODESNIFFER_CBF') === false) {
define('PHP_CODESNIFFER_CBF', 0);
}
}
protected function getTestFiles($testFileBase) : array {
$testFiles = [];
$dir = substr($testFileBase, 0, strrpos($testFileBase, DIRECTORY_SEPARATOR));
$di = new \DirectoryIterator($dir);
foreach ($di as $file) {
$path = $file
->getPathname();
if (substr($path, 0, strlen($testFileBase)) === $testFileBase) {
if ($path !== $testFileBase . 'php' && substr($path, -5) !== 'fixed') {
$testFiles[] = $path;
}
}
}
sort($testFiles);
return $testFiles;
}
protected function shouldSkipTest() {
return false;
}
public final function testSniff() {
if ($this
->shouldSkipTest() === true) {
$this
->markTestSkipped();
}
$sniffCode = Common::getSniffCode(get_class($this));
list($standardName, $categoryName, $sniffName) = explode('.', $sniffCode);
if ($this
->checkAllSniffCodes() !== false) {
list($standardName) = explode('\\', get_class($this));
}
$testFileBase = $this->rootDir . 'tests' . DIRECTORY_SEPARATOR . $standardName . DIRECTORY_SEPARATOR . $categoryName . DIRECTORY_SEPARATOR . $sniffName . 'UnitTest.';
$this->standardsDir = $this->rootDir . 'coder_sniffer' . DIRECTORY_SEPARATOR . $standardName . DIRECTORY_SEPARATOR;
$testFiles = $this
->getTestFiles($testFileBase);
$config = new Config();
$config->cache = false;
$GLOBALS['PHP_CODESNIFFER_CONFIG'] = $config;
$config->ignored = [];
$config->standards = [
$this->standardsDir,
];
$failureMessages = [];
foreach ($testFiles as $testFile) {
if ($this
->checkAllSniffCodes() !== false) {
$config->sniffs = [];
}
else {
$config->sniffs = [
$sniffCode,
];
}
$ruleset = new Ruleset($config);
$GLOBALS['PHP_CODESNIFFER_RULESET'] = $ruleset;
$filename = basename($testFile);
$oldConfig = $config
->getSettings();
$this
->setCliValues($filename, $config);
$phpcsFile = new LocalFile($testFile, $ruleset, $config);
$phpcsFile
->process();
$failures = $this
->generateFailureMessages($phpcsFile);
$failureMessages = array_merge($failureMessages, $failures);
if ($phpcsFile
->getFixableCount() > 0) {
$config->sniffs = [];
$ruleset = new Ruleset($config);
try {
$this
->setCliValues($filename, $config);
$phpcsFile = new LocalFile($testFile, $ruleset, $config);
$phpcsFile
->process();
} catch (RuntimeException $e) {
$this
->fail('An unexpected exception has been caught: ' . $e
->getMessage());
}
$phpcsFile->fixer
->fixFile();
$fixable = $phpcsFile
->getFixableCount();
if ($fixable > 0) {
$failureMessages[] = "Failed to fix {$fixable} fixable violations in {$filename}";
}
$fixedFile = $testFile . '.fixed';
if (file_exists($fixedFile) === true) {
$diff = $phpcsFile->fixer
->generateDiff($fixedFile);
if (trim($diff) !== '') {
$filename = basename($testFile);
$fixedFilename = basename($fixedFile);
$failureMessages[] = "Fixed version of {$filename} does not match expected version in {$fixedFilename}; the diff is\n{$diff}";
}
}
}
$config
->setSettings($oldConfig);
}
if (empty($failureMessages) === false) {
$this
->fail(implode(PHP_EOL, $failureMessages));
}
}
public function generateFailureMessages(LocalFile $file) : array {
$testFile = $file
->getFilename();
$foundErrors = $file
->getErrors();
$foundWarnings = $file
->getWarnings();
$expectedErrors = $this
->getErrorList(basename($testFile));
$expectedWarnings = $this
->getWarningList(basename($testFile));
$allProblems = [];
$failureMessages = [];
$GLOBALS['PHP_CODESNIFFER_SNIFF_CODES'] = [];
$GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES'] = [];
foreach ($foundErrors as $line => $lineErrors) {
foreach ($lineErrors as $column => $errors) {
if (isset($allProblems[$line]) === false) {
$allProblems[$line] = [
'expected_errors' => 0,
'expected_warnings' => 0,
'found_errors' => [],
'found_warnings' => [],
];
}
$foundErrorsTemp = [];
foreach ($allProblems[$line]['found_errors'] as $foundError) {
$foundErrorsTemp[] = $foundError;
}
$errorsTemp = [];
foreach ($errors as $foundError) {
$errorsTemp[] = $foundError['message'] . ' (' . $foundError['source'] . ')';
$source = $foundError['source'];
if (in_array($source, $GLOBALS['PHP_CODESNIFFER_SNIFF_CODES']) === false) {
$GLOBALS['PHP_CODESNIFFER_SNIFF_CODES'][] = $source;
}
if ($foundError['fixable'] === true && in_array($source, $GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES']) === false) {
$GLOBALS['PHP_CODESNIFFER_FIXABLE_CODES'][] = $source;
}
}
$allProblems[$line]['found_errors'] = array_merge($foundErrorsTemp, $errorsTemp);
}
if (isset($expectedErrors[$line]) === true) {
$allProblems[$line]['expected_errors'] = $expectedErrors[$line];
}
else {
$allProblems[$line]['expected_errors'] = 0;
}
unset($expectedErrors[$line]);
}
foreach ($expectedErrors as $line => $numErrors) {
if (isset($allProblems[$line]) === false) {
$allProblems[$line] = [
'expected_errors' => 0,
'expected_warnings' => 0,
'found_errors' => [],
'found_warnings' => [],
];
}
$allProblems[$line]['expected_errors'] = $numErrors;
}
foreach ($foundWarnings as $line => $lineWarnings) {
foreach ($lineWarnings as $column => $warnings) {
if (isset($allProblems[$line]) === false) {
$allProblems[$line] = [
'expected_errors' => 0,
'expected_warnings' => 0,
'found_errors' => [],
'found_warnings' => [],
];
}
$foundWarningsTemp = [];
foreach ($allProblems[$line]['found_warnings'] as $foundWarning) {
$foundWarningsTemp[] = $foundWarning;
}
$warningsTemp = [];
foreach ($warnings as $warning) {
$warningsTemp[] = $warning['message'] . ' (' . $warning['source'] . ')';
}
$allProblems[$line]['found_warnings'] = array_merge($foundWarningsTemp, $warningsTemp);
}
if (isset($expectedWarnings[$line]) === true) {
$allProblems[$line]['expected_warnings'] = $expectedWarnings[$line];
}
else {
$allProblems[$line]['expected_warnings'] = 0;
}
unset($expectedWarnings[$line]);
}
foreach ($expectedWarnings as $line => $numWarnings) {
if (isset($allProblems[$line]) === false) {
$allProblems[$line] = [
'expected_errors' => 0,
'expected_warnings' => 0,
'found_errors' => [],
'found_warnings' => [],
];
}
$allProblems[$line]['expected_warnings'] = $numWarnings;
}
ksort($allProblems);
foreach ($allProblems as $line => $problems) {
$numErrors = count($problems['found_errors']);
$numWarnings = count($problems['found_warnings']);
$expectedErrors = $problems['expected_errors'];
$expectedWarnings = $problems['expected_warnings'];
$errors = '';
$foundString = '';
if ($expectedErrors !== $numErrors || $expectedWarnings !== $numWarnings) {
$lineMessage = "[LINE {$line}]";
$expectedMessage = 'Expected ';
$foundMessage = 'in ' . basename($testFile) . ' but found ';
if ($expectedErrors !== $numErrors) {
$expectedMessage .= "{$expectedErrors} error(s)";
$foundMessage .= "{$numErrors} error(s)";
if ($numErrors !== 0) {
$foundString .= 'error(s)';
$errors .= implode(PHP_EOL . ' -> ', $problems['found_errors']);
}
if ($expectedWarnings !== $numWarnings) {
$expectedMessage .= ' and ';
$foundMessage .= ' and ';
if ($numWarnings !== 0) {
if ($foundString !== '') {
$foundString .= ' and ';
}
}
}
}
if ($expectedWarnings !== $numWarnings) {
$expectedMessage .= "{$expectedWarnings} warning(s)";
$foundMessage .= "{$numWarnings} warning(s)";
if ($numWarnings !== 0) {
$foundString .= 'warning(s)';
if (empty($errors) === false) {
$errors .= PHP_EOL . ' -> ';
}
$errors .= implode(PHP_EOL . ' -> ', $problems['found_warnings']);
}
}
$fullMessage = "{$lineMessage} {$expectedMessage} {$foundMessage}.";
if ($errors !== '') {
$fullMessage .= " The {$foundString} found were:" . PHP_EOL . " -> {$errors}";
}
$failureMessages[] = $fullMessage;
}
}
return $failureMessages;
}
public function setCliValues($filename, $config) {
return;
}
protected abstract function getErrorList(string $testFile) : array;
protected abstract function getWarningList(string $testFile) : array;
protected function checkAllSniffCodes() {
return false;
}
}