Skip to content

Commit fd8f4a3

Browse files
committed
Add tests for hook variants
1 parent d1849f6 commit fd8f4a3

File tree

7 files changed

+233
-29
lines changed

7 files changed

+233
-29
lines changed

src/phpDocumentor/Reflection/Php/Factory/PropertyBuilder.php

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,7 @@ private function __construct(
5858
$this->visibility = new Visibility(Visibility::PUBLIC_);
5959
}
6060

61-
/**
62-
* @param iterable<Reducer> $reducers
63-
*/
61+
/** @param iterable<Reducer> $reducers */
6462
public static function create(
6563
PrettyPrinter $valueConverter,
6664
DocBlockFactoryInterface $docBlockFactory,
@@ -154,7 +152,7 @@ public function build(ContextStack $context): PropertyElement
154152
(new Type())->fromPhpParser($this->type),
155153
$this->readOnly,
156154
array_filter(array_map(
157-
fn (PropertyHookNode $hook) => $this->buildHook($hook, $context),
155+
fn (PropertyHookNode $hook) => $this->buildHook($hook, $context, $this->visibility),
158156
$this->hooks,
159157
)),
160158
);
@@ -183,6 +181,10 @@ private function buildVisibility(Param|PropertyIterator $node): Visibility
183181
$readVisibility = $this->buildReadVisibility($node);
184182
$writeVisibility = $this->buildWriteVisibility($node);
185183

184+
if ((string) $writeVisibility === (string) $readVisibility) {
185+
return $readVisibility;
186+
}
187+
186188
return new AsyncVisibility(
187189
$readVisibility,
188190
$writeVisibility,
@@ -232,17 +234,17 @@ private function buildWriteVisibility(Param|PropertyIterator $node): Visibility
232234
return new Visibility(Visibility::PUBLIC_);
233235
}
234236

235-
private function buildHook(PropertyHookNode $hook, ContextStack $context): PropertyHook|null
237+
private function buildHook(PropertyHookNode $hook, ContextStack $context, Visibility $propertyVisibility): PropertyHook|null
236238
{
237239
$doc = $hook->getDocComment();
238240

239241
$result = new PropertyHook(
240242
$hook->name->toString(),
241-
$this->buildVisibilityFromFlags($hook->flags),
243+
$this->buildHookVisibility($hook->name->toString(), $propertyVisibility),
242244
$doc !== null ? $this->docBlockFactory->create($doc->getText(), $context->getTypeContext()) : null,
243245
$hook->isFinal(),
244-
new Location($hook->getStartLine(), $hook->getStartFilePos()),
245-
new Location($hook->getEndLine(), $hook->getEndFilePos()),
246+
new Location($hook->getStartLine()),
247+
new Location($hook->getEndLine()),
246248
);
247249

248250
foreach ($this->reducers as $reducer) {
@@ -261,4 +263,17 @@ private function buildHook(PropertyHookNode $hook, ContextStack $context): Prope
261263

262264
return $result;
263265
}
266+
267+
private function buildHookVisibility(string $hookName, Visibility $propertyVisibility): Visibility
268+
{
269+
if ($propertyVisibility instanceof AsyncVisibility === false) {
270+
return $propertyVisibility;
271+
}
272+
273+
return match ($hookName) {
274+
'get' => $propertyVisibility->getReadVisibility(),
275+
'set' => $propertyVisibility->getWriteVisibility(),
276+
default => $propertyVisibility,
277+
};
278+
}
264279
}

src/phpDocumentor/Reflection/Php/Property.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,10 @@ public function isReadOnly(): bool
143143
{
144144
return $this->readOnly;
145145
}
146+
147+
/** @return PropertyHook[] */
148+
public function getHooks(): array
149+
{
150+
return $this->hooks;
151+
}
146152
}

tests/integration/PropertyHookTest.php

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,90 @@
55
namespace integration;
66

77
use EliasHaeussler\PHPUnitAttributes\Attribute\RequiresPackage;
8+
use phpDocumentor\Reflection\DocBlock;
89
use phpDocumentor\Reflection\File\LocalFile;
10+
use phpDocumentor\Reflection\Location;
11+
use phpDocumentor\Reflection\Php\Argument;
12+
use phpDocumentor\Reflection\Php\AsyncVisibility;
13+
use phpDocumentor\Reflection\Php\Attribute;
914
use phpDocumentor\Reflection\Php\ProjectFactory;
15+
use phpDocumentor\Reflection\Php\PropertyHook;
16+
use phpDocumentor\Reflection\Php\Visibility;
17+
use phpDocumentor\Reflection\Types\Compound;
18+
use phpDocumentor\Reflection\Types\Integer;
19+
use phpDocumentor\Reflection\Types\String_;
20+
use PHPUnit\Framework\Attributes\CoversNothing;
1021
use PHPUnit\Framework\TestCase;
1122

