project_analyzer->getCodebase()->find_unused_variables = true; } public function testIssueSuppressedOnFunction(): void { $this->expectException(CodeException::class); $this->expectExceptionMessage('UnusedPsalmSuppress'); $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'barBar()->bat()->baz()->bam()->bas()->bee()->bet()->bes()->bis(); } }', ); $this->analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', new Context()); } public function testIssueSuppressedOnStatement(): void { $this->expectException(CodeException::class); $this->expectExceptionMessage('UnusedPsalmSuppress'); $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', new Context()); } public function testUnusedSuppressAllOnFunction(): void { $this->expectException(CodeException::class); $this->expectExceptionMessage('UnusedPsalmSuppress'); $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', new Context()); } public function testUnusedSuppressAllOnStatement(): void { $this->expectException(CodeException::class); $this->expectExceptionMessage('UnusedPsalmSuppress'); $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', new Context()); } public function testMissingThrowsDocblockSuppressed(): void { Config::getInstance()->check_for_throws_docblock = true; $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', $context); } public function testMissingThrowsDocblockSuppressedWithoutThrow(): void { $this->expectException(CodeException::class); $this->expectExceptionMessage('UnusedPsalmSuppress'); Config::getInstance()->check_for_throws_docblock = true; $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', $context); } public function testMissingThrowsDocblockSuppressedDuplicate(): void { $this->expectException(CodeException::class); $this->expectExceptionMessage('UnusedPsalmSuppress'); Config::getInstance()->check_for_throws_docblock = true; $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', $context); } public function testUncaughtThrowInGlobalScopeSuppressed(): void { Config::getInstance()->check_for_throws_in_global_scope = true; $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', $context); } public function testUncaughtThrowInGlobalScopeSuppressedWithoutThrow(): void { $this->expectException(CodeException::class); $this->expectExceptionMessage('UnusedPsalmSuppress'); Config::getInstance()->check_for_throws_in_global_scope = true; $this->addFile( getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', 'analyzeFile(getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php', $context); } public function testPossiblyUnusedPropertySuppressedOnClass(): void { $this->project_analyzer->getCodebase()->find_unused_code = "always"; $file_path = getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context(), false); $this->project_analyzer->consolidateAnalyzedData(); IssueBuffer::processUnusedSuppressions($this->project_analyzer->getCodebase()->file_provider); } public function testPossiblyUnusedPropertySuppressedOnProperty(): void { $this->project_analyzer->getCodebase()->find_unused_code = "always"; $file_path = getcwd() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context(), false); $this->project_analyzer->consolidateAnalyzedData(); IssueBuffer::processUnusedSuppressions($this->project_analyzer->getCodebase()->file_provider); } public function providerValidCodeParse(): iterable { return [ 'undefinedClassSimple' => [ 'code' => 'barBar()->bat()->baz()->bam()->bas()->bee()->bet()->bes()->bis(); } }', ], 'multipleIssues' => [ 'code' => 'barBar()->bat()->baz()->bam()->bas()->bee()->bet()->bes()->bis(); } }', ], 'undefinedClassOneLine' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => ['UndefinedFunction'], ], 'suppressWithNewlineAfterComment' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => 'mightBeNull->format(""); } } ', ], 'methodSignatureMismatchSuppressedAtClassLevel' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' 'UndefinedClass - src' . DIRECTORY_SEPARATOR . 'somefile.php:8:33 - Class, interface or enum named C', ], 'undefinedClassOneLineInFileAfter' => [ 'code' => ' 'UndefinedClass - src' . DIRECTORY_SEPARATOR . 'somefile.php:6:25 - Class, interface or enum named C', ], 'missingParamTypeShouldntPreventUndefinedClassError' => [ 'code' => ' 'UndefinedClass', ], 'suppressUnusedSuppressionByItselfIsNotSuppressed' => [ 'code' => ' 'UnusedPsalmSuppress', ], ]; } }