1<?php declare(strict_types=1); 2 3namespace PhpParser; 4 5use PhpParser\Builder\Class_; 6use PhpParser\Node\Identifier; 7use PhpParser\Node\Scalar; 8use PhpParser\Node\Stmt; 9use PhpParser\Node\Expr; 10 11class BuilderHelpersTest extends \PHPUnit\Framework\TestCase { 12 public function testNormalizeNode(): void { 13 $builder = new Class_('SomeClass'); 14 $this->assertEquals($builder->getNode(), BuilderHelpers::normalizeNode($builder)); 15 16 $attribute = new Node\Attribute(new Node\Name('Test')); 17 $this->assertSame($attribute, BuilderHelpers::normalizeNode($attribute)); 18 19 $this->expectException(\LogicException::class); 20 $this->expectExceptionMessage('Expected node or builder object'); 21 BuilderHelpers::normalizeNode('test'); 22 } 23 24 public function testNormalizeStmt(): void { 25 $stmt = new Node\Stmt\Class_('Class'); 26 $this->assertSame($stmt, BuilderHelpers::normalizeStmt($stmt)); 27 28 $expr = new Expr\Variable('fn'); 29 $normalizedExpr = BuilderHelpers::normalizeStmt($expr); 30 $this->assertEquals(new Stmt\Expression($expr), $normalizedExpr); 31 $this->assertSame($expr, $normalizedExpr->expr); 32 33 $this->expectException(\LogicException::class); 34 $this->expectExceptionMessage('Expected statement or expression node'); 35 BuilderHelpers::normalizeStmt(new Node\Attribute(new Node\Name('Test'))); 36 } 37 38 public function testNormalizeStmtInvalidType(): void { 39 $this->expectException(\LogicException::class); 40 $this->expectExceptionMessage('Expected node or builder object'); 41 BuilderHelpers::normalizeStmt('test'); 42 } 43 44 public function testNormalizeIdentifier(): void { 45 $identifier = new Node\Identifier('fn'); 46 $this->assertSame($identifier, BuilderHelpers::normalizeIdentifier($identifier)); 47 $this->assertEquals($identifier, BuilderHelpers::normalizeIdentifier('fn')); 48 49 $this->expectException(\LogicException::class); 50 $this->expectExceptionMessage('Expected string or instance of Node\Identifier'); 51 BuilderHelpers::normalizeIdentifier(1); 52 } 53 54 public function testNormalizeIdentifierOrExpr(): void { 55 $identifier = new Node\Identifier('fn'); 56 $this->assertSame($identifier, BuilderHelpers::normalizeIdentifierOrExpr($identifier)); 57 58 $expr = new Expr\Variable('fn'); 59 $this->assertSame($expr, BuilderHelpers::normalizeIdentifierOrExpr($expr)); 60 $this->assertEquals($identifier, BuilderHelpers::normalizeIdentifierOrExpr('fn')); 61 62 $this->expectException(\LogicException::class); 63 $this->expectExceptionMessage('Expected string or instance of Node\Identifier'); 64 BuilderHelpers::normalizeIdentifierOrExpr(1); 65 } 66 67 public function testNormalizeName(): void { 68 $name = new Node\Name('test'); 69 $this->assertSame($name, BuilderHelpers::normalizeName($name)); 70 $this->assertEquals( 71 new Node\Name\FullyQualified(['Namespace', 'Test']), 72 BuilderHelpers::normalizeName('\\Namespace\\Test') 73 ); 74 $this->assertEquals( 75 new Node\Name\Relative(['Test']), 76 BuilderHelpers::normalizeName('namespace\\Test') 77 ); 78 $this->assertEquals($name, BuilderHelpers::normalizeName('test')); 79 80 $this->expectException(\LogicException::class); 81 $this->expectExceptionMessage('Name cannot be empty'); 82 BuilderHelpers::normalizeName(''); 83 } 84 85 public function testNormalizeNameInvalidType(): void { 86 $this->expectException(\LogicException::class); 87 $this->expectExceptionMessage('Name must be a string or an instance of Node\Name'); 88 BuilderHelpers::normalizeName(1); 89 } 90 91 public function testNormalizeNameOrExpr(): void { 92 $expr = new Expr\Variable('fn'); 93 $this->assertSame($expr, BuilderHelpers::normalizeNameOrExpr($expr)); 94 95 $name = new Node\Name('test'); 96 $this->assertSame($name, BuilderHelpers::normalizeNameOrExpr($name)); 97 $this->assertEquals( 98 new Node\Name\FullyQualified(['Namespace', 'Test']), 99 BuilderHelpers::normalizeNameOrExpr('\\Namespace\\Test') 100 ); 101 $this->assertEquals( 102 new Node\Name\Relative(['Test']), 103 BuilderHelpers::normalizeNameOrExpr('namespace\\Test') 104 ); 105 $this->assertEquals($name, BuilderHelpers::normalizeNameOrExpr('test')); 106 107 $this->expectException(\LogicException::class); 108 $this->expectExceptionMessage('Name cannot be empty'); 109 BuilderHelpers::normalizeNameOrExpr(''); 110 } 111 112 public function testNormalizeNameOrExpInvalidType(): void { 113 $this->expectException(\LogicException::class); 114 $this->expectExceptionMessage('Name must be a string or an instance of Node\Name or Node\Expr'); 115 BuilderHelpers::normalizeNameOrExpr(1); 116 } 117 118 public function testNormalizeType(): void { 119 $this->assertEquals(new Node\Identifier('array'), BuilderHelpers::normalizeType('array')); 120 $this->assertEquals(new Node\Identifier('callable'), BuilderHelpers::normalizeType('callable')); 121 $this->assertEquals(new Node\Identifier('string'), BuilderHelpers::normalizeType('string')); 122 $this->assertEquals(new Node\Identifier('int'), BuilderHelpers::normalizeType('int')); 123 $this->assertEquals(new Node\Identifier('float'), BuilderHelpers::normalizeType('float')); 124 $this->assertEquals(new Node\Identifier('bool'), BuilderHelpers::normalizeType('bool')); 125 $this->assertEquals(new Node\Identifier('iterable'), BuilderHelpers::normalizeType('iterable')); 126 $this->assertEquals(new Node\Identifier('void'), BuilderHelpers::normalizeType('void')); 127 $this->assertEquals(new Node\Identifier('object'), BuilderHelpers::normalizeType('object')); 128 $this->assertEquals(new Node\Identifier('null'), BuilderHelpers::normalizeType('null')); 129 $this->assertEquals(new Node\Identifier('false'), BuilderHelpers::normalizeType('false')); 130 $this->assertEquals(new Node\Identifier('mixed'), BuilderHelpers::normalizeType('mixed')); 131 $this->assertEquals(new Node\Identifier('never'), BuilderHelpers::normalizeType('never')); 132 $this->assertEquals(new Node\Identifier('true'), BuilderHelpers::normalizeType('true')); 133 134 $intIdentifier = new Node\Identifier('int'); 135 $this->assertSame($intIdentifier, BuilderHelpers::normalizeType($intIdentifier)); 136 137 $intName = new Node\Name('int'); 138 $this->assertSame($intName, BuilderHelpers::normalizeType($intName)); 139 140 $intNullable = new Node\NullableType(new Identifier('int')); 141 $this->assertSame($intNullable, BuilderHelpers::normalizeType($intNullable)); 142 143 $unionType = new Node\UnionType([new Node\Identifier('int'), new Node\Identifier('string')]); 144 $this->assertSame($unionType, BuilderHelpers::normalizeType($unionType)); 145 146 $intersectionType = new Node\IntersectionType([new Node\Name('A'), new Node\Name('B')]); 147 $this->assertSame($intersectionType, BuilderHelpers::normalizeType($intersectionType)); 148 149 $expectedNullable = new Node\NullableType($intIdentifier); 150 $nullable = BuilderHelpers::normalizeType('?int'); 151 $this->assertEquals($expectedNullable, $nullable); 152 $this->assertEquals($intIdentifier, $nullable->type); 153 154 $this->expectException(\LogicException::class); 155 $this->expectExceptionMessage('Type must be a string, or an instance of Name, Identifier or ComplexType'); 156 BuilderHelpers::normalizeType(1); 157 } 158 159 public function testNormalizeTypeNullableVoid(): void { 160 $this->expectException(\LogicException::class); 161 $this->expectExceptionMessage('void type cannot be nullable'); 162 BuilderHelpers::normalizeType('?void'); 163 } 164 165 public function testNormalizeTypeNullableMixed(): void { 166 $this->expectException(\LogicException::class); 167 $this->expectExceptionMessage('mixed type cannot be nullable'); 168 BuilderHelpers::normalizeType('?mixed'); 169 } 170 171 public function testNormalizeTypeNullableNever(): void { 172 $this->expectException(\LogicException::class); 173 $this->expectExceptionMessage('never type cannot be nullable'); 174 BuilderHelpers::normalizeType('?never'); 175 } 176 177 public function testNormalizeValue(): void { 178 $expression = new Scalar\Int_(1); 179 $this->assertSame($expression, BuilderHelpers::normalizeValue($expression)); 180 181 $this->assertEquals(new Expr\ConstFetch(new Node\Name('null')), BuilderHelpers::normalizeValue(null)); 182 $this->assertEquals(new Expr\ConstFetch(new Node\Name('true')), BuilderHelpers::normalizeValue(true)); 183 $this->assertEquals(new Expr\ConstFetch(new Node\Name('false')), BuilderHelpers::normalizeValue(false)); 184 $this->assertEquals(new Scalar\Int_(2), BuilderHelpers::normalizeValue(2)); 185 $this->assertEquals(new Scalar\Float_(2.5), BuilderHelpers::normalizeValue(2.5)); 186 $this->assertEquals(new Scalar\String_('text'), BuilderHelpers::normalizeValue('text')); 187 $this->assertEquals( 188 new Expr\Array_([ 189 new Node\ArrayItem(new Scalar\Int_(0)), 190 new Node\ArrayItem(new Scalar\Int_(1), new Scalar\String_('test')), 191 ]), 192 BuilderHelpers::normalizeValue([ 193 0, 194 'test' => 1, 195 ]) 196 ); 197 198 $this->expectException(\LogicException::class); 199 $this->expectExceptionMessage('Invalid value'); 200 BuilderHelpers::normalizeValue(new \stdClass()); 201 } 202 203 public function testNormalizeDocComment(): void { 204 $docComment = new Comment\Doc('Some doc comment'); 205 $this->assertSame($docComment, BuilderHelpers::normalizeDocComment($docComment)); 206 207 $this->assertEquals($docComment, BuilderHelpers::normalizeDocComment('Some doc comment')); 208 209 $this->expectException(\LogicException::class); 210 $this->expectExceptionMessage('Doc comment must be a string or an instance of PhpParser\Comment\Doc'); 211 BuilderHelpers::normalizeDocComment(1); 212 } 213 214 public function testNormalizeAttribute(): void { 215 $attribute = new Node\Attribute(new Node\Name('Test')); 216 $attributeGroup = new Node\AttributeGroup([$attribute]); 217 218 $this->assertEquals($attributeGroup, BuilderHelpers::normalizeAttribute($attribute)); 219 $this->assertSame($attributeGroup, BuilderHelpers::normalizeAttribute($attributeGroup)); 220 221 $this->expectException(\LogicException::class); 222 $this->expectExceptionMessage('Attribute must be an instance of PhpParser\Node\Attribute or PhpParser\Node\AttributeGroup'); 223 BuilderHelpers::normalizeAttribute('test'); 224 } 225} 226