Skip to content

Commit

Permalink
Move some tests from PhpInternalSourceLocatorTest to ReflectionSource…
Browse files Browse the repository at this point in the history
…StubberTest
  • Loading branch information
kukulich committed Sep 22, 2017
1 parent b79a1d3 commit a8f8c84
Show file tree
Hide file tree
Showing 2 changed files with 260 additions and 230 deletions.
262 changes: 260 additions & 2 deletions test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,21 @@
namespace Roave\BetterReflectionTest\SourceLocator\SourceStubber;

use ClassWithoutNamespaceForSourceStubber;
use Closure;
use IntlGregorianCalendar;
use PHPUnit\Framework\TestCase;
use RecursiveArrayIterator;
use ReflectionClass as CoreReflectionClass;
use ReflectionMethod as CoreReflectionMethod;
use ReflectionParameter as CoreReflectionParameter;
use Roave\BetterReflection\Reflection\ReflectionClass;
use Roave\BetterReflection\Reflection\ReflectionMethod;
use Roave\BetterReflection\Reflection\ReflectionParameter;
use Roave\BetterReflection\Reflector\ClassReflector;
use Roave\BetterReflection\Reflector\FunctionReflector;
use Roave\BetterReflection\SourceLocator\SourceStubber\ReflectionSourceStubber;
use Roave\BetterReflection\SourceLocator\Type\PhpInternalSourceLocator;
use Roave\BetterReflectionTest\BetterReflectionSingleton;
use Roave\BetterReflectionTest\Fixture\ClassForSourceStubber;
use Roave\BetterReflectionTest\Fixture\EmptyTrait;
use Roave\BetterReflectionTest\Fixture\InterfaceForSourceStubber;
Expand All @@ -24,13 +36,25 @@ class ReflectionSourceStubberTest extends TestCase
private $stubber;

/**
* {@inheritDoc}
* @var PhpInternalSourceLocator
*/
private $phpInternalSourceLocator;

/**
* @var ClassReflector
*/
private $classReflector;

protected function setUp() : void
{
parent::setUp();

$this->stubber = new ReflectionSourceStubber();
$this->stubber = new ReflectionSourceStubber();
$this->phpInternalSourceLocator = new PhpInternalSourceLocator(
BetterReflectionSingleton::instance()->astLocator(),
$this->stubber
);
$this->classReflector = new ClassReflector($this->phpInternalSourceLocator);
}

public function testCanStubClass() : void
Expand Down Expand Up @@ -81,4 +105,238 @@ public function testTraitStub() : void
$classReflection = new CoreReflectionClass(TraitForSourceStubber::class);
self::assertStringEqualsFile(__DIR__ . '/../../Fixture/TraitForSourceStubberExpected.php', $this->stubber->getClassStub($classReflection));
}

/**
* @return string[][]
*/
public function internalClassesProvider() : array
{
$allSymbols = \array_merge(
\get_declared_classes(),
\get_declared_interfaces(),
\get_declared_traits()
);

return \array_map(
function (string $symbol) : array {
return [$symbol];
},
\array_filter(
$allSymbols,
function (string $symbol) : bool {
return (new CoreReflectionClass($symbol))->isInternal();
}
)
);
}

/**
* @dataProvider internalClassesProvider
*
* @param string $className
* @throws \ReflectionException
*/
public function testInternalClasses(string $className) : void
{
$class = $this->classReflector->reflect($className);

self::assertInstanceOf(ReflectionClass::class, $class);
self::assertSame($className, $class->getName());
self::assertTrue($class->isInternal());
self::assertFalse($class->isUserDefined());

$internalReflection = new CoreReflectionClass($className);

self::assertSame($internalReflection->isInterface(), $class->isInterface());
self::assertSame($internalReflection->isTrait(), $class->isTrait());

$this->assertSameClassAttributes($internalReflection, $class);
}

private function assertSameParentClass(CoreReflectionClass $original, ReflectionClass $stubbed) : void
{
$originalParentClass = $original->getParentClass();
$stubbedParentClass = $stubbed->getParentClass();

self::assertSame(
$originalParentClass ? $originalParentClass->getName() : null,
$stubbedParentClass ? $stubbedParentClass->getName() : null
);
}

private function assertSameInterfaces(CoreReflectionClass $original, ReflectionClass $stubbed) : void
{
$originalInterfacesNames = $original->getInterfaceNames();
$stubbedInterfacesNames = $stubbed->getInterfaceNames();

\sort($originalInterfacesNames);
\sort($stubbedInterfacesNames);

self::assertSame($originalInterfacesNames, $stubbedInterfacesNames);
}

private function assertSameClassAttributes(CoreReflectionClass $original, ReflectionClass $stubbed) : void
{
self::assertSame($original->getName(), $stubbed->getName());

$this->assertSameParentClass($original, $stubbed);
$this->assertSameInterfaces($original, $stubbed);

$originalMethods = $original->getMethods();

$originalMethodNames = \array_map(
function (CoreReflectionMethod $method) : string {
return $method->getName();
},
$originalMethods
);

$stubbedMethodNames = \array_map(
function (ReflectionMethod $method) : string {
return $method->getName();
},
$stubbed->getMethods()
);

\sort($originalMethodNames);
\sort($stubbedMethodNames);

foreach ($originalMethods as $method) {
$this->assertSameMethodAttributes($method, $stubbed->getMethod($method->getName()));
}

if (IntlGregorianCalendar::class === $original->getName()) {
// See https://bugs.php.net/bug.php?id=75090
} elseif (RecursiveArrayIterator::class === $original->getName()) {
// See https://bugs.php.net/bug.php?id=75242
} else {
self::assertEquals($original->getConstants(), $stubbed->getConstants());
}
}

