1<?php declare(strict_types=1); 2 3namespace PhpParser\Builder; 4 5use PhpParser\Comment; 6use PhpParser\Modifiers; 7use PhpParser\Node; 8use PhpParser\Node\Arg; 9use PhpParser\Node\Attribute; 10use PhpParser\Node\AttributeGroup; 11use PhpParser\Node\Identifier; 12use PhpParser\Node\Name; 13use PhpParser\Node\Scalar\Int_; 14use PhpParser\Node\Stmt; 15 16class ClassTest extends \PHPUnit\Framework\TestCase { 17 protected function createClassBuilder($class) { 18 return new Class_($class); 19 } 20 21 public function testExtendsImplements(): void { 22 $node = $this->createClassBuilder('SomeLogger') 23 ->extend('BaseLogger') 24 ->implement('Namespaced\Logger', new Name('SomeInterface')) 25 ->implement('\Fully\Qualified', 'namespace\NamespaceRelative') 26 ->getNode() 27 ; 28 29 $this->assertEquals( 30 new Stmt\Class_('SomeLogger', [ 31 'extends' => new Name('BaseLogger'), 32 'implements' => [ 33 new Name('Namespaced\Logger'), 34 new Name('SomeInterface'), 35 new Name\FullyQualified('Fully\Qualified'), 36 new Name\Relative('NamespaceRelative'), 37 ], 38 ]), 39 $node 40 ); 41 } 42 43 public function testAbstract(): void { 44 $node = $this->createClassBuilder('Test') 45 ->makeAbstract() 46 ->getNode() 47 ; 48 49 $this->assertEquals( 50 new Stmt\Class_('Test', [ 51 'flags' => Modifiers::ABSTRACT 52 ]), 53 $node 54 ); 55 } 56 57 public function testFinal(): void { 58 $node = $this->createClassBuilder('Test') 59 ->makeFinal() 60 ->getNode() 61 ; 62 63 $this->assertEquals( 64 new Stmt\Class_('Test', [ 65 'flags' => Modifiers::FINAL 66 ]), 67 $node 68 ); 69 } 70 71 public function testReadonly(): void { 72 $node = $this->createClassBuilder('Test') 73 ->makeReadonly() 74 ->getNode() 75 ; 76 77 $this->assertEquals( 78 new Stmt\Class_('Test', [ 79 'flags' => Modifiers::READONLY 80 ]), 81 $node 82 ); 83 } 84 85 public function testStatementOrder(): void { 86 $method = new Stmt\ClassMethod('testMethod'); 87 $property = new Stmt\Property( 88 Modifiers::PUBLIC, 89 [new Node\PropertyItem('testProperty')] 90 ); 91 $const = new Stmt\ClassConst([ 92 new Node\Const_('TEST_CONST', new Node\Scalar\String_('ABC')) 93 ]); 94 $use = new Stmt\TraitUse([new Name('SomeTrait')]); 95 96 $node = $this->createClassBuilder('Test') 97 ->addStmt($method) 98 ->addStmt($property) 99 ->addStmts([$const, $use]) 100 ->getNode() 101 ; 102 103 $this->assertEquals( 104 new Stmt\Class_('Test', [ 105 'stmts' => [$use, $const, $property, $method] 106 ]), 107 $node 108 ); 109 } 110 111 public function testDocComment(): void { 112 $docComment = <<<'DOC' 113/** 114 * Test 115 */ 116DOC; 117 $class = $this->createClassBuilder('Test') 118 ->setDocComment($docComment) 119 ->getNode(); 120 121 $this->assertEquals( 122 new Stmt\Class_('Test', [], [ 123 'comments' => [ 124 new Comment\Doc($docComment) 125 ] 126 ]), 127 $class 128 ); 129 130 $class = $this->createClassBuilder('Test') 131 ->setDocComment(new Comment\Doc($docComment)) 132 ->getNode(); 133 134 $this->assertEquals( 135 new Stmt\Class_('Test', [], [ 136 'comments' => [ 137 new Comment\Doc($docComment) 138 ] 139 ]), 140 $class 141 ); 142 } 143 144 public function testAddAttribute(): void { 145 $attribute = new Attribute( 146 new Name('Attr'), 147 [new Arg(new Int_(1), false, false, [], new Identifier('name'))] 148 ); 149 $attributeGroup = new AttributeGroup([$attribute]); 150 151 $class = $this->createClassBuilder('ATTR_GROUP') 152 ->addAttribute($attributeGroup) 153 ->getNode(); 154 155 $this->assertEquals( 156 new Stmt\Class_('ATTR_GROUP', [ 157 'attrGroups' => [ 158 $attributeGroup, 159 ] 160 ], []), 161 $class 162 ); 163 } 164 165 public function testInvalidStmtError(): void { 166 $this->expectException(\LogicException::class); 167 $this->expectExceptionMessage('Unexpected node of type "Stmt_Echo"'); 168 $this->createClassBuilder('Test') 169 ->addStmt(new Stmt\Echo_([])) 170 ; 171 } 172 173 public function testInvalidDocComment(): void { 174 $this->expectException(\LogicException::class); 175 $this->expectExceptionMessage('Doc comment must be a string or an instance of PhpParser\Comment\Doc'); 176 $this->createClassBuilder('Test') 177 ->setDocComment(new Comment('Test')); 178 } 179 180 public function testEmptyName(): void { 181 $this->expectException(\LogicException::class); 182 $this->expectExceptionMessage('Name cannot be empty'); 183 $this->createClassBuilder('Test') 184 ->extend(''); 185 } 186 187 public function testInvalidName(): void { 188 $this->expectException(\LogicException::class); 189 $this->expectExceptionMessage('Name must be a string or an instance of Node\Name'); 190 $this->createClassBuilder('Test') 191 ->extend(['Foo']); 192 } 193} 194