Files
Sentri/vendor/symfony/property-info/Tests/Extractor/PhpStanExtractorTest.php
2026-01-01 10:54:18 +01:00

584 lines
26 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\PropertyInfo\Tests\Extractor;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Clazz;
use Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummyWithoutDocBlock;
use Symfony\Component\PropertyInfo\Tests\Fixtures\DefaultValue;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyCollection;
use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyGeneric;
use Symfony\Component\PropertyInfo\Tests\Fixtures\IFace;
use Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php80Dummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php80PromotedDummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\RootDummy\RootDummyItem;
use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\AnotherNamespace\DummyInAnotherNamespace;
use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsedInTrait;
use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait;
use Symfony\Component\PropertyInfo\Type;
require_once __DIR__.'/../Fixtures/Extractor/DummyNamespace.php';
/**
* @author Baptiste Leduc <baptiste.leduc@gmail.com>
*/
class PhpStanExtractorTest extends TestCase
{
private PhpStanExtractor $extractor;
private PhpDocExtractor $phpDocExtractor;
protected function setUp(): void
{
$this->extractor = new PhpStanExtractor();
$this->phpDocExtractor = new PhpDocExtractor();
}
/**
* @dataProvider typesProvider
*/
public function testExtract($property, ?array $type = null)
{
$this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
}
public function testParamTagTypeIsOmitted()
{
$this->assertNull($this->extractor->getTypes(PhpStanOmittedParamTagTypeDocBlock::class, 'omittedType'));
}
public static function invalidTypesProvider()
{
return [
'pub' => ['pub'],
'stat' => ['stat'],
'foo' => ['foo'],
'bar' => ['bar'],
];
}
/**
* @dataProvider invalidTypesProvider
*/
public function testInvalid($property)
{
$this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property));
}
/**
* @dataProvider typesWithNoPrefixesProvider
*/
public function testExtractTypesWithNoPrefixes($property, ?array $type = null)
{
$noPrefixExtractor = new PhpStanExtractor([], [], []);
$this->assertEquals($type, $noPrefixExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
}
public static function typesProvider()
{
return [
['foo', null],
['bar', [new Type(Type::BUILTIN_TYPE_STRING)]],
['baz', [new Type(Type::BUILTIN_TYPE_INT)]],
['foo2', [new Type(Type::BUILTIN_TYPE_FLOAT)]],
['foo3', [new Type(Type::BUILTIN_TYPE_CALLABLE)]],
['foo4', [new Type(Type::BUILTIN_TYPE_NULL)]],
['foo5', null],
[
'files',
[
new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')),
new Type(Type::BUILTIN_TYPE_RESOURCE),
],
],
['bal', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]],
['parent', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]],
['collection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]],
['nestedCollection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING, false)))]],
['mixedCollection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], null)]],
['a', [new Type(Type::BUILTIN_TYPE_INT)]],
['b', [new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]],
['c', [new Type(Type::BUILTIN_TYPE_BOOL, true)]],
['d', [new Type(Type::BUILTIN_TYPE_BOOL)]],
['e', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_RESOURCE))]],
['f', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]],
['g', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]],
['h', [new Type(Type::BUILTIN_TYPE_STRING, true)]],
['j', [new Type(Type::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')]],
['nullableCollectionOfNonNullableElements', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_INT, false))]],
['donotexist', null],
['staticGetter', null],
['staticSetter', null],
['emptyVar', null],
['arrayWithKeys', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_STRING))]],
['arrayOfMixed', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_STRING), null)]],
['listOfStrings', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))]],
['self', [new Type(Type::BUILTIN_TYPE_OBJECT, false, Dummy::class)]],
['rootDummyItems', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, RootDummyItem::class))]],
['rootDummyItem', [new Type(Type::BUILTIN_TYPE_OBJECT, false, RootDummyItem::class)]],
['collectionAsObject', [new Type(Type::BUILTIN_TYPE_OBJECT, false, DummyCollection::class, true, [new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_STRING)])]],
];
}
/**
* @dataProvider provideCollectionTypes
*/
public function testExtractCollection($property, ?array $type = null)
{
$this->testExtract($property, $type);
}
public static function provideCollectionTypes()
{
return [
['iteratorCollection', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, null, new Type(Type::BUILTIN_TYPE_STRING))]],
['iteratorCollectionWithKey', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))]],
[
'nestedIterators',
[new Type(
Type::BUILTIN_TYPE_OBJECT,
false,
'Iterator',
true,
new Type(Type::BUILTIN_TYPE_INT),
new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))
)],
],
[
'arrayWithKeys',
[new Type(
Type::BUILTIN_TYPE_ARRAY,
false,
null,
true,
new Type(Type::BUILTIN_TYPE_STRING),
new Type(Type::BUILTIN_TYPE_STRING)
)],
],
[
'arrayWithKeysAndComplexValue',
[new Type(
Type::BUILTIN_TYPE_ARRAY,
false,
null,
true,
new Type(Type::BUILTIN_TYPE_STRING),
new Type(
Type::BUILTIN_TYPE_ARRAY,
true,
null,
true,
new Type(Type::BUILTIN_TYPE_INT),
new Type(Type::BUILTIN_TYPE_STRING, true)
)
)],
],
];
}
/**
* @dataProvider typesWithCustomPrefixesProvider
*/
public function testExtractTypesWithCustomPrefixes($property, ?array $type = null)
{
$customExtractor = new PhpStanExtractor(['add', 'remove'], ['is', 'can']);
$this->assertEquals($type, $customExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
}
public static function typesWithCustomPrefixesProvider()
{
return [
['foo', null],
['bar', [new Type(Type::BUILTIN_TYPE_STRING)]],
['baz', [new Type(Type::BUILTIN_TYPE_INT)]],
['foo2', [new Type(Type::BUILTIN_TYPE_FLOAT)]],
['foo3', [new Type(Type::BUILTIN_TYPE_CALLABLE)]],
['foo4', [new Type(Type::BUILTIN_TYPE_NULL)]],
['foo5', null],
[
'files',
[
new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')),
new Type(Type::BUILTIN_TYPE_RESOURCE),
],
],
['bal', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]],
['parent', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]],
['collection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]],
['nestedCollection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING, false)))]],
['mixedCollection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], null)]],
['a', null],
['b', null],
['c', [new Type(Type::BUILTIN_TYPE_BOOL, true)]],
['d', [new Type(Type::BUILTIN_TYPE_BOOL)]],
['e', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_RESOURCE))]],
['f', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]],
['g', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]],
['h', [new Type(Type::BUILTIN_TYPE_STRING, true)]],
['j', [new Type(Type::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')]],
['nullableCollectionOfNonNullableElements', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_INT, false))]],
['donotexist', null],
['staticGetter', null],
['staticSetter', null],
];
}
public static function typesWithNoPrefixesProvider()
{
return [
['foo', null],
['bar', [new Type(Type::BUILTIN_TYPE_STRING)]],
['baz', [new Type(Type::BUILTIN_TYPE_INT)]],
['foo2', [new Type(Type::BUILTIN_TYPE_FLOAT)]],
['foo3', [new Type(Type::BUILTIN_TYPE_CALLABLE)]],
['foo4', [new Type(Type::BUILTIN_TYPE_NULL)]],
['foo5', null],
[
'files',
[
new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')),
new Type(Type::BUILTIN_TYPE_RESOURCE),
],
],
['bal', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]],
['parent', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]],
['collection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]],
['nestedCollection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING, false)))]],
['mixedCollection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], null)]],
['a', null],
['b', null],
['c', null],
['d', null],
['e', null],
['f', null],
['g', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]],
['h', [new Type(Type::BUILTIN_TYPE_STRING, true)]],
['j', [new Type(Type::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')]],
['nullableCollectionOfNonNullableElements', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_INT, false))]],
['donotexist', null],
['staticGetter', null],
['staticSetter', null],
];
}
public static function dockBlockFallbackTypesProvider()
{
return [
'pub' => [
'pub', [new Type(Type::BUILTIN_TYPE_STRING)],
],
'protAcc' => [
'protAcc', [new Type(Type::BUILTIN_TYPE_INT)],
],
'protMut' => [
'protMut', [new Type(Type::BUILTIN_TYPE_BOOL)],
],
];
}
/**
* @dataProvider dockBlockFallbackTypesProvider
*/
public function testDocBlockFallback($property, $types)
{
$this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback', $property));
}
/**
* @dataProvider propertiesDefinedByTraitsProvider
*/
public function testPropertiesDefinedByTraits(string $property, Type $type)
{
$this->assertEquals([$type], $this->extractor->getTypes(DummyUsingTrait::class, $property));
}
public static function propertiesDefinedByTraitsProvider(): array
{
return [
['propertyInTraitPrimitiveType', new Type(Type::BUILTIN_TYPE_STRING)],
['propertyInTraitObjectSameNamespace', new Type(Type::BUILTIN_TYPE_OBJECT, false, DummyUsedInTrait::class)],
['propertyInTraitObjectDifferentNamespace', new Type(Type::BUILTIN_TYPE_OBJECT, false, Dummy::class)],
['dummyInAnotherNamespace', new Type(Type::BUILTIN_TYPE_OBJECT, false, DummyInAnotherNamespace::class)],
];
}
/**
* @dataProvider propertiesStaticTypeProvider
*/
public function testPropertiesStaticType(string $class, string $property, Type $type)
{
$this->assertEquals([$type], $this->extractor->getTypes($class, $property));
}
public static function propertiesStaticTypeProvider(): array
{
return [
[ParentDummy::class, 'propertyTypeStatic', new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)],
[Dummy::class, 'propertyTypeStatic', new Type(Type::BUILTIN_TYPE_OBJECT, false, Dummy::class)],
];
}
/**
* @dataProvider propertiesParentTypeProvider
*/
public function testPropertiesParentType(string $class, string $property, ?array $types)
{
$this->assertEquals($types, $this->extractor->getTypes($class, $property));
}
public static function propertiesParentTypeProvider(): array
{
return [
[ParentDummy::class, 'parentAnnotationNoParent', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'parent')]],
[Dummy::class, 'parentAnnotation', [new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]],
];
}
/**
* @dataProvider constructorTypesProvider
*/
public function testExtractConstructorTypes($property, ?array $type = null)
{
$this->assertEquals($type, $this->extractor->getTypesFromConstructor('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property));
}
/**
* @dataProvider constructorTypesProvider
*/
public function testExtractConstructorTypesReturnNullOnEmptyDocBlock($property)
{
$this->assertNull($this->extractor->getTypesFromConstructor(ConstructorDummyWithoutDocBlock::class, $property));
}
public static function constructorTypesProvider()
{
return [
['date', [new Type(Type::BUILTIN_TYPE_INT)]],
['timezone', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeZone')]],
['dateObject', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeInterface')]],
['dateTime', null],
['ddd', null],
];
}
/**
* @dataProvider unionTypesProvider
*/
public function testExtractorUnionTypes(string $property, ?array $types)
{
$this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DummyUnionType', $property));
}
public static function unionTypesProvider(): array
{
return [
['a', [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)]],
['b', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)])]],
['c', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)])]],
['d', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING)])])]],
['e', [new Type(Type::BUILTIN_TYPE_OBJECT, true, Dummy::class, false, [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING)])], [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_OBJECT, false, \Traversable::class, true, [], [new Type(Type::BUILTIN_TYPE_OBJECT, false, DefaultValue::class)])])]), new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]],
['f', null],
['g', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)])]],
];
}
/**
* @dataProvider pseudoTypesProvider
*/
public function testPseudoTypes($property, array $type)
{
$this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\PhpStanPseudoTypesDummy', $property));
}
public static function pseudoTypesProvider(): array
{
return [
['classString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['classStringGeneric', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['htmlEscapedString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['lowercaseString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['nonEmptyLowercaseString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['nonEmptyString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['numericString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['traitString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['interfaceString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['literalString', [new Type(Type::BUILTIN_TYPE_STRING, false, null)]],
['positiveInt', [new Type(Type::BUILTIN_TYPE_INT, false, null)]],
['negativeInt', [new Type(Type::BUILTIN_TYPE_INT, false, null)]],
['nonEmptyArray', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)]],
['nonEmptyList', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT))]],
['scalar', [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT), new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_BOOL)]],
['number', [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT)]],
['numeric', [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT), new Type(Type::BUILTIN_TYPE_STRING)]],
['arrayKey', [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)]],
['double', [new Type(Type::BUILTIN_TYPE_FLOAT)]],
];
}
public function testDummyNamespace()
{
$this->assertEquals(
[new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy')],
$this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DummyNamespace', 'dummy')
);
}
public function testDummyNamespaceWithProperty()
{
$phpStanTypes = $this->extractor->getTypes(\B\Dummy::class, 'property');
$phpDocTypes = $this->phpDocExtractor->getTypes(\B\Dummy::class, 'property');
$this->assertEquals('A\Property', $phpStanTypes[0]->getClassName());
$this->assertEquals($phpDocTypes[0]->getClassName(), $phpStanTypes[0]->getClassName());
}
/**
* @dataProvider intRangeTypeProvider
*/
public function testExtractorIntRangeType(string $property, ?array $types)
{
$this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\IntRangeDummy', $property));
}
public static function intRangeTypeProvider(): array
{
return [
['a', [new Type(Type::BUILTIN_TYPE_INT)]],
['b', [new Type(Type::BUILTIN_TYPE_INT, true)]],
['c', [new Type(Type::BUILTIN_TYPE_INT)]],
];
}
/**
* @dataProvider php80TypesProvider
*/
public function testExtractPhp80Type(string $class, $property, ?array $type = null)
{
$this->assertEquals($type, $this->extractor->getTypes($class, $property, []));
}
public static function php80TypesProvider()
{
return [
[Php80Dummy::class, 'promotedWithDocCommentAndType', [new Type(Type::BUILTIN_TYPE_INT)]],
[Php80Dummy::class, 'promotedWithDocComment', [new Type(Type::BUILTIN_TYPE_STRING)]],
[Php80Dummy::class, 'promotedAndMutated', [new Type(Type::BUILTIN_TYPE_STRING)]],
[Php80Dummy::class, 'promoted', null],
[Php80Dummy::class, 'collection', [new Type(Type::BUILTIN_TYPE_ARRAY, collection: true, collectionValueType: new Type(Type::BUILTIN_TYPE_STRING))]],
[Php80PromotedDummy::class, 'promoted', null],
];
}
public function testGenericInterface()
{
$this->assertEquals(
[
new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: \BackedEnum::class,
collectionValueType: new Type(
builtinType: Type::BUILTIN_TYPE_STRING,
)
),
],
$this->extractor->getTypes(Dummy::class, 'genericInterface')
);
}
/**
* @param list<Type> $expectedTypes
* @dataProvider genericsProvider
*/
public function testGenericsLegacy(string $property, array $expectedTypes)
{
$this->assertEquals($expectedTypes, $this->extractor->getTypes(DummyGeneric::class, $property));
}
/**
* @return iterable<array{0: string, 1: list<Type>}>
*/
public static function genericsProvider(): iterable
{
yield [
'basicClass',
[
new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: Clazz::class,
collectionValueType: new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: Dummy::class,
)
),
],
];
yield [
'nullableClass',
[
new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: Clazz::class,
nullable: true,
collectionValueType: new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: Dummy::class,
)
),
],
];
yield [
'basicInterface',
[
new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: IFace::class,
collectionValueType: new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: Dummy::class,
)
),
],
];
yield [
'nullableInterface',
[
new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: IFace::class,
nullable: true,
collectionValueType: new Type(
builtinType: Type::BUILTIN_TYPE_OBJECT,
class: Dummy::class,
)
),
],
];
}
}
class PhpStanOmittedParamTagTypeDocBlock
{
/**
* The type is omitted here to ensure that the extractor doesn't choke on missing types.
*
* @param $omittedTagType
*/
public function setOmittedType(array $omittedTagType)
{
}
}