Skip to content

Commit

Permalink
Create a Not expression
Browse files Browse the repository at this point in the history
This will reduce the amount of expressions needed
and allow for complex expressions (within an OR
or an AND) to be negated.
  • Loading branch information
Herberto Graca committed Jul 26, 2023
1 parent 976c200 commit 5cb4c9c
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/Expression/ForClasses/Not.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Arkitect\Expression\ForClasses;

use Arkitect\Analyzer\ClassDescription;
use Arkitect\Expression\Description;
use Arkitect\Expression\Expression;
use Arkitect\Rules\Violation;
use Arkitect\Rules\ViolationMessage;
use Arkitect\Rules\Violations;

final class Not implements Expression
{
/** @var Expression */
private $expression;

public function __construct(Expression $expression)
{
$this->expression = $expression;
}

public function describe(ClassDescription $theClass, string $because): Description
{
return new Description('must NOT (' . $this->expression->describe($theClass, '')->toString() . ')', $because);
}

public function evaluate(ClassDescription $theClass, Violations $violations, string $because): void
{
$newViolations = new Violations();
$this->expression->evaluate($theClass, $newViolations, $because);
if (0 !== $newViolations->count()) {
return;
}

$violations->add(Violation::create(
$theClass->getFQCN(),
ViolationMessage::selfExplanatory($this->describe($theClass, $because))
));
}
}
59 changes: 59 additions & 0 deletions tests/Unit/Expressions/ForClasses/NotTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace Arkitect\Tests\Unit\Expressions\ForClasses;

use Arkitect\Analyzer\ClassDescription;
use Arkitect\Analyzer\FullyQualifiedClassName;
use Arkitect\Expression\ForClasses\IsInterface;
use Arkitect\Expression\ForClasses\Not;
use Arkitect\Rules\Violations;
use PHPUnit\Framework\TestCase;

class NotTest extends TestCase
{
public function test_it_should_return_violation_error(): void
{
$isNotInterface = new Not(new IsInterface());
$classDescription = new ClassDescription(
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null,
false,
false,
true,
false,
false
);
$because = 'we want to add this rule for our software';
$violationError = $isNotInterface->describe($classDescription, $because)->toString();

$violations = new Violations();
$isNotInterface->evaluate($classDescription, $violations, $because);
self::assertNotEquals(0, $violations->count());

$this->assertEquals('must NOT (HappyIsland should be an interface) because we want to add this rule for our software', $violationError);
}

public function test_it_should_return_true_if_is_not_interface(): void
{
$isNotInterface = new Not(new IsInterface());
$classDescription = new ClassDescription(
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null,
false,
false,
false,
false,
false
);
$because = 'we want to add this rule for our software';
$violations = new Violations();
$isNotInterface->evaluate($classDescription, $violations, $because);
self::assertEquals(0, $violations->count());
}
}

0 comments on commit 5cb4c9c

Please sign in to comment.