From fba45a37189a12ff98089e73c0f42429885f0541 Mon Sep 17 00:00:00 2001 From: Jaapio Date: Wed, 24 Dec 2025 16:09:27 +0100 Subject: [PATCH] More cleanup of tag creation TagWithType need to be created via a factory now. --- docs/upgrade-to-v6.rst | 0 src/DocBlock/StandardTagFactory.php | 98 +++++++---- src/DocBlock/Tags/Factory/MixinFactory.php | 52 ++++++ src/DocBlock/Tags/Factory/ParamFactory.php | 5 +- src/DocBlock/Tags/Factory/ThrowsFactory.php | 52 ++++++ src/DocBlock/Tags/Mixin.php | 21 --- src/DocBlock/Tags/Param.php | 2 - src/DocBlock/Tags/TagWithType.php | 2 +- src/DocBlock/Tags/TemplateCovariant.php | 21 --- src/DocBlock/Tags/Throws.php | 21 --- src/DocBlockFactory.php | 46 +----- src/Exception/ParserException.php | 19 +++ src/Exception/ReflectionDocblockException.php | 11 ++ .../integration/InterpretingDocBlocksTest.php | 33 ++-- .../unit/DocBlock/StandardTagFactoryTest.php | 80 ++++----- tests/unit/DocBlock/Tags/CoversTest.php | 5 +- tests/unit/DocBlock/Tags/LinkTest.php | 11 +- tests/unit/DocBlock/Tags/SeeTest.php | 5 +- tests/unit/DocBlock/Tags/ThrowsTest.php | 152 ------------------ tests/unit/DocBlock/Tags/UsesTest.php | 8 +- 20 files changed, 267 insertions(+), 377 deletions(-) create mode 100644 docs/upgrade-to-v6.rst create mode 100644 src/DocBlock/Tags/Factory/MixinFactory.php create mode 100644 src/DocBlock/Tags/Factory/ThrowsFactory.php create mode 100644 src/Exception/ParserException.php create mode 100644 src/Exception/ReflectionDocblockException.php diff --git a/docs/upgrade-to-v6.rst b/docs/upgrade-to-v6.rst new file mode 100644 index 0000000..e69de29 diff --git a/src/DocBlock/StandardTagFactory.php b/src/DocBlock/StandardTagFactory.php index e580ef6..75caea2 100644 --- a/src/DocBlock/StandardTagFactory.php +++ b/src/DocBlock/StandardTagFactory.php @@ -17,26 +17,34 @@ use InvalidArgumentException; use phpDocumentor\Reflection\DocBlock\Tags\Author; use phpDocumentor\Reflection\DocBlock\Tags\Covers; use phpDocumentor\Reflection\DocBlock\Tags\Deprecated; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\AbstractPHPStanFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\ExtendsFactory; use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\ImplementsFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\MethodFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\ParamFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyReadFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyWriteFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\ReturnFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateExtendsFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateImplementsFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\ThrowsFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\VarFactory; use phpDocumentor\Reflection\DocBlock\Tags\Generic; use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; use phpDocumentor\Reflection\DocBlock\Tags\Link as LinkTag; use phpDocumentor\Reflection\DocBlock\Tags\Method; -use phpDocumentor\Reflection\DocBlock\Tags\Mixin; -use phpDocumentor\Reflection\DocBlock\Tags\Param; -use phpDocumentor\Reflection\DocBlock\Tags\Property; -use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead; -use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite; -use phpDocumentor\Reflection\DocBlock\Tags\Return_; use phpDocumentor\Reflection\DocBlock\Tags\See as SeeTag; use phpDocumentor\Reflection\DocBlock\Tags\Since; use phpDocumentor\Reflection\DocBlock\Tags\Source; use phpDocumentor\Reflection\DocBlock\Tags\TemplateCovariant; use phpDocumentor\Reflection\DocBlock\Tags\Throws; use phpDocumentor\Reflection\DocBlock\Tags\Uses; -use phpDocumentor\Reflection\DocBlock\Tags\Var_; use phpDocumentor\Reflection\DocBlock\Tags\Version; use phpDocumentor\Reflection\FqsenResolver; +use phpDocumentor\Reflection\TypeResolver; use phpDocumentor\Reflection\Types\Context as TypeContext; use ReflectionMethod; use ReflectionNamedType; @@ -77,7 +85,7 @@ final class StandardTagFactory implements TagFactory public const REGEX_TAGNAME = '[\w\-\_\\\\:]+'; /** - * @var array|Factory> An array with a tag as a key, and an + * @var array|Tag|Factory> An array with a tag as a key, and an * FQCN to a class that handles it as an array value. */ private array $tagHandlerMappings = [ @@ -86,21 +94,13 @@ final class StandardTagFactory implements TagFactory 'deprecated' => Deprecated::class, // 'example' => '\phpDocumentor\Reflection\DocBlock\Tags\Example', 'link' => LinkTag::class, - 'mixin' => Mixin::class, 'method' => Method::class, - 'param' => Param::class, - 'property-read' => PropertyRead::class, - 'property' => Property::class, - 'property-write' => PropertyWrite::class, - 'return' => Return_::class, 'see' => SeeTag::class, 'since' => Since::class, 'source' => Source::class, 'template-covariant' => TemplateCovariant::class, 'throw' => Throws::class, - 'throws' => Throws::class, 'uses' => Uses::class, - 'var' => Var_::class, 'version' => Version::class, ]; @@ -124,26 +124,60 @@ final class StandardTagFactory implements TagFactory */ private array $serviceLocator = []; - /** - * Initialize this tag factory with the means to resolve an FQSEN and optionally a list of tag handlers. - * - * If no tag handlers are provided than the default list in the {@see self::$tagHandlerMappings} property - * is used. - * - * @see self::registerTagHandler() to add a new tag handler to the existing default list. - * - * @param array> $tagHandlers - */ - public function __construct(FqsenResolver $fqsenResolver, ?array $tagHandlers = null) + private function __construct(FqsenResolver $fqsenResolver) { $this->fqsenResolver = $fqsenResolver; - if ($tagHandlers !== null) { - $this->tagHandlerMappings = $tagHandlers; - } $this->addService($fqsenResolver, FqsenResolver::class); } + /** + * Initialize this tag factory with the means to resolve an FQSEN. + * + * @see self::registerTagHandler() to add a new tag handler to the existing default list. + */ + public static function createInstance(FqsenResolver $fqsenResolver): self + { + $tagFactory = new self($fqsenResolver); + $descriptionFactory = new DescriptionFactory($tagFactory); + + $typeResolver = new TypeResolver($fqsenResolver); + + $phpstanTagFactory = new AbstractPHPStanFactory( + new ParamFactory($typeResolver, $descriptionFactory), + new VarFactory($typeResolver, $descriptionFactory), + new ReturnFactory($typeResolver, $descriptionFactory), + new PropertyFactory($typeResolver, $descriptionFactory), + new PropertyReadFactory($typeResolver, $descriptionFactory), + new PropertyWriteFactory($typeResolver, $descriptionFactory), + new MethodFactory($typeResolver, $descriptionFactory), + new ImplementsFactory($typeResolver, $descriptionFactory), + new ExtendsFactory($typeResolver, $descriptionFactory), + new TemplateFactory($typeResolver, $descriptionFactory), + new TemplateImplementsFactory($typeResolver, $descriptionFactory), + new TemplateExtendsFactory($typeResolver, $descriptionFactory), + new ThrowsFactory($typeResolver, $descriptionFactory), + ); + + $tagFactory->addService($descriptionFactory); + $tagFactory->addService($typeResolver); + $tagFactory->registerTagHandler('param', $phpstanTagFactory); + $tagFactory->registerTagHandler('var', $phpstanTagFactory); + $tagFactory->registerTagHandler('return', $phpstanTagFactory); + $tagFactory->registerTagHandler('property', $phpstanTagFactory); + $tagFactory->registerTagHandler('property-read', $phpstanTagFactory); + $tagFactory->registerTagHandler('property-write', $phpstanTagFactory); + $tagFactory->registerTagHandler('method', $phpstanTagFactory); + $tagFactory->registerTagHandler('extends', $phpstanTagFactory); + $tagFactory->registerTagHandler('implements', $phpstanTagFactory); + $tagFactory->registerTagHandler('template', $phpstanTagFactory); + $tagFactory->registerTagHandler('template-extends', $phpstanTagFactory); + $tagFactory->registerTagHandler('template-implements', $phpstanTagFactory); + $tagFactory->registerTagHandler('throws', $phpstanTagFactory); + + return $tagFactory; + } + public function create(string $tagLine, ?TypeContext $context = null): Tag { if (!$context) { @@ -238,7 +272,7 @@ final class StandardTagFactory implements TagFactory /** * Determines the Fully Qualified Class Name of the Factory or Tag (containing a Factory Method `create`). * - * @return class-string|Factory + * @return class-string|Tag|Factory */ private function findHandlerClassName(string $tagName, TypeContext $context) { @@ -302,7 +336,7 @@ final class StandardTagFactory implements TagFactory * Retrieves a series of ReflectionParameter objects for the static 'create' method of the given * tag handler class name. * - * @param class-string|Factory $handler + * @param class-string|Tag|Factory $handler * * @return ReflectionParameter[] */ diff --git a/src/DocBlock/Tags/Factory/MixinFactory.php b/src/DocBlock/Tags/Factory/MixinFactory.php new file mode 100644 index 0000000..03e4421 --- /dev/null +++ b/src/DocBlock/Tags/Factory/MixinFactory.php @@ -0,0 +1,52 @@ +descriptionFactory = $descriptionFactory; + $this->typeResolver = $typeResolver; + } + + public function create(PhpDocTagNode $node, Context $context): Tag + { + $tagValue = $node->value; + Assert::isInstanceOf($tagValue, MixinTagValueNode::class); + + $description = $tagValue->getAttribute('description'); + if (is_string($description) === false) { + $description = $tagValue->description; + } + + return new Mixin( + $this->typeResolver->createType($tagValue->type, $context), + $this->descriptionFactory->create($description, $context) + ); + } + + public function supports(PhpDocTagNode $node, Context $context): bool + { + return $node->value instanceof MixinTagValueNode; + } +} diff --git a/src/DocBlock/Tags/Factory/ParamFactory.php b/src/DocBlock/Tags/Factory/ParamFactory.php index a0970d9..fc74a32 100644 --- a/src/DocBlock/Tags/Factory/ParamFactory.php +++ b/src/DocBlock/Tags/Factory/ParamFactory.php @@ -8,6 +8,7 @@ use phpDocumentor\Reflection\DocBlock\DescriptionFactory; use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; use phpDocumentor\Reflection\DocBlock\Tags\Param; +use phpDocumentor\Reflection\Exception\ParserException; use phpDocumentor\Reflection\TypeResolver; use phpDocumentor\Reflection\Types\Context; use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode; @@ -40,7 +41,9 @@ final class ParamFactory implements PHPStanFactory $tagValue = $node->value; if ($tagValue instanceof InvalidTagValueNode) { - return InvalidTag::create($tagValue->value, 'param')->withError($tagValue->exception); + return InvalidTag::create($tagValue->value, 'param')->withError( + ParserException::from($tagValue->exception) + ); } Assert::isInstanceOfAny( diff --git a/src/DocBlock/Tags/Factory/ThrowsFactory.php b/src/DocBlock/Tags/Factory/ThrowsFactory.php new file mode 100644 index 0000000..e547adc --- /dev/null +++ b/src/DocBlock/Tags/Factory/ThrowsFactory.php @@ -0,0 +1,52 @@ +descriptionFactory = $descriptionFactory; + $this->typeResolver = $typeResolver; + } + + public function create(PhpDocTagNode $node, Context $context): Tag + { + $tagValue = $node->value; + Assert::isInstanceOf($tagValue, ThrowsTagValueNode::class); + + $description = $tagValue->getAttribute('description'); + if (is_string($description) === false) { + $description = $tagValue->description; + } + + return new Throws( + $this->typeResolver->createType($tagValue->type, $context), + $this->descriptionFactory->create($description, $context) + ); + } + + public function supports(PhpDocTagNode $node, Context $context): bool + { + return $node->value instanceof ThrowsTagValueNode; + } +} diff --git a/src/DocBlock/Tags/Mixin.php b/src/DocBlock/Tags/Mixin.php index 4dd8a47..2b0909c 100644 --- a/src/DocBlock/Tags/Mixin.php +++ b/src/DocBlock/Tags/Mixin.php @@ -14,11 +14,7 @@ declare(strict_types=1); namespace phpDocumentor\Reflection\DocBlock\Tags; use phpDocumentor\Reflection\DocBlock\Description; -use phpDocumentor\Reflection\DocBlock\DescriptionFactory; use phpDocumentor\Reflection\Type; -use phpDocumentor\Reflection\TypeResolver; -use phpDocumentor\Reflection\Types\Context as TypeContext; -use Webmozart\Assert\Assert; /** * Reflection class for a {@}mixin tag in a Docblock. @@ -31,21 +27,4 @@ final class Mixin extends TagWithType $this->type = $type; $this->description = $description; } - - public static function create( - string $body, - ?TypeResolver $typeResolver = null, - ?DescriptionFactory $descriptionFactory = null, - ?TypeContext $context = null - ): self { - Assert::notNull($typeResolver); - Assert::notNull($descriptionFactory); - - [$type, $description] = self::extractTypeFromBody($body); - - $type = $typeResolver->resolve($type, $context); - $description = $descriptionFactory->create($description, $context); - - return new static($type, $description); - } } diff --git a/src/DocBlock/Tags/Param.php b/src/DocBlock/Tags/Param.php index bb513ca..1653365 100644 --- a/src/DocBlock/Tags/Param.php +++ b/src/DocBlock/Tags/Param.php @@ -16,8 +16,6 @@ namespace phpDocumentor\Reflection\DocBlock\Tags; use phpDocumentor\Reflection\DocBlock\Description; use phpDocumentor\Reflection\Type; -use function strpos; - /** * Reflection class for the {@}param tag in a Docblock. */ diff --git a/src/DocBlock/Tags/TagWithType.php b/src/DocBlock/Tags/TagWithType.php index 2923cf2..3611436 100644 --- a/src/DocBlock/Tags/TagWithType.php +++ b/src/DocBlock/Tags/TagWithType.php @@ -37,7 +37,7 @@ abstract class TagWithType extends BaseTag return $this->type; } - public static function create(string $body): Tag + final public static function create(string $body): Tag { throw new CannotCreateTag('Typed tag cannot be created'); } diff --git a/src/DocBlock/Tags/TemplateCovariant.php b/src/DocBlock/Tags/TemplateCovariant.php index 9a0bfc3..4ce2a94 100644 --- a/src/DocBlock/Tags/TemplateCovariant.php +++ b/src/DocBlock/Tags/TemplateCovariant.php @@ -14,11 +14,7 @@ declare(strict_types=1); namespace phpDocumentor\Reflection\DocBlock\Tags; use phpDocumentor\Reflection\DocBlock\Description; -use phpDocumentor\Reflection\DocBlock\DescriptionFactory; use phpDocumentor\Reflection\Type; -use phpDocumentor\Reflection\TypeResolver; -use phpDocumentor\Reflection\Types\Context as TypeContext; -use Webmozart\Assert\Assert; /** * Reflection class for a {@}template-covariant tag in a Docblock. @@ -31,21 +27,4 @@ final class TemplateCovariant extends TagWithType $this->type = $type; $this->description = $description; } - - public static function create( - string $body, - ?TypeResolver $typeResolver = null, - ?DescriptionFactory $descriptionFactory = null, - ?TypeContext $context = null - ): self { - Assert::notNull($typeResolver); - Assert::notNull($descriptionFactory); - - [$type, $description] = self::extractTypeFromBody($body); - - $type = $typeResolver->resolve($type, $context); - $description = $descriptionFactory->create($description, $context); - - return new static($type, $description); - } } diff --git a/src/DocBlock/Tags/Throws.php b/src/DocBlock/Tags/Throws.php index 6ce75de..675b6f0 100644 --- a/src/DocBlock/Tags/Throws.php +++ b/src/DocBlock/Tags/Throws.php @@ -14,11 +14,7 @@ declare(strict_types=1); namespace phpDocumentor\Reflection\DocBlock\Tags; use phpDocumentor\Reflection\DocBlock\Description; -use phpDocumentor\Reflection\DocBlock\DescriptionFactory; use phpDocumentor\Reflection\Type; -use phpDocumentor\Reflection\TypeResolver; -use phpDocumentor\Reflection\Types\Context as TypeContext; -use Webmozart\Assert\Assert; /** * Reflection class for a {@}throws tag in a Docblock. @@ -31,21 +27,4 @@ final class Throws extends TagWithType $this->type = $type; $this->description = $description; } - - public static function create( - string $body, - ?TypeResolver $typeResolver = null, - ?DescriptionFactory $descriptionFactory = null, - ?TypeContext $context = null - ): self { - Assert::notNull($typeResolver); - Assert::notNull($descriptionFactory); - - [$type, $description] = self::extractTypeFromBody($body); - - $type = $typeResolver->resolve($type, $context); - $description = $descriptionFactory->create($description, $context); - - return new static($type, $description); - } } diff --git a/src/DocBlockFactory.php b/src/DocBlockFactory.php index ca33fbb..bdd29d1 100644 --- a/src/DocBlockFactory.php +++ b/src/DocBlockFactory.php @@ -19,20 +19,7 @@ use phpDocumentor\Reflection\DocBlock\DescriptionFactory; use phpDocumentor\Reflection\DocBlock\StandardTagFactory; use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\TagFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\AbstractPHPStanFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\ExtendsFactory; use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\ImplementsFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\MethodFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\ParamFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyReadFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyWriteFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\ReturnFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateExtendsFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateImplementsFactory; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\VarFactory; use Webmozart\Assert\Assert; use function array_shift; @@ -70,39 +57,8 @@ final class DocBlockFactory implements DocBlockFactoryInterface public static function createInstance(array $additionalTags = []): DocBlockFactoryInterface { $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); + $tagFactory = StandardTagFactory::createInstance($fqsenResolver); $descriptionFactory = new DescriptionFactory($tagFactory); - $typeResolver = new TypeResolver($fqsenResolver); - - $phpstanTagFactory = new AbstractPHPStanFactory( - new ParamFactory($typeResolver, $descriptionFactory), - new VarFactory($typeResolver, $descriptionFactory), - new ReturnFactory($typeResolver, $descriptionFactory), - new PropertyFactory($typeResolver, $descriptionFactory), - new PropertyReadFactory($typeResolver, $descriptionFactory), - new PropertyWriteFactory($typeResolver, $descriptionFactory), - new MethodFactory($typeResolver, $descriptionFactory), - new ImplementsFactory($typeResolver, $descriptionFactory), - new ExtendsFactory($typeResolver, $descriptionFactory), - new TemplateFactory($typeResolver, $descriptionFactory), - new TemplateImplementsFactory($typeResolver, $descriptionFactory), - new TemplateExtendsFactory($typeResolver, $descriptionFactory), - ); - - $tagFactory->addService($descriptionFactory); - $tagFactory->addService($typeResolver); - $tagFactory->registerTagHandler('param', $phpstanTagFactory); - $tagFactory->registerTagHandler('var', $phpstanTagFactory); - $tagFactory->registerTagHandler('return', $phpstanTagFactory); - $tagFactory->registerTagHandler('property', $phpstanTagFactory); - $tagFactory->registerTagHandler('property-read', $phpstanTagFactory); - $tagFactory->registerTagHandler('property-write', $phpstanTagFactory); - $tagFactory->registerTagHandler('method', $phpstanTagFactory); - $tagFactory->registerTagHandler('extends', $phpstanTagFactory); - $tagFactory->registerTagHandler('implements', $phpstanTagFactory); - $tagFactory->registerTagHandler('template', $phpstanTagFactory); - $tagFactory->registerTagHandler('template-extends', $phpstanTagFactory); - $tagFactory->registerTagHandler('template-implements', $phpstanTagFactory); $docBlockFactory = new self($descriptionFactory, $tagFactory); foreach ($additionalTags as $tagName => $tagHandler) { diff --git a/src/Exception/ParserException.php b/src/Exception/ParserException.php new file mode 100644 index 0000000..2a2ce80 --- /dev/null +++ b/src/Exception/ParserException.php @@ -0,0 +1,19 @@ +getMessage(), + 0, + $exception + ); + } +} diff --git a/src/Exception/ReflectionDocblockException.php b/src/Exception/ReflectionDocblockException.php new file mode 100644 index 0000000..1cb6641 --- /dev/null +++ b/src/Exception/ReflectionDocblockException.php @@ -0,0 +1,11 @@ +create($docComment); - self::assertEquals( - [ - InvalidTag::create( - 'array\Foo> $test', - 'param', - )->withError( - new \InvalidArgumentException( - 'Could not find type in array\Foo> $test, please check for malformed notations') - ), - ], - $docblock->getTags() - ); + $tags = $docblock->getTags(); + + self::assertCount(1, $docblock->getTags()); + self::assertInstanceOf(InvalidTag::class, $tags[0]); + self::assertCount(1, $docblock->getTags()); + self::assertSame('Failed to parse docblock: Unexpected token ">", expected variable at offset 16 on line 1', $tags[0]->getException()->getMessage()); + + +// self::assertEquals( +// [ +// InvalidTag::create( +// 'array\Foo> $test', +// 'param', +// )->withError( +// new ParserException( +// 'Could not find type in array\Foo> $test, please check for malformed notations', 'aa', 1) +// ), +// ], +// $docblock->getTags() +// ); } public function testConstantReferenceTypes(): void diff --git a/tests/unit/DocBlock/StandardTagFactoryTest.php b/tests/unit/DocBlock/StandardTagFactoryTest.php index a75f5e6..0b3aa46 100644 --- a/tests/unit/DocBlock/StandardTagFactoryTest.php +++ b/tests/unit/DocBlock/StandardTagFactoryTest.php @@ -20,11 +20,10 @@ use phpDocumentor\Reflection\Assets\CustomServiceClass; use phpDocumentor\Reflection\Assets\CustomServiceInterface; use phpDocumentor\Reflection\Assets\CustomTagFactory; use phpDocumentor\Reflection\DocBlock\Tags\Author; +use phpDocumentor\Reflection\DocBlock\Tags\Deprecated; use phpDocumentor\Reflection\DocBlock\Tags\Formatter; use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter; use phpDocumentor\Reflection\DocBlock\Tags\Generic; -use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; -use phpDocumentor\Reflection\DocBlock\Tags\Return_; use phpDocumentor\Reflection\DocBlock\Tags\See; use phpDocumentor\Reflection\Fqsen; use phpDocumentor\Reflection\FqsenResolver; @@ -69,7 +68,7 @@ class StandardTagFactoryTest extends TestCase ->with($expectedDescriptionText, $context) ->andReturn($expectedDescription); - $tagFactory = new StandardTagFactory(m::mock(FqsenResolver::class)); + $tagFactory = StandardTagFactory::createInstance(m::mock(FqsenResolver::class)); $tagFactory->addService($descriptionFactory, DescriptionFactory::class); $tag = $tagFactory->create('@' . $expectedTagName . ' This is a description', $context); @@ -94,7 +93,7 @@ class StandardTagFactoryTest extends TestCase $expectedDescriptionText = ' foo Bar 123 '; $context = new Context(''); - $tagFactory = new StandardTagFactory(new FqsenResolver()); + $tagFactory = StandardTagFactory::createInstance(new FqsenResolver()); $tagFactory->addService(new DescriptionFactory($tagFactory), DescriptionFactory::class); $tag = $tagFactory->create('@' . $expectedTagName . $expectedDescriptionText, $context); @@ -114,7 +113,7 @@ class StandardTagFactoryTest extends TestCase public function testCreatingASpecificTag(): void { $context = new Context(''); - $tagFactory = new StandardTagFactory(m::mock(FqsenResolver::class)); + $tagFactory = StandardTagFactory::createInstance(m::mock(FqsenResolver::class)); $tag = $tagFactory->create('@author Mike van Riel ', $context); @@ -143,7 +142,7 @@ class StandardTagFactoryTest extends TestCase $descriptionFactory = m::mock(DescriptionFactory::class); $descriptionFactory->shouldIgnoreMissing(); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); $tagFactory->addService($descriptionFactory, DescriptionFactory::class); $tag = $tagFactory->create('@see Tag'); @@ -163,7 +162,8 @@ class StandardTagFactoryTest extends TestCase public function testPassingYourOwnSetOfTagHandlers(): void { $context = new Context(''); - $tagFactory = new StandardTagFactory(m::mock(FqsenResolver::class), ['user' => Author::class]); + $tagFactory = StandardTagFactory::createInstance(m::mock(FqsenResolver::class)); + $tagFactory->registerTagHandler('user', Author::class); $tag = $tagFactory->create('@user Mike van Riel ', $context); @@ -181,16 +181,11 @@ class StandardTagFactoryTest extends TestCase */ public function testPassingYourOwnSetOfTagHandlersWithGermanChars(): void { - $typeResolver = new TypeResolver(); $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); + $tagFactory = StandardTagFactory::createInstance($fqsenResolver); $context = new Context(''); - $tagFactory = new StandardTagFactory( - $fqsenResolver, - ['my-täg' => Author::class] - ); + $tagFactory->registerTagHandler('my-täg', Author::class); $tag = $tagFactory->create('@my-täg foo bar ', $context); @@ -209,17 +204,11 @@ class StandardTagFactoryTest extends TestCase */ public function testPassingYourOwnSetOfTagHandlersWithoutComment(): void { - $typeResolver = new TypeResolver(); $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); + $tagFactory = StandardTagFactory::createInstance($fqsenResolver); $context = new Context(''); - $tagFactory = new StandardTagFactory( - $fqsenResolver, - ['my-täg' => Author::class] - ); - + $tagFactory->registerTagHandler('my-täg', Author::class); $tag = $tagFactory->create('@my-täg', $context); $this->assertInstanceOf(Author::class, $tag); @@ -233,7 +222,7 @@ class StandardTagFactoryTest extends TestCase $customFactory = new CustomTagFactory(); $injectedClass = new CustomServiceClass(); - $tagFactory = new StandardTagFactory($fqsenResolver); + $tagFactory = StandardTagFactory::createInstance($fqsenResolver); $tagFactory->addService($injectedClass); $tagFactory->registerTagHandler('param', $customFactory); $tag = $tagFactory->create('@param foo'); @@ -259,11 +248,11 @@ class StandardTagFactoryTest extends TestCase $typeResolver = new TypeResolver(); $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); + $tagFactory = StandardTagFactory::createInstance($fqsenResolver); $descriptionFactory = new DescriptionFactory($tagFactory); $context = new Context(''); - $tagFactory = new StandardTagFactory( + $tagFactory = StandardTagFactory::createInstance( $fqsenResolver, ['my-täg' => Author::class] ); @@ -283,7 +272,7 @@ class StandardTagFactoryTest extends TestCase $this->expectExceptionMessage( 'The tag "@user[myuser" does not seem to be wellformed, please check it for errors' ); - $tagFactory = new StandardTagFactory(m::mock(FqsenResolver::class)); + $tagFactory = StandardTagFactory::createInstance(m::mock(FqsenResolver::class)); $tagFactory->create('@user[myuser'); } @@ -296,7 +285,7 @@ class StandardTagFactoryTest extends TestCase public function testAddParameterToServiceLocator(): void { $resolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); $tagFactory->registerTagHandler('spy', CustomParam::class); $tagFactory->addParameter('myParam', 'myValue'); @@ -316,7 +305,7 @@ class StandardTagFactoryTest extends TestCase $service = new PassthroughFormatter(); $resolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); $tagFactory->addService($service); $tagFactory->registerTagHandler('spy', CustomServiceClass::class); @@ -336,7 +325,7 @@ class StandardTagFactoryTest extends TestCase $service = new PassthroughFormatter(); $resolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); $tagFactory->addService($service, $interfaceName); $tagFactory->registerTagHandler('spy', CustomServiceInterface::class); @@ -356,7 +345,7 @@ class StandardTagFactoryTest extends TestCase public function testRegisteringAHandlerForANewTag(): void { $resolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); $tagFactory->registerTagHandler('my-tag', Author::class); @@ -375,7 +364,7 @@ class StandardTagFactoryTest extends TestCase { $this->expectException('InvalidArgumentException'); $resolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); // phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName $tagFactory->registerTagHandler(\Name\Spaced\Tag::class, Author::class); } @@ -390,7 +379,7 @@ class StandardTagFactoryTest extends TestCase { $this->expectException('InvalidArgumentException'); $resolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); $tagFactory->registerTagHandler('my-tag', ''); } @@ -404,7 +393,7 @@ class StandardTagFactoryTest extends TestCase { $this->expectException('InvalidArgumentException'); $resolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); $tagFactory->registerTagHandler('my-tag', 'IDoNotExist'); } @@ -418,7 +407,7 @@ class StandardTagFactoryTest extends TestCase { $this->expectException('InvalidArgumentException'); $resolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($resolver); + $tagFactory = StandardTagFactory::createInstance($resolver); $tagFactory->registerTagHandler('my-tag', 'stdClass'); } @@ -439,28 +428,19 @@ class StandardTagFactoryTest extends TestCase $descriptionFactory ->shouldReceive('create') ->once() - ->with('', $context) + ->with('mixed test', $context) ->andReturn(new Description('')); $typeResolver = new TypeResolver(); - $tagFactory = new StandardTagFactory(m::mock(FqsenResolver::class)); + $tagFactory = StandardTagFactory::createInstance(m::mock(FqsenResolver::class)); $tagFactory->addService($descriptionFactory, DescriptionFactory::class); $tagFactory->addService($typeResolver, TypeResolver::class); - $tag = $tagFactory->create('@return mixed', $context); + $tag = $tagFactory->create('@deprecated mixed test', $context); - $this->assertInstanceOf(Return_::class, $tag); - $this->assertSame('return', $tag->getName()); - } - - public function testInvalidTagIsReturnedOnFailure(): void - { - $tagFactory = new StandardTagFactory(m::mock(FqsenResolver::class)); - - $tag = $tagFactory->create('@see $name some invalid tag'); - - $this->assertInstanceOf(InvalidTag::class, $tag); + $this->assertInstanceOf(Deprecated::class, $tag); + $this->assertSame('deprecated', $tag->getName()); } /** @@ -469,7 +449,7 @@ class StandardTagFactoryTest extends TestCase public function testValidFormattedTags(string $input, string $tagName, string $render): void { $fqsenResolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($fqsenResolver); + $tagFactory = StandardTagFactory::createInstance($fqsenResolver); $tagFactory->registerTagHandler('tag', Generic::class); $tag = $tagFactory->create($input); @@ -540,7 +520,7 @@ class StandardTagFactoryTest extends TestCase { $this->expectException(InvalidArgumentException::class); $fqsenResolver = m::mock(FqsenResolver::class); - $tagFactory = new StandardTagFactory($fqsenResolver); + $tagFactory = StandardTagFactory::createInstance($fqsenResolver); $tagFactory->registerTagHandler('tag', Generic::class); $tagFactory->create($input); } diff --git a/tests/unit/DocBlock/Tags/CoversTest.php b/tests/unit/DocBlock/Tags/CoversTest.php index fafe757..9e6c884 100644 --- a/tests/unit/DocBlock/Tags/CoversTest.php +++ b/tests/unit/DocBlock/Tags/CoversTest.php @@ -16,7 +16,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags; use Mockery as m; use phpDocumentor\Reflection\DocBlock\Description; use phpDocumentor\Reflection\DocBlock\DescriptionFactory; -use phpDocumentor\Reflection\DocBlock\StandardTagFactory; +use phpDocumentor\Reflection\DocBlock\TagFactory; use phpDocumentor\Reflection\Fqsen; use phpDocumentor\Reflection\FqsenResolver; use phpDocumentor\Reflection\Types\Context; @@ -188,8 +188,7 @@ class CoversTest extends TestCase public function testFactoryMethodWithSpaceBeforeClass(): void { $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); + $descriptionFactory = new DescriptionFactory($this->createMock(TagFactory::class)); $context = new Context(''); $fixture = Covers::create( diff --git a/tests/unit/DocBlock/Tags/LinkTest.php b/tests/unit/DocBlock/Tags/LinkTest.php index 8990692..14298f2 100644 --- a/tests/unit/DocBlock/Tags/LinkTest.php +++ b/tests/unit/DocBlock/Tags/LinkTest.php @@ -16,8 +16,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags; use Mockery as m; use phpDocumentor\Reflection\DocBlock\Description; use phpDocumentor\Reflection\DocBlock\DescriptionFactory; -use phpDocumentor\Reflection\DocBlock\StandardTagFactory; -use phpDocumentor\Reflection\FqsenResolver; +use phpDocumentor\Reflection\DocBlock\TagFactory; use phpDocumentor\Reflection\Types\Context; use PHPUnit\Framework\TestCase; @@ -177,9 +176,7 @@ class LinkTest extends TestCase */ public function testFactoryMethodWithoutSpaceBeforeUrl(): void { - $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); + $descriptionFactory = new DescriptionFactory($this->createMock(TagFactory::class)); $context = new Context(''); $fixture = Link::create( @@ -204,9 +201,7 @@ class LinkTest extends TestCase */ public function testFactoryMethodWithSpaceBeforeUrl(): void { - $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); + $descriptionFactory = new DescriptionFactory($this->createMock(TagFactory::class)); $context = new Context(''); $fixture = Link::create( diff --git a/tests/unit/DocBlock/Tags/SeeTest.php b/tests/unit/DocBlock/Tags/SeeTest.php index 3b3681d..dcae48b 100644 --- a/tests/unit/DocBlock/Tags/SeeTest.php +++ b/tests/unit/DocBlock/Tags/SeeTest.php @@ -16,7 +16,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags; use Mockery as m; use phpDocumentor\Reflection\DocBlock\Description; use phpDocumentor\Reflection\DocBlock\DescriptionFactory; -use phpDocumentor\Reflection\DocBlock\StandardTagFactory; +use phpDocumentor\Reflection\DocBlock\TagFactory; use phpDocumentor\Reflection\DocBlock\Tags\Reference\Fqsen as FqsenRef; use phpDocumentor\Reflection\DocBlock\Tags\Reference\Fqsen as TagsFqsen; use phpDocumentor\Reflection\DocBlock\Tags\Reference\Url as UrlRef; @@ -266,8 +266,7 @@ class SeeTest extends TestCase public function testFactoryMethodWithoutUrl(): void { $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); + $descriptionFactory = new DescriptionFactory($this->createMock(TagFactory::class)); $context = new Context(''); $fixture = See::create( diff --git a/tests/unit/DocBlock/Tags/ThrowsTest.php b/tests/unit/DocBlock/Tags/ThrowsTest.php index 54182de..3764708 100644 --- a/tests/unit/DocBlock/Tags/ThrowsTest.php +++ b/tests/unit/DocBlock/Tags/ThrowsTest.php @@ -13,12 +13,8 @@ declare(strict_types=1); namespace phpDocumentor\Reflection\DocBlock\Tags; -use InvalidArgumentException; use Mockery as m; use phpDocumentor\Reflection\DocBlock\Description; -use phpDocumentor\Reflection\DocBlock\DescriptionFactory; -use phpDocumentor\Reflection\TypeResolver; -use phpDocumentor\Reflection\Types\Context; use phpDocumentor\Reflection\Types\String_; use PHPUnit\Framework\TestCase; @@ -146,152 +142,4 @@ class ThrowsTest extends TestCase $this->assertSame('string', (string) $fixture); } - - /** - * @uses \phpDocumentor\Reflection\DocBlock\Tags\Throws:: - * @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory - * @uses \phpDocumentor\Reflection\TypeResolver - * @uses \phpDocumentor\Reflection\DocBlock\Description - * @uses \phpDocumentor\Reflection\Types\String_ - * @uses \phpDocumentor\Reflection\Types\Context - * - * @covers ::create - */ - public function testFactoryMethod(): void - { - $descriptionFactory = m::mock(DescriptionFactory::class); - $resolver = new TypeResolver(); - $context = new Context(''); - - $type = new String_(); - $description = new Description('My Description'); - $descriptionFactory->shouldReceive('create')->with('My Description', $context)->andReturn($description); - - $fixture = Throws::create('string My Description', $resolver, $descriptionFactory, $context); - - $this->assertSame('string My Description', (string) $fixture); - $this->assertEquals($type, $fixture->getType()); - $this->assertSame($description, $fixture->getDescription()); - } - - /** - * This test checks whether a braces in a Type are allowed. - * - * The advent of generics poses a few issues, one of them is that spaces can now be part of a type. In the past we - * could purely rely on spaces to split the individual parts of the body of a tag; but when there is a type in play - * we now need to check for braces. - * - * This test tests whether an error occurs demonstrating that the braces were taken into account; this test is still - * expected to produce an exception because the TypeResolver does not support generics. - * - * @uses \phpDocumentor\Reflection\DocBlock\Tags\Throws:: - * @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory - * @uses \phpDocumentor\Reflection\TypeResolver - * @uses \phpDocumentor\Reflection\DocBlock\Description - * @uses \phpDocumentor\Reflection\Types\String_ - * @uses \phpDocumentor\Reflection\Types\Context - * - * @covers ::create - */ - public function testFactoryMethodWithGenericWithSpace(): void - { - $descriptionFactory = m::mock(DescriptionFactory::class); - $resolver = new TypeResolver(); - $context = new Context(''); - - $description = new Description('My Description'); - $descriptionFactory->shouldReceive('create') - ->with('My Description', $context) - ->andReturn($description); - - $fixture = Throws::create('array My Description', $resolver, $descriptionFactory, $context); - - $this->assertSame('array My Description', (string) $fixture); - $this->assertEquals('array', $fixture->getType()); - $this->assertSame($description, $fixture->getDescription()); - } - - /** - * @see self::testFactoryMethodWithGenericWithSpace() - * @uses \phpDocumentor\Reflection\DocBlock\Tags\Throws:: - * @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory - * @uses \phpDocumentor\Reflection\TypeResolver - * @uses \phpDocumentor\Reflection\DocBlock\Description - * @uses \phpDocumentor\Reflection\Types\String_ - * @uses \phpDocumentor\Reflection\Types\Context - * - * @covers ::create - */ - public function testFactoryMethodWithGenericWithSpaceAndAddedEmojisToVerifyMultiByteBehaviour(): void - { - $this->markTestSkipped('A bug in the TypeResolver breaks this test'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('"\array😁" is not a valid Fqsen.'); - - $descriptionFactory = m::mock(DescriptionFactory::class); - $resolver = new TypeResolver(); - $context = new Context(''); - - $description = new Description('My Description'); - $descriptionFactory->shouldReceive('create') - ->with('My Description', $context) - ->andReturn($description); - - Throws::create('array😁 My Description', $resolver, $descriptionFactory, $context); - } - - /** - * @uses \phpDocumentor\Reflection\DocBlock\Tags\Throws:: - * @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory - * @uses \phpDocumentor\Reflection\TypeResolver - * @uses \phpDocumentor\Reflection\DocBlock\Description - * @uses \phpDocumentor\Reflection\Types\String_ - * @uses \phpDocumentor\Reflection\Types\Context - * - * @covers ::create - */ - public function testFactoryMethodWithEmojisToVerifyMultiByteBehaviour(): void - { - $descriptionFactory = m::mock(DescriptionFactory::class); - $resolver = new TypeResolver(); - $context = new Context(''); - - $description = new Description('My Description'); - $descriptionFactory->shouldReceive('create') - ->with('My Description', $context) - ->andReturn($description); - - $fixture = Throws::create('\My😁Class My Description', $resolver, $descriptionFactory, $context); - - $this->assertSame('\My😁Class My Description', (string) $fixture); - $this->assertEquals('\My😁Class', $fixture->getType()); - $this->assertSame($description, $fixture->getDescription()); - } - - /** - * @covers ::create - */ - public function testFactoryMethodFailsIfBodyIsNotEmpty(): void - { - $this->expectException('InvalidArgumentException'); - $this->assertNull(Throws::create('')); - } - - /** - * @covers ::create - */ - public function testFactoryMethodFailsIfResolverIsNull(): void - { - $this->expectException('InvalidArgumentException'); - Throws::create('body'); - } - - /** - * @covers ::create - */ - public function testFactoryMethodFailsIfDescriptionFactoryIsNull(): void - { - $this->expectException('InvalidArgumentException'); - Throws::create('body', new TypeResolver()); - } } diff --git a/tests/unit/DocBlock/Tags/UsesTest.php b/tests/unit/DocBlock/Tags/UsesTest.php index 84bd5e8..c2b103a 100644 --- a/tests/unit/DocBlock/Tags/UsesTest.php +++ b/tests/unit/DocBlock/Tags/UsesTest.php @@ -16,7 +16,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags; use Mockery as m; use phpDocumentor\Reflection\DocBlock\Description; use phpDocumentor\Reflection\DocBlock\DescriptionFactory; -use phpDocumentor\Reflection\DocBlock\StandardTagFactory; +use phpDocumentor\Reflection\DocBlock\TagFactory; use phpDocumentor\Reflection\Fqsen; use phpDocumentor\Reflection\FqsenResolver; use phpDocumentor\Reflection\Types\Context; @@ -190,8 +190,7 @@ class UsesTest extends TestCase public function testFactoryMethodWithoutSpaceBeforeClass(): void { $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); + $descriptionFactory = new DescriptionFactory($this->createMock(TagFactory::class)); $context = new Context(''); $fixture = Uses::create( @@ -220,8 +219,7 @@ class UsesTest extends TestCase public function testFactoryMethodWithSpaceBeforeClass(): void { $fqsenResolver = new FqsenResolver(); - $tagFactory = new StandardTagFactory($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); + $descriptionFactory = new DescriptionFactory($this->createMock(TagFactory::class)); $context = new Context(''); $fixture = Uses::create(