From d9de704da7a303ebdcfaa56ba4010e5b57f70b61 Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sat, 23 Mar 2024 13:41:59 +0100 Subject: [PATCH] [analyzer] add file analyzer (#5) * chore(tests): add fixture path helper * chore(tests): add syntax error fixture * feat(analyzer): add file analyzer --- src/Analyzer/AnalyzerInterface.php | 10 +++ src/Analyzer/FileAnalyzer.php | 64 ++++++++++++++++ tests/Analyzer/FileAnalyzerTest.php | 106 ++++++++++++++++++++++++++ tests/TestCase.php | 10 ++- tests/fixtures/misc/syntax_error.stub | 3 + 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 src/Analyzer/AnalyzerInterface.php create mode 100644 src/Analyzer/FileAnalyzer.php create mode 100644 tests/Analyzer/FileAnalyzerTest.php create mode 100644 tests/fixtures/misc/syntax_error.stub diff --git a/src/Analyzer/AnalyzerInterface.php b/src/Analyzer/AnalyzerInterface.php new file mode 100644 index 0000000..b4c7165 --- /dev/null +++ b/src/Analyzer/AnalyzerInterface.php @@ -0,0 +1,10 @@ +parser->parse($content); + } catch (ParserError $e) { + return [$this->parserErrorToResult($e, $filePath)]; + } + + $firstStatement = $statements[0] ?? null; + $inspector = new MissingDeclareStrictTypesInspector($firstStatement); + try { + $inspector->inspect(); + } catch (InspectionError $e) { + return [$this->inspectionErrorToResult($e, $filePath, $inspector)]; + } + + return []; + } + + private function parserErrorToResult(ParserError $e, string $filePath): array + { + return [ + 'severity' => 'error', + 'message' => $e->getMessage(), + 'file' => $filePath, + 'description' => 'Parser error occurred while parsing the file', + ]; + } + + private function inspectionErrorToResult(InspectionError $e, string $filePath, InspectorInterface $inspector): array + { + return [ + 'severity' => 'warning', + 'message' => $e->getMessage(), + 'file' => $filePath, + 'description' => $inspector->description(), + ]; + } +} diff --git a/tests/Analyzer/FileAnalyzerTest.php b/tests/Analyzer/FileAnalyzerTest.php new file mode 100644 index 0000000..c929deb --- /dev/null +++ b/tests/Analyzer/FileAnalyzerTest.php @@ -0,0 +1,106 @@ +fixturePath('misc/syntax_error.stub'); + $parser = ParserBuilder::init()->build(); + $sut = new FileAnalyzer($parser); + $data = [ + 'path' => $filePath, + 'type' => 'file', + ]; + + $result = $sut->analyze($data); + + $expected = [ + [ + 'severity' => 'error', + 'description' => 'Parser error occurred while parsing the file', + 'message' => 'Syntax error, unexpected T_ENCAPSED_AND_WHITESPACE on line 3', + 'file' => $filePath, + ], + ]; + $this->assertEqualsCanonicalizing($expected, $result); + } + + #[Test] + public function it_can_detect_missing_strict_types_declaration(): void + { + $filePath = $this->fixturePath('type_compatibility/missing_declare_strict_types.php'); + $parser = ParserBuilder::init()->build(); + $data = [ + 'path' => $filePath, + 'type' => 'file', + ]; + $sut = new FileAnalyzer($parser); + + $result = $sut->analyze($data); + + $inspector = new MissingDeclareStrictTypesInspector(); + $expected = [ + [ + 'severity' => 'warning', + 'message' => 'Strict types declaration is missing', + 'file' => $filePath, + 'description' => $inspector->description(), + ], + ]; + $this->assertEqualsCanonicalizing($expected, $result); + } + + #[Test] + public function it_can_detect_invalid_declare_strict_types(): void + { + $filePath = $this->fixturePath('type_compatibility/invalid_declare_strict_types.php'); + $parser = ParserBuilder::init()->build(); + $data = [ + 'path' => $filePath, + 'type' => 'file', + ]; + $sut = new FileAnalyzer($parser); + + $result = $sut->analyze($data); + + $inspector = new MissingDeclareStrictTypesInspector(); + $expected = [ + [ + 'severity' => 'warning', + 'message' => 'Strict types declaration is missing', + 'file' => $filePath, + 'description' => $inspector->description(), + ], + ]; + $this->assertEqualsCanonicalizing($expected, $result); + } + + #[Test] + public function it_can_detect_valid_declare_strict_types(): void + { + $filePath = $this->fixturePath('type_compatibility/valid_declare_strict_types.php'); + $parser = ParserBuilder::init()->build(); + $data = [ + 'path' => $filePath, + 'type' => 'file', + ]; + $sut = new FileAnalyzer($parser); + + $result = $sut->analyze($data); + + $this->assertEmpty($result); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 7f38d92..199e5a3 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -13,9 +13,17 @@ abstract class TestCase extends PHPUnitTestCase { protected function fixture(string $path): string { - $contents = file_get_contents(__DIR__.'/fixtures/'.$path); + $contents = file_get_contents($this->fixturePath($path)); assert(is_string($contents), 'Fixture not found.'); return $contents; } + + protected function fixturePath(string $path): string + { + $realpath = realpath(__DIR__.'/fixtures/'.$path); + assert(is_string($realpath), 'Fixture not found.'); + + return $realpath; + } } diff --git a/tests/fixtures/misc/syntax_error.stub b/tests/fixtures/misc/syntax_error.stub new file mode 100644 index 0000000..16b9fb1 --- /dev/null +++ b/tests/fixtures/misc/syntax_error.stub @@ -0,0 +1,3 @@ +