diff --git a/README.md b/README.md index 27e65019..882dc41a 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ Currently, you can check if a class: ```php $rules[] = Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces('App\Domain')) - ->should(new DependsOnlyOnTheseNamespaces('App\Domain', 'Ramsey\Uuid')) + ->should(new DependsOnlyOnTheseNamespaces(['App\Domain', 'Ramsey\Uuid'], ['App\Excluded'])) ->because('we want to protect our domain from external dependencies except for Ramsey\Uuid'); ``` @@ -348,7 +348,7 @@ $rules[] = Rule::allClasses() ```php $rules[] = Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces('App\Application')) - ->should(new NotDependsOnTheseNamespaces('App\Infrastructure')) + ->should(new NotDependsOnTheseNamespaces(['App\Infrastructure'], ['App\Infrastructure\Repository'])) ->because('we want to avoid coupling between application layer and infrastructure layer'); ``` diff --git a/src/Expression/ForClasses/DependsOnlyOnTheseNamespaces.php b/src/Expression/ForClasses/DependsOnlyOnTheseNamespaces.php index 4b647254..a2dedc87 100644 --- a/src/Expression/ForClasses/DependsOnlyOnTheseNamespaces.php +++ b/src/Expression/ForClasses/DependsOnlyOnTheseNamespaces.php @@ -17,9 +17,13 @@ class DependsOnlyOnTheseNamespaces implements Expression /** @var array */ private array $namespaces; - public function __construct(string ...$namespace) + /** @var array */ + private array $exclude; + + public function __construct(array $namespaces = [], array $exclude = []) { - $this->namespaces = $namespace; + $this->namespaces = $namespaces; + $this->exclude = $exclude; } public function describe(ClassDescription $theClass, string $because): Description @@ -35,11 +39,16 @@ public function evaluate(ClassDescription $theClass, Violations $violations, str /** @var ClassDependency $dependency */ foreach ($dependencies as $dependency) { - if ( - '' === $dependency->getFQCN()->namespace() - || $theClass->namespaceMatches($dependency->getFQCN()->namespace()) - ) { - continue; + if ('' === $dependency->getFQCN()->namespace()) { + continue; // skip root namespace + } + + if ($theClass->namespaceMatches($dependency->getFQCN()->namespace())) { + continue; // skip classes in the same namespace + } + + if ($dependency->matchesOneOf(...$this->exclude)) { + continue; // skip excluded namespaces } if (!$dependency->matchesOneOf(...$this->namespaces)) { diff --git a/src/Expression/ForClasses/NotDependsOnTheseNamespaces.php b/src/Expression/ForClasses/NotDependsOnTheseNamespaces.php index e9ee5b48..2840b4b0 100644 --- a/src/Expression/ForClasses/NotDependsOnTheseNamespaces.php +++ b/src/Expression/ForClasses/NotDependsOnTheseNamespaces.php @@ -17,9 +17,13 @@ class NotDependsOnTheseNamespaces implements Expression /** @var array */ private array $namespaces; - public function __construct(string ...$namespace) + /** @var array */ + private array $exclude; + + public function __construct(array $namespaces, array $exclude = []) { - $this->namespaces = $namespace; + $this->namespaces = $namespaces; + $this->exclude = $exclude; } public function describe(ClassDescription $theClass, string $because): Description @@ -36,7 +40,11 @@ public function evaluate(ClassDescription $theClass, Violations $violations, str /** @var ClassDependency $dependency */ foreach ($dependencies as $dependency) { if ('' === $dependency->getFQCN()->namespace()) { - continue; + continue; // skip root namespace + } + + if ($dependency->matchesOneOf(...$this->exclude)) { + continue; // skip excluded namespaces } if ($dependency->matchesOneOf(...$this->namespaces)) { diff --git a/src/RuleBuilders/Architecture/Architecture.php b/src/RuleBuilders/Architecture/Architecture.php index 22a95d6e..3468830d 100644 --- a/src/RuleBuilders/Architecture/Architecture.php +++ b/src/RuleBuilders/Architecture/Architecture.php @@ -90,13 +90,13 @@ public function rules(string $because = 'of component architecture'): iterable $forbiddenComponents = array_diff($layerNames, [$name], $this->allowedDependencies[$name]); if (!empty($forbiddenComponents)) { - $forbiddenSelectors = array_map(function (string $componentName): string { + $forbiddenSelectors = array_values(array_map(function (string $componentName): string { return $this->componentSelectors[$componentName]; - }, $forbiddenComponents); + }, $forbiddenComponents)); yield Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces($selector)) - ->should(new NotDependsOnTheseNamespaces(...$forbiddenSelectors)) + ->should(new NotDependsOnTheseNamespaces($forbiddenSelectors)) ->because($because); } } @@ -105,13 +105,13 @@ public function rules(string $because = 'of component architecture'): iterable continue; } - $allowedDependencies = array_map(function (string $componentName): string { + $allowedDependencies = array_values(array_map(function (string $componentName): string { return $this->componentSelectors[$componentName]; - }, $this->componentDependsOnlyOnTheseNamespaces[$name]); + }, $this->componentDependsOnlyOnTheseNamespaces[$name])); yield Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces($selector)) - ->should(new DependsOnlyOnTheseNamespaces(...$allowedDependencies)) + ->should(new DependsOnlyOnTheseNamespaces($allowedDependencies)) ->because($because); } } diff --git a/tests/E2E/_fixtures/configDependenciesLeak.php b/tests/E2E/_fixtures/configDependenciesLeak.php index da280d1b..64abebe4 100644 --- a/tests/E2E/_fixtures/configDependenciesLeak.php +++ b/tests/E2E/_fixtures/configDependenciesLeak.php @@ -12,7 +12,7 @@ $rule_1 = Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces('App\DependenciesLeak\SecondModule')) - ->should(new NotDependsOnTheseNamespaces('App\DependenciesLeak\FirstModule')) + ->should(new NotDependsOnTheseNamespaces(['App\DependenciesLeak\FirstModule'])) ->because('modules should be independent'); $config diff --git a/tests/E2E/_fixtures/configIgnoreBaselineLineNumbers.php b/tests/E2E/_fixtures/configIgnoreBaselineLineNumbers.php index 9fc5c54e..69f8de27 100644 --- a/tests/E2E/_fixtures/configIgnoreBaselineLineNumbers.php +++ b/tests/E2E/_fixtures/configIgnoreBaselineLineNumbers.php @@ -15,7 +15,7 @@ $rules = [ Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces('App\Application')) - ->should(new DependsOnlyOnTheseNamespaces('App\Application')) + ->should(new DependsOnlyOnTheseNamespaces(['App\Application'])) ->because('That is how I want it'), ]; diff --git a/tests/Integration/CheckAttributeDependencyTest.php b/tests/Integration/CheckAttributeDependencyTest.php index 4b57395b..c01bf85a 100644 --- a/tests/Integration/CheckAttributeDependencyTest.php +++ b/tests/Integration/CheckAttributeDependencyTest.php @@ -21,7 +21,7 @@ public function test_assertion_should_fail_on_invalid_dependency(): void $rule = Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces('App')) - ->should(new NotDependsOnTheseNamespaces('App\Invalid')) + ->should(new NotDependsOnTheseNamespaces(['App\Invalid'])) ->because('i said so'); $runner->run($dir, $rule); diff --git a/tests/Unit/Analyzer/FileVisitorTest.php b/tests/Unit/Analyzer/FileVisitorTest.php index eaa7d0d4..a24e5e8b 100644 --- a/tests/Unit/Analyzer/FileVisitorTest.php +++ b/tests/Unit/Analyzer/FileVisitorTest.php @@ -23,6 +23,14 @@ class FileVisitorTest extends TestCase { + public function test_should_parse_non_php_file(): void + { + $fp = FileParserFactory::createFileParser(TargetPhpVersion::create('7.4')); + $fp->parse('', 'path/to/class.php'); + + self::assertEmpty($fp->getClassDescriptions()); + } + public function test_should_parse_empty_file(): void { $code = <<< 'EOF' @@ -59,7 +67,7 @@ public function __construct(Request $request) $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Foo'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Foo']); $dependsOnTheseNamespaces->evaluate($fp->getClassDescriptions()[0], $violations, 'because'); self::assertCount(2, $violations); @@ -231,7 +239,7 @@ public function __construct(Request $request) $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Foo', 'Symfony', 'Doctrine'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Foo', 'Symfony', 'Doctrine']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(0, $violations); @@ -300,7 +308,7 @@ public function __construct() $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Foo', 'Symfony', 'Doctrine'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Foo', 'Symfony', 'Doctrine']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(0, $violations); @@ -679,7 +687,7 @@ class ApplicationLevelDto $violations = new Violations(); - $notHaveDependencyOutsideNamespace = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application'); + $notHaveDependencyOutsideNamespace = new DependsOnlyOnTheseNamespaces(['MyProject\AppBundle\Application']); $notHaveDependencyOutsideNamespace->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -707,7 +715,7 @@ class ApplicationLevelDto $violations = new Violations(); - $notHaveDependencyOutsideNamespace = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application'); + $notHaveDependencyOutsideNamespace = new DependsOnlyOnTheseNamespaces(['MyProject\AppBundle\Application']); $notHaveDependencyOutsideNamespace->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -801,7 +809,7 @@ class ApplicationLevelDto $violations = new Violations(); - $notHaveDependencyOutsideNamespace = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application'); + $notHaveDependencyOutsideNamespace = new DependsOnlyOnTheseNamespaces(['MyProject\AppBundle\Application']); $notHaveDependencyOutsideNamespace->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -831,7 +839,7 @@ class ApplicationLevelDto $violations = new Violations(); - $notHaveDependencyOutsideNamespace = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application'); + $notHaveDependencyOutsideNamespace = new DependsOnlyOnTheseNamespaces(['MyProject\AppBundle\Application']); $notHaveDependencyOutsideNamespace->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -894,7 +902,7 @@ class ApplicationLevelDto $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['MyProject\AppBundle\Application']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -920,7 +928,7 @@ public function getBookList(): QueryBuilder; $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['MyProject\AppBundle\Application']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -991,7 +999,7 @@ public function getRequest(): Request //the violations is reported here $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Foo', 'Symfony', 'Doctrine'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Foo', 'Symfony', 'Doctrine']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(0, $violations); @@ -1020,7 +1028,7 @@ class ApplicationLevelDto $violations = new Violations(); - $dependsOnlyOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application'); + $dependsOnlyOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['MyProject\AppBundle\Application']); $dependsOnlyOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(0, $violations); @@ -1079,7 +1087,7 @@ class MyClass $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1109,7 +1117,7 @@ class MyClass $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1139,7 +1147,7 @@ class MyClass $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1171,7 +1179,7 @@ public function __construct(array $dtoList) $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1203,7 +1211,7 @@ public function __construct(array $dtoList) $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1235,7 +1243,7 @@ public function __construct(array $dtoList) $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1270,7 +1278,7 @@ public function __construct(string $var1, array $dtoList, $var2, array $voList) $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1303,7 +1311,7 @@ public function getList(): array $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1336,7 +1344,7 @@ public function getList(): array $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1369,7 +1377,7 @@ public function getList(): array $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('Domain'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['Domain']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); @@ -1398,7 +1406,7 @@ public function getBookList(): QueryBuilder $violations = new Violations(); - $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application'); + $dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces(['MyProject\AppBundle\Application']); $dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software'); self::assertCount(1, $violations); diff --git a/tests/Unit/Architecture/ArchitectureTest.php b/tests/Unit/Architecture/ArchitectureTest.php index b4f484f3..97fe2966 100644 --- a/tests/Unit/Architecture/ArchitectureTest.php +++ b/tests/Unit/Architecture/ArchitectureTest.php @@ -28,11 +28,11 @@ public function test_layered_architecture(): void $expectedRules = [ Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces('App\*\Domain\*')) - ->should(new NotDependsOnTheseNamespaces('App\*\Application\*', 'App\*\Infrastructure\*')) + ->should(new NotDependsOnTheseNamespaces(['App\*\Application\*', 'App\*\Infrastructure\*'])) ->because('of component architecture'), Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces('App\*\Application\*')) - ->should(new NotDependsOnTheseNamespaces('App\*\Infrastructure\*')) + ->should(new NotDependsOnTheseNamespaces(['App\*\Infrastructure\*'])) ->because('of component architecture'), ]; @@ -50,7 +50,7 @@ public function test_layered_architecture_with_depends_only_on_components(): voi $expectedRules = [ Rule::allClasses() ->that(new ResideInOneOfTheseNamespaces('App\*\Domain\*')) - ->should(new DependsOnlyOnTheseNamespaces('App\*\Domain\*')) + ->should(new DependsOnlyOnTheseNamespaces(['App\*\Domain\*'])) ->because('of component architecture'), ]; diff --git a/tests/Unit/Expressions/ForClasses/DependsOnlyOnTheseNamespacesTest.php b/tests/Unit/Expressions/ForClasses/DependsOnlyOnTheseNamespacesTest.php index 34475f72..3ab2c58a 100644 --- a/tests/Unit/Expressions/ForClasses/DependsOnlyOnTheseNamespacesTest.php +++ b/tests/Unit/Expressions/ForClasses/DependsOnlyOnTheseNamespacesTest.php @@ -14,7 +14,7 @@ class DependsOnlyOnTheseNamespacesTest extends TestCase { public function test_it_should_return_true_if_it_has_no_dependencies(): void { - $dependOnClasses = new DependsOnlyOnTheseNamespaces('myNamespace'); + $dependOnClasses = new DependsOnlyOnTheseNamespaces(['myNamespace']); $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php')->build(); @@ -31,7 +31,7 @@ public function test_it_should_return_true_if_it_has_no_dependencies(): void public function test_it_should_return_true_if_not_depends_on_namespace(): void { - $dependOnClasses = new DependsOnlyOnTheseNamespaces('myNamespace'); + $dependOnClasses = new DependsOnlyOnTheseNamespaces(['myNamespace']); $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php') ->addDependency(new ClassDependency('myNamespace\Banana', 0)) @@ -51,7 +51,7 @@ public function test_it_should_return_true_if_not_depends_on_namespace(): void public function test_it_should_return_true_if_depends_on_class_in_root_namespace(): void { - $dependOnClasses = new DependsOnlyOnTheseNamespaces('myNamespace'); + $dependOnClasses = new DependsOnlyOnTheseNamespaces(['myNamespace']); $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php') ->addDependency(new ClassDependency('myNamespace\Banana', 0)) @@ -69,7 +69,7 @@ public function test_it_should_return_true_if_depends_on_class_in_root_namespace public function test_it_should_return_false_if_depends_on_namespace(): void { - $dependOnClasses = new DependsOnlyOnTheseNamespaces('myNamespace'); + $dependOnClasses = new DependsOnlyOnTheseNamespaces(['myNamespace']); $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php') ->addDependency(new ClassDependency('myNamespace\Banana', 0)) @@ -98,4 +98,20 @@ public function test_it_should_return_true_if_depends_on_same_namespace_without_ self::assertEquals(1, $violations->count()); } + + public function test_it_should_return_false_if_namespace_is_excluded(): void + { + $dependOnClasses = new DependsOnlyOnTheseNamespaces(['HappyIsland'], ['myNamespace']); + + $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php') + ->addDependency(new ClassDependency('HappyIsland\Banana', 0)) + ->addDependency(new ClassDependency('myNamespace\Mango', 10)) + ->build(); + + $because = 'we want to add this rule for our software'; + $violations = new Violations(); + $dependOnClasses->evaluate($classDescription, $violations, $because); + + self::assertEquals(0, $violations->count()); + } } diff --git a/tests/Unit/Expressions/ForClasses/NotDependsOnTheseNamespacesTest.php b/tests/Unit/Expressions/ForClasses/NotDependsOnTheseNamespacesTest.php index 0477b2df..c3155139 100644 --- a/tests/Unit/Expressions/ForClasses/NotDependsOnTheseNamespacesTest.php +++ b/tests/Unit/Expressions/ForClasses/NotDependsOnTheseNamespacesTest.php @@ -14,7 +14,7 @@ class NotDependsOnTheseNamespacesTest extends TestCase { public function test_it_should_return_true_if_it_has_no_dependencies(): void { - $notDependOnClasses = new NotDependsOnTheseNamespaces('myNamespace'); + $notDependOnClasses = new NotDependsOnTheseNamespaces(['myNamespace']); $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php')->build(); $because = 'we want to add this rule for our software'; @@ -26,7 +26,7 @@ public function test_it_should_return_true_if_it_has_no_dependencies(): void public function test_it_should_return_true_if_not_depends_on_namespace(): void { - $notDependOnClasses = new NotDependsOnTheseNamespaces('myNamespace'); + $notDependOnClasses = new NotDependsOnTheseNamespaces(['myNamespace']); $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php') ->addDependency(new ClassDependency('myNamespace\Banana', 0)) @@ -46,7 +46,7 @@ public function test_it_should_return_true_if_not_depends_on_namespace(): void public function test_it_should_return_true_if_depends_on_class_in_root_namespace(): void { - $notDependOnClasses = new NotDependsOnTheseNamespaces('myNamespace'); + $notDependOnClasses = new NotDependsOnTheseNamespaces(['myNamespace']); $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php') ->addDependency(new ClassDependency('myNamespace\Banana', 0)) @@ -67,7 +67,7 @@ public function test_it_should_return_true_if_depends_on_class_in_root_namespace public function test_it_should_return_false_if_depends_on_namespace(): void { - $notDependOnClasses = new NotDependsOnTheseNamespaces('myNamespace'); + $notDependOnClasses = new NotDependsOnTheseNamespaces(['myNamespace']); $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php') ->addDependency(new ClassDependency('myNamespace\Banana', 0)) @@ -84,4 +84,20 @@ public function test_it_should_return_false_if_depends_on_namespace(): void $violations->get(0)->getError() ); } + + public function test_it_should_ignore_excluded_namespaces(): void + { + $notDependOnClasses = new NotDependsOnTheseNamespaces(['myNamespace'], ['myNamespace\Mango']); + + $classDescription = ClassDescription::getBuilder('HappyIsland\Myclass', 'src/Foo.php') + ->addDependency(new ClassDependency('myNamespace\Banana', 0)) + ->addDependency(new ClassDependency('myNamespace\Mango', 10)) + ->build(); + + $because = 'we want to add this rule for our software'; + $violations = new Violations(); + $notDependOnClasses->evaluate($classDescription, $violations, $because); + + self::assertEquals(1, $violations->count()); + } }