> $sniffProperties * @param list $codesToCheck * @param list $cliArgs */ protected static function checkFile(string $filePath, array $sniffProperties = [], array $codesToCheck = [], array $cliArgs = []): File { if (defined('PHP_CODESNIFFER_CBF') === false) { define('PHP_CODESNIFFER_CBF', false); } $codeSniffer = new Runner(); $codeSniffer->config = new Config(array_merge(['-s'], $cliArgs)); $codeSniffer->init(); if (count($sniffProperties) > 0) { /** @phpstan-ignore-next-line */ if (version_compare(Config::VERSION, '3.8.0', '>=')) { foreach ($sniffProperties as $name => $value) { $sniffProperties[$name] = [ 'value' => $value, 'scope' => 'sniff', ]; } } $codeSniffer->ruleset->ruleset[self::getSniffName()]['properties'] = $sniffProperties; } $sniffClassName = static::getSniffClassName(); /** @var Sniff $sniff */ $sniff = new $sniffClassName(); $codeSniffer->ruleset->sniffs = [$sniffClassName => $sniff]; if (count($codesToCheck) > 0) { foreach (self::getSniffClassReflection()->getConstants() as $constantName => $constantValue) { if (strpos($constantName, 'CODE_') !== 0 || in_array($constantValue, $codesToCheck, true)) { continue; } $codeSniffer->ruleset->ruleset[sprintf('%s.%s', self::getSniffName(), $constantValue)]['severity'] = 0; } } $codeSniffer->ruleset->populateTokenListeners(); $file = new LocalFile($filePath, $codeSniffer->ruleset, $codeSniffer->config); $file->process(); return $file; } protected static function assertNoSniffErrorInFile(File $phpcsFile): void { $errors = $phpcsFile->getErrors(); self::assertEmpty($errors, sprintf('No errors expected, but %d errors found.', count($errors))); } protected static function assertNoSniffWarningInFile(File $phpcsFile): void { $warnings = $phpcsFile->getWarnings(); self::assertEmpty($warnings, sprintf('No warnings expected, but %d warnings found.', count($warnings))); } protected static function assertSniffError(File $phpcsFile, int $line, string $code, ?string $message = null): void { $errors = $phpcsFile->getErrors(); self::assertTrue(isset($errors[$line]), sprintf('Expected error on line %s, but none found.', $line)); $sniffCode = sprintf('%s.%s', self::getSniffName(), $code); self::assertTrue( self::hasError($errors[$line], $sniffCode, $message), sprintf( 'Expected error %s%s, but none found on line %d.%sErrors found on line %d:%s%s%s', $sniffCode, $message !== null ? sprintf(' with message "%s"', $message) : '', $line, PHP_EOL . PHP_EOL, $line, PHP_EOL, self::getFormattedErrors($errors[$line]), PHP_EOL ) ); } protected static function assertSniffWarning(File $phpcsFile, int $line, string $code, ?string $message = null): void { $errors = $phpcsFile->getWarnings(); self::assertTrue(isset($errors[$line]), sprintf('Expected warning on line %s, but none found.', $line)); $sniffCode = sprintf('%s.%s', self::getSniffName(), $code); self::assertTrue( self::hasError($errors[$line], $sniffCode, $message), sprintf( 'Expected warning %s%s, but none found on line %d.%sWarnings found on line %d:%s%s%s', $sniffCode, $message !== null ? sprintf(' with message "%s"', $message) : '', $line, PHP_EOL . PHP_EOL, $line, PHP_EOL, self::getFormattedErrors($errors[$line]), PHP_EOL ) ); } protected static function assertNoSniffError(File $phpcsFile, int $line): void { $errors = $phpcsFile->getErrors(); self::assertFalse( isset($errors[$line]), sprintf( 'Expected no error on line %s, but found:%s%s%s', $line, PHP_EOL . PHP_EOL, isset($errors[$line]) ? self::getFormattedErrors($errors[$line]) : '', PHP_EOL ) ); } protected static function assertAllFixedInFile(File $phpcsFile): void { $phpcsFile->disableCaching(); $phpcsFile->fixer->fixFile(); self::assertStringEqualsFile(preg_replace('~(\\.php)$~', '.fixed\\1', $phpcsFile->getFilename()), $phpcsFile->fixer->getContents()); } /** * @return class-string */ protected static function getSniffClassName(): string { /** @var class-string $sniffClassName */ $sniffClassName = substr(static::class, 0, -strlen('Test')); return $sniffClassName; } protected static function getSniffName(): string { return Common::getSniffCode(static::getSniffClassName()); } private static function getSniffClassReflection(): ReflectionClass { static $reflections = []; $className = static::getSniffClassName(); return $reflections[$className] ?? $reflections[$className] = new ReflectionClass($className); } /** * @param list> $errorsOnLine */ private static function hasError(array $errorsOnLine, string $sniffCode, ?string $message): bool { $hasError = false; foreach ($errorsOnLine as $errorsOnPosition) { foreach ($errorsOnPosition as $error) { /** @var string $errorSource */ $errorSource = $error['source']; /** @var string $errorMessage */ $errorMessage = $error['message']; if ( $errorSource === $sniffCode && ( $message === null || strpos($errorMessage, $message) !== false ) ) { $hasError = true; break; } } } return $hasError; } /** * @param list> $errors */ private static function getFormattedErrors(array $errors): string { return implode(PHP_EOL, array_map(static function (array $errors): string { return implode(PHP_EOL, array_map(static function (array $error): string { return sprintf("\t%s: %s", $error['source'], $error['message']); }, $errors)); }, $errors)); } }