From 380af7829be88d2b8b78fc66c50de98388773506 Mon Sep 17 00:00:00 2001 From: smoench Date: Fri, 23 Oct 2020 15:52:22 +0200 Subject: [PATCH] report unmatched skipped violations --- examples/SkipViolations.yaml | 1 + .../ConfigurationSkippedViolation.php | 10 +- src/Console/Command/AnalyzeCommand.php | 2 +- .../ConsoleOutputFormatter.php | 14 ++- .../GithubActionsOutputFormatter.php | 13 ++- .../GraphVizOutputFormatter.php | 2 +- src/OutputFormatter/JUnitOutputFormatter.php | 2 +- src/OutputFormatter/TableOutputFormatter.php | 20 +++- src/RulesetEngine.php | 15 ++- src/RulesetEngine/Context.php | 25 ++++- src/RulesetEngine/Error.php | 23 +++++ src/RulesetEngine/SkippedViolationHelper.php | 46 ++++++++++ .../ConfigurationSkippedViolationTest.php | 43 --------- tests/Configuration/ConfigurationTest.php | 9 +- .../ConsoleOutputFormatterTest.php | 16 +++- .../GithubActionsOutputFormatterTest.php | 16 +++- .../GraphVizOutputFormatterTest.php | 2 +- .../JUnitOutputFormatterTest.php | 2 +- .../TableOutputFormatterTest.php | 32 ++++++- .../XMLOutputFormatterTest.php | 2 +- .../SkippedViolationHelperTest.php | 91 +++++++++++++++++++ 21 files changed, 314 insertions(+), 72 deletions(-) create mode 100644 src/RulesetEngine/Error.php create mode 100644 src/RulesetEngine/SkippedViolationHelper.php delete mode 100644 tests/Configuration/ConfigurationSkippedViolationTest.php create mode 100644 tests/RulesetEngine/SkippedViolationHelperTest.php diff --git a/examples/SkipViolations.yaml b/examples/SkipViolations.yaml index 3e0415540..77aa05c3f 100644 --- a/examples/SkipViolations.yaml +++ b/examples/SkipViolations.yaml @@ -14,4 +14,5 @@ ruleset: skip_violations: Library\LibClass: - Core\CoreClass + - Core\Unmatched diff --git a/src/Configuration/ConfigurationSkippedViolation.php b/src/Configuration/ConfigurationSkippedViolation.php index 9d3126b74..d831647c8 100644 --- a/src/Configuration/ConfigurationSkippedViolation.php +++ b/src/Configuration/ConfigurationSkippedViolation.php @@ -4,8 +4,6 @@ namespace SensioLabs\Deptrac\Configuration; -use SensioLabs\Deptrac\AstRunner\AstMap\ClassLikeName; - /** * @author Dmitry Balabka */ @@ -30,9 +28,11 @@ private function __construct(array $classesDeps) $this->classesDeps = $classesDeps; } - public function isViolationSkipped(ClassLikeName $classLikeNameA, ClassLikeName $classLikeNameB): bool + /** + * @return array + */ + public function all(): array { - return isset($this->classesDeps[$classLikeNameA->toString()]) - && \in_array($classLikeNameB->toString(), $this->classesDeps[$classLikeNameA->toString()], true); + return $this->classesDeps; } } diff --git a/src/Console/Command/AnalyzeCommand.php b/src/Console/Command/AnalyzeCommand.php index c45d413e9..a895d49a0 100644 --- a/src/Console/Command/AnalyzeCommand.php +++ b/src/Console/Command/AnalyzeCommand.php @@ -125,7 +125,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 1; } - return $context->hasViolations() ? 1 : 0; + return $context->hasViolations() || $context->hasErrors() ? 1 : 0; } protected function printCollectViolations(SymfonyOutput $output): void diff --git a/src/OutputFormatter/ConsoleOutputFormatter.php b/src/OutputFormatter/ConsoleOutputFormatter.php index f6ee744a0..3ca4d9b85 100644 --- a/src/OutputFormatter/ConsoleOutputFormatter.php +++ b/src/OutputFormatter/ConsoleOutputFormatter.php @@ -57,7 +57,7 @@ public function finish( $output->writeLineFormatted(''); } - foreach ($context->all() as $rule) { + foreach ($context->rules() as $rule) { if (!$rule instanceof Violation && !$rule instanceof SkippedViolation) { continue; } @@ -70,6 +70,10 @@ public function finish( $this->printUncovered($context, $output); } + if ($context->hasErrors()) { + $this->printErrors($context, $output); + } + $this->printSummary($context, $output); } @@ -178,4 +182,12 @@ private function printFileOccurrence(Output $output, FileOccurrence $fileOccurre { $output->writeLineFormatted($fileOccurrence->getFilepath().'::'.$fileOccurrence->getLine()); } + + private function printErrors(Context $context, Output $output): void + { + $output->writeLineFormatted(''); + foreach ($context->errors() as $error) { + $output->writeLineFormatted(sprintf('[ERROR] %s', $error->toString())); + } + } } diff --git a/src/OutputFormatter/GithubActionsOutputFormatter.php b/src/OutputFormatter/GithubActionsOutputFormatter.php index b31bb8a2a..51911cd91 100644 --- a/src/OutputFormatter/GithubActionsOutputFormatter.php +++ b/src/OutputFormatter/GithubActionsOutputFormatter.php @@ -60,7 +60,7 @@ public function finish(Context $context, Output $output, OutputFormatterInput $o $output->writeLineFormatted(''); } - foreach ($context->all() as $rule) { + foreach ($context->rules() as $rule) { if (!$rule instanceof Violation && !$rule instanceof SkippedViolation) { continue; } @@ -92,6 +92,10 @@ public function finish(Context $context, Output $output, OutputFormatterInput $o || $outputFormatterInput->getOptionAsBoolean(AnalyzeCommand::OPTION_REPORT_UNCOVERED)) { $this->printUncovered($context, $output); } + + if ($context->hasErrors()) { + $this->printErrors($context, $output); + } } private function determineLogLevel(Rule $rule): string @@ -145,4 +149,11 @@ private function inheritPathMessage(InheritDependency $dependency): string return implode(' ->%0A', $buffer); } + + private function printErrors(Context $context, Output $output): void + { + foreach ($context->errors() as $error) { + $output->writeLineFormatted('::error ::'.$error->toString()); + } + } } diff --git a/src/OutputFormatter/GraphVizOutputFormatter.php b/src/OutputFormatter/GraphVizOutputFormatter.php index aa01550a2..28c33fd98 100644 --- a/src/OutputFormatter/GraphVizOutputFormatter.php +++ b/src/OutputFormatter/GraphVizOutputFormatter.php @@ -76,7 +76,7 @@ public function finish( $this->reportDeprecation(!empty($legacyDumpHtml), self::LEGACY_DUMP_HTML, self::DUMP_HTML, $output); $layerViolations = $this->calculateViolations($context->violations()); - $layersDependOnLayers = $this->calculateLayerDependencies($context->all()); + $layersDependOnLayers = $this->calculateLayerDependencies($context->rules()); $graph = new Graph(); diff --git a/src/OutputFormatter/JUnitOutputFormatter.php b/src/OutputFormatter/JUnitOutputFormatter.php index b34827bd2..da6d9b47c 100644 --- a/src/OutputFormatter/JUnitOutputFormatter.php +++ b/src/OutputFormatter/JUnitOutputFormatter.php @@ -93,7 +93,7 @@ private function addTestSuites(Context $context, \DOMDocument $xmlDoc): void private function addTestSuite(Context $context, \DOMDocument $xmlDoc, \DOMElement $testSuites): void { $layers = []; - foreach ($context->all() as $rule) { + foreach ($context->rules() as $rule) { if ($rule instanceof Allowed || $rule instanceof Violation || $rule instanceof SkippedViolation) { $layers[$rule->getLayerA()][] = $rule; } elseif ($rule instanceof Uncovered) { diff --git a/src/OutputFormatter/TableOutputFormatter.php b/src/OutputFormatter/TableOutputFormatter.php index f6419ddee..75dbf9dd1 100644 --- a/src/OutputFormatter/TableOutputFormatter.php +++ b/src/OutputFormatter/TableOutputFormatter.php @@ -9,6 +9,7 @@ use SensioLabs\Deptrac\Dependency\InheritDependency; use SensioLabs\Deptrac\RulesetEngine\Allowed; use SensioLabs\Deptrac\RulesetEngine\Context; +use SensioLabs\Deptrac\RulesetEngine\Error; use SensioLabs\Deptrac\RulesetEngine\Rule; use SensioLabs\Deptrac\RulesetEngine\SkippedViolation; use SensioLabs\Deptrac\RulesetEngine\Uncovered; @@ -40,7 +41,7 @@ public function finish( $groupedRules = []; $reportUncovered = $outputFormatterInput->getOptionAsBoolean(AnalyzeCommand::OPTION_REPORT_UNCOVERED); - foreach ($context->all() as $rule) { + foreach ($context->rules() as $rule) { if ($rule instanceof Allowed) { continue; } @@ -67,6 +68,10 @@ public function finish( $style->table(['Reason', $layer], $rows); } + if ($context->hasErrors()) { + $this->printErrors($context, $output); + } + $this->printSummary($context, $output); } @@ -156,4 +161,17 @@ private function uncoveredRow(Uncovered $rule): array $message, ]; } + + private function printErrors(Context $context, Output $output): void + { + $output->getStyle()->table( + ['Errors'], + array_map( + static function (Error $error) { + return [$error->toString()]; + }, + $context->errors() + ) + ); + } } diff --git a/src/RulesetEngine.php b/src/RulesetEngine.php index 0a42b9d55..110a265b5 100644 --- a/src/RulesetEngine.php +++ b/src/RulesetEngine.php @@ -10,7 +10,9 @@ use SensioLabs\Deptrac\Dependency\Result; use SensioLabs\Deptrac\RulesetEngine\Allowed; use SensioLabs\Deptrac\RulesetEngine\Context; +use SensioLabs\Deptrac\RulesetEngine\Error; use SensioLabs\Deptrac\RulesetEngine\SkippedViolation; +use SensioLabs\Deptrac\RulesetEngine\SkippedViolationHelper; use SensioLabs\Deptrac\RulesetEngine\Uncovered; use SensioLabs\Deptrac\RulesetEngine\Violation; @@ -24,7 +26,7 @@ public function process( $rules = []; $configurationRuleset = $configuration->getRuleset(); - $configurationSkippedViolation = $configuration->getSkipViolations(); + $skippedViolationHelper = new SkippedViolationHelper($configuration->getSkipViolations()); foreach ($dependencyResult->getDependenciesAndInheritDependencies() as $dependency) { $layerNames = $classNameLayerResolver->getLayersByClassName($dependency->getClassLikeNameA()); @@ -51,7 +53,7 @@ public function process( continue; } - if ($configurationSkippedViolation->isViolationSkipped($dependency->getClassLikeNameA(), $dependency->getClassLikeNameB())) { + if ($skippedViolationHelper->isViolationSkipped($dependency->getClassLikeNameA(), $dependency->getClassLikeNameB())) { $rules[] = new SkippedViolation($dependency, $layerName, $layerNameOfDependency); continue; } @@ -61,7 +63,14 @@ public function process( } } - return new Context($rules); + $errors = []; + foreach ($skippedViolationHelper->unmatchedSkippedViolations() as $classLikeNameA => $classLikes) { + foreach ($classLikes as $classLikeNameB) { + $errors[] = new Error(sprintf('Skipped violation "%s" for "%s" was not matched.', $classLikeNameB, $classLikeNameA)); + } + } + + return new Context($rules, $errors); } private function ignoreUncoveredInternalClass(Configuration $configuration, ClassLikeName $classLikeName): bool diff --git a/src/RulesetEngine/Context.php b/src/RulesetEngine/Context.php index 2b8fbf5e7..07469ab51 100644 --- a/src/RulesetEngine/Context.php +++ b/src/RulesetEngine/Context.php @@ -10,19 +10,25 @@ final class Context * @var Rule[] */ private $rules; + /** + * @var Error[] + */ + private $errors; /** - * @param Rule[] $rules + * @param Rule[] $rules + * @param Error[] $errors */ - public function __construct(array $rules) + public function __construct(array $rules, array $errors) { $this->rules = $rules; + $this->errors = $errors; } /** * @return Rule[] */ - public function all(): array + public function rules(): array { return $this->rules; } @@ -76,4 +82,17 @@ public function allowed(): array return $rule instanceof Allowed; }); } + + public function hasErrors(): bool + { + return \count($this->errors) > 0; + } + + /** + * @return Error[] + */ + public function errors(): array + { + return $this->errors; + } } diff --git a/src/RulesetEngine/Error.php b/src/RulesetEngine/Error.php new file mode 100644 index 000000000..7f5ee369c --- /dev/null +++ b/src/RulesetEngine/Error.php @@ -0,0 +1,23 @@ +message = $message; + } + + public function toString(): string + { + return $this->message; + } +} diff --git a/src/RulesetEngine/SkippedViolationHelper.php b/src/RulesetEngine/SkippedViolationHelper.php new file mode 100644 index 000000000..e81c08d39 --- /dev/null +++ b/src/RulesetEngine/SkippedViolationHelper.php @@ -0,0 +1,46 @@ + + */ + private $skippedViolation; + + /** + * @var array + */ + private $unmatchedSkippedViolation; + + public function __construct(ConfigurationSkippedViolation $configuration) + { + $this->skippedViolation = $configuration->all(); + $this->unmatchedSkippedViolation = $configuration->all(); + } + + public function isViolationSkipped(ClassLikeName $classLikeNameA, ClassLikeName $classLikeNameB): bool + { + $a = $classLikeNameA->toString(); + $b = $classLikeNameB->toString(); + + $matched = isset($this->skippedViolation[$a]) && \in_array($b, $this->skippedViolation[$a], true); + + if ($matched && false !== ($key = array_search($b, $this->unmatchedSkippedViolation[$a], true))) { + unset($this->unmatchedSkippedViolation[$a][$key]); + } + + return $matched; + } + + public function unmatchedSkippedViolations(): array + { + return array_filter($this->unmatchedSkippedViolation); + } +} diff --git a/tests/Configuration/ConfigurationSkippedViolationTest.php b/tests/Configuration/ConfigurationSkippedViolationTest.php deleted file mode 100644 index b4f2a1d29..000000000 --- a/tests/Configuration/ConfigurationSkippedViolationTest.php +++ /dev/null @@ -1,43 +0,0 @@ - [ - 'DependencyClass', - ], - 'ClassWithEmptyDeps' => [], - 'ClassWithMultipleDeps' => [ - 'DependencyClass1', - 'DependencyClass2', - 'DependencyClass2', - ], - ]); - self::assertTrue($configuration->isViolationSkipped(ClassLikeName::fromFQCN('ClassWithOneDep'), ClassLikeName::fromFQCN('DependencyClass'))); - self::assertFalse($configuration->isViolationSkipped(ClassLikeName::fromFQCN('ClassWithEmptyDeps'), ClassLikeName::fromFQCN('DependencyClass'))); - self::assertTrue($configuration->isViolationSkipped(ClassLikeName::fromFQCN('ClassWithMultipleDeps'), ClassLikeName::fromFQCN('DependencyClass1'))); - self::assertTrue($configuration->isViolationSkipped(ClassLikeName::fromFQCN('ClassWithMultipleDeps'), ClassLikeName::fromFQCN('DependencyClass2'))); - } - - public function testFromArrayWithEmptyArrayAcceptable(): void - { - $configuration = ConfigurationSkippedViolation::fromArray([]); - self::assertFalse($configuration->isViolationSkipped(ClassLikeName::fromFQCN('AnyClass'), ClassLikeName::fromFQCN('AnotherAnyClass'))); - } - - public function testFromArrayRequireOneArgument(): void - { - $this->expectException(\TypeError::class); - ConfigurationSkippedViolation::fromArray(); - } -} diff --git a/tests/Configuration/ConfigurationTest.php b/tests/Configuration/ConfigurationTest.php index 8d7d61a9f..a9ffedfd0 100644 --- a/tests/Configuration/ConfigurationTest.php +++ b/tests/Configuration/ConfigurationTest.php @@ -5,7 +5,6 @@ namespace Tests\SensioLabs\Deptrac\Configuration; use PHPUnit\Framework\TestCase; -use SensioLabs\Deptrac\AstRunner\AstMap\ClassLikeName; use SensioLabs\Deptrac\Configuration\Configuration; use SensioLabs\Deptrac\Configuration\Exception; @@ -184,8 +183,12 @@ public function testSkipViolations(): void ], ]); - self::assertTrue($configuration->getSkipViolations()->isViolationSkipped(ClassLikeName::fromFQCN('FooClass'), ClassLikeName::fromFQCN('BarClass'))); - self::assertTrue($configuration->getSkipViolations()->isViolationSkipped(ClassLikeName::fromFQCN('FooClass'), ClassLikeName::fromFQCN('AnotherClass'))); + self::assertSame([ + 'FooClass' => [ + 'BarClass', + 'AnotherClass', + ], + ], $configuration->getSkipViolations()->all()); } public function testIgnoreUncoveredInternalClassesSetToFalse(): void diff --git a/tests/OutputFormatter/ConsoleOutputFormatterTest.php b/tests/OutputFormatter/ConsoleOutputFormatterTest.php index 7d7433dbb..f101a221f 100644 --- a/tests/OutputFormatter/ConsoleOutputFormatterTest.php +++ b/tests/OutputFormatter/ConsoleOutputFormatterTest.php @@ -16,6 +16,7 @@ use SensioLabs\Deptrac\OutputFormatter\ConsoleOutputFormatter; use SensioLabs\Deptrac\OutputFormatter\OutputFormatterInput; use SensioLabs\Deptrac\RulesetEngine\Context; +use SensioLabs\Deptrac\RulesetEngine\Error; use SensioLabs\Deptrac\RulesetEngine\SkippedViolation; use SensioLabs\Deptrac\RulesetEngine\Uncovered; use SensioLabs\Deptrac\RulesetEngine\Violation; @@ -54,6 +55,7 @@ public function basicDataProvider(): iterable 'LayerB' ), ], + [], ' ClassA must not depend on ClassB (LayerA on LayerB) originalA.php::12 @@ -79,6 +81,7 @@ public function basicDataProvider(): iterable 'LayerB' ), ], + [], ' OriginalA must not depend on OriginalB (LayerA on LayerB) originalA.php::12 @@ -92,6 +95,7 @@ public function basicDataProvider(): iterable ]; yield [ + [], [], ' @@ -111,6 +115,7 @@ public function basicDataProvider(): iterable 'LayerB' ), ], + [], '[SKIPPED] OriginalA must not depend on OriginalB (LayerA on LayerB) originalA.php::12 @@ -129,6 +134,7 @@ public function basicDataProvider(): iterable 'LayerA' ), ], + [], ' Uncovered dependencies: OriginalA has uncovered dependency on OriginalB (LayerA) @@ -140,12 +146,18 @@ public function basicDataProvider(): iterable Allowed: 0 ', ]; + + yield 'an error occurred' => [ + [], + [new Error('an error occurred')], + '[ERROR]anerroroccurredReport:Violations:0Skippedviolations:0Uncovered:0Allowed:0', + ]; } /** * @dataProvider basicDataProvider */ - public function testBasic(array $rules, string $expectedOutput): void + public function testBasic(array $rules, array $errors, string $expectedOutput): void { $bufferedOutput = new BufferedOutput(); $output = new SymfonyOutput( @@ -155,7 +167,7 @@ public function testBasic(array $rules, string $expectedOutput): void $formatter = new ConsoleOutputFormatter(new EmptyEnv()); $formatter->finish( - new Context($rules), + new Context($rules, $errors), $output, new OutputFormatterInput([ AnalyzeCommand::OPTION_REPORT_UNCOVERED => true, diff --git a/tests/OutputFormatter/GithubActionsOutputFormatterTest.php b/tests/OutputFormatter/GithubActionsOutputFormatterTest.php index e75e6098c..6042c4cc1 100644 --- a/tests/OutputFormatter/GithubActionsOutputFormatterTest.php +++ b/tests/OutputFormatter/GithubActionsOutputFormatterTest.php @@ -14,6 +14,7 @@ use SensioLabs\Deptrac\OutputFormatter\GithubActionsOutputFormatter; use SensioLabs\Deptrac\OutputFormatter\OutputFormatterInput; use SensioLabs\Deptrac\RulesetEngine\Context; +use SensioLabs\Deptrac\RulesetEngine\Error; use SensioLabs\Deptrac\RulesetEngine\SkippedViolation; use SensioLabs\Deptrac\RulesetEngine\Uncovered; use SensioLabs\Deptrac\RulesetEngine\Violation; @@ -32,13 +33,13 @@ public function testGetName() /** * @dataProvider finishProvider */ - public function testFinish(array $rules, string $expectedOutput): void + public function testFinish(array $rules, array $errors, string $expectedOutput): void { $bufferedOutput = new BufferedOutput(); $formatter = new GithubActionsOutputFormatter(); $formatter->finish( - new Context($rules), + new Context($rules, $errors), $this->createSymfonyOutput($bufferedOutput), new OutputFormatterInput([ AnalyzeCommand::OPTION_REPORT_UNCOVERED => true, @@ -52,6 +53,7 @@ public function testFinish(array $rules, string $expectedOutput): void public function finishProvider(): iterable { yield 'No Rules, No Output' => [ + [], [], '', ]; @@ -68,6 +70,7 @@ public function finishProvider(): iterable 'LayerB' ), ], + [], "::error file=/home/testuser/originalA.php,line=12::ACME\OriginalA must not depend on ACME\OriginalB (LayerA on LayerB)\n", ]; @@ -79,6 +82,7 @@ public function finishProvider(): iterable 'LayerB' ), ], + [], "::warning file=/home/testuser/originalA.php,line=12::[SKIPPED] ACME\OriginalA must not depend on ACME\OriginalB (LayerA on LayerB)\n", ]; @@ -89,6 +93,7 @@ public function finishProvider(): iterable 'LayerA' ), ], + [], "::warning file=/home/testuser/originalA.php,line=12::ACME\OriginalA has uncovered dependency on ACME\OriginalB (LayerA)\n", ]; @@ -110,8 +115,15 @@ public function finishProvider(): iterable 'LayerB' ), ], + [], "::error file=originalA.php,line=12::ClassA must not depend on ClassB (LayerA on LayerB)%0AClassInheritD::6 ->%0AClassInheritC::5 ->%0AClassInheritB::4 ->%0AClassInheritA::3 ->%0AACME\OriginalB::12\n", ]; + + yield 'an error occurred' => [ + [], + [new Error('an error occurred')], + "::error ::an error occurred\n", + ]; } public function testGithubActionsOutputFormatterIsNotEnabledByDefault(): void diff --git a/tests/OutputFormatter/GraphVizOutputFormatterTest.php b/tests/OutputFormatter/GraphVizOutputFormatterTest.php index 3c0423c22..eef4dfb30 100644 --- a/tests/OutputFormatter/GraphVizOutputFormatterTest.php +++ b/tests/OutputFormatter/GraphVizOutputFormatterTest.php @@ -39,7 +39,7 @@ public function testFinish(): void new Violation(new Dependency(ClassLikeName::fromFQCN('ClassAB'), ClassLikeName::fromFQCN('ClassBA'), FileOccurrence::fromFilepath('classAB.php', 1)), 'LayerA', 'LayerB'), new Allowed(new Dependency($classA, ClassLikeName::fromFQCN('ClassC'), $fileOccurrenceA), 'LayerA', 'LayerC'), new Uncovered(new Dependency($classA, ClassLikeName::fromFQCN('ClassD'), $fileOccurrenceA), 'LayerC'), - ]); + ], []); $bufferedOutput = new BufferedOutput(); $input = new OutputFormatterInput([ diff --git a/tests/OutputFormatter/JUnitOutputFormatterTest.php b/tests/OutputFormatter/JUnitOutputFormatterTest.php index de7005421..4ab209669 100644 --- a/tests/OutputFormatter/JUnitOutputFormatterTest.php +++ b/tests/OutputFormatter/JUnitOutputFormatterTest.php @@ -124,7 +124,7 @@ public function testBasic(array $rules, string $expectedOutputFile): void { $formatter = new JUnitOutputFormatter(); $formatter->finish( - new Context($rules), + new Context($rules, []), $this->createSymfonyOutput(new BufferedOutput()), new OutputFormatterInput([ JUnitOutputFormatter::DUMP_XML => __DIR__.'/data/'.self::$actual_junit_report_file, diff --git a/tests/OutputFormatter/TableOutputFormatterTest.php b/tests/OutputFormatter/TableOutputFormatterTest.php index 848c4f9f1..703b79903 100644 --- a/tests/OutputFormatter/TableOutputFormatterTest.php +++ b/tests/OutputFormatter/TableOutputFormatterTest.php @@ -16,6 +16,7 @@ use SensioLabs\Deptrac\OutputFormatter\OutputFormatterInput; use SensioLabs\Deptrac\OutputFormatter\TableOutputFormatter; use SensioLabs\Deptrac\RulesetEngine\Context; +use SensioLabs\Deptrac\RulesetEngine\Error; use SensioLabs\Deptrac\RulesetEngine\SkippedViolation; use SensioLabs\Deptrac\RulesetEngine\Uncovered; use SensioLabs\Deptrac\RulesetEngine\Violation; @@ -67,6 +68,7 @@ public function basicDataProvider(): iterable 'LayerB' ), ], + [], ' ----------- ------------------------------------------- Reason LayerA ----------- ------------------------------------------- @@ -100,6 +102,7 @@ public function basicDataProvider(): iterable 'LayerB' ), ], + [], ' ----------- ------------------------------------------------- Reason LayerA ----------- ------------------------------------------------- @@ -121,6 +124,7 @@ public function basicDataProvider(): iterable ]; yield [ + [], [], ' -------------------- ----- @@ -143,6 +147,7 @@ public function basicDataProvider(): iterable 'LayerB' ), ], + [], ' --------- ------------------------------------------------- Reason LayerA --------- ------------------------------------------------- @@ -170,6 +175,7 @@ public function basicDataProvider(): iterable 'LayerA' ), ], + [], ' ----------- ------------------------------------------------- Reason LayerA ----------- ------------------------------------------------- @@ -187,6 +193,28 @@ public function basicDataProvider(): iterable Allowed 0 -------------------- ----- +', + ]; + + yield 'an error occurred' => [ + [], + [new Error('an error occurred')], + ' ------------------- + Errors + ------------------- + an error occurred + ------------------- + + + -------------------- ----- + Report + -------------------- ----- + Violations 0 + Skipped violations 0 + Uncovered 0 + Allowed 0 + -------------------- ----- + ', ]; } @@ -194,7 +222,7 @@ public function basicDataProvider(): iterable /** * @dataProvider basicDataProvider */ - public function testBasic(array $rules, string $expectedOutput): void + public function testBasic(array $rules, array $errors, string $expectedOutput): void { $bufferedOutput = new BufferedOutput(); $output = new SymfonyOutput( @@ -204,7 +232,7 @@ public function testBasic(array $rules, string $expectedOutput): void $formatter = new TableOutputFormatter(); $formatter->finish( - new Context($rules), + new Context($rules, $errors), $output, new OutputFormatterInput([AnalyzeCommand::OPTION_REPORT_UNCOVERED => true]) ); diff --git a/tests/OutputFormatter/XMLOutputFormatterTest.php b/tests/OutputFormatter/XMLOutputFormatterTest.php index 11bca4dc1..73d716e74 100644 --- a/tests/OutputFormatter/XMLOutputFormatterTest.php +++ b/tests/OutputFormatter/XMLOutputFormatterTest.php @@ -120,7 +120,7 @@ public function testBasic(array $rules, $expectedOutputFile): void $formatter = new XMLOutputFormatter(); $formatter->finish( - new Context($rules), + new Context($rules, []), $this->createSymfonyOutput($bufferedOutput), new OutputFormatterInput([ XMLOutputFormatter::DUMP_XML => __DIR__.'/data/'.self::$actual_xml_report_file, diff --git a/tests/RulesetEngine/SkippedViolationHelperTest.php b/tests/RulesetEngine/SkippedViolationHelperTest.php new file mode 100644 index 000000000..0f76650a2 --- /dev/null +++ b/tests/RulesetEngine/SkippedViolationHelperTest.php @@ -0,0 +1,91 @@ + [ + 'DependencyClass', + ], + 'ClassWithEmptyDeps' => [], + 'ClassWithMultipleDeps' => [ + 'DependencyClass1', + 'DependencyClass2', + 'DependencyClass2', + ], + ] + ); + $helper = new SkippedViolationHelper($configuration); + + self::assertTrue( + $helper->isViolationSkipped( + ClassLikeName::fromFQCN('ClassWithOneDep'), + ClassLikeName::fromFQCN('DependencyClass') + ) + ); + self::assertFalse( + $helper->isViolationSkipped( + ClassLikeName::fromFQCN('ClassWithEmptyDeps'), + ClassLikeName::fromFQCN('DependencyClass') + ) + ); + self::assertTrue( + $helper->isViolationSkipped( + ClassLikeName::fromFQCN('ClassWithMultipleDeps'), + ClassLikeName::fromFQCN('DependencyClass1') + ) + ); + self::assertTrue( + $helper->isViolationSkipped( + ClassLikeName::fromFQCN('ClassWithMultipleDeps'), + ClassLikeName::fromFQCN('DependencyClass2') + ) + ); + } + + public function testUnmatchedSkippedViolations(): void + { + $configuration = ConfigurationSkippedViolation::fromArray( + [ + 'ClassWithOneDep' => [ + 'DependencyClass', + ], + 'ClassWithEmptyDeps' => [], + 'ClassWithMultipleDeps' => [ + 'DependencyClass1', + 'DependencyClass2', + 'DependencyClass2', + ], + ] + ); + $helper = new SkippedViolationHelper($configuration); + + self::assertTrue( + $helper->isViolationSkipped( + ClassLikeName::fromFQCN('ClassWithOneDep'), + ClassLikeName::fromFQCN('DependencyClass') + ) + ); + self::assertSame( + [ + 'ClassWithMultipleDeps' => [ + 'DependencyClass1', + 'DependencyClass2', + 'DependencyClass2', + ], + ], + $helper->unmatchedSkippedViolations() + ); + } +}