1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
<?php
declare(strict_types=1);
namespace ProxyManagerTest\ProxyGenerator;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
use ProxyManager\Proxy\NullObjectInterface;
use ProxyManager\ProxyGenerator\NullObjectGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManagerTestAsset\BaseClass;
use ProxyManagerTestAsset\BaseInterface;
use ProxyManagerTestAsset\ClassWithByRefMagicMethods;
use ProxyManagerTestAsset\ClassWithMagicMethods;
use ProxyManagerTestAsset\ClassWithMixedProperties;
use ProxyManagerTestAsset\ClassWithMixedReferenceableTypedProperties;
use ProxyManagerTestAsset\ClassWithMixedTypedProperties;
use ProxyManagerTestAsset\ClassWithPhp80TypedMethods;
use ProxyManagerTestAsset\ClassWithPhp81Defaults;
use ProxyManagerTestAsset\ClassWithReadOnlyProperties;
use ReflectionClass;
use ReflectionMethod;
use const PHP_VERSION_ID;
/**
* Tests for {@see \ProxyManager\ProxyGenerator\NullObjectGenerator}
*
* @covers \ProxyManager\ProxyGenerator\NullObjectGenerator
* @group Coverage
*/
final class NullObjectGeneratorTest extends AbstractProxyGeneratorTest
{
/**
* @psalm-param class-string $className
*
* @dataProvider getTestedImplementations
*
* Verifies that generated code is valid and implements expected interfaces
* @psalm-suppress MoreSpecificImplementedParamType
*/
public function testGeneratesValidCode(string $className): void
{
if (false !== strpos($className, 'TypedProp') && \PHP_VERSION_ID < 70400) {
self::markTestSkipped('PHP 7.4 required.');
}
$generator = $this->getProxyGenerator();
$generatedClassName = UniqueIdentifierGenerator::getIdentifier('AbstractProxyGeneratorTest');
$generatedClass = new ClassGenerator($generatedClassName);
$originalClass = new ReflectionClass($className);
$generatorStrategy = new EvaluatingGeneratorStrategy();
$generator->generate($originalClass, $generatedClass);
$generatorStrategy->generate($generatedClass);
$generatedReflection = new ReflectionClass($generatedClassName);
if ($originalClass->isInterface()) {
self::assertTrue($generatedReflection->implementsInterface($className));
}
self::assertSame($generatedClassName, $generatedReflection->getName());
foreach ($this->getExpectedImplementedInterfaces() as $interface) {
self::assertTrue($generatedReflection->implementsInterface($interface));
}
/**
* @psalm-suppress InvalidStringClass
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
$proxy = $generatedClassName::staticProxyConstructor();
self::assertInstanceOf($className, $proxy);
foreach (
Properties::fromReflectionClass($generatedReflection)
->onlyNullableProperties()
->getPublicProperties() as $property
) {
/** @psalm-suppress MixedPropertyFetch */
self::assertNull($proxy->{$property->getName()});
}
foreach ($generatedReflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
if ($method->getNumberOfParameters() || $method->isStatic()) {
continue;
}
$callback = [$proxy, $method->getName()];
self::assertIsCallable($callback);
self::assertEmpty($callback());
}
}
protected function getProxyGenerator(): ProxyGeneratorInterface
{
return new NullObjectGenerator();
}
/**
* {@inheritDoc}
*/
protected function getExpectedImplementedInterfaces(): array
{
return [
NullObjectInterface::class,
];
}
/**
* @psalm-return array<int, array<int, class-string>>
*/
public function getTestedImplementations(): array
{
$implementations = [
[BaseClass::class],
[ClassWithMagicMethods::class],
[ClassWithByRefMagicMethods::class],
[ClassWithMixedProperties::class],
[ClassWithMixedTypedProperties::class],
[ClassWithMixedReferenceableTypedProperties::class],
[BaseInterface::class],
];
if (PHP_VERSION_ID >= 80000) {
$implementations[] = [ClassWithPhp80TypedMethods::class];
}
if (PHP_VERSION_ID >= 80100) {
$implementations['php81defaults'] = [ClassWithPhp81Defaults::class];
$implementations['readonly'] = [ClassWithReadOnlyProperties::class];
}
return $implementations;
}
}
|