1223
#[RequiresPackage('nikic/php-parser', '>= 5.2')]
24+
#[CoversNothing]
1325
final class PropertyHookTest extends TestCase
1426
{
15-
public function testPropertyHook()
27+
public function testPropertyHookWithDocblocks()
1628
{
1729
$file = __DIR__ . '/data/PHP84/PropertyHook.php';
1830
$projectFactory = ProjectFactory::createInstance();
1931
$project = $projectFactory->create('My project', [new LocalFile($file)]);
2032

2133
$class = $project->getFiles()[$file]->getClasses()['\PropertyHook'];
34+
$hooks = $class->getProperties()['\PropertyHook::$example']->getHooks();
35+
36+
$this->assertCount(2, $hooks);
37+
$this->assertEquals('get', $hooks[0]->getName());
38+
$this->assertEquals(new Visibility(Visibility::PUBLIC_), $hooks[0]->getVisibility());
39+
$this->assertCount(1, $hooks[0]->getAttributes());
40+
$this->assertCount(0, $hooks[0]->getArguments());
41+
$this->assertSame('Not sure this works, but it gets', $hooks[0]->getDocBlock()->getSummary());
42+
43+
$this->assertEquals('set', $hooks[1]->getName());
44+
$this->assertEquals(new Visibility(Visibility::PUBLIC_), $hooks[1]->getVisibility());
45+
$this->assertCount(1, $hooks[1]->getAttributes());
46+
$this->assertCount(1, $hooks[1]->getArguments());
47+
$this->assertEquals(new Argument(
48+
'value',
49+
new Compound(
50+
[
51+
new String_(),
52+
new Integer()
53+
]
54+
),
55+
), $hooks[1]->getArguments()[0]);
56+
$this->assertSame('Not sure this works, but it gets', $hooks[0]->getDocBlock()->getSummary());
57+
}
58+
59+
public function testPropertyHookAsync()
60+
{
61+
$file = __DIR__ . '/data/PHP84/PropertyHookAsync.php';
62+
$projectFactory = ProjectFactory::createInstance();
63+
$project = $projectFactory->create('My project', [new LocalFile($file)]);
64+
65+
$class = $project->getFiles()[$file]->getClasses()['\PropertyHook'];
66+
$hooks = $class->getProperties()['\PropertyHook::$example']->getHooks();
67+
68+
69+
$this->assertEquals(
70+
new AsyncVisibility(
71+
new Visibility(Visibility::PUBLIC_),
72+
new Visibility(Visibility::PRIVATE_)
73+
),
74+
$class->getProperties()['\PropertyHook::$example']->getVisibility()
75+
);
76+
$this->assertCount(2, $hooks);
77+
$this->assertEquals('get', $hooks[0]->getName());
78+
$this->assertEquals(new Visibility(Visibility::PUBLIC_), $hooks[0]->getVisibility());
79+
$this->assertCount(0, $hooks[0]->getArguments());
80+
81+
$this->assertEquals('set', $hooks[1]->getName());
82+
$this->assertEquals(new Visibility(Visibility::PRIVATE_), $hooks[1]->getVisibility());
83+
$this->assertCount(1, $hooks[1]->getArguments());
84+
$this->assertEquals(new Argument(
85+
'value',
86+
new Compound(
87+
[
88+
new String_(),
89+
new Integer()
90+
]
91+
),
92+
), $hooks[1]->getArguments()[0]);
2293
}
2394
}

