From 850c97d2c3ac34486a31c0ed7cfb036705c1b063 Mon Sep 17 00:00:00 2001 From: sasezaki Date: Sat, 25 Sep 2021 16:22:21 +0900 Subject: [PATCH 1/3] Add checkstyle printer --- README.md | 7 ++- src/Console/Command.php | 11 +++++ src/Printer/CheckStyle.php | 57 ++++++++++++++++++++++++ src/Printer/Util.php | 35 +++++++++++++++ src/Printer/Xml.php | 27 +----------- tests/Printer/CheckStyleTest.php | 74 ++++++++++++++++++++++++++++++++ tests/Printer/XmlTest.php | 13 ++++-- 7 files changed, 192 insertions(+), 32 deletions(-) create mode 100644 src/Printer/CheckStyle.php create mode 100644 src/Printer/Util.php create mode 100644 tests/Printer/CheckStyleTest.php diff --git a/README.md b/README.md index 3b6b78a..efdbddb 100644 --- a/README.md +++ b/README.md @@ -95,8 +95,6 @@ The ``--exclude-path`` option will exclude a path, which must be relative to the The ``--exclude`` option will exclude a directory, which must be relative to the source, from the code analysis. Multiple values are allowed (e.g. --exclude=tests --exclude=examples). -The ``--extensions`` option lets you extend the code analysis. The provided extensions must be comma separated. - The ``--hint`` option will suggest replacements for magic numbers based on your codebase constants. The ``--ignore-funcs`` option will exclude a list of comma separated functions from the code analysis, when using the "argument" extension. Defaults to `intval`, `floatval`, `strval`. @@ -118,6 +116,11 @@ The ``--suffixes`` option will configure a comma separated list of valid source The ``--whitelist`` option will only process the files listed in the file specified. This is useful for incremental analysis. The ``--xml-output`` option will generate an report in an Xml format to the path specified by the option. + +The ``--checkstyle-output`` option will generate a report in checkstyle xml format to the path specified by the option. + +The ``--extensions`` option lets you extend the code analysis. The provided extensions must be comma separated. + **By default it analyses conditions, return statements, and switch cases.** #### Extensions diff --git a/src/Console/Command.php b/src/Console/Command.php index cc88557..62313bd 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -137,6 +137,12 @@ protected function configure(): void InputOption::VALUE_REQUIRED, 'Generate an XML output to the specified path' ) + ->addOption( + 'checkstyle-output', + null, + InputOption::VALUE_REQUIRED, + 'Generate an checkstyle output to the specified path' + ) ->addOption( 'whitelist', null, @@ -198,6 +204,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $xmlOutput->printData($output, $fileReportList, $hintList); } + if ($input->getOption('checkstyle-output')) { + $checkStyleOutput = new Printer\CheckStyle($input->getOption('checkstyle-output')); + $checkStyleOutput->printData($output, $fileReportList, $hintList); + } + if ($output->getVerbosity() !== OutputInterface::VERBOSITY_QUIET) { $output->writeln(''); $printer->printData($output, $fileReportList, $hintList); diff --git a/src/Printer/CheckStyle.php b/src/Printer/CheckStyle.php new file mode 100644 index 0000000..87ac85e --- /dev/null +++ b/src/Printer/CheckStyle.php @@ -0,0 +1,57 @@ +outputPath = $outputPath; + } + + public function printData(OutputInterface $output, FileReportList $fileReportList, HintList $hintList): void + { + $output->writeln('Generate checkstyle report output...'); + $dom = new \DOMDocument('1.0', 'UTF-8'); + $rootNode = $dom->createElement('checkstyle'); + + $total = 0; + foreach ($fileReportList->getFileReports() as $fileReport) { + $fileNode = $dom->createElement('file'); + $fileNode->setAttribute('name', $fileReport->getFile()->getRelativePathname()); + + $entries = $fileReport->getEntries(); + $total += count($entries); + foreach ($entries as $entry) { + $snippet = Util::getSnippet($fileReport->getFile()->getContents(), $entry['line'], $entry['value']); + $errorNode = $dom->createElement('error'); + $errorNode->setAttribute('line', $entry['line']); + $errorNode->setAttribute('column', $snippet['col']); + $errorNode->setAttribute('severity', 'error'); + $errorNode->setAttribute('message', sprintf('Magic number: %s', $entry['value'])); + + $fileNode->appendChild($errorNode); + } + $rootNode->appendChild($fileNode); + } + + $dom->appendChild($rootNode); + + $dom->save($this->outputPath); + + $output->writeln('Total of Magic Numbers ' . $total); + $output->writeln('checkstyle XML generated at '. $this->outputPath); + } +} diff --git a/src/Printer/Util.php b/src/Printer/Util.php new file mode 100644 index 0000000..927e6b6 --- /dev/null +++ b/src/Printer/Util.php @@ -0,0 +1,35 @@ + $lineContent, + 'line' => $line, + 'magic' => $text, + 'col' => $start + ]; + } +} diff --git a/src/Printer/Xml.php b/src/Printer/Xml.php index 69b120f..4425cf9 100644 --- a/src/Printer/Xml.php +++ b/src/Printer/Xml.php @@ -42,7 +42,7 @@ public function printData(OutputInterface $output, FileReportList $fileReportLis $total += count($entries); foreach ($entries as $entry) { - $snippet = $this->getSnippet($fileReport->getFile()->getContents(), $entry['line'], $entry['value']); + $snippet = Util::getSnippet($fileReport->getFile()->getContents(), $entry['line'], $entry['value']); $entryNode = $dom->createElement('entry'); $entryNode->setAttribute('line', $entry['line']); $entryNode->setAttribute('start', $snippet['col']); @@ -80,29 +80,4 @@ public function printData(OutputInterface $output, FileReportList $fileReportLis $output->writeln('XML generated at '.$this->outputPath); } - - /** - * Get the snippet and information about it - * - * @param string $content - * @param int $line - * @param int|string $text - * @return array - */ - private function getSnippet(string $content, int $line, $text): array - { - $content = str_replace(array("\r\n", "\r"), "\n", $content); - $lines = explode("\n", $content); - - $lineContent = array_slice($lines, $line-1, 1); - $lineContent = reset($lineContent); - $start = strpos($lineContent, $text.''); - - return [ - 'snippet' => $lineContent, - 'line' => $line, - 'magic' => $text, - 'col' => $start - ]; - } } diff --git a/tests/Printer/CheckStyleTest.php b/tests/Printer/CheckStyleTest.php new file mode 100644 index 0000000..1f10e1c --- /dev/null +++ b/tests/Printer/CheckStyleTest.php @@ -0,0 +1,74 @@ +printData(new NullOutput(), new FileReportList(), new HintList()); + + $this->assertXmlStringEqualsXmlString( + <<<'XML' + + +XML + , + file_get_contents($outputPath) + ); + } + + public function testPrintData() : void + { + $testMagicNumber = 12; + + $splFileInfo = $this->createMock(SplFileInfo::class); + $splFileInfo + ->method('getRelativePathname') + ->willReturn('Foo/Bar.php'); + $splFileInfo + ->method('getContents') + ->willReturn(sprintf( + '$rootNode->setAttribute(\'fileCount\', count($fileReportList->getFileReports()) + %d);', + $testMagicNumber + )); + + $fileReport = new FileReport($splFileInfo); + $fileReport->addEntry(1, $testMagicNumber); + $fileReportList = new FileReportList(); + $fileReportList->addFileReport($fileReport); + + $outputPath = tempnam(sys_get_temp_dir(), 'phpmnd_'); + $xmlPrinter = new CheckStyle($outputPath); + $xmlPrinter->printData(new NullOutput(), $fileReportList, new HintList()); + + $this->assertXmlStringEqualsXmlString( + <<<'XML' + + + + + + +XML + , + file_get_contents($outputPath) + ); + } +} diff --git a/tests/Printer/XmlTest.php b/tests/Printer/XmlTest.php index 93310d5..b7a1017 100644 --- a/tests/Printer/XmlTest.php +++ b/tests/Printer/XmlTest.php @@ -30,7 +30,7 @@ public function testEmpty() : void XML - , + , $outputPath ); } @@ -45,7 +45,10 @@ public function testPrintData() : void ->willReturn('Foo/Bar.php'); $splFileInfo ->method('getContents') - ->willReturn(sprintf('$rootNode->setAttribute(\'fileCount\', count($fileReportList->getFileReports()) + %d);', $testMagicNumber)); + ->willReturn(sprintf( + '$rootNode->setAttribute(\'fileCount\', count($fileReportList->getFileReports()) + %d);', + $testMagicNumber + )); $fileReport = new FileReport($splFileInfo); $fileReport->addEntry(1, $testMagicNumber); @@ -66,7 +69,9 @@ public function testPrintData() : void - setAttribute('fileCount', count($fileReportList->getFileReports()) + 12);]]> + + setAttribute('fileCount', count($fileReportList->getFileReports()) + 12);]]> + Povils\PHPMND\Tests\Printer\XmlTest::WELL_KNOWN_MAGIC @@ -75,7 +80,7 @@ public function testPrintData() : void XML - , + , $outputPath ); } From b33f4adface74d87552e84903d0ce550ae130de7 Mon Sep 17 00:00:00 2001 From: sasezaki Date: Sat, 25 Sep 2021 22:02:33 +0900 Subject: [PATCH 2/3] prefer short array syntax --- src/Printer/Util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Printer/Util.php b/src/Printer/Util.php index 927e6b6..d6c4ba7 100644 --- a/src/Printer/Util.php +++ b/src/Printer/Util.php @@ -18,7 +18,7 @@ abstract class Util */ final public static function getSnippet(string $content, int $line, $text): array { - $content = str_replace(array("\r\n", "\r"), "\n", $content); + $content = str_replace(["\r\n", "\r"], "\n", $content); $lines = explode("\n", $content); $lineContent = array_slice($lines, $line-1, 1); From fb64a9b95f26a8c561022c8e9994a865868ead6c Mon Sep 17 00:00:00 2001 From: sasezaki Date: Sat, 25 Sep 2021 22:11:27 +0900 Subject: [PATCH 3/3] string cast clearly https://github.com/povils/phpmnd/pull/139#discussion_r716012902 --- src/Printer/Util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Printer/Util.php b/src/Printer/Util.php index d6c4ba7..b4d281c 100644 --- a/src/Printer/Util.php +++ b/src/Printer/Util.php @@ -23,7 +23,7 @@ final public static function getSnippet(string $content, int $line, $text): arra $lineContent = array_slice($lines, $line-1, 1); $lineContent = reset($lineContent); - $start = strpos($lineContent, $text.''); + $start = strpos($lineContent, (string) $text); return [ 'snippet' => $lineContent,