1<?php declare(strict_types=1);
2
3namespace PhpParser\Node;
4
5use PhpParser\Modifiers;
6use PhpParser\Node\Expr\Assign;
7use PhpParser\Node\Expr\PropertyFetch;
8use PhpParser\Node\Expr\Variable;
9use PhpParser\Node\Scalar\Int_;
10use PhpParser\Node\Stmt\Expression;
11use PhpParser\Node\Stmt\Return_;
12use PhpParser\ParserFactory;
13use PhpParser\PrettyPrinter\Standard;
14
15class PropertyHookTest extends \PHPUnit\Framework\TestCase {
16    /**
17     * @dataProvider provideModifiers
18     */
19    public function testModifiers($modifier): void {
20        $node = new PropertyHook(
21            'get',
22            null,
23            [
24                'flags' => constant(Modifiers::class . '::' . strtoupper($modifier)),
25            ]
26        );
27
28        $this->assertTrue($node->{'is' . $modifier}());
29    }
30
31    public function testNoModifiers(): void {
32        $node = new PropertyHook('get', null);
33
34        $this->assertFalse($node->isFinal());
35    }
36
37    public static function provideModifiers() {
38        return [
39            ['final'],
40        ];
41    }
42
43    public function testGetStmts(): void {
44        $expr = new Variable('test');
45        $get = new PropertyHook('get', $expr);
46        $this->assertEquals([new Return_($expr)], $get->getStmts());
47
48        $set = new PropertyHook('set', $expr, [], ['propertyName' => 'abc']);
49        $this->assertEquals([
50            new Expression(new Assign(new PropertyFetch(new Variable('this'), 'abc'), $expr))
51        ], $set->getStmts());
52    }
53
54    public function testGetStmtsSetHookFromParser(): void {
55        $parser = (new ParserFactory())->createForNewestSupportedVersion();
56        $prettyPrinter = new Standard();
57        $stmts = $parser->parse(<<<'CODE'
58        <?php
59        class Test {
60            public $prop1 { set => 123; }
61
62            public function __construct(public $prop2 { set => 456; }) {}
63        }
64        CODE);
65
66        $hook1 = $stmts[0]->stmts[0]->hooks[0];
67        $this->assertEquals('$this->prop1 = 123;', $prettyPrinter->prettyPrint($hook1->getStmts()));
68
69        $hook2 = $stmts[0]->stmts[1]->params[0]->hooks[0];
70        $this->assertEquals('$this->prop2 = 456;', $prettyPrinter->prettyPrint($hook2->getStmts()));
71    }
72
73    public function testGetStmtsUnknownHook(): void {
74        $expr = new Variable('test');
75        $hook = new PropertyHook('foobar', $expr);
76
77        $this->expectException(\LogicException::class);
78        $this->expectExceptionMessage('Unknown property hook "foobar"');
79        $hook->getStmts();
80    }
81
82    public function testGetStmtsSetHookWithoutPropertyName(): void {
83        $expr = new Variable('test');
84        $set = new PropertyHook('set', $expr);
85        $this->expectException(\LogicException::class);
86        $this->expectExceptionMessage('Can only use getStmts() on a "set" hook if the "propertyName" attribute is set');
87        $set->getStmts();
88    }
89}
90