Skip to content

Commit c1111a0

Browse files
committed
Add tests for factories
1 parent 3f6d648 commit c1111a0

13 files changed

+488
-108
lines changed

phpunit.xml.dist

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,24 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
3-
<phpunit
4-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5-
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.0/phpunit.xsd"
6-
colors="true"
7-
convertDeprecationsToExceptions="false"
8-
beStrictAboutOutputDuringTests="false"
9-
forceCoversAnnotation="true"
10-
verbose="true"
11-
bootstrap="vendor/autoload.php"
12-
>
13-
<testsuites>
14-
<testsuite name="unit">
15-
<directory>./tests/unit</directory>
16-
</testsuite>
17-
<testsuite name="integration">
18-
<directory>./tests/integration</directory>
19-
</testsuite>
20-
</testsuites>
21-
<filter>
22-
<whitelist>
23-
<directory suffix=".php">./src/</directory>
24-
</whitelist>
25-
</filter>
26-
<logging>
27-
<log type="coverage-html"
28-
target="build/coverage"
29-
lowUpperBound="35"
30-
highLowerBound="70"/>
31-
<log type="coverage-clover" target="build/logs/clover.xml"/>
32-
</logging>
33-
<listeners>
34-
<listener
35-
class="Mockery\Adapter\Phpunit\TestListener"
36-
file="vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/TestListener.php"
37-
/>
38-
</listeners>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" colors="true" convertDeprecationsToExceptions="false" beStrictAboutOutputDuringTests="false" forceCoversAnnotation="true" verbose="true" bootstrap="vendor/autoload.php">
3+
<coverage>
4+
<include>
5+
<directory suffix=".php">./src/</directory>
6+
</include>
7+
<report>
8+
<clover outputFile="build/logs/clover.xml"/>
9+
<html outputDirectory="build/coverage" lowUpperBound="35" highLowerBound="70"/>
10+
</report>
11+
</coverage>
12+
<testsuites>
13+
<testsuite name="unit">
14+
<directory>./tests/unit</directory>
15+
</testsuite>
16+
<testsuite name="integration">
17+
<directory>./tests/integration</directory>
18+
</testsuite>
19+
</testsuites>
20+
<logging/>
21+
<listeners>
22+
<listener class="Mockery\Adapter\Phpunit\TestListener" file="vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/TestListener.php"/>
23+
</listeners>
3924
</phpunit>

src/DocBlock/StandardTagFactory.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,8 @@
2828
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyReadFactory;
2929
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyWriteFactory;
3030
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ReturnFactory;
31-
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateExtendsFactory;
31+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateCovariantFactory;
3232
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateFactory;
33-
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateImplementsFactory;
3433
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ThrowsFactory;
3534
use phpDocumentor\Reflection\DocBlock\Tags\Factory\VarFactory;
3635
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
@@ -156,8 +155,7 @@ public static function createInstance(FqsenResolver $fqsenResolver): self
156155
new ImplementsFactory($typeResolver, $descriptionFactory),
157156
new ExtendsFactory($typeResolver, $descriptionFactory),
158157
new TemplateFactory($typeResolver, $descriptionFactory),
159-
new TemplateImplementsFactory($typeResolver, $descriptionFactory),
160-
new TemplateExtendsFactory($typeResolver, $descriptionFactory),
158+
new TemplateCovariantFactory($typeResolver, $descriptionFactory),
161159
new ThrowsFactory($typeResolver, $descriptionFactory),
162160
);
163161

src/DocBlock/Tags/Factory/AbstractPHPStanFactory.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use phpDocumentor\Reflection\Types\Context as TypeContext;
1919
use PHPStan\PhpDocParser\Lexer\Lexer;
2020
use PHPStan\PhpDocParser\Parser\ConstExprParser;
21+
use PHPStan\PhpDocParser\Parser\ParserException;
2122
use PHPStan\PhpDocParser\Parser\PhpDocParser;
2223
use PHPStan\PhpDocParser\Parser\TokenIterator;
2324
use PHPStan\PhpDocParser\Parser\TypeParser;
@@ -59,13 +60,17 @@ public function __construct(PHPStanFactory ...$factories)
5960

