1<?php declare(strict_types=1); 2 3namespace PhpParser\Builder; 4 5use PhpParser\Modifiers; 6use PhpParser\Node; 7use PhpParser\Node\Arg; 8use PhpParser\Node\Attribute; 9use PhpParser\Node\AttributeGroup; 10use PhpParser\Node\Expr; 11use PhpParser\Node\Identifier; 12use PhpParser\Node\Name; 13use PhpParser\Node\Scalar; 14use PhpParser\Node\Scalar\Int_; 15 16class ParamTest extends \PHPUnit\Framework\TestCase { 17 public function createParamBuilder($name) { 18 return new Param($name); 19 } 20 21 /** 22 * @dataProvider provideTestDefaultValues 23 */ 24 public function testDefaultValues($value, $expectedValueNode): void { 25 $node = $this->createParamBuilder('test') 26 ->setDefault($value) 27 ->getNode() 28 ; 29 30 $this->assertEquals($expectedValueNode, $node->default); 31 } 32 33 public static function provideTestDefaultValues() { 34 return [ 35 [ 36 null, 37 new Expr\ConstFetch(new Node\Name('null')) 38 ], 39 [ 40 true, 41 new Expr\ConstFetch(new Node\Name('true')) 42 ], 43 [ 44 false, 45 new Expr\ConstFetch(new Node\Name('false')) 46 ], 47 [ 48 31415, 49 new Scalar\Int_(31415) 50 ], 51 [ 52 3.1415, 53 new Scalar\Float_(3.1415) 54 ], 55 [ 56 'Hallo World', 57 new Scalar\String_('Hallo World') 58 ], 59 [ 60 [1, 2, 3], 61 new Expr\Array_([ 62 new Node\ArrayItem(new Scalar\Int_(1)), 63 new Node\ArrayItem(new Scalar\Int_(2)), 64 new Node\ArrayItem(new Scalar\Int_(3)), 65 ]) 66 ], 67 [ 68 ['foo' => 'bar', 'bar' => 'foo'], 69 new Expr\Array_([ 70 new Node\ArrayItem( 71 new Scalar\String_('bar'), 72 new Scalar\String_('foo') 73 ), 74 new Node\ArrayItem( 75 new Scalar\String_('foo'), 76 new Scalar\String_('bar') 77 ), 78 ]) 79 ], 80 [ 81 new Scalar\MagicConst\Dir(), 82 new Scalar\MagicConst\Dir() 83 ] 84 ]; 85 } 86 87 /** 88 * @dataProvider provideTestTypes 89 * @dataProvider provideTestNullableTypes 90 * @dataProvider provideTestUnionTypes 91 */ 92 public function testTypes($typeHint, $expectedType): void { 93 $node = $this->createParamBuilder('test') 94 ->setType($typeHint) 95 ->getNode() 96 ; 97 $type = $node->type; 98 99 /* Manually implement comparison to avoid __toString stupidity */ 100 if ($expectedType instanceof Node\NullableType) { 101 $this->assertInstanceOf(get_class($expectedType), $type); 102 $expectedType = $expectedType->type; 103 $type = $type->type; 104 } 105 106 $this->assertInstanceOf(get_class($expectedType), $type); 107 $this->assertEquals($expectedType, $type); 108 } 109 110 public static function provideTestTypes() { 111 return [ 112 ['array', new Node\Identifier('array')], 113 ['callable', new Node\Identifier('callable')], 114 ['bool', new Node\Identifier('bool')], 115 ['int', new Node\Identifier('int')], 116 ['float', new Node\Identifier('float')], 117 ['string', new Node\Identifier('string')], 118 ['iterable', new Node\Identifier('iterable')], 119 ['object', new Node\Identifier('object')], 120 ['Array', new Node\Identifier('array')], 121 ['CALLABLE', new Node\Identifier('callable')], 122 ['mixed', new Node\Identifier('mixed')], 123 ['Some\Class', new Node\Name('Some\Class')], 124 ['\Foo', new Node\Name\FullyQualified('Foo')], 125 ['self', new Node\Name('self')], 126 [new Node\Name('Some\Class'), new Node\Name('Some\Class')], 127 ]; 128 } 129 130 public static function provideTestNullableTypes() { 131 return [ 132 ['?array', new Node\NullableType(new Node\Identifier('array'))], 133 ['?Some\Class', new Node\NullableType(new Node\Name('Some\Class'))], 134 [ 135 new Node\NullableType(new Node\Identifier('int')), 136 new Node\NullableType(new Node\Identifier('int')) 137 ], 138 [ 139 new Node\NullableType(new Node\Name('Some\Class')), 140 new Node\NullableType(new Node\Name('Some\Class')) 141 ], 142 ]; 143 } 144 145 public static function provideTestUnionTypes() { 146 return [ 147 [ 148 new Node\UnionType([ 149 new Node\Name('Some\Class'), 150 new Node\Identifier('array'), 151 ]), 152 new Node\UnionType([ 153 new Node\Name('Some\Class'), 154 new Node\Identifier('array'), 155 ]), 156 ], 157 [ 158 new Node\UnionType([ 159 new Node\Identifier('self'), 160 new Node\Identifier('array'), 161 new Node\Name\FullyQualified('Foo') 162 ]), 163 new Node\UnionType([ 164 new Node\Identifier('self'), 165 new Node\Identifier('array'), 166 new Node\Name\FullyQualified('Foo') 167 ]), 168 ], 169 ]; 170 } 171 172 public function testVoidTypeError(): void { 173 $this->expectException(\LogicException::class); 174 $this->expectExceptionMessage('Parameter type cannot be void'); 175 $this->createParamBuilder('test')->setType('void'); 176 } 177 178 public function testInvalidTypeError(): void { 179 $this->expectException(\LogicException::class); 180 $this->expectExceptionMessage('Type must be a string, or an instance of Name, Identifier or ComplexType'); 181 $this->createParamBuilder('test')->setType(new \stdClass()); 182 } 183 184 public function testByRef(): void { 185 $node = $this->createParamBuilder('test') 186 ->makeByRef() 187 ->getNode() 188 ; 189 190 $this->assertEquals( 191 new Node\Param(new Expr\Variable('test'), null, null, true), 192 $node 193 ); 194 } 195 196 public function testVariadic(): void { 197 $node = $this->createParamBuilder('test') 198 ->makeVariadic() 199 ->getNode() 200 ; 201 202 $this->assertEquals( 203 new Node\Param(new Expr\Variable('test'), null, null, false, true), 204 $node 205 ); 206 } 207 208 public function testMakePublic(): void { 209 $node = $this->createParamBuilder('test') 210 ->makePublic() 211 ->getNode() 212 ; 213 214 $this->assertEquals( 215 new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PUBLIC), 216 $node 217 ); 218 } 219 220 public function testMakeProtected(): void { 221 $node = $this->createParamBuilder('test') 222 ->makeProtected() 223 ->getNode() 224 ; 225 226 $this->assertEquals( 227 new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PROTECTED), 228 $node 229 ); 230 231 $node = $this->createParamBuilder('test') 232 ->makeProtectedSet() 233 ->getNode() 234 ; 235 236 $this->assertEquals( 237 new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PROTECTED_SET), 238 $node 239 ); 240 } 241 242 public function testMakePrivate(): void { 243 $node = $this->createParamBuilder('test') 244 ->makePrivate() 245 ->getNode() 246 ; 247 248 $this->assertEquals( 249 new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PRIVATE), 250 $node 251 ); 252 253 $node = $this->createParamBuilder('test') 254 ->makePrivateSet() 255 ->getNode() 256 ; 257 258 $this->assertEquals( 259 new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PRIVATE_SET), 260 $node 261 ); 262 } 263 264 public function testMakeReadonly(): void { 265 $node = $this->createParamBuilder('test') 266 ->makeReadonly() 267 ->getNode() 268 ; 269 270 $this->assertEquals( 271 new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::READONLY), 272 $node 273 ); 274 } 275 276 public function testAddAttribute(): void { 277 $attribute = new Attribute( 278 new Name('Attr'), 279 [new Arg(new Int_(1), false, false, [], new Identifier('name'))] 280 ); 281 $attributeGroup = new AttributeGroup([$attribute]); 282 283 $node = $this->createParamBuilder('attributeGroup') 284 ->addAttribute($attributeGroup) 285 ->getNode(); 286 287 $this->assertEquals( 288 new Node\Param(new Expr\Variable('attributeGroup'), null, null, false, false, [], 0, [$attributeGroup]), 289 $node 290 ); 291 } 292} 293