1<?php declare(strict_types=1);
2
3namespace PhpParser\Builder;
4
5use PhpParser\Comment;
6use PhpParser\Error;
7use PhpParser\Modifiers;
8use PhpParser\Node\Arg;
9use PhpParser\Node\Attribute;
10use PhpParser\Node\AttributeGroup;
11use PhpParser\Node\Expr;
12use PhpParser\Node\Identifier;
13use PhpParser\Node\Name;
14use PhpParser\Node\PropertyHook;
15use PhpParser\Node\PropertyItem;
16use PhpParser\Node\Scalar;
17use PhpParser\Node\Scalar\Int_;
18use PhpParser\Node\Stmt;
19
20class PropertyTest extends \PHPUnit\Framework\TestCase {
21    public function createPropertyBuilder($name) {
22        return new Property($name);
23    }
24
25    public function testModifiers(): void {
26        $node = $this->createPropertyBuilder('test')
27            ->makePrivate()
28            ->makeStatic()
29            ->getNode()
30        ;
31
32        $this->assertEquals(
33            new Stmt\Property(
34                Modifiers::PRIVATE | Modifiers::STATIC,
35                [new PropertyItem('test')]
36            ),
37            $node
38        );
39
40        $node = $this->createPropertyBuilder('test')
41            ->makeProtected()
42            ->getNode()
43        ;
44
45        $this->assertEquals(
46            new Stmt\Property(
47                Modifiers::PROTECTED,
48                [new PropertyItem('test')]
49            ),
50            $node
51        );
52
53        $node = $this->createPropertyBuilder('test')
54            ->makePublic()
55            ->getNode()
56        ;
57
58        $this->assertEquals(
59            new Stmt\Property(
60                Modifiers::PUBLIC,
61                [new PropertyItem('test')]
62            ),
63            $node
64        );
65
66        $node = $this->createPropertyBuilder('test')
67            ->makeReadonly()
68            ->getNode()
69        ;
70
71        $this->assertEquals(
72            new Stmt\Property(
73                Modifiers::READONLY,
74                [new PropertyItem('test')]
75            ),
76            $node
77        );
78
79        $node = $this->createPropertyBuilder('test')
80            ->makeFinal()
81            ->getNode();
82        $this->assertEquals(
83            new Stmt\Property(Modifiers::FINAL, [new PropertyItem('test')]),
84            $node);
85
86        $node = $this->createPropertyBuilder('test')
87            ->makePrivateSet()
88            ->getNode();
89        $this->assertEquals(
90            new Stmt\Property(Modifiers::PRIVATE_SET, [new PropertyItem('test')]),
91            $node);
92
93        $node = $this->createPropertyBuilder('test')
94            ->makeProtectedSet()
95            ->getNode();
96        $this->assertEquals(
97            new Stmt\Property(Modifiers::PROTECTED_SET, [new PropertyItem('test')]),
98            $node);
99    }
100
101    public function testAbstractWithoutHook() {
102        $this->expectException(Error::class);
103        $this->expectExceptionMessage('Only hooked properties may be declared abstract');
104        $this->createPropertyBuilder('test')->makeAbstract()->getNode();
105    }
106
107    public function testDocComment(): void {
108        $node = $this->createPropertyBuilder('test')
109            ->setDocComment('/** Test */')
110            ->getNode();
111
112        $this->assertEquals(new Stmt\Property(
113            Modifiers::PUBLIC,
114            [
115                new \PhpParser\Node\PropertyItem('test')
116            ],
117            [
118                'comments' => [new Comment\Doc('/** Test */')]
119            ]
120        ), $node);
121    }
122
123    /**
124     * @dataProvider provideTestDefaultValues
125     */
126    public function testDefaultValues($value, $expectedValueNode): void {
127        $node = $this->createPropertyBuilder('test')
128            ->setDefault($value)
129            ->getNode()
130        ;
131
132        $this->assertEquals($expectedValueNode, $node->props[0]->default);
133    }
134
135    public function testAddAttribute(): void {
136        $attribute = new Attribute(
137            new Name('Attr'),
138            [new Arg(new Int_(1), false, false, [], new Identifier('name'))]
139        );
140        $attributeGroup = new AttributeGroup([$attribute]);
141
142        $node = $this->createPropertyBuilder('test')
143            ->addAttribute($attributeGroup)
144            ->getNode()
145        ;
146
147        $this->assertEquals(
148            new Stmt\Property(
149                Modifiers::PUBLIC,
150                [
151                    new \PhpParser\Node\PropertyItem('test')
152                ],
153                [],
154                null,
155                [$attributeGroup]
156            ),
157            $node
158        );
159    }
160
161    public function testAddHook(): void {
162        $get = new PropertyHook('get', null);
163        $set = new PropertyHook('set', null);
164        $node = $this->createPropertyBuilder('test')
165            ->addHook($get)
166            ->addHook($set)
167            ->makeAbstract()
168            ->getNode();
169        $this->assertEquals(
170            new Stmt\Property(
171                Modifiers::ABSTRACT,
172                [new PropertyItem('test')],
173                [], null, [],
174                [$get, $set]),
175            $node);
176    }
177
178    public static function provideTestDefaultValues() {
179        return [
180            [
181                null,
182                new Expr\ConstFetch(new Name('null'))
183            ],
184            [
185                true,
186                new Expr\ConstFetch(new Name('true'))
187            ],
188            [
189                false,
190                new Expr\ConstFetch(new Name('false'))
191            ],
192            [
193                31415,
194                new Scalar\Int_(31415)
195            ],
196            [
197                3.1415,
198                new Scalar\Float_(3.1415)
199            ],
200            [
201                'Hallo World',
202                new Scalar\String_('Hallo World')
203            ],
204            [
205                [1, 2, 3],
206                new Expr\Array_([
207                    new \PhpParser\Node\ArrayItem(new Scalar\Int_(1)),
208                    new \PhpParser\Node\ArrayItem(new Scalar\Int_(2)),
209                    new \PhpParser\Node\ArrayItem(new Scalar\Int_(3)),
210                ])
211            ],
212            [
213                ['foo' => 'bar', 'bar' => 'foo'],
214                new Expr\Array_([
215                    new \PhpParser\Node\ArrayItem(
216                        new Scalar\String_('bar'),
217                        new Scalar\String_('foo')
218                    ),
219                    new \PhpParser\Node\ArrayItem(
220                        new Scalar\String_('foo'),
221                        new Scalar\String_('bar')
222                    ),
223                ])
224            ],
225            [
226                new Scalar\MagicConst\Dir(),
227                new Scalar\MagicConst\Dir()
228            ]
229        ];
230    }
231}
232