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\Identifier;
11use PhpParser\Node\Name;
12use PhpParser\Node\Scalar\Float_;
13use PhpParser\Node\Scalar\Int_;
14use PhpParser\Node\Stmt;
15
16class InterfaceTest extends \PHPUnit\Framework\TestCase {
17    protected function createInterfaceBuilder() {
18        return new Interface_('Contract');
19    }
20
21    private function dump($node) {
22        $pp = new \PhpParser\PrettyPrinter\Standard();
23        return $pp->prettyPrint([$node]);
24    }
25
26    public function testEmpty(): void {
27        $contract = $this->createInterfaceBuilder()->getNode();
28        $this->assertInstanceOf(Stmt\Interface_::class, $contract);
29        $this->assertEquals(new Node\Identifier('Contract'), $contract->name);
30    }
31
32    public function testExtending(): void {
33        $contract = $this->createInterfaceBuilder()
34            ->extend('Space\Root1', 'Root2')->getNode();
35        $this->assertEquals(
36            new Stmt\Interface_('Contract', [
37                'extends' => [
38                    new Node\Name('Space\Root1'),
39                    new Node\Name('Root2')
40                ],
41            ]), $contract
42        );
43    }
44
45    public function testAddMethod(): void {
46        $method = new Stmt\ClassMethod('doSomething');
47        $contract = $this->createInterfaceBuilder()->addStmt($method)->getNode();
48        $this->assertSame([$method], $contract->stmts);
49    }
50
51    public function testAddConst(): void {
52        $const = new Stmt\ClassConst([
53            new Node\Const_('SPEED_OF_LIGHT', new Float_(299792458.0))
54        ]);
55        $contract = $this->createInterfaceBuilder()->addStmt($const)->getNode();
56        $this->assertSame(299792458.0, $contract->stmts[0]->consts[0]->value->value);
57    }
58
59    public function testOrder(): void {
60        $const = new Stmt\ClassConst([
61            new Node\Const_('SPEED_OF_LIGHT', new Float_(299792458))
62        ]);
63        $method = new Stmt\ClassMethod('doSomething');
64        $contract = $this->createInterfaceBuilder()
65            ->addStmt($method)
66            ->addStmt($const)
67            ->getNode()
68        ;
69
70        $this->assertInstanceOf(Stmt\ClassConst::class, $contract->stmts[0]);
71        $this->assertInstanceOf(Stmt\ClassMethod::class, $contract->stmts[1]);
72    }
73
74    public function testDocComment(): void {
75        $node = $this->createInterfaceBuilder()
76            ->setDocComment('/** Test */')
77            ->getNode();
78
79        $this->assertEquals(new Stmt\Interface_('Contract', [], [
80            'comments' => [new Comment\Doc('/** Test */')]
81        ]), $node);
82    }
83
84    public function testAddAttribute(): void {
85        $attribute = new Attribute(
86            new Name('Attr'),
87            [new Arg(new Int_(1), false, false, [], new Identifier('name'))]
88        );
89        $attributeGroup = new AttributeGroup([$attribute]);
90
91        $node = $this->createInterfaceBuilder()
92            ->addAttribute($attributeGroup)
93            ->getNode();
94
95        $this->assertEquals(new Stmt\Interface_('Contract', [
96            'attrGroups' => [$attributeGroup],
97        ], []), $node);
98    }
99
100    public function testInvalidStmtError(): void {
101        $this->expectException(\LogicException::class);
102        $this->expectExceptionMessage('Unexpected node of type "PropertyItem"');
103        $this->createInterfaceBuilder()->addStmt(new Node\PropertyItem('invalid'));
104    }
105
106    public function testFullFunctional(): void {
107        $const = new Stmt\ClassConst([
108            new Node\Const_('SPEED_OF_LIGHT', new Float_(299792458))
109        ]);
110        $method = new Stmt\ClassMethod('doSomething');
111        $contract = $this->createInterfaceBuilder()
112            ->addStmt($method)
113            ->addStmt($const)
114            ->getNode()
115        ;
116
117        eval($this->dump($contract));
118
119        $this->assertTrue(interface_exists('Contract', false));
120    }
121}
122