private function assertSameMethodAttributes(CoreReflectionMethod $original, ReflectionMethod $stubbed) : void
{
$originalParameterNames = \array_map(
function (CoreReflectionParameter $parameter) : string {
return $parameter->getDeclaringFunction()->getName() . '.' . $parameter->getName();
},
$original->getParameters()
);
$stubParameterNames = \array_map(
function (ReflectionParameter $parameter) : string {
return $parameter->getDeclaringFunction()->getName() . '.' . $parameter->getName();
},
$stubbed->getParameters()
);

self::assertSame($originalParameterNames, $stubParameterNames);

foreach ($original->getParameters() as $parameter) {
$this->assertSameParameterAttributes(
$original,
$parameter,
$stubbed->getParameter($parameter->getName())
);
}

self::assertSame($original->isPublic(), $stubbed->isPublic());
self::assertSame($original->isPrivate(), $stubbed->isPrivate());
self::assertSame($original->isProtected(), $stubbed->isProtected());
self::assertSame($original->returnsReference(), $stubbed->returnsReference());
self::assertSame($original->isStatic(), $stubbed->isStatic());
self::assertSame($original->isFinal(), $stubbed->isFinal());
}

private function assertSameParameterAttributes(
CoreReflectionMethod $originalMethod,
CoreReflectionParameter $original,
ReflectionParameter $stubbed
) : void {
$parameterName = $original->getDeclaringClass()->getName()
. '#' . $originalMethod->getName()
. '.' . $original->getName();

self::assertSame($original->getName(), $stubbed->getName(), $parameterName);
self::assertSame($original->isArray(), $stubbed->isArray(), $parameterName);
if (Closure::class === $original->getDeclaringClass()->getName() && 'fromCallable' === $originalMethod->getName()) {
// Bug in PHP: https://3v4l.org/EeHXS
} else {
self::assertSame($original->isCallable(), $stubbed->isCallable(), $parameterName);
}
//self::assertSame($original->allowsNull(), $stubbed->allowsNull()); @TODO WTF?
self::assertSame($original->canBePassedByValue(), $stubbed->canBePassedByValue(), $parameterName);
if (\in_array($parameterName, ['mysqli_stmt#bind_param.vars', 'mysqli_stmt#bind_result.vars'], true)) {
// Parameter is variadic but not optinal
} else {
self::assertSame($original->isOptional(), $stubbed->isOptional(), $parameterName);
}
self::assertSame($original->isPassedByReference(), $stubbed->isPassedByReference(), $parameterName);
self::assertSame($original->isVariadic(), $stubbed->isVariadic(), $parameterName);

if ($class = $original->getClass()) {
$stubbedClass = $stubbed->getClass();

self::assertInstanceOf(ReflectionClass::class, $stubbedClass, $parameterName);
self::assertSame($class->getName(), $stubbedClass->getName(), $parameterName);
} else {
self::assertNull($stubbed->getClass(), $parameterName);
}
}

public function testFunctionWithParameterPassedByReference() : void
{
$reflector = new FunctionReflector($this->phpInternalSourceLocator, $this->classReflector);
$functionReflection = $reflector->reflect('sort');

self::assertSame('sort', $functionReflection->getName());
self::assertSame(2, $functionReflection->getNumberOfParameters());

$parameterReflection = $functionReflection->getParameters()[0];
self::assertSame('arg', $parameterReflection->getName());
self::assertFalse($parameterReflection->isOptional());
self::assertTrue($parameterReflection->isPassedByReference());
self::assertFalse($parameterReflection->canBePassedByValue());
}

public function testFunctionWithOptionalParameter() : void
{
$reflector = new FunctionReflector($this->phpInternalSourceLocator, $this->classReflector);
$functionReflection = $reflector->reflect('preg_match');

self::assertSame('preg_match', $functionReflection->getName());
self::assertSame(5, $functionReflection->getNumberOfParameters());
self::assertSame(2, $functionReflection->getNumberOfRequiredParameters());

$parameterReflection = $functionReflection->getParameters()[2];
self::assertSame('subpatterns', $parameterReflection->getName());
self::assertTrue($parameterReflection->isOptional());
}

public function variadicParametersProvider() : array
{
return [
['sprintf', 1, true, true],
['printf', 1, true, true],
];
}

/**
* @param string $functionName
* @param int $parameterPosition
* @param bool $parameterIsVariadic
* @param bool $parameterIsOptional
* @dataProvider variadicParametersProvider
*/
public function testFunctionWithVariadicParameter(string $functionName, int $parameterPosition, bool $parameterIsVariadic, bool $parameterIsOptional) : void
{
$reflector = new FunctionReflector($this->phpInternalSourceLocator, $this->classReflector);
$functionReflection = $reflector->reflect($functionName);

self::assertSame($functionName, $functionReflection->getName());

$parametersReflections = $functionReflection->getParameters();
self::assertArrayHasKey($parameterPosition, $parametersReflections);
self::assertSame($parameterIsVariadic, $parametersReflections[$parameterPosition]->isVariadic());
self::assertSame($parameterIsOptional, $parametersReflections[$parameterPosition]->isOptional());
}
}
Loading

0 comments on commit a8f8c84

Please sign in to comment.