Skip to content

Commit

Permalink
added isFinal and isNotFinal rule (#241)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlessandroMinoccheri authored Feb 23, 2022
1 parent efc2ea8 commit ee33724
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 16 deletions.
18 changes: 16 additions & 2 deletions src/Analyzer/ClassDescription.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,21 @@ class ClassDescription
*/
private $extends;

public function __construct(FullyQualifiedClassName $FQCN, array $dependencies, array $interfaces, ?FullyQualifiedClassName $extends)
{
/** @var bool */
private $final;

public function __construct(
FullyQualifiedClassName $FQCN,
array $dependencies,
array $interfaces,
?FullyQualifiedClassName $extends,
bool $final
) {
$this->FQCN = $FQCN;
$this->dependencies = $dependencies;
$this->interfaces = $interfaces;
$this->extends = $extends;
$this->final = $final;
}

public function setFullPath(string $fullPath): void
Expand Down Expand Up @@ -116,4 +125,9 @@ public function getExtends(): ?FullyQualifiedClassName
{
return $this->extends;
}

public function isFinal(): bool
{
return $this->final;
}
}
13 changes: 12 additions & 1 deletion src/Analyzer/ClassDescriptionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class ClassDescriptionBuilder
/** @var string */
private $filePath;

/** @var bool */
private $final;

private function __construct()
{
}
Expand All @@ -31,6 +34,7 @@ public static function create(string $FQCN): self
$cdb->filePath = '';
$cdb->classDependencies = [];
$cdb->interfaces = [];
$cdb->final = false;

return $cdb;
}
Expand Down Expand Up @@ -67,9 +71,16 @@ public function setExtends(string $FQCN, int $line): self

public function get(): ClassDescription
{
$cd = new ClassDescription($this->FQCN, $this->classDependencies, $this->interfaces, $this->extend);
$cd = new ClassDescription($this->FQCN, $this->classDependencies, $this->interfaces, $this->extend, $this->final);
$cd->setFullPath($this->filePath);

return $cd;
}

public function setFinal(bool $final): self
{
$this->final = $final;

return $this;
}
}
4 changes: 4 additions & 0 deletions src/Analyzer/FileVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public function enterNode(Node $node): void
$this->classDescriptionBuilder
->setExtends($node->extends->toString(), $node->getLine());
}

if ($node->isFinal()) {
$this->classDescriptionBuilder->setFinal(true);
}
}

