diff --git a/src/Expression/ForClasses/Andx.php b/src/Expression/ForClasses/Andx.php new file mode 100644 index 00000000..d5ca94d1 --- /dev/null +++ b/src/Expression/ForClasses/Andx.php @@ -0,0 +1,58 @@ +expressions = $expressions; + } + + public function describe(ClassDescription $theClass, string $because): Description + { + $expressionsDescriptions = []; + foreach ($this->expressions as $expression) { + $expressionsDescriptions[] = $expression->describe($theClass, '')->toString(); + } + return new Description( + 'all expressions must be true (' . implode(', ', $expressionsDescriptions) . ')', + $because + ); + } + + public function evaluate(ClassDescription $theClass, Violations $violations, string $because): void + { + foreach ($this->expressions as $expression) { + $newViolations = new Violations(); + $expression->evaluate($theClass, $newViolations, $because); + if (0 !== $newViolations->count()) { + $violations->add(Violation::create( + $theClass->getFQCN(), + ViolationMessage::withDescription( + $this->describe($theClass, $because), + "The class '" . $theClass->getFQCN() . "' violated the expression " + . $expression->describe($theClass, '')->toString() + ) + )); + + return; + } + } + } +} diff --git a/tests/Unit/Expressions/ForClasses/AndxTest.php b/tests/Unit/Expressions/ForClasses/AndxTest.php new file mode 100644 index 00000000..0da6db1c --- /dev/null +++ b/tests/Unit/Expressions/ForClasses/AndxTest.php @@ -0,0 +1,81 @@ +evaluate($classDescription, $violations, $because); + + self::assertEquals(0, $violations->count()); + } + + public function test_it_should_not_pass_the_rule(): void + { + $interface = 'SomeInterface'; + $class = 'SomeClass'; + + $classDescription = new ClassDescription( + FullyQualifiedClassName::fromString('HappyIsland'), + [], + [FullyQualifiedClassName::fromString($interface)], + null, + false, + false, + false, + false, + false + ); + + $implementConstraint = new Implement($interface); + $extendsConstraint = new Extend($class); + $andConstraint = new Andx($implementConstraint, $extendsConstraint); + + $because = 'reasons'; + $violationError = $andConstraint->describe($classDescription, $because)->toString(); + + $violations = new Violations(); + $andConstraint->evaluate($classDescription, $violations, $because); + self::assertNotEquals(0, $violations->count()); + + $this->assertEquals( + 'all expressions must be true (should implement SomeInterface, should extend SomeClass) because reasons', + $violationError + ); + $this->assertEquals( + "The class 'HappyIsland' violated the expression should extend SomeClass, but " + . "all expressions must be true (should implement SomeInterface, should extend SomeClass) because reasons", + $violations->get(0)->getError() + ); + } +}