Skip to content

Commit

Permalink
Check filtered attributes on instance type (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
cspray authored Aug 11, 2022
1 parent 03d99ec commit 190be08
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 1 deletion.
3 changes: 3 additions & 0 deletions fixture_src/Fixtures.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,7 @@ public static function classOnlyAttributeSingleInterface() : ClassOnlyAttributeS
return new ClassOnlyAttributeSingleInterfaceFixture();
}

public static function targetAttributeInterface() : TargetAttributeInterfaceFixture {
return new TargetAttributeInterfaceFixture();
}
}
9 changes: 9 additions & 0 deletions fixture_src/TargetAttributeImplementation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Cspray\AnnotatedTargetFixture;

#[\Attribute(\Attribute::TARGET_CLASS)]
final class TargetAttributeImplementation implements TargetAttributeInterface {

public function __construct(public readonly string $value) {}
}
7 changes: 7 additions & 0 deletions fixture_src/TargetAttributeInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Cspray\AnnotatedTargetFixture;

interface TargetAttributeInterface {

}
10 changes: 10 additions & 0 deletions fixture_src/TargetAttributeInterface/TargetClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Cspray\AnnotatedTargetFixture\TargetAttributeInterface;

use Cspray\AnnotatedTargetFixture\TargetAttributeImplementation;

#[TargetAttributeImplementation('target-attr')]
class TargetClass {

}
18 changes: 18 additions & 0 deletions fixture_src/TargetAttributeInterfaceFixture.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Cspray\AnnotatedTargetFixture;

use Cspray\AnnotatedTargetFixture\TargetAttributeInterface\TargetClass;
use Cspray\Typiphy\ObjectType;
use function Cspray\Typiphy\objectType;

final class TargetAttributeInterfaceFixture implements Fixture {

public function getPath() : string {
return __DIR__ . '/TargetAttributeInterface';
}

public function targetClass() : ObjectType {
return objectType(TargetClass::class);
}
}
12 changes: 11 additions & 1 deletion src/PhpParserAnnotatedTargetParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public function leaveNode(Node $node) {
foreach ($node->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
$attrType = $attr->name->toString();
if (!empty($this->filteredAttributes) && !in_array($attrType, $this->filteredAttributes)) {
if (!empty($this->filteredAttributes) && !$this->isAttributeInstanceOfFilteredAttribute($attrType)) {
continue;
}
if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Interface_) {
Expand All @@ -106,6 +106,16 @@ public function leaveNode(Node $node) {
}
}

private function isAttributeInstanceOfFilteredAttribute(string $attrType) : bool {
foreach ($this->filteredAttributes as $filteredAttribute) {
if (is_a($attrType, $filteredAttribute, true)) {
return true;
}
}

return false;
}

private function getAnnotatedTargetFromClassNode(Node\Stmt\Class_|Node\Stmt\Interface_ $class, int $index) : AnnotatedTarget {
$classType = $class->namespacedName->toString();
return $this->getAnnotatedTarget(fn() => new ReflectionClass($classType), $index);
Expand Down
49 changes: 49 additions & 0 deletions tests/Unit/TargetAttributeInterfaceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Cspray\AnnotatedTarget\Unit;

use Cspray\AnnotatedTargetFixture\Fixtures;
use Cspray\AnnotatedTargetFixture\TargetAttributeImplementation;
use Cspray\AnnotatedTargetFixture\TargetAttributeInterface;
use function Cspray\Typiphy\objectType;

uses(AnnotatedTargetParserTestCase::class);

beforeEach()->withFixtures(Fixtures::targetAttributeInterface())
->withFilteredAttributes(objectType(TargetAttributeInterface::class));

it('counts parsed targets for single class')
->expect(fn() => $this->getTargets())
->toHaveCount(1);

it('ensures all targets are correct type')
->expect(fn() => $this->getTargets())
->toContainOnlyAnnotatedTargets();

it('ensures all targets share target reflection')
->expect(fn() => $this->getTargets())
->toShareTargetReflection();

it('ensures all targets share attribute reflection')
->expect(fn() => $this->getTargets())
->toShareAttributeReflection();

it('ensures all targets share attribute instance')
->expect(fn() => $this->getTargets())
->toShareAttributeInstance();

it('includes target reflection class')
->expect(fn() => $this->getTargets())
->toContainTargetClass(Fixtures::targetAttributeInterface()->targetClass());

it('includes attribute reflection class')
->expect(fn() => $this->getTargets())
->toContainTargetClassWithAttribute(Fixtures::targetAttributeInterface()->targetClass(), objectType(TargetAttributeImplementation::class));

it('includes attribute instance with correct value')
->expect(fn() => $this->getTargets())
->toContainTargetClassWithAttributeInstance(
Fixtures::targetAttributeInterface()->targetClass(),
objectType(TargetAttributeImplementation::class),
fn(TargetAttributeImplementation $classOnly) => $classOnly->value === 'target-attr'
);

0 comments on commit 190be08

Please sign in to comment.