annotate vendor/phpspec/prophecy/tests/Doubler/Generator/ClassMirrorTest.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Tests\Prophecy\Doubler\Generator;
Chris@0 4
Chris@0 5 use Prophecy\Doubler\Generator\ClassMirror;
Chris@0 6
Chris@0 7 class ClassMirrorTest extends \PHPUnit_Framework_TestCase
Chris@0 8 {
Chris@0 9 /**
Chris@0 10 * @test
Chris@0 11 */
Chris@0 12 public function it_reflects_allowed_magic_methods()
Chris@0 13 {
Chris@0 14 $class = new \ReflectionClass('Fixtures\Prophecy\SpecialMethods');
Chris@0 15
Chris@0 16 $mirror = new ClassMirror();
Chris@0 17
Chris@0 18 $node = $mirror->reflect($class, array());
Chris@0 19
Chris@0 20 $this->assertCount(7, $node->getMethods());
Chris@0 21 }
Chris@0 22
Chris@0 23 /**
Chris@0 24 * @test
Chris@0 25 */
Chris@0 26 public function it_reflects_protected_abstract_methods()
Chris@0 27 {
Chris@0 28 $class = new \ReflectionClass('Fixtures\Prophecy\WithProtectedAbstractMethod');
Chris@0 29
Chris@0 30 $mirror = new ClassMirror();
Chris@0 31
Chris@0 32 $classNode = $mirror->reflect($class, array());
Chris@0 33
Chris@0 34 $this->assertEquals('Fixtures\Prophecy\WithProtectedAbstractMethod', $classNode->getParentClass());
Chris@0 35
Chris@0 36 $methodNodes = $classNode->getMethods();
Chris@0 37 $this->assertCount(1, $methodNodes);
Chris@0 38
Chris@0 39 $this->assertEquals('protected', $methodNodes['innerDetail']->getVisibility());
Chris@0 40 }
Chris@0 41
Chris@0 42 /**
Chris@0 43 * @test
Chris@0 44 */
Chris@0 45 public function it_reflects_public_static_methods()
Chris@0 46 {
Chris@0 47 $class = new \ReflectionClass('Fixtures\Prophecy\WithStaticMethod');
Chris@0 48
Chris@0 49 $mirror = new ClassMirror();
Chris@0 50
Chris@0 51 $classNode = $mirror->reflect($class, array());
Chris@0 52
Chris@0 53 $this->assertEquals('Fixtures\Prophecy\WithStaticMethod', $classNode->getParentClass());
Chris@0 54
Chris@0 55 $methodNodes = $classNode->getMethods();
Chris@0 56 $this->assertCount(1, $methodNodes);
Chris@0 57
Chris@0 58 $this->assertTrue($methodNodes['innerDetail']->isStatic());
Chris@0 59 }
Chris@0 60
Chris@0 61 /**
Chris@0 62 * @test
Chris@0 63 */
Chris@0 64 public function it_marks_required_args_without_types_as_not_optional()
Chris@0 65 {
Chris@0 66 $class = new \ReflectionClass('Fixtures\Prophecy\WithArguments');
Chris@0 67
Chris@0 68 $mirror = new ClassMirror();
Chris@0 69
Chris@0 70 $classNode = $mirror->reflect($class, array());
Chris@0 71 $methodNode = $classNode->getMethod('methodWithoutTypeHints');
Chris@0 72 $argNodes = $methodNode->getArguments();
Chris@0 73
Chris@0 74 $this->assertCount(1, $argNodes);
Chris@0 75
Chris@0 76 $this->assertEquals('arg', $argNodes[0]->getName());
Chris@0 77 $this->assertNull($argNodes[0]->getTypeHint());
Chris@0 78 $this->assertFalse($argNodes[0]->isOptional());
Chris@0 79 $this->assertNull($argNodes[0]->getDefault());
Chris@0 80 $this->assertFalse($argNodes[0]->isPassedByReference());
Chris@0 81 $this->assertFalse($argNodes[0]->isVariadic());
Chris@0 82 }
Chris@0 83
Chris@0 84 /**
Chris@0 85 * @test
Chris@0 86 */
Chris@0 87 public function it_properly_reads_methods_arguments_with_types()
Chris@0 88 {
Chris@0 89 $class = new \ReflectionClass('Fixtures\Prophecy\WithArguments');
Chris@0 90
Chris@0 91 $mirror = new ClassMirror();
Chris@0 92
Chris@0 93 $classNode = $mirror->reflect($class, array());
Chris@0 94 $methodNode = $classNode->getMethod('methodWithArgs');
Chris@0 95 $argNodes = $methodNode->getArguments();
Chris@0 96
Chris@0 97 $this->assertCount(3, $argNodes);
Chris@0 98
Chris@0 99 $this->assertEquals('arg_1', $argNodes[0]->getName());
Chris@0 100 $this->assertEquals('array', $argNodes[0]->getTypeHint());
Chris@0 101 $this->assertTrue($argNodes[0]->isOptional());
Chris@0 102 $this->assertEquals(array(), $argNodes[0]->getDefault());
Chris@0 103 $this->assertFalse($argNodes[0]->isPassedByReference());
Chris@0 104 $this->assertFalse($argNodes[0]->isVariadic());
Chris@0 105
Chris@0 106 $this->assertEquals('arg_2', $argNodes[1]->getName());
Chris@0 107 $this->assertEquals('ArrayAccess', $argNodes[1]->getTypeHint());
Chris@0 108 $this->assertFalse($argNodes[1]->isOptional());
Chris@0 109
Chris@0 110 $this->assertEquals('arg_3', $argNodes[2]->getName());
Chris@0 111 $this->assertEquals('ArrayAccess', $argNodes[2]->getTypeHint());
Chris@0 112 $this->assertTrue($argNodes[2]->isOptional());
Chris@0 113 $this->assertNull($argNodes[2]->getDefault());
Chris@0 114 $this->assertFalse($argNodes[2]->isPassedByReference());
Chris@0 115 $this->assertFalse($argNodes[2]->isVariadic());
Chris@0 116 }
Chris@0 117
Chris@0 118 /**
Chris@0 119 * @test
Chris@0 120 * @requires PHP 5.4
Chris@0 121 */
Chris@0 122 public function it_properly_reads_methods_arguments_with_callable_types()
Chris@0 123 {
Chris@0 124 $class = new \ReflectionClass('Fixtures\Prophecy\WithCallableArgument');
Chris@0 125
Chris@0 126 $mirror = new ClassMirror();
Chris@0 127
Chris@0 128 $classNode = $mirror->reflect($class, array());
Chris@0 129 $methodNode = $classNode->getMethod('methodWithArgs');
Chris@0 130 $argNodes = $methodNode->getArguments();
Chris@0 131
Chris@0 132 $this->assertCount(2, $argNodes);
Chris@0 133
Chris@0 134 $this->assertEquals('arg_1', $argNodes[0]->getName());
Chris@0 135 $this->assertEquals('callable', $argNodes[0]->getTypeHint());
Chris@0 136 $this->assertFalse($argNodes[0]->isOptional());
Chris@0 137 $this->assertFalse($argNodes[0]->isPassedByReference());
Chris@0 138 $this->assertFalse($argNodes[0]->isVariadic());
Chris@0 139
Chris@0 140 $this->assertEquals('arg_2', $argNodes[1]->getName());
Chris@0 141 $this->assertEquals('callable', $argNodes[1]->getTypeHint());
Chris@0 142 $this->assertTrue($argNodes[1]->isOptional());
Chris@0 143 $this->assertNull($argNodes[1]->getDefault());
Chris@0 144 $this->assertFalse($argNodes[1]->isPassedByReference());
Chris@0 145 $this->assertFalse($argNodes[1]->isVariadic());
Chris@0 146 }
Chris@0 147
Chris@0 148 /**
Chris@0 149 * @test
Chris@0 150 * @requires PHP 5.6
Chris@0 151 */
Chris@0 152 public function it_properly_reads_methods_variadic_arguments()
Chris@0 153 {
Chris@0 154 $class = new \ReflectionClass('Fixtures\Prophecy\WithVariadicArgument');
Chris@0 155
Chris@0 156 $mirror = new ClassMirror();
Chris@0 157
Chris@0 158 $classNode = $mirror->reflect($class, array());
Chris@0 159 $methodNode = $classNode->getMethod('methodWithArgs');
Chris@0 160 $argNodes = $methodNode->getArguments();
Chris@0 161
Chris@0 162 $this->assertCount(1, $argNodes);
Chris@0 163
Chris@0 164 $this->assertEquals('args', $argNodes[0]->getName());
Chris@0 165 $this->assertNull($argNodes[0]->getTypeHint());
Chris@0 166 $this->assertFalse($argNodes[0]->isOptional());
Chris@0 167 $this->assertFalse($argNodes[0]->isPassedByReference());
Chris@0 168 $this->assertTrue($argNodes[0]->isVariadic());
Chris@0 169 }
Chris@0 170
Chris@0 171 /**
Chris@0 172 * @test
Chris@0 173 * @requires PHP 5.6
Chris@0 174 */
Chris@0 175 public function it_properly_reads_methods_typehinted_variadic_arguments()
Chris@0 176 {
Chris@0 177 if (defined('HHVM_VERSION_ID')) {
Chris@0 178 $this->markTestSkipped('HHVM does not support typehints on variadic arguments.');
Chris@0 179 }
Chris@0 180
Chris@0 181 $class = new \ReflectionClass('Fixtures\Prophecy\WithTypehintedVariadicArgument');
Chris@0 182
Chris@0 183 $mirror = new ClassMirror();
Chris@0 184
Chris@0 185 $classNode = $mirror->reflect($class, array());
Chris@0 186 $methodNode = $classNode->getMethod('methodWithTypeHintedArgs');
Chris@0 187 $argNodes = $methodNode->getArguments();
Chris@0 188
Chris@0 189 $this->assertCount(1, $argNodes);
Chris@0 190
Chris@0 191 $this->assertEquals('args', $argNodes[0]->getName());
Chris@0 192 $this->assertEquals('array', $argNodes[0]->getTypeHint());
Chris@0 193 $this->assertFalse($argNodes[0]->isOptional());
Chris@0 194 $this->assertFalse($argNodes[0]->isPassedByReference());
Chris@0 195 $this->assertTrue($argNodes[0]->isVariadic());
Chris@0 196 }
Chris@0 197
Chris@0 198 /**
Chris@0 199 * @test
Chris@0 200 */
Chris@0 201 public function it_marks_passed_by_reference_args_as_passed_by_reference()
Chris@0 202 {
Chris@0 203 $class = new \ReflectionClass('Fixtures\Prophecy\WithReferences');
Chris@0 204
Chris@0 205 $mirror = new ClassMirror();
Chris@0 206
Chris@0 207 $classNode = $mirror->reflect($class, array());
Chris@0 208
Chris@0 209 $this->assertTrue($classNode->hasMethod('methodWithReferenceArgument'));
Chris@0 210
Chris@0 211 $argNodes = $classNode->getMethod('methodWithReferenceArgument')->getArguments();
Chris@0 212
Chris@0 213 $this->assertCount(2, $argNodes);
Chris@0 214
Chris@0 215 $this->assertTrue($argNodes[0]->isPassedByReference());
Chris@0 216 $this->assertTrue($argNodes[1]->isPassedByReference());
Chris@0 217 }
Chris@0 218
Chris@0 219 /**
Chris@0 220 * @test
Chris@0 221 */
Chris@0 222 public function it_throws_an_exception_if_class_is_final()
Chris@0 223 {
Chris@0 224 $class = new \ReflectionClass('Fixtures\Prophecy\FinalClass');
Chris@0 225
Chris@0 226 $mirror = new ClassMirror();
Chris@0 227
Chris@0 228 $this->setExpectedException('Prophecy\Exception\Doubler\ClassMirrorException');
Chris@0 229
Chris@0 230 $mirror->reflect($class, array());
Chris@0 231 }
Chris@0 232
Chris@0 233 /**
Chris@0 234 * @test
Chris@0 235 */
Chris@0 236 public function it_ignores_final_methods()
Chris@0 237 {
Chris@0 238 $class = new \ReflectionClass('Fixtures\Prophecy\WithFinalMethod');
Chris@0 239
Chris@0 240 $mirror = new ClassMirror();
Chris@0 241
Chris@0 242 $classNode = $mirror->reflect($class, array());
Chris@0 243
Chris@0 244 $this->assertCount(0, $classNode->getMethods());
Chris@0 245 }
Chris@0 246
Chris@0 247 /**
Chris@0 248 * @test
Chris@0 249 */
Chris@0 250 public function it_marks_final_methods_as_unextendable()
Chris@0 251 {
Chris@0 252 $class = new \ReflectionClass('Fixtures\Prophecy\WithFinalMethod');
Chris@0 253
Chris@0 254 $mirror = new ClassMirror();
Chris@0 255
Chris@0 256 $classNode = $mirror->reflect($class, array());
Chris@0 257
Chris@0 258 $this->assertCount(1, $classNode->getUnextendableMethods());
Chris@0 259 $this->assertFalse($classNode->isExtendable('finalImplementation'));
Chris@0 260 }
Chris@0 261
Chris@0 262 /**
Chris@0 263 * @test
Chris@0 264 */
Chris@0 265 public function it_throws_an_exception_if_interface_provided_instead_of_class()
Chris@0 266 {
Chris@0 267 $class = new \ReflectionClass('Fixtures\Prophecy\EmptyInterface');
Chris@0 268
Chris@0 269 $mirror = new ClassMirror();
Chris@0 270
Chris@0 271 $this->setExpectedException('Prophecy\Exception\InvalidArgumentException');
Chris@0 272
Chris@0 273 $mirror->reflect($class, array());
Chris@0 274 }
Chris@0 275
Chris@0 276 /**
Chris@0 277 * @test
Chris@0 278 */
Chris@0 279 public function it_reflects_all_interfaces_methods()
Chris@0 280 {
Chris@0 281 $mirror = new ClassMirror();
Chris@0 282
Chris@0 283 $classNode = $mirror->reflect(null, array(
Chris@0 284 new \ReflectionClass('Fixtures\Prophecy\Named'),
Chris@0 285 new \ReflectionClass('Fixtures\Prophecy\ModifierInterface'),
Chris@0 286 ));
Chris@0 287
Chris@0 288 $this->assertEquals('stdClass', $classNode->getParentClass());
Chris@0 289 $this->assertEquals(array(
Chris@0 290 'Prophecy\Doubler\Generator\ReflectionInterface',
Chris@0 291 'Fixtures\Prophecy\ModifierInterface',
Chris@0 292 'Fixtures\Prophecy\Named',
Chris@0 293 ), $classNode->getInterfaces());
Chris@0 294
Chris@0 295 $this->assertCount(3, $classNode->getMethods());
Chris@0 296 $this->assertTrue($classNode->hasMethod('getName'));
Chris@0 297 $this->assertTrue($classNode->hasMethod('isAbstract'));
Chris@0 298 $this->assertTrue($classNode->hasMethod('getVisibility'));
Chris@0 299 }
Chris@0 300
Chris@0 301 /**
Chris@0 302 * @test
Chris@0 303 */
Chris@0 304 public function it_ignores_virtually_private_methods()
Chris@0 305 {
Chris@0 306 $class = new \ReflectionClass('Fixtures\Prophecy\WithVirtuallyPrivateMethod');
Chris@0 307
Chris@0 308 $mirror = new ClassMirror();
Chris@0 309
Chris@0 310 $classNode = $mirror->reflect($class, array());
Chris@0 311
Chris@0 312 $this->assertCount(2, $classNode->getMethods());
Chris@0 313 $this->assertTrue($classNode->hasMethod('isAbstract'));
Chris@0 314 $this->assertTrue($classNode->hasMethod('__toString'));
Chris@0 315 $this->assertFalse($classNode->hasMethod('_getName'));
Chris@0 316 }
Chris@0 317
Chris@0 318 /**
Chris@0 319 * @test
Chris@0 320 */
Chris@0 321 public function it_does_not_throw_exception_for_virtually_private_finals()
Chris@0 322 {
Chris@0 323 $class = new \ReflectionClass('Fixtures\Prophecy\WithFinalVirtuallyPrivateMethod');
Chris@0 324
Chris@0 325 $mirror = new ClassMirror();
Chris@0 326
Chris@0 327 $classNode = $mirror->reflect($class, array());
Chris@0 328
Chris@0 329 $this->assertCount(0, $classNode->getMethods());
Chris@0 330 }
Chris@0 331
Chris@0 332 /**
Chris@0 333 * @test
Chris@0 334 * @requires PHP 7
Chris@0 335 */
Chris@0 336 public function it_reflects_return_typehints()
Chris@0 337 {
Chris@0 338 $class = new \ReflectionClass('Fixtures\Prophecy\WithReturnTypehints');
Chris@0 339
Chris@0 340 $mirror = new ClassMirror();
Chris@0 341
Chris@0 342 $classNode = $mirror->reflect($class, array());
Chris@0 343
Chris@0 344 $this->assertCount(3, $classNode->getMethods());
Chris@0 345 $this->assertTrue($classNode->hasMethod('getName'));
Chris@0 346 $this->assertTrue($classNode->hasMethod('getSelf'));
Chris@0 347 $this->assertTrue($classNode->hasMethod('getParent'));
Chris@0 348
Chris@0 349 $this->assertEquals('string', $classNode->getMethod('getName')->getReturnType());
Chris@0 350 $this->assertEquals('\Fixtures\Prophecy\WithReturnTypehints', $classNode->getMethod('getSelf')->getReturnType());
Chris@0 351 $this->assertEquals('\Fixtures\Prophecy\EmptyClass', $classNode->getMethod('getParent')->getReturnType());
Chris@0 352 }
Chris@0 353
Chris@0 354 /**
Chris@0 355 * @test
Chris@0 356 */
Chris@0 357 public function it_throws_an_exception_if_class_provided_in_interfaces_list()
Chris@0 358 {
Chris@0 359 $class = new \ReflectionClass('Fixtures\Prophecy\EmptyClass');
Chris@0 360
Chris@0 361 $mirror = new ClassMirror();
Chris@0 362
Chris@0 363 $this->setExpectedException('InvalidArgumentException');
Chris@0 364
Chris@0 365 $mirror->reflect(null, array($class));
Chris@0 366 }
Chris@0 367
Chris@0 368 /**
Chris@0 369 * @test
Chris@0 370 */
Chris@0 371 public function it_throws_an_exception_if_not_reflection_provided_as_interface()
Chris@0 372 {
Chris@0 373 $mirror = new ClassMirror();
Chris@0 374
Chris@0 375 $this->setExpectedException('InvalidArgumentException');
Chris@0 376
Chris@0 377 $mirror->reflect(null, array(null));
Chris@0 378 }
Chris@0 379
Chris@0 380 /**
Chris@0 381 * @test
Chris@0 382 */
Chris@0 383 public function it_doesnt_use_scalar_typehints()
Chris@0 384 {
Chris@0 385 $mirror = new ClassMirror();
Chris@0 386
Chris@0 387 $classNode = $mirror->reflect(new \ReflectionClass('ReflectionMethod'), array());
Chris@0 388 $method = $classNode->getMethod('export');
Chris@0 389 $arguments = $method->getArguments();
Chris@0 390
Chris@0 391 $this->assertNull($arguments[0]->getTypeHint());
Chris@0 392 $this->assertNull($arguments[1]->getTypeHint());
Chris@0 393 $this->assertNull($arguments[2]->getTypeHint());
Chris@0 394 }
Chris@0 395
Chris@0 396 /**
Chris@0 397 * @test
Chris@0 398 */
Chris@0 399 public function it_doesnt_fail_to_typehint_nonexistent_FQCN()
Chris@0 400 {
Chris@0 401 $mirror = new ClassMirror();
Chris@0 402
Chris@0 403 $classNode = $mirror->reflect(new \ReflectionClass('Fixtures\Prophecy\OptionalDepsClass'), array());
Chris@0 404 $method = $classNode->getMethod('iHaveAStrangeTypeHintedArg');
Chris@0 405 $arguments = $method->getArguments();
Chris@0 406 $this->assertEquals('I\Simply\Am\Nonexistent', $arguments[0]->getTypeHint());
Chris@0 407 }
Chris@0 408
Chris@0 409 /**
Chris@0 410 * @test
Chris@0 411 */
Chris@0 412 public function it_doesnt_fail_to_typehint_nonexistent_RQCN()
Chris@0 413 {
Chris@0 414 $mirror = new ClassMirror();
Chris@0 415
Chris@0 416 $classNode = $mirror->reflect(new \ReflectionClass('Fixtures\Prophecy\OptionalDepsClass'), array());
Chris@0 417 $method = $classNode->getMethod('iHaveAnEvenStrangerTypeHintedArg');
Chris@0 418 $arguments = $method->getArguments();
Chris@0 419 $this->assertEquals('I\Simply\Am\Not', $arguments[0]->getTypeHint());
Chris@0 420 }
Chris@0 421
Chris@0 422 /**
Chris@0 423 * @test
Chris@0 424 */
Chris@0 425 function it_changes_argument_names_if_they_are_varying()
Chris@0 426 {
Chris@0 427 // Use test doubles in this test, as arguments named ... in the Reflection API can only happen for internal classes
Chris@0 428 $class = $this->prophesize('ReflectionClass');
Chris@0 429 $method = $this->prophesize('ReflectionMethod');
Chris@0 430 $parameter = $this->prophesize('ReflectionParameter');
Chris@0 431
Chris@0 432 $class->getName()->willReturn('Custom\ClassName');
Chris@0 433 $class->isInterface()->willReturn(false);
Chris@0 434 $class->isFinal()->willReturn(false);
Chris@0 435 $class->getMethods(\ReflectionMethod::IS_PUBLIC)->willReturn(array($method));
Chris@0 436 $class->getMethods(\ReflectionMethod::IS_ABSTRACT)->willReturn(array());
Chris@0 437
Chris@0 438 $method->getParameters()->willReturn(array($parameter));
Chris@0 439 $method->getName()->willReturn('methodName');
Chris@0 440 $method->isFinal()->willReturn(false);
Chris@0 441 $method->isProtected()->willReturn(false);
Chris@0 442 $method->isStatic()->willReturn(false);
Chris@0 443 $method->returnsReference()->willReturn(false);
Chris@0 444
Chris@0 445 if (version_compare(PHP_VERSION, '7.0', '>=')) {
Chris@0 446 $method->hasReturnType()->willReturn(false);
Chris@0 447 }
Chris@0 448
Chris@0 449 $parameter->getName()->willReturn('...');
Chris@0 450 $parameter->isDefaultValueAvailable()->willReturn(true);
Chris@0 451 $parameter->getDefaultValue()->willReturn(null);
Chris@0 452 $parameter->isPassedByReference()->willReturn(false);
Chris@0 453 $parameter->getClass()->willReturn($class);
Chris@0 454 if (version_compare(PHP_VERSION, '5.6', '>=')) {
Chris@0 455 $parameter->isVariadic()->willReturn(false);
Chris@0 456 }
Chris@0 457
Chris@0 458 $mirror = new ClassMirror();
Chris@0 459
Chris@0 460 $classNode = $mirror->reflect($class->reveal(), array());
Chris@0 461
Chris@0 462 $methodNodes = $classNode->getMethods();
Chris@0 463
Chris@0 464 $argumentNodes = $methodNodes['methodName']->getArguments();
Chris@0 465 $argumentNode = $argumentNodes[0];
Chris@0 466
Chris@0 467 $this->assertEquals('__dot_dot_dot__', $argumentNode->getName());
Chris@0 468 }
Chris@0 469 }