project_start/phpstorm-stubs/tests/BaseFunctionsTest.php

194 lines
8.4 KiB
PHP

<?php
declare(strict_types=1);
namespace StubTests;
use PHPUnit\Framework\Attributes\DataProviderExternal;
use PHPUnit\Framework\Exception;
use RuntimeException;
use StubTests\Model\BasePHPElement;
use StubTests\Model\PHPClass;
use StubTests\Model\PHPFunction;
use StubTests\Model\PHPInterface;
use StubTests\Model\PHPMethod;
use StubTests\Model\PHPParameter;
use StubTests\Model\StubProblemType;
use StubTests\TestData\Providers\EntitiesFilter;
use StubTests\TestData\Providers\PhpStormStubsSingleton;
use StubTests\TestData\Providers\Reflection\ReflectionFunctionsProvider;
use StubTests\TestData\Providers\Reflection\ReflectionParametersProvider;
class BaseFunctionsTest extends AbstractBaseStubsTestCase
{
/**
* @throws RuntimeException
*/
#[DataProviderExternal(ReflectionFunctionsProvider::class, 'allFunctionsProvider')]
public function testFunctionsExist(PHPFunction $function): void
{
$functionName = $function->name;
$stubFunction = PhpStormStubsSingleton::getPhpStormStubs()->getFunction($functionName);
$params = AbstractBaseStubsTestCase::getParameterRepresentation($function);
static::assertNotEmpty($stubFunction, "Missing function: function $functionName($params){}");
}
/**
* @throws RuntimeException
*/
#[DataProviderExternal(ReflectionFunctionsProvider::class, 'functionsForDeprecationTestsProvider')]
public function testFunctionsDeprecation(PHPFunction $function)
{
$functionName = $function->name;
$stubFunction = PhpStormStubsSingleton::getPhpStormStubs()->getFunction($functionName);
static::assertFalse(
$function->isDeprecated && $stubFunction->isDeprecated !== true,
"Function $functionName is not deprecated in stubs"
);
}
/**
* @throws Exception|RuntimeException
*/
#[DataProviderExternal(ReflectionFunctionsProvider::class, 'functionsForParamsAmountTestsProvider')]
public function testFunctionsParametersAmount(PHPFunction $function)
{
$functionName = $function->name;
$stubFunction = PhpStormStubsSingleton::getPhpStormStubs()->getFunction($functionName);
$filteredStubParameters = array_filter(
$stubFunction->parameters,
fn ($parameter) => BasePHPElement::entitySuitsCurrentPhpVersion($parameter)
);
$uniqueParameterNames = array_unique(array_map(fn (PHPParameter $parameter) => $parameter->name, $filteredStubParameters));
static::assertSameSize(
$function->parameters,
$uniqueParameterNames,
"Parameter number mismatch for function $functionName.
Expected: " . AbstractBaseStubsTestCase::getParameterRepresentation($function) . "\n" .
'Actual: ' . AbstractBaseStubsTestCase::getParameterRepresentation($stubFunction)
);
}
/**
* @throws RuntimeException
*/
public function testFunctionsDuplicates()
{
$filtered = EntitiesFilter::getFiltered(
PhpStormStubsSingleton::getPhpStormStubs()->getFunctions(),
problemTypes: StubProblemType::HAS_DUPLICATION
);
$duplicates = self::getDuplicatedFunctions($filtered);
self::assertCount(
0,
$duplicates,
"Functions \"" . implode(', ', $duplicates) .
"\" have duplicates in stubs.\nPlease use #[LanguageLevelTypeAware] or #[PhpStormStubsElementAvailable] if possible"
);
}
/**
* @throws RuntimeException
*/
#[DataProviderExternal(ReflectionParametersProvider::class, 'functionOptionalParametersProvider')]
public function testFunctionsOptionalParameters(PHPFunction $function, PHPParameter $parameter)
{
$phpstormFunction = PhpStormStubsSingleton::getPhpStormStubs()->getFunction($function->name);
$stubParameters = array_filter($phpstormFunction->parameters, fn (PHPParameter $stubParameter) => $stubParameter->indexInSignature === $parameter->indexInSignature);
/** @var PHPParameter $stubOptionalParameter */
$stubOptionalParameter = array_pop($stubParameters);
self::assertEquals(
$parameter->isOptional,
$stubOptionalParameter->isOptional,
sprintf(
'Reflection function %s %s optional parameter %s with index %d
but stubs parameter %s with index %d %s',
$function->name,
$parameter->isOptional ? 'has' : 'has no',
$parameter->name,
$parameter->indexInSignature,
$stubOptionalParameter->name,
$stubOptionalParameter->indexInSignature,
$stubOptionalParameter->isOptional ? 'is optional' : 'is not optional'
)
);
self::assertEquals(
$parameter->is_vararg,
$stubOptionalParameter->is_vararg,
sprintf(
'Reflection function %s %s vararg parameter %s with index %d
but stubs parameter %s with index %d %s',
$function->name,
$parameter->is_vararg ? 'has' : 'has no',
$parameter->name,
$parameter->indexInSignature,
$stubOptionalParameter->name,
$stubOptionalParameter->indexInSignature,
$stubOptionalParameter->is_vararg ? 'is vararg' : 'is not vararg'
)
);
}
/**
* @throws RuntimeException
*/
#[DataProviderExternal(ReflectionParametersProvider::class, 'methodOptionalParametersProvider')]
public function testMethodsOptionalParameters(PHPClass|PHPInterface $class, PHPMethod $method, PHPParameter $parameter)
{
if ($class instanceof PHPClass) {
$phpstormFunction = PhpStormStubsSingleton::getPhpStormStubs()->getClass($class->name)->getMethod($method->name);
} else {
$phpstormFunction = PhpStormStubsSingleton::getPhpStormStubs()->getInterface($class->name)->getMethod($method->name);
}
$stubParameters = array_filter($phpstormFunction->parameters, fn (PHPParameter $stubParameter) => $stubParameter->indexInSignature === $parameter->indexInSignature);
/** @var PHPParameter $stubOptionalParameter */
$stubOptionalParameter = array_pop($stubParameters);
self::assertEquals(
$parameter->isOptional,
$stubOptionalParameter->isOptional,
sprintf(
'Reflection method %s::%s has %s optional parameter %s with index %d but stub parameter %s with index %d is %s optional',
$class->name,
$method->name,
$parameter->isOptional ? "" : "not",
$parameter->name,
$parameter->indexInSignature,
$stubOptionalParameter->name,
$stubOptionalParameter->indexInSignature,
$stubOptionalParameter->isOptional ? "" : "not"
)
);
}
/**
* @throws Exception
*/
public function testImplodeFunctionIsCorrect()
{
$implodeFunctions = array_filter(
PhpStormStubsSingleton::getPhpStormStubs()->getFunctions(),
fn (PHPFunction $function) => $function->name === 'implode'
);
self::assertCount(1, $implodeFunctions);
/** @var PHPFunction $implodeFunction */
$implodeFunction = array_pop($implodeFunctions);
$implodeParameters = $implodeFunction->parameters;
$separatorParameters = array_filter($implodeParameters, fn (PHPParameter $parameter) => $parameter->name === 'separator');
$arrayParameters = array_filter($implodeParameters, fn (PHPParameter $parameter) => $parameter->name === 'array');
/** @var PHPParameter $separatorParameter */
$separatorParameter = array_pop($separatorParameters);
/** @var PHPParameter $arrayParameter */
$arrayParameter = array_pop($arrayParameters);
self::assertCount(2, $implodeParameters);
self::assertEquals(['array', 'string'], $separatorParameter->typesFromSignature);
if (property_exists($separatorParameter->defaultValue, 'value')) {
self::assertEquals('', $separatorParameter->defaultValue->value);
} else {
self::fail("Couldn't read default value");
}
self::assertEquals(['?array'], $arrayParameter->typesFromSignature);
self::assertEquals(['string'], $implodeFunction->returnTypesFromSignature);
self::assertEquals(['string'], $implodeFunction->returnTypesFromPhpDoc);
}
}