1<?php declare(strict_types=1);
2
3namespace PhpParser\Builder;
4
5use PhpParser\Comment;
6use PhpParser\Node;
7use PhpParser\Node\Arg;
8use PhpParser\Node\Attribute;
9use PhpParser\Node\AttributeGroup;
10use PhpParser\Node\Expr\Print_;
11use PhpParser\Node\Expr\Variable;
12use PhpParser\Node\Identifier;
13use PhpParser\Node\Name;
14use PhpParser\Node\Scalar\Int_;
15use PhpParser\Node\Scalar\String_;
16use PhpParser\Node\Stmt;
17
18class FunctionTest extends \PHPUnit\Framework\TestCase {
19    public function createFunctionBuilder($name) {
20        return new Function_($name);
21    }
22
23    public function testReturnByRef(): void {
24        $node = $this->createFunctionBuilder('test')
25            ->makeReturnByRef()
26            ->getNode()
27        ;
28
29        $this->assertEquals(
30            new Stmt\Function_('test', [
31                'byRef' => true
32            ]),
33            $node
34        );
35    }
36
37    public function testParams(): void {
38        $param1 = new Node\Param(new Variable('test1'));
39        $param2 = new Node\Param(new Variable('test2'));
40        $param3 = new Node\Param(new Variable('test3'));
41
42        $node = $this->createFunctionBuilder('test')
43            ->addParam($param1)
44            ->addParams([$param2, $param3])
45            ->getNode()
46        ;
47
48        $this->assertEquals(
49            new Stmt\Function_('test', [
50                'params' => [$param1, $param2, $param3]
51            ]),
52            $node
53        );
54    }
55
56    public function testStmts(): void {
57        $stmt1 = new Print_(new String_('test1'));
58        $stmt2 = new Print_(new String_('test2'));
59        $stmt3 = new Print_(new String_('test3'));
60
61        $node = $this->createFunctionBuilder('test')
62            ->addStmt($stmt1)
63            ->addStmts([$stmt2, $stmt3])
64            ->getNode()
65        ;
66
67        $this->assertEquals(
68            new Stmt\Function_('test', [
69                'stmts' => [
70                    new Stmt\Expression($stmt1),
71                    new Stmt\Expression($stmt2),
72                    new Stmt\Expression($stmt3),
73                ]
74            ]),
75            $node
76        );
77    }
78
79    public function testDocComment(): void {
80        $node = $this->createFunctionBuilder('test')
81            ->setDocComment('/** Test */')
82            ->getNode();
83
84        $this->assertEquals(new Stmt\Function_('test', [], [
85            'comments' => [new Comment\Doc('/** Test */')]
86        ]), $node);
87    }
88
89    public function testAddAttribute(): void {
90        $attribute = new Attribute(
91            new Name('Attr'),
92            [new Arg(new Int_(1), false, false, [], new Identifier('name'))]
93        );
94        $attributeGroup = new AttributeGroup([$attribute]);
95
96        $node = $this->createFunctionBuilder('attrGroup')
97            ->addAttribute($attributeGroup)
98            ->getNode();
99
100        $this->assertEquals(new Stmt\Function_('attrGroup', [
101            'attrGroups' => [$attributeGroup],
102        ], []), $node);
103    }
104
105    public function testReturnType(): void {
106        $node = $this->createFunctionBuilder('test')
107            ->setReturnType('void')
108            ->getNode();
109
110        $this->assertEquals(new Stmt\Function_('test', [
111            'returnType' => new Identifier('void'),
112        ], []), $node);
113    }
114
115    public function testInvalidNullableVoidType(): void {
116        $this->expectException(\LogicException::class);
117        $this->expectExceptionMessage('void type cannot be nullable');
118        $this->createFunctionBuilder('test')->setReturnType('?void');
119    }
120
121    public function testInvalidParamError(): void {
122        $this->expectException(\LogicException::class);
123        $this->expectExceptionMessage('Expected parameter node, got "Name"');
124        $this->createFunctionBuilder('test')
125            ->addParam(new Node\Name('foo'))
126        ;
127    }
128
129    public function testAddNonStmt(): void {
130        $this->expectException(\LogicException::class);
131        $this->expectExceptionMessage('Expected statement or expression node');
132        $this->createFunctionBuilder('test')
133            ->addStmt(new Node\Name('Test'));
134    }
135}
136