diff --git a/src/Configuration/Configuration.php b/src/Configuration/Configuration.php index 2bc173a39..6cb6ccc40 100644 --- a/src/Configuration/Configuration.php +++ b/src/Configuration/Configuration.php @@ -23,6 +23,8 @@ class Configuration /** * @param array $args + * + * @throws Exception\InvalidConfigurationException */ public static function fromArray(array $args): self { @@ -45,11 +47,35 @@ public static function fromArray(array $args): self return new self($options); } + /** + * @throws Exception\InvalidConfigurationException + */ private function __construct(array $options) { $this->layers = array_map(static function (array $v): ConfigurationLayer { return ConfigurationLayer::fromArray($v); }, $options['layers']); + + $layerNames = array_values(array_map(static function (ConfigurationLayer $configurationLayer): string { + return $configurationLayer->getName(); + }, $this->layers)); + + $layerNamesUsedInRuleset = array_unique(array_merge( + array_keys($options['ruleset']), + ...array_values(array_map(static function (?array $rules): array { + return (array) $rules; + }, $options['ruleset'])) + )); + + $unknownLayerNames = array_diff( + $layerNamesUsedInRuleset, + $layerNames + ); + + if ([] !== $unknownLayerNames) { + throw Exception\InvalidConfigurationException::fromUnknownLayerNames(...$unknownLayerNames); + } + $this->ruleset = ConfigurationRuleset::fromArray($options['ruleset']); $this->paths = $options['paths']; $this->skipViolations = ConfigurationSkippedViolation::fromArray($options['skip_violations']); diff --git a/src/Configuration/Exception/InvalidConfigurationException.php b/src/Configuration/Exception/InvalidConfigurationException.php new file mode 100644 index 000000000..dce3ea75e --- /dev/null +++ b/src/Configuration/Exception/InvalidConfigurationException.php @@ -0,0 +1,18 @@ +expectException(Exception\InvalidConfigurationException::class); + $this->expectExceptionMessage('Configuration can not reference rule sets with unknown layer names, got "quux", "qux" as unknown.'); + + Configuration::fromArray([ + 'layers' => [ + [ + 'name' => 'foo', + 'collectors' => [], + ], + [ + 'name' => 'bar', + 'collectors' => [], + ], + [ + 'name' => 'baz', + 'collectors' => [], + ], + ], + 'paths' => [ + 'src', + ], + 'ruleset' => [ + 'foo' => [ + 'bar', + ], + 'bar' => null, + 'baz' => [ + 'bar', + 'qux', + ], + 'quux' => null, + ], + ]); + } + public function testFromArray(): void { $configuration = Configuration::fromArray([ @@ -19,7 +60,11 @@ public function testFromArray(): void 'collectors' => [], ], [ - 'name' => 'some_name', + 'name' => 'xx', + 'collectors' => [], + ], + [ + 'name' => 'yy', 'collectors' => [], ], ], @@ -32,15 +77,15 @@ public function testFromArray(): void 'bar2', ], 'ruleset' => [ - 'lala' => ['xx', 'yy'], + 'some_name' => ['xx', 'yy'], ], ]); - static::assertCount(2, $configuration->getLayers()); + static::assertCount(3, $configuration->getLayers()); static::assertEquals('some_name', $configuration->getLayers()[0]->getName()); static::assertEquals(['foo', 'bar'], $configuration->getPaths()); static::assertEquals(['foo2', 'bar2'], $configuration->getExcludeFiles()); - static::assertEquals(['xx', 'yy'], $configuration->getRuleset()->getAllowedDependencies('lala')); + static::assertEquals(['xx', 'yy'], $configuration->getRuleset()->getAllowedDependencies('some_name')); static::assertTrue($configuration->ignoreUncoveredInternalClasses()); } @@ -53,7 +98,7 @@ public function testExcludedFilesAreOptional(): void 'collectors' => [], ], [ - 'name' => 'some_name', + 'name' => 'some_other_name', 'collectors' => [], ], ], @@ -62,7 +107,7 @@ public function testExcludedFilesAreOptional(): void 'bar', ], 'ruleset' => [ - 'lala' => ['xx', 'yy'], + 'some_name' => ['some_other_name'], ], ]); diff --git a/tests/Configuration/Exception/InvalidConfigurationExceptionTest.php b/tests/Configuration/Exception/InvalidConfigurationExceptionTest.php new file mode 100644 index 000000000..8ff084da7 --- /dev/null +++ b/tests/Configuration/Exception/InvalidConfigurationExceptionTest.php @@ -0,0 +1,40 @@ +getMessage()); + } +} diff --git a/tests/RulesetEngineTest.php b/tests/RulesetEngineTest.php index fd9cbcaee..5609a22ed 100644 --- a/tests/RulesetEngineTest.php +++ b/tests/RulesetEngineTest.php @@ -13,6 +13,9 @@ use SensioLabs\Deptrac\Dependency\Result; use SensioLabs\Deptrac\RulesetEngine; +/** + * @covers \SensioLabs\Deptrac\RulesetEngine + */ class RulesetEngineTest extends TestCase { private function createDependencies(array $fromTo): iterable @@ -38,6 +41,16 @@ public function dependencyProvider(): iterable 'ClassA' => ['LayerA'], 'ClassB' => ['LayerB'], ], + [ + [ + 'name' => 'LayerA', + 'collectors' => [], + ], + [ + 'name' => 'LayerB', + 'collectors' => [], + ], + ], [ 'LayerA' => [ 'LayerB', @@ -54,6 +67,16 @@ public function dependencyProvider(): iterable 'ClassA' => ['LayerA'], 'ClassB' => ['LayerB'], ], + [ + [ + 'name' => 'LayerA', + 'collectors' => [], + ], + [ + 'name' => 'LayerB', + 'collectors' => [], + ], + ], [ 'LayerA' => [], 'LayerB' => [], @@ -69,6 +92,16 @@ public function dependencyProvider(): iterable 'ClassA' => ['LayerA'], 'ClassB' => ['LayerB'], ], + [ + [ + 'name' => 'LayerA', + 'collectors' => [], + ], + [ + 'name' => 'LayerB', + 'collectors' => [], + ], + ], [], 1, ]; @@ -82,6 +115,7 @@ public function dependencyProvider(): iterable 'ClassB' => [], ], [], + [], 0, ]; @@ -93,6 +127,16 @@ public function dependencyProvider(): iterable 'ClassA' => ['LayerA'], 'ClassB' => ['LayerB'], ], + [ + [ + 'name' => 'LayerA', + 'collectors' => [], + ], + [ + 'name' => 'LayerB', + 'collectors' => [], + ], + ], [ 'LayerA' => ['LayerB'], ], @@ -107,6 +151,16 @@ public function dependencyProvider(): iterable 'ClassA' => ['LayerA'], 'ClassB' => ['LayerB'], ], + [ + [ + 'name' => 'LayerA', + 'collectors' => [], + ], + [ + 'name' => 'LayerB', + 'collectors' => [], + ], + ], [ 'LayerB' => ['LayerA'], ], @@ -125,6 +179,24 @@ public function dependencyProvider(): iterable 'ClassC' => ['LayerC'], 'ClassD' => ['LayerD'], ], + [ + [ + 'name' => 'LayerA', + 'collectors' => [], + ], + [ + 'name' => 'LayerB', + 'collectors' => [], + ], + [ + 'name' => 'LayerC', + 'collectors' => [], + ], + [ + 'name' => 'LayerD', + 'collectors' => [], + ], + ], [], 3, ]; @@ -136,6 +208,12 @@ public function dependencyProvider(): iterable [ 'ClassA' => ['LayerA'], ], + [ + [ + 'name' => 'LayerA', + 'collectors' => [], + ], + ], [], 0, ]; @@ -144,8 +222,13 @@ public function dependencyProvider(): iterable /** * @dataProvider dependencyProvider */ - public function testProcess(array $dependenciesAsArray, array $classesInLayers, array $rulesetConfiguration, int $expectedCount): void - { + public function testProcess( + array $dependenciesAsArray, + array $classesInLayers, + array $layersConfiguration, + array $rulesetConfiguration, + int $expectedCount + ): void { $dependencyResult = new Result(); foreach ($this->createDependencies($dependenciesAsArray) as $dep) { $dependencyResult->addDependency($dep); @@ -157,7 +240,7 @@ public function testProcess(array $dependenciesAsArray, array $classesInLayers, } $configuration = Configuration::fromArray([ - 'layers' => [], + 'layers' => $layersConfiguration, 'paths' => [], 'ruleset' => $rulesetConfiguration, ]);