diff --git a/fixture_src/Fixtures.php b/fixture_src/Fixtures.php index b807c13..d686dbc 100644 --- a/fixture_src/Fixtures.php +++ b/fixture_src/Fixtures.php @@ -82,4 +82,7 @@ public static function classOnlyAttributeSingleInterface() : ClassOnlyAttributeS return new ClassOnlyAttributeSingleInterfaceFixture(); } + public static function targetAttributeInterface() : TargetAttributeInterfaceFixture { + return new TargetAttributeInterfaceFixture(); + } } \ No newline at end of file diff --git a/fixture_src/TargetAttributeImplementation.php b/fixture_src/TargetAttributeImplementation.php new file mode 100644 index 0000000..7a82f58 --- /dev/null +++ b/fixture_src/TargetAttributeImplementation.php @@ -0,0 +1,9 @@ +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_) { @@ -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); diff --git a/tests/Unit/TargetAttributeInterfaceTest.php b/tests/Unit/TargetAttributeInterfaceTest.php new file mode 100644 index 0000000..6c42862 --- /dev/null +++ b/tests/Unit/TargetAttributeInterfaceTest.php @@ -0,0 +1,49 @@ +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' + );