6061
public function create(string $tagLine, ?TypeContext $context = null): Tag
6162
{
62-
$tokens = $this->tokenizeLine($tagLine . "\n");
63-
$ast = $this->parser->parseTag($tokens);
64-
if (property_exists($ast->value, 'description') === true) {
65-
$ast->value->setAttribute(
66-
'description',
67-
rtrim($ast->value->description . $tokens->joinUntil(Lexer::TOKEN_END), "\n")
68-
);
63+
try {
64+
$tokens = $this->tokenizeLine($tagLine . "\n");
65+
$ast = $this->parser->parseTag($tokens);
66+
if (property_exists($ast->value, 'description') === true) {
67+
$ast->value->setAttribute(
68+
'description',
69+
rtrim($ast->value->description . $tokens->joinUntil(Lexer::TOKEN_END), "\n")
70+
);
71+
}
72+
} catch (ParserException $e) {
73+
return InvalidTag::create($tagLine, '')->withError($e);
6974
}
7075

7176
if ($context === null) {
@@ -80,6 +85,8 @@ public function create(string $tagLine, ?TypeContext $context = null): Tag
8085
}
8186
} catch (RuntimeException $e) {
8287
return InvalidTag::create((string) $ast->value, 'method')->withError($e);
88+
} catch (ParserException $e) {
89+
return InvalidTag::create((string) $ast->value, $ast->name)->withError($e);
8390
}
8491

8592
return InvalidTag::create(

src/DocBlock/Tags/Factory/TemplateExtendsFactory.php renamed to src/DocBlock/Tags/Factory/TemplateCovariantFactory.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,20 @@
66

77
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
88
use phpDocumentor\Reflection\DocBlock\Tag;
9-
use phpDocumentor\Reflection\DocBlock\Tags\TemplateExtends;
9+
use phpDocumentor\Reflection\DocBlock\Tags\TemplateCovariant;
1010
use phpDocumentor\Reflection\TypeResolver;
1111
use phpDocumentor\Reflection\Types\Context;
12-
use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode;
1312
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
13+
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
14+
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
1415
use Webmozart\Assert\Assert;
1516

1617
use function is_string;
1718

1819
/**
1920
* @internal This class is not part of the BC promise of this library.
2021
*/
21-
final class TemplateExtendsFactory implements PHPStanFactory
22+
final class TemplateCovariantFactory implements PHPStanFactory
2223
{
2324
private DescriptionFactory $descriptionFactory;
2425
private TypeResolver $typeResolver;
@@ -31,21 +32,21 @@ public function __construct(TypeResolver $typeResolver, DescriptionFactory $desc
3132

3233
public function supports(PhpDocTagNode $node, Context $context): bool
3334
{
34-
return $node->value instanceof ExtendsTagValueNode && $node->name === '@template-extends';
35+
return $node->value instanceof TemplateTagValueNode && $node->name === '@template-covariant';
3536
}
3637

3738
public function create(PhpDocTagNode $node, Context $context): Tag
3839
{
3940
$tagValue = $node->value;
40-
Assert::isInstanceOf($tagValue, ExtendsTagValueNode::class);
41+
Assert::isInstanceOf($tagValue, TemplateTagValueNode::class);
4142

4243
$description = $tagValue->getAttribute('description');
4344
if (is_string($description) === false) {
4445
$description = $tagValue->description;
4546
}
4647

47-
return new TemplateExtends(
48-
$this->typeResolver->createType($tagValue->type, $context),
48+
return new TemplateCovariant(
49+
$this->typeResolver->createType(new IdentifierTypeNode($tagValue->name), $context),
4950
$this->descriptionFactory->create($description, $context)
5051
);
5152
}

src/DocBlock/Tags/Factory/TemplateImplementsFactory.php

Lines changed: 0 additions & 52 deletions
This file was deleted.
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link http://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
15+
16+
use Exception;
17+
use Mockery as m;
18+
use phpDocumentor\Reflection\DocBlock\Tag;
19+
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
20+
use PHPStan\PhpDocParser\Parser\ParserException;
21+
use PHPUnit\Framework\TestCase;
22+
use RuntimeException;
23+
24+
/**
25+
* @uses \phpDocumentor\Reflection\DocBlock\Tags\Factory\AbstractPHPStanFactory
26+
* @uses \phpDocumentor\Reflection\DocBlock\Tags\InvalidTag
27+
*
28+
* @coversDefaultClass \phpDocumentor\Reflection\DocBlock\Tags\Factory\AbstractPHPStanFactory
29+
* @covers ::<private>
30+
*/
31+
class AbstractPHPStanFactoryTest extends TestCase
32+
{
33+
/**
34+
* Call Mockery::close after each test.
35+
*/
36+
public function tearDown(): void
37+
{
38+
m::close();
39+
}
40+
41+
/**
42+
* @covers ::create
43+
*/
44+
public function testCreateReturnsTagFromSupportingFactory(): void
45+
{
46+
$tag = m::mock(Tag::class);
47+
$factory = m::mock(PHPStanFactory::class);
48+
$factory->shouldReceive('supports')->andReturn(true);
49+
$factory->shouldReceive('create')->andReturn($tag);
50+
51+
$sut = new AbstractPHPStanFactory($factory);
52+
53+
$result = $sut->create('@param string $param');
54+
55+
self::assertSame($tag, $result);
56+
}
57+
58+
/**
59+
* @covers ::create
60+
*/
61+
public function testCreateReturnsInvalidTagWhenNoFactorySupports(): void
62+
{
63+
$factory = m::mock(PHPStanFactory::class);
64+
$factory->shouldReceive('supports')->andReturn(false);
65+
66+
$sut = new AbstractPHPStanFactory($factory);
67+
68+
$result = $sut->create('@unknown string $param');
69+
70+
self::assertInstanceOf(InvalidTag::class, $result);
71+
self::assertEquals('@unknown', $result->getName());
72+
}
73+
74+
/**
75+
* @covers ::create
76+
*/
77+
public function testCreateReturnsInvalidTagWithErrorOnFactoryRuntimeException(): void
78+
{
79+
$factory = m::mock(PHPStanFactory::class);
80+
$factory->shouldReceive('supports')->andReturn(true);
81+
$factory->shouldReceive('create')->andThrow(new RuntimeException('Factory error'));
82+
83+
$sut = new AbstractPHPStanFactory($factory);
84+
85+
$result = $sut->create('@param string $param');
86+
87+
self::assertInstanceOf(InvalidTag::class, $result);
88+
self::assertInstanceOf(Exception::class, $result->getException());
89+
self::assertEquals('Factory error', $result->getException()->getMessage());
90+
}
91+
92+
/**
93+
* @covers ::create
94+
*/
95+
public function testCreateReturnsInvalidTagWithErrorOnFactoryParserException(): void
96+
{
97+
$exception = m::mock(ParserException::class);
98+
$exception->shouldReceive('getMessage')->andReturn('Parser error');
99+
100+
$factory = m::mock(PHPStanFactory::class);
101+
$factory->shouldReceive('supports')->andReturn(true);
102+
$factory->shouldReceive('create')->andThrow($exception);
103+
104+
$sut = new AbstractPHPStanFactory($factory);
105+
106+
$result = $sut->create('@param string $param');
107+
108+
self::assertInstanceOf(InvalidTag::class, $result);
109+
self::assertSame($exception, $result->getException());
110+
}
111+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link http://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
15+
16+
use phpDocumentor\Reflection\DocBlock\Description;
17+
use phpDocumentor\Reflection\DocBlock\Tags\Extends_;
18+
use phpDocumentor\Reflection\Fqsen;
19+
use phpDocumentor\Reflection\PseudoTypes\Generic;
20+
use phpDocumentor\Reflection\Types\Context;
21+
use phpDocumentor\Reflection\Types\Object_;
22+
23+
final class ExtendsFactoryTest extends TagFactoryTestCase
24+
{
25+
/**
26+
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\ExtendsFactory::__construct
27+
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\ExtendsFactory::create
28+
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\ExtendsFactory::supports
29+
*/
30+
public function testExtendsIsCreated(): void
31+
{
32+
$ast = $this->parseTag('@extends SomeClass<OtherType>');
33+
$factory = new ExtendsFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
34+
$context = new Context('global');
35+
36+
self::assertTrue($factory->supports($ast, $context));
37+
self::assertEquals(
38+
new Extends_(
39+
new Generic(new Fqsen('\\SomeClass'), [new Object_(new Fqsen('\\OtherType'))]),
40+
new Description('')
41+
),
42+
$factory->create($ast, $context)
43+
);
44+
}
45+
}

0 commit comments

Comments
 (0)