/**
Expand Down
33 changes: 33 additions & 0 deletions src/Expression/ForClasses/IsFinal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);

namespace Arkitect\Expression\ForClasses;

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

class IsFinal implements Expression
{
public function describe(ClassDescription $theClass): Description
{
return new PositiveDescription("{$theClass->getName()} should be final");
}

public function evaluate(ClassDescription $theClass, Violations $violations): void
{
if ($theClass->isFinal()) {
return;
}

$violation = Violation::create(
$theClass->getFQCN(),
$this->describe($theClass)->toString()
);

$violations->add($violation);
}
}
33 changes: 33 additions & 0 deletions src/Expression/ForClasses/IsNotFinal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);

namespace Arkitect\Expression\ForClasses;

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

class IsNotFinal implements Expression
{
public function describe(ClassDescription $theClass): Description
{
return new PositiveDescription("{$theClass->getName()} should not be final");
}

public function evaluate(ClassDescription $theClass, Violations $violations): void
{
if (!$theClass->isFinal()) {
return;
}

$violation = Violation::create(
$theClass->getFQCN(),
$this->describe($theClass)->toString()
);

$violations->add($violation);
}
}
26 changes: 26 additions & 0 deletions tests/Unit/Analyzer/ClassDescriptionBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,30 @@ public function test_it_should_create_builder_with_dependency_and_interface(): v
$this->assertEquals($FQCN, $classDescription->getName());
$this->assertEquals($FQCN, $classDescription->getFQCN());
}

public function test_it_should_create_final_class(): void
{
$FQCN = 'HappyIsland';
$classDescriptionBuilder = ClassDescriptionBuilder::create($FQCN);
$classDescriptionBuilder->setFinal(true);

$classDescription = $classDescriptionBuilder->get();

$this->assertInstanceOf(ClassDescription::class, $classDescription);

$this->assertTrue($classDescription->isFinal());
}

public function test_it_should_create_not_final_class(): void
{
$FQCN = 'HappyIsland';
$classDescriptionBuilder = ClassDescriptionBuilder::create($FQCN);
$classDescriptionBuilder->setFinal(false);

$classDescription = $classDescriptionBuilder->get();

$this->assertInstanceOf(ClassDescription::class, $classDescription);

$this->assertFalse($classDescription->isFinal());
}
}
6 changes: 4 additions & 2 deletions tests/Unit/Expressions/ForClasses/ExtendTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public function test_it_should_return_violation_error(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
FullyQualifiedClassName::fromString('My\AnotherClass')
FullyQualifiedClassName::fromString('My\AnotherClass'),
false
);

$violationError = $extend->describe($classDescription)->toString();
Expand All @@ -40,7 +41,8 @@ public function test_it_should_return_violation_error_if_extend_is_null(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null
null,
false
);

$violationError = $extend->describe($classDescription)->toString();
Expand Down
9 changes: 6 additions & 3 deletions tests/Unit/Expressions/ForClasses/ImplementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public function test_it_should_return_violation_error(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null
null,
false
);

$violationError = $implementConstraint->describe($classDescription)->toString();
Expand All @@ -42,7 +43,8 @@ public function test_it_should_return_true_if_not_depends_on_namespace(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[FullyQualifiedClassName::fromString('foo')],
null
null,
false
);

$violations = new Violations();
Expand All @@ -59,7 +61,8 @@ public function test_it_should_return_false_if_depends_on_namespace(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[FullyQualifiedClassName::fromString('interface')],
null
null,
false
);

$violations = new Violations();
Expand Down
52 changes: 52 additions & 0 deletions tests/Unit/Expressions/ForClasses/IsFinalTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Arkitect\Tests\Unit\Expressions\ForClasses;

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

class IsFinalTest extends TestCase
{
public function test_it_should_return_violation_error(): void
{
$isFinal = new IsFinal();
$classDescription = new ClassDescription(
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null,
false
);

$violationError = $isFinal->describe($classDescription)->toString();

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

$this->assertEquals('HappyIsland should be final', $violationError);
}

public function test_it_should_return_true_if_is_final(): void
{
$class = 'myClass';

$isFinal = new IsFinal();
$classDescription = new ClassDescription(
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null,
true
);

$violations = new Violations();
$isFinal->evaluate($classDescription, $violations);
self::assertEquals(0, $violations->count());
}
}
50 changes: 50 additions & 0 deletions tests/Unit/Expressions/ForClasses/IsNotFinalTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace Arkitect\Tests\Unit\Expressions\ForClasses;

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

class IsNotFinalTest extends TestCase
{
public function test_it_should_return_violation_error(): void
{
$isFinal = new IsNotFinal();
$classDescription = new ClassDescription(
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null,
true
);

$violationError = $isFinal->describe($classDescription)->toString();

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

$this->assertEquals('HappyIsland should not be final', $violationError);
}

public function test_it_should_return_true_if_is_final(): void
{
$isFinal = new IsNotFinal();
$classDescription = new ClassDescription(
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null,
false
);

$violations = new Violations();
$isFinal->evaluate($classDescription, $violations);
self::assertEquals(0, $violations->count());
}
}
3 changes: 2 additions & 1 deletion tests/Unit/Expressions/ForClasses/NotExtendTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public function test_it_should_return_violation_error(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
FullyQualifiedClassName::fromString('My\BaseClass')
FullyQualifiedClassName::fromString('My\BaseClass'),
false
);

$violationError = $notExtend->describe($classDescription)->toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public function test_it_should_return_violation_error(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[],
[],
null
null,
false
);

$violationError = $notHaveDependencyOutsideNamespace->describe($classDescription)->toString();
Expand All @@ -36,7 +37,8 @@ public function test_it_should_return_true_if_not_depends_on_namespace(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[new ClassDependency('myNamespace', 100)],
[],
null
null,
false
);

$violations = new Violations();
Expand All @@ -51,7 +53,8 @@ public function test_it_should_return_false_if_depends_on_namespace(): void
FullyQualifiedClassName::fromString('HappyIsland'),
[new ClassDependency('myNamespace', 100), new ClassDependency('another\class', 200)],
[],
null
null,
false
);

$violations = new Violations();
Expand All @@ -66,7 +69,8 @@ public function test_it_should_not_return_violation_error_if_dependency_excluded
FullyQualifiedClassName::fromString('HappyIsland'),
[new ClassDependency('foo', 100)],
[],
null
null,
false
);

$violations = new Violations();
Expand Down
Loading

0 comments on commit ee33724

Please sign in to comment.