From 6e089d53955ae01bbffaa701f824ba8cd37004a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sun, 16 May 2021 14:10:55 +0200 Subject: [PATCH 1/3] Drop unneeded %currentWorkingDirectory% There is only one directory for which this will work. --- phpstan.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index 4b405006..af7bc298 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -9,4 +9,4 @@ parameters: - tests excludes_analyse: - - %currentWorkingDirectory%/tests/Doctrine/Tests/Persistence/Mapping/_files/TestEntity.php + - tests/Doctrine/Tests/Persistence/Mapping/_files/TestEntity.php From afcdd920870acf4936c898be9dce94170dd2ef14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sun, 16 May 2021 14:36:31 +0200 Subject: [PATCH 2/3] Reach PHPStan level 7 We have found that there were lots of conflicts during the last merge up to 3.0. Reaching level 7 on lower branches reduces differences between them and thus the amount of conflits for future merges. It should also ensure that no new PHPStan error are discovered when merging up because they are detected at level 7 and not at level 5. --- .../Common/Persistence/PersistentObject.php | 6 +- .../Persistence/AbstractManagerRegistry.php | 3 + .../Event/LoadClassMetadataEventArgs.php | 9 +- .../Mapping/AbstractClassMetadataFactory.php | 2 + .../Mapping/Driver/AnnotationDriver.php | 5 +- .../Persistence/Mapping/Driver/FileDriver.php | 8 +- .../Mapping/Driver/MappingDriver.php | 1 + .../Persistence/Mapping/Driver/PHPDriver.php | 5 +- .../Mapping/Driver/SymfonyFileLocator.php | 7 +- .../Persistence/Mapping/ReflectionService.php | 5 +- .../Mapping/RuntimeReflectionService.php | 12 +- .../Mapping/StaticReflectionService.php | 2 + lib/Doctrine/Persistence/ObjectManager.php | 1 + .../Persistence/ObjectManagerAware.php | 2 + .../RuntimePublicReflectionProperty.php | 3 + .../TypedNoDefaultReflectionProperty.php | 4 + phpstan-baseline.neon | 7 + phpstan.neon | 2 +- .../Mapping/ClassMetadataFactoryTest.php | 12 +- .../Mapping/RuntimeReflectionServiceTest.php | 7 - .../Mapping/StaticPHPDriverTest.php | 3 + .../ObjectManagerDecoratorTest.php | 218 +++++++++++++----- .../RuntimePublicReflectionPropertyTest.php | 30 ++- 23 files changed, 265 insertions(+), 89 deletions(-) diff --git a/lib/Doctrine/Common/Persistence/PersistentObject.php b/lib/Doctrine/Common/Persistence/PersistentObject.php index c024d7d9..b3127293 100644 --- a/lib/Doctrine/Common/Persistence/PersistentObject.php +++ b/lib/Doctrine/Common/Persistence/PersistentObject.php @@ -51,7 +51,10 @@ abstract class PersistentObject implements ObjectManagerAware /** @var ObjectManager|null */ private static $objectManager = null; - /** @var ClassMetadata|null */ + /** + * @var ClassMetadata|null + * @psalm-var ClassMetadata|null + */ private $cm = null; /** @@ -141,6 +144,7 @@ private function get($field) * @param string $field * @param string $targetClass * @param object $targetObject + * @psalm-param class-string $targetClass * * @return void */ diff --git a/lib/Doctrine/Persistence/AbstractManagerRegistry.php b/lib/Doctrine/Persistence/AbstractManagerRegistry.php index ddc8b67d..8aa786e8 100644 --- a/lib/Doctrine/Persistence/AbstractManagerRegistry.php +++ b/lib/Doctrine/Persistence/AbstractManagerRegistry.php @@ -238,6 +238,9 @@ public function resetManager($name = null) return $this->getManager($name); } + /** + * @psalm-param class-string $persistentObjectName + */ private function selectManager(string $persistentObjectName, ?string $persistentManagerName = null): ObjectManager { if ($persistentManagerName !== null) { diff --git a/lib/Doctrine/Persistence/Event/LoadClassMetadataEventArgs.php b/lib/Doctrine/Persistence/Event/LoadClassMetadataEventArgs.php index 627cc5c1..642d20b3 100644 --- a/lib/Doctrine/Persistence/Event/LoadClassMetadataEventArgs.php +++ b/lib/Doctrine/Persistence/Event/LoadClassMetadataEventArgs.php @@ -11,12 +11,18 @@ */ class LoadClassMetadataEventArgs extends EventArgs { - /** @var ClassMetadata */ + /** + * @var ClassMetadata + * @psalm-var ClassMetadata + */ private $classMetadata; /** @var ObjectManager */ private $objectManager; + /** + * @psalm-param ClassMetadata $classMetadata + */ public function __construct(ClassMetadata $classMetadata, ObjectManager $objectManager) { $this->classMetadata = $classMetadata; @@ -27,6 +33,7 @@ public function __construct(ClassMetadata $classMetadata, ObjectManager $objectM * Retrieves the associated ClassMetadata. * * @return ClassMetadata + * @psalm-return ClassMetadata */ public function getClassMetadata() { diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index f378503c..7d9853df 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -19,6 +19,7 @@ use function array_unshift; use function assert; use function explode; +use function is_array; use function sprintf; use function str_replace; use function strpos; @@ -251,6 +252,7 @@ public function getMetadataFor($className) array_map([$this, 'getCacheKey'], $loadedMetadata), $loadedMetadata ); + assert(is_array($classNames)); foreach ($this->cache->getItems(array_keys($classNames)) as $item) { if (! isset($classNames[$item->getKey()])) { diff --git a/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php index fb461a3d..fd5420c7 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php @@ -13,6 +13,7 @@ use function array_merge; use function array_unique; +use function assert; use function get_class; use function get_declared_classes; use function in_array; @@ -223,7 +224,9 @@ public function getAllClassNames() } foreach ($this->excludePaths as $excludePath) { - $exclude = str_replace('\\', '/', realpath($excludePath)); + $realExcludePath = realpath($excludePath); + assert($realExcludePath !== false); + $exclude = str_replace('\\', '/', $realExcludePath); $current = str_replace('\\', '/', $sourceFile); if (strpos($current, $exclude) !== false) { diff --git a/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php index 3f32aba3..86e4e0f6 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php @@ -24,7 +24,10 @@ abstract class FileDriver implements MappingDriver /** @var FileLocator */ protected $locator; - /** @var ClassMetadata[]|null */ + /** + * @var ClassMetadata[]|null + * @psalm-var ClassMetadata[]|null + */ protected $classCache; /** @var string|null */ @@ -76,6 +79,7 @@ public function getGlobalBasename() * @param string $className * * @return ClassMetadata The element of schema meta data. + * @psalm-return ClassMetadata * * @throws MappingException */ @@ -141,7 +145,7 @@ public function getAllClassNames() * @param string $file The mapping file to load. * * @return ClassMetadata[] - * @psalm-return array + * @psalm-return array> */ abstract protected function loadMappingFile($file); diff --git a/lib/Doctrine/Persistence/Mapping/Driver/MappingDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/MappingDriver.php index b54d528f..71ac9935 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/MappingDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/MappingDriver.php @@ -13,6 +13,7 @@ interface MappingDriver * Loads the metadata for the specified class into the provided container. * * @param string $className + * @psalm-param ClassMetadata $metadata * * @return void */ diff --git a/lib/Doctrine/Persistence/Mapping/Driver/PHPDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/PHPDriver.php index 7b844ca6..cc7f0fe0 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/PHPDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/PHPDriver.php @@ -10,7 +10,10 @@ */ class PHPDriver extends FileDriver { - /** @var ClassMetadata */ + /** + * @var ClassMetadata + * @psalm-var ClassMetadata + */ protected $metadata; /** diff --git a/lib/Doctrine/Persistence/Mapping/Driver/SymfonyFileLocator.php b/lib/Doctrine/Persistence/Mapping/Driver/SymfonyFileLocator.php index 5d91b80c..c2a70891 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/SymfonyFileLocator.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/SymfonyFileLocator.php @@ -9,6 +9,7 @@ use function array_keys; use function array_merge; +use function assert; use function is_dir; use function is_file; use function realpath; @@ -183,8 +184,12 @@ public function getAllClassNames($globalBasename = null) // NOTE: All files found here means classes are not transient! if (isset($this->prefixes[$path])) { // Calculate namespace suffix for given prefix as a relative path from basepath to file path + $basepath = realpath($path); + $filepath = realpath($file->getPath()); + assert($basepath !== false); + assert($filepath !== false); $nsSuffix = strtr( - substr(realpath($file->getPath()), strlen(realpath($path))), + substr($filepath, strlen($basepath)), $this->nsSeparator, '\\' ); diff --git a/lib/Doctrine/Persistence/Mapping/ReflectionService.php b/lib/Doctrine/Persistence/Mapping/ReflectionService.php index 47cdbeed..fc8b4964 100644 --- a/lib/Doctrine/Persistence/Mapping/ReflectionService.php +++ b/lib/Doctrine/Persistence/Mapping/ReflectionService.php @@ -48,9 +48,12 @@ public function getClassNamespace($class); * Returns a reflection class instance or null. * * @param string $class - * @psalm-param class-string $class + * @psalm-param class-string $class * * @return ReflectionClass|null + * @psalm-return ReflectionClass|null + * + * @template T of object */ public function getClass($class); diff --git a/lib/Doctrine/Persistence/Mapping/RuntimeReflectionService.php b/lib/Doctrine/Persistence/Mapping/RuntimeReflectionService.php index 446c2433..fe6f5080 100644 --- a/lib/Doctrine/Persistence/Mapping/RuntimeReflectionService.php +++ b/lib/Doctrine/Persistence/Mapping/RuntimeReflectionService.php @@ -10,6 +10,7 @@ use ReflectionProperty; use function array_key_exists; +use function assert; use function class_exists; use function class_parents; use function phpversion; @@ -37,7 +38,11 @@ public function getParentClasses($class) throw MappingException::nonExistingClass($class); } - return class_parents($class); + $parents = class_parents($class); + + assert($parents !== false); + + return $parents; } /** @@ -62,9 +67,12 @@ public function getClassNamespace($class) /** * @param string $class - * @psalm-param class-string $class + * @psalm-param class-string $class * * @return ReflectionClass + * @psalm-return ReflectionClass + * + * @template T of object */ public function getClass($class) { diff --git a/lib/Doctrine/Persistence/Mapping/StaticReflectionService.php b/lib/Doctrine/Persistence/Mapping/StaticReflectionService.php index 56886e65..e8c908a2 100644 --- a/lib/Doctrine/Persistence/Mapping/StaticReflectionService.php +++ b/lib/Doctrine/Persistence/Mapping/StaticReflectionService.php @@ -49,6 +49,8 @@ public function getClassNamespace($className) /** * {@inheritDoc} + * + * @return null */ public function getClass($class) { diff --git a/lib/Doctrine/Persistence/ObjectManager.php b/lib/Doctrine/Persistence/ObjectManager.php index 7a3fffae..74f0016c 100644 --- a/lib/Doctrine/Persistence/ObjectManager.php +++ b/lib/Doctrine/Persistence/ObjectManager.php @@ -144,6 +144,7 @@ public function getClassMetadata($className); * Gets the metadata factory used to gather the metadata of classes. * * @return ClassMetadataFactory + * @psalm-return ClassMetadataFactory> */ public function getMetadataFactory(); diff --git a/lib/Doctrine/Persistence/ObjectManagerAware.php b/lib/Doctrine/Persistence/ObjectManagerAware.php index 2bf43359..ebe80e68 100644 --- a/lib/Doctrine/Persistence/ObjectManagerAware.php +++ b/lib/Doctrine/Persistence/ObjectManagerAware.php @@ -23,6 +23,8 @@ interface ObjectManagerAware /** * Injects responsible ObjectManager and the ClassMetadata into this persistent object. * + * @psalm-param ClassMetadata $classMetadata + * * @return void */ public function injectObjectManager(ObjectManager $objectManager, ClassMetadata $classMetadata); diff --git a/lib/Doctrine/Persistence/Reflection/RuntimePublicReflectionProperty.php b/lib/Doctrine/Persistence/Reflection/RuntimePublicReflectionProperty.php index 80124c24..7e7d7d5e 100644 --- a/lib/Doctrine/Persistence/Reflection/RuntimePublicReflectionProperty.php +++ b/lib/Doctrine/Persistence/Reflection/RuntimePublicReflectionProperty.php @@ -40,6 +40,9 @@ public function getValue($object = null) * is a {@see \Doctrine\Common\Proxy\Proxy}. * * @link https://bugs.php.net/bug.php?id=63463 + * + * @param object $object + * @param mixed $value */ public function setValue($object, $value = null) { diff --git a/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php b/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php index 93e3c92a..8118b633 100644 --- a/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php +++ b/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php @@ -18,6 +18,8 @@ class TypedNoDefaultReflectionProperty extends ReflectionProperty * Checks that a typed property is initialized before accessing its value. * This is necessary to avoid PHP error "Error: Typed property must not be accessed before initialization". * Should be used only for reflecting typed properties without a default value. + * + * @param object $object */ public function getValue($object = null) { @@ -31,6 +33,8 @@ public function getValue($object = null) * NULL which is not supported, instead unset() to uninitialize. * * @link https://github.com/doctrine/orm/issues/7999 + * + * @param object $object */ public function setValue($object, $value = null) { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 569468ee..ebf697bc 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -13,3 +13,10 @@ parameters: message: "#^Parameter \\#1 \\$class of method Doctrine\\\\Persistence\\\\Mapping\\\\RuntimeReflectionService\\:\\:getParentClasses\\(\\) expects class-string, string given.$#" count: 1 path: tests/Doctrine/Tests/Persistence/Mapping/RuntimeReflectionServiceTest.php + + - + message: '#Method Doctrine\\Persistence\\AbstractManagerRegistry\:\:getRealClassName\(\) should return class\-string but returns string\.#' + path: 'lib/Doctrine/Persistence/AbstractManagerRegistry.php' + - + message: '#Method Doctrine\\Tests\\Persistence\\Mapping\\TestClassMetadataFactory\:\:getFqcnFromAlias\(\) should return class\-string but returns string\.#' + path: 'tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php' diff --git a/phpstan.neon b/phpstan.neon index af7bc298..bf412b71 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,7 +2,7 @@ includes: - phpstan-baseline.neon parameters: - level: 5 + level: 7 paths: - lib diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index e8cdd775..73168a9c 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -24,12 +24,17 @@ */ class ClassMetadataFactoryTest extends DoctrineTestCase { - /** @var TestClassMetadataFactory */ + /** + * @var TestClassMetadataFactory + * @psalm-var TestClassMetadataFactory> + */ private $cmf; protected function setUp(): void { - $driver = $this->createMock(MappingDriver::class); + $driver = $this->createMock(MappingDriver::class); + + /** @psalm-var ClassMetadata */ $metadata = $this->createMock(ClassMetadata::class); $this->cmf = new TestClassMetadataFactory($driver, $metadata); } @@ -242,6 +247,9 @@ public function testWillNotCacheFallbackMetadata(): void self::assertSame($metadata, $this->cmf->getMetadataFor('Foo')); } + /** + * @psalm-param AbstractClassMetadataFactory> $classMetadataFactory + */ private static function getCache(AbstractClassMetadataFactory $classMetadataFactory): ?CacheItemPoolInterface { $method = new ReflectionMethod($classMetadataFactory, 'getCache'); diff --git a/tests/Doctrine/Tests/Persistence/Mapping/RuntimeReflectionServiceTest.php b/tests/Doctrine/Tests/Persistence/Mapping/RuntimeReflectionServiceTest.php index c61e7aad..957adb3a 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/RuntimeReflectionServiceTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/RuntimeReflectionServiceTest.php @@ -6,7 +6,6 @@ use Doctrine\Persistence\Mapping\RuntimeReflectionService; use Doctrine\Persistence\Reflection\RuntimePublicReflectionProperty; use PHPUnit\Framework\TestCase; -use ReflectionClass; use ReflectionProperty; use function count; @@ -49,12 +48,6 @@ public function testGetParentClassesForAbsentClass(): void $this->reflectionService->getParentClasses(__NAMESPACE__ . '\AbsentClass'); } - public function testGetReflectionClass(): void - { - $class = $this->reflectionService->getClass(self::class); - self::assertInstanceOf(ReflectionClass::class, $class); - } - public function testGetMethods(): void { self::assertTrue($this->reflectionService->hasPublicMethod(self::class, 'testGetMethods')); diff --git a/tests/Doctrine/Tests/Persistence/Mapping/StaticPHPDriverTest.php b/tests/Doctrine/Tests/Persistence/Mapping/StaticPHPDriverTest.php index a9312d11..3a1af7fc 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/StaticPHPDriverTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/StaticPHPDriverTest.php @@ -28,6 +28,9 @@ public function testGetAllClassNames(): void class TestEntity { + /** + * @psalm-param ClassMetadata $metadata + */ public static function loadMetadata(ClassMetadata $metadata): void { $metadata->getFieldNames(); diff --git a/tests/Doctrine/Tests/Persistence/ObjectManagerDecoratorTest.php b/tests/Doctrine/Tests/Persistence/ObjectManagerDecoratorTest.php index 8e6a3486..dea3541a 100644 --- a/tests/Doctrine/Tests/Persistence/ObjectManagerDecoratorTest.php +++ b/tests/Doctrine/Tests/Persistence/ObjectManagerDecoratorTest.php @@ -2,23 +2,13 @@ namespace Doctrine\Tests\Persistence; +use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\ClassMetadataFactory; use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManagerDecorator; +use Doctrine\Persistence\ObjectRepository; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use ReflectionClass; - -use function array_fill; -use function call_user_func_array; -use function in_array; - -class NullObjectManagerDecorator extends ObjectManagerDecorator -{ - public function __construct(ObjectManager $wrapped) - { - $this->wrapped = $wrapped; - } -} class ObjectManagerDecoratorTest extends TestCase { @@ -34,56 +24,166 @@ protected function setUp(): void $this->decorated = new NullObjectManagerDecorator($this->wrapped); } - /** - * @return list, bool}> - */ - public function getMethodParameters() - { - $class = new ReflectionClass(ObjectManager::class); - $voidMethods = [ - 'persist', - 'remove', - 'clear', - 'detach', - 'refresh', - 'flush', - 'initializeObject', - ]; - - $methods = []; - foreach ($class->getMethods() as $method) { - $isVoidMethod = in_array($method->getName(), $voidMethods, true); - if ($method->getNumberOfRequiredParameters() === 0) { - $methods[] = [$method->getName(), [], $isVoidMethod]; - } elseif ($method->getNumberOfRequiredParameters() > 0) { - $methods[] = [$method->getName(), array_fill(0, $method->getNumberOfRequiredParameters(), 'req') ?: [], $isVoidMethod]; - } - - if ($method->getNumberOfParameters() === $method->getNumberOfRequiredParameters()) { - continue; - } - - $methods[] = [$method->getName(), array_fill(0, $method->getNumberOfParameters(), 'all') ?: [], $isVoidMethod]; - } - - return $methods; + public function testFind(): void + { + $object = new TestObject(); + + $this->wrapped->expects(self::once()) + ->method('find') + ->with(TestObject::class, 1) + ->willReturn($object); + + self::assertSame($object, $this->decorated->find(TestObject::class, 1)); } - /** - * @param mixed[] $parameters - * - * @dataProvider getMethodParameters - */ - public function testAllMethodCallsAreDelegatedToTheWrappedInstance(string $method, array $parameters, bool $isVoidMethod): void + public function testPersist(): void + { + $object = new TestObject(); + + $this->wrapped->expects(self::once()) + ->method('persist') + ->with($object); + + $this->decorated->persist($object); + } + + public function testRemove(): void { - $returnedValue = $isVoidMethod ? null : 'INNER VALUE FROM ' . $method; - $stub = $this->wrapped - ->expects($this->once()) - ->method($method) - ->will($this->returnValue($returnedValue)); + $object = new TestObject(); - call_user_func_array([$stub, 'with'], $parameters); + $this->wrapped->expects(self::once()) + ->method('remove') + ->with($object); - self::assertSame($returnedValue, call_user_func_array([$this->decorated, $method], $parameters)); + $this->decorated->remove($object); + } + + public function testMerge(): void + { + $object1 = new TestObject(); + $object2 = new TestObject(); + + $this->wrapped->expects(self::once()) + ->method('merge') + ->with($object1) + ->willReturn($object2); + + self::assertSame($object2, $this->decorated->merge($object1)); + } + + public function testClearWithNoArgument(): void + { + $this->wrapped->expects(self::once()) + ->method('clear'); + + $this->decorated->clear(); + } + + public function testClearWithArgument(): void + { + $this->wrapped->expects(self::once()) + ->method('clear') + ->with(TestObject::class); + + $this->decorated->clear(TestObject::class); + } + + public function testDetach(): void + { + $object = new TestObject(); + + $this->wrapped->expects(self::once()) + ->method('detach') + ->with($object); + + $this->decorated->detach($object); + } + + public function testRefresh(): void + { + $object = new TestObject(); + + $this->wrapped->expects(self::once()) + ->method('refresh') + ->with($object); + + $this->decorated->refresh($object); + } + + public function testFlush(): void + { + $this->wrapped->expects(self::once()) + ->method('flush'); + + $this->decorated->flush(); + } + + public function testGetRepository(): void + { + $repository = $this->createMock(ObjectRepository::class); + + $this->wrapped->expects(self::once()) + ->method('getRepository') + ->with(TestObject::class) + ->willReturn($repository); + + self::assertSame($repository, $this->decorated->getRepository(TestObject::class)); + } + + public function testGetClassMetadata(): void + { + $classMetadata = $this->createMock(ClassMetadata::class); + + $this->wrapped->expects(self::once()) + ->method('getClassMetadata') + ->with(TestObject::class) + ->willReturn($classMetadata); + + self::assertSame($classMetadata, $this->decorated->getClassMetadata(TestObject::class)); + } + + public function testGetClassMetadataFactory(): void + { + $classMetadataFactory = $this->createMock(ClassMetadataFactory::class); + + $this->wrapped->expects(self::once()) + ->method('getMetadataFactory') + ->willReturn($classMetadataFactory); + + self::assertSame($classMetadataFactory, $this->decorated->getMetadataFactory()); + } + + public function testInitializeObject(): void + { + $object = new TestObject(); + + $this->wrapped->expects(self::once()) + ->method('initializeObject') + ->with($object); + + $this->decorated->initializeObject($object); + } + + public function testContains(): void + { + $object = new TestObject(); + + $this->wrapped->expects(self::once()) + ->method('contains') + ->with($object) + ->willReturn(true); + + self::assertTrue($this->decorated->contains($object)); + } +} + +class NullObjectManagerDecorator extends ObjectManagerDecorator +{ + /** + * @psalm-param ObjectManager&MockObject $wrapped + */ + public function __construct(ObjectManager $wrapped) + { + $this->wrapped = $wrapped; } } diff --git a/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php b/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php index 341ba0b6..71cde933 100644 --- a/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php +++ b/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php @@ -7,9 +7,17 @@ use Doctrine\Persistence\Reflection\RuntimePublicReflectionProperty; use LogicException; use PHPUnit\Framework\TestCase; -use stdClass; -use function call_user_func; +class DummyObject +{ + public function callGet(): void + { + } + + public function callSet(): void + { + } +} class RuntimePublicReflectionPropertyTest extends TestCase { @@ -41,8 +49,10 @@ public function testSetValue(): void public function testGetValueOnProxyPublicProperty(): void { - $initializer = static function (): void { - self::fail('The initializer should not be called.'); + $getCheckMock = $this->createMock(DummyObject::class); + $getCheckMock->expects(self::never())->method('callGet'); + $initializer = static function () use ($getCheckMock): void { + $getCheckMock->callGet(); }; $mockProxy = new RuntimePublicReflectionPropertyTestProxyMock(); @@ -60,10 +70,10 @@ public function testGetValueOnProxyPublicProperty(): void public function testSetValueOnProxyPublicProperty(): void { - $setCheckMock = $this->getMockBuilder(stdClass::class)->setMethods(['neverCallSet'])->getMock(); - $setCheckMock->expects($this->never())->method('neverCallSet'); + $setCheckMock = $this->createMock(DummyObject::class); + $setCheckMock->expects(self::never())->method('callSet'); $initializer = static function () use ($setCheckMock): void { - call_user_func([$setCheckMock, 'neverCallSet']); + $setCheckMock->callSet(); }; $mockProxy = new RuntimePublicReflectionPropertyTestProxyMock(); @@ -81,10 +91,10 @@ public function testSetValueOnProxyPublicProperty(): void $reflProperty->setValue($mockProxy, 'otherNewValue'); self::assertSame('otherNewValue', $mockProxy->checkedProperty); - $setCheckMock = $this->getMockBuilder(stdClass::class)->setMethods(['callSet'])->getMock(); - $setCheckMock->expects($this->once())->method('callSet'); + $setCheckMock = $this->createMock(DummyObject::class); + $setCheckMock->expects(self::once())->method('callSet'); $initializer = static function () use ($setCheckMock): void { - call_user_func([$setCheckMock, 'callSet']); + $setCheckMock->callSet(); }; $mockProxy->__setInitializer($initializer); From 26aa7fb107706785e651ac166db7bd40686df8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sun, 16 May 2021 15:07:47 +0200 Subject: [PATCH 3/3] Add contributing guide specific to this package --- CONTRIBUTING.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..268200ad --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Circular dependency + +This package has a development dependency on `doctrine/common`, which has a +regular dependency on this package (`^2.0` at the time of writing). + +To be able to use Composer, one has to let it understand that this is version 2 +(even when developing on 3.0.x), as follows: + +```shell +COMPOSER_ROOT_VERSION=2.0 composer update -v +```