tests/integration/data/PHP84/PropertyHook.php

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,22 @@ class PropertyHook
66
{
77
private bool $modified = false;
88

9-
/** @param string $example this is my property */
10-
public function __construct(
11-
/** @var string this is my property */
12-
#[Property(new DateTimeImmutable())]
13-
public string $example = 'default value' {
14-
/** Not sure this works, but it gets */
15-
#[Getter(new DateTimeImmutable())]
16-
get {
17-
if ($this->modified) {
18-
return $this->foo . ' (modified)';
19-
}
20-
return $this->foo;
21-
}
22-
/** Not sure this works, but it sets */
23-
#[Setter(new DateTimeImmutable())]
24-
set(string|int $value) {
25-
$this->foo = strtolower($value);
26-
$this->modified = true;
9+
/** @var string this is my property */
10+
#[Property(new DateTimeImmutable())]
11+
public string $example = 'default value' {
12+
/** Not sure this works, but it gets */
13+
#[Getter(new DateTimeImmutable())]
14+
get {
15+
if ($this->modified) {
16+
return $this->foo . ' (modified)';
2717
}
18+
return $this->foo;
19+
}
20+
/** Not sure this works, but it sets */
21+
#[Setter(new DateTimeImmutable())]
22+
set(string|int $value) {
23+
$this->foo = strtolower($value);
24+
$this->modified = true;
2825
}
29-
)
30-
{
3126
}
3227
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
class PropertyHook
6+
{
7+
private bool $modified = false;
8+
9+
/** @var string this is my property */
10+
#[Property(new DateTimeImmutable())]
11+
public private(set) string $example = 'default value' {
12+
get {
13+
if ($this->modified) {
14+
return $this->foo . ' (modified)';
15+
}
16+
return $this->foo;
17+
}
18+
set(string|int $value) {
19+
$this->foo = strtolower($value);
20+
$this->modified = true;
21+
}
22+
}
23+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
class PropertyHook
6+
{
7+
private bool $modified = false;
8+
9+
/** @param string $example this is my property */
10+
public function __construct(
11+
/** @var string this is my property */
12+
#[Property(new DateTimeImmutable())]
13+
public string $example = 'default value' {
14+
/** Not sure this works, but it gets */
15+
#[Getter(new DateTimeImmutable())]
16+
get {
17+
if ($this->modified) {
18+
return $this->foo . ' (modified)';
19+
}
20+
return $this->foo;
21+
}
22+
/** Not sure this works, but it sets */
23+
#[Setter(new DateTimeImmutable())]
24+
set(string|int $value) {
25+
$this->foo = strtolower($value);
26+
$this->modified = true;
27+
}
28+
}
29+
)
30+
{
31+
}
32+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\Php\Factory;
6+
7+
use phpDocumentor\Reflection\DocBlockFactoryInterface;
8+
use phpDocumentor\Reflection\Fqsen;
9+
use phpDocumentor\Reflection\Location;
10+
use phpDocumentor\Reflection\Php\StrategyContainer;
11+
use phpDocumentor\Reflection\Php\Visibility;
12+
use PhpParser\Node\Stmt\Property as PropertyNode;
13+
use PhpParser\Node\Stmt\PropertyProperty;
14+
use PhpParser\PrettyPrinter;
15+
use PHPUnit\Framework\Attributes\CoversClass;
16+
use PHPUnit\Framework\TestCase;
17+
18+
#[CoversClass(PropertyBuilder::class)]
19+
class PropertyBuilderTest extends TestCase
20+
{
21+
public function testBuildsPropertyElementWithCorrectAttributes(): void
22+
{
23+
$fqsen = new Fqsen('\MyClass::$property');
24+
$visibility = new Visibility(Visibility::PUBLIC_);
25+
$startLocation = new Location(10);
26+
$endLocation = new Location(20);
27+
28+
$docBlockFactory = $this->createMock(DocBlockFactoryInterface::class);
29+
$valueConverter = $this->createMock(PrettyPrinter\Standard::class);
30+
$strategies = $this->createMock(StrategyContainer::class);
31+
$reducers = [];
32+
33+
$prop1 = new PropertyProperty('prop1');
34+
$propertyNode = new PropertyNode(1, [$prop1]);
35+
$properties = new PropertyIterator($propertyNode);
36+
37+
$builder = PropertyBuilder::create($valueConverter, $docBlockFactory, $strategies, $reducers);
38+
$builder->fqsen($fqsen)
39+
->visibility($properties)
40+
->docblock($properties->getDocComment())
41+
->default($properties->getDefault())
42+
->static(true)
43+
->startLocation($startLocation)
44+
->endLocation($endLocation)
45+
->type($properties->getType())
46+
->readOnly(true)
47+
->hooks($properties->getHooks());
48+
49+
$context = \phpDocumentor\Reflection\Php\Factory\TestCase::createContext();
50+
$property = $builder->build($context);
51+
52+
$this->assertSame($fqsen, $property->getFqsen());
53+
$this->assertEquals($visibility, $property->getVisibility());
54+
$this->assertNull($property->getDocBlock());
55+
$this->assertNull($property->getDefault());
56+
$this->assertTrue($property->isStatic());
57+
$this->assertSame($startLocation, $property->getLocation());
58+
$this->assertSame($endLocation, $property->getEndLocation());
59+
$this->assertNull($property->getType());
60+
$this->assertTrue($property->isReadOnly());
61+
}
62+
}

0 commit comments

Comments
 (0)