TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

311 lines
12 KiB

<?php
namespace PhpAot\Tests;
use PHPUnit\Framework\TestCase;
use PhpAot\Php\CompilerTest;
use PhpAot\Php\CompilerBase;
use PhpAot\Php\ArgInfo;
class TraitsTest extends TestCase
{
private string $testDir;
private CompilerTest $compiler;
private \ReflectionClass $ref;
protected function setUp(): void
{
parent::setUp();
$this->testDir = sys_get_temp_dir() . '/traits_test_' . uniqid();
mkdir($this->testDir, 0777, true);
$this->compiler = CompilerTest::create($this->testDir);
$this->ref = new \ReflectionClass($this->compiler);
}
protected function tearDown(): void
{
parent::tearDown();
if (is_dir($this->testDir)) {
$this->removeDirectory($this->testDir);
}
}
private function removeDirectory(string $dir): void
{
if (!is_dir($dir)) {
return;
}
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir . DIRECTORY_SEPARATOR . $file;
is_dir($path) ? $this->removeDirectory($path) : unlink($path);
}
rmdir($dir);
}
private function invoke(string $method, ...$args): mixed
{
$m = $this->ref->getMethod($method);
$m->setAccessible(true);
return $m->invoke($this->compiler, ...$args);
}
// ========================================================================
// MagicMethodDetector::checkArgType
// ========================================================================
public function testCheckArgTypeExactMatch(): void
{
$this->assertTrue($this->invoke('checkArgType', 'php::Int', 'php::Int'));
$this->assertTrue($this->invoke('checkArgType', 'php::Str', 'php::Str'));
$this->assertTrue($this->invoke('checkArgType', 'php::Array', 'php::Array'));
}
public function testCheckArgTypeMismatch(): void
{
$this->assertFalse($this->invoke('checkArgType', 'php::Int', 'php::Str'));
$this->assertFalse($this->invoke('checkArgType', 'php::Float', 'php::Int'));
}
public function testCheckArgTypeVarMatchesAny(): void
{
// TYPE_VAR matches any expected type when canBeVar is true (default)
$this->assertTrue($this->invoke('checkArgType', 'php::Var', 'php::Int'));
$this->assertTrue($this->invoke('checkArgType', 'php::Var', 'php::Str'));
$this->assertTrue($this->invoke('checkArgType', 'php::Var', 'php::Array'));
}
public function testCheckArgTypeVarDoesNotMatchWhenCannotBeVar(): void
{
// TYPE_VAR does NOT match when canBeVar is false
$this->assertFalse($this->invoke('checkArgType', 'php::Var', 'php::Str', false));
$this->assertFalse($this->invoke('checkArgType', 'php::Var', 'php::Int', false));
}
public function testCheckArgTypeExactMatchWithCannotBeVar(): void
{
$this->assertTrue($this->invoke('checkArgType', 'php::Str', 'php::Str', false));
$this->assertTrue($this->invoke('checkArgType', 'php::Array', 'php::Array', false));
}
public function testCheckArgTypeVoid(): void
{
$this->assertTrue($this->invoke('checkArgType', 'void', 'void'));
$this->assertFalse($this->invoke('checkArgType', 'void', 'php::Str'));
}
// ========================================================================
// FuncCallOptimizer::isValidDefineName
// ========================================================================
public function testIsValidDefineNameValid(): void
{
$this->assertTrue($this->invoke('isValidDefineName', 'MY_CONSTANT'));
$this->assertTrue($this->invoke('isValidDefineName', 'APP_NAME'));
$this->assertTrue($this->invoke('isValidDefineName', '_PRIVATE'));
$this->assertTrue($this->invoke('isValidDefineName', 'camelCase'));
$this->assertTrue($this->invoke('isValidDefineName', 'Test123'));
$this->assertTrue($this->invoke('isValidDefineName', '_'));
}
public function testIsValidDefineNameInvalid(): void
{
$this->assertFalse($this->invoke('isValidDefineName', '123abc')); // starts with digit
$this->assertFalse($this->invoke('isValidDefineName', 'has space')); // contains space
$this->assertFalse($this->invoke('isValidDefineName', 'has-dash')); // contains dash
$this->assertFalse($this->invoke('isValidDefineName', '')); // empty
$this->assertFalse($this->invoke('isValidDefineName', '0abc')); // starts with zero
}
// ========================================================================
// StdContainerParser::isStdContainerType
// ========================================================================
public function testIsStdContainerTypeTrue(): void
{
$this->assertTrue($this->invoke('isStdContainerType', CompilerBase::TYPE_STD_ARRAY));
$this->assertTrue($this->invoke('isStdContainerType', CompilerBase::TYPE_STD_VECTOR));
$this->assertTrue($this->invoke('isStdContainerType', CompilerBase::TYPE_STD_MAP));
$this->assertTrue($this->invoke('isStdContainerType', CompilerBase::TYPE_STD_UNORDERED_MAP));
}
public function testIsStdContainerTypeFalse(): void
{
$this->assertFalse($this->invoke('isStdContainerType', CompilerBase::TYPE_ARRAY));
$this->assertFalse($this->invoke('isStdContainerType', CompilerBase::TYPE_INT));
$this->assertFalse($this->invoke('isStdContainerType', CompilerBase::TYPE_VAR));
$this->assertFalse($this->invoke('isStdContainerType', CompilerBase::TYPE_OBJECT));
}
// ========================================================================
// StdContainerParser::getStdTypeKey
// ========================================================================
public function testGetStdTypeKeyBasic(): void
{
$info = [
'kind' => 'vector',
'decl' => 'php::StdVector<php::Int>',
'type' => 'php::Int',
'class' => '',
];
$key = $this->invoke('getStdTypeKey', $info);
$this->assertStringContainsString('kind=vector', $key);
$this->assertStringContainsString('decl=php::StdVector<php::Int>', $key);
$this->assertStringContainsString('type=php::Int', $key);
$this->assertStringContainsString('class=', $key);
}
public function testGetStdTypeKeyWithClass(): void
{
$info = [
'kind' => 'vector',
'decl' => 'php::StdVector<php::Object>',
'type' => 'php::Object',
'class' => 'App\\Entity\\User',
];
$key = $this->invoke('getStdTypeKey', $info);
$this->assertStringContainsString('class=App\\Entity\\User', $key);
}
public function testGetStdTypeKeyWithKeyType(): void
{
$info = [
'kind' => 'map',
'decl' => 'php::StdMap<php::Str, php::Int>',
'type' => 'php::Int',
'class' => '',
'keyType' => 'php::Str',
];
$key = $this->invoke('getStdTypeKey', $info);
$this->assertStringContainsString('keyType=php::Str', $key);
}
public function testGetStdTypeKeyWithoutKeyType(): void
{
$info = [
'kind' => 'array',
'decl' => 'php::StdArray<php::Int, 10>',
'type' => 'php::Int',
'class' => '',
];
$key = $this->invoke('getStdTypeKey', $info);
$this->assertStringNotContainsString('keyType', $key);
}
public function testGetStdTypeKeyUnorderedMap(): void
{
$info = [
'kind' => 'unordered_map',
'decl' => 'php::StdUnorderedMap<php::Str, php::Int>',
'type' => 'php::Int',
'class' => '',
'keyType' => 'php::Str',
];
$key = $this->invoke('getStdTypeKey', $info);
$this->assertStringContainsString('kind=unordered_map', $key);
}
// ========================================================================
// PropertyPromotion::genPropertyPromotion
// ========================================================================
public function testGenPropertyPromotion(): void
{
// Need context initialized for genCharPtr
$this->invoke('resetFunction');
$argInfo = new ArgInfo();
$argInfo->name = 'title';
$argInfo->type = 'php::Str';
$result = $this->invoke('genPropertyPromotion', $argInfo);
$this->assertStringContainsString('this_.setProperty', $result);
$this->assertStringContainsString('title', $result);
}
public function testGenPropertyPromotionWithNumber(): void
{
$this->invoke('resetFunction');
$argInfo = new ArgInfo();
$argInfo->name = 'count';
$argInfo->type = 'php::Int';
$result = $this->invoke('genPropertyPromotion', $argInfo);
$this->assertStringContainsString('count', $result);
}
// ========================================================================
// ClosureGenerator::genScopeSwitchCode
// ========================================================================
public function testGenScopeSwitchCode(): void
{
$this->invoke('resetFunction');
$result = $this->invoke('genScopeSwitchCode');
$this->assertStringContainsString('php_switch_scope', $result);
$this->assertStringContainsString('ON_SCOPE_EXIT', $result);
$this->assertStringContainsString('php_restore_scope', $result);
}
public function testGenScopeSwitchCodeTemplate(): void
{
$this->invoke('resetFunction');
$result = $this->invoke('genScopeSwitchCode');
// Should have the pattern: auto tmp_var_X = php_switch_scope(this_);
$this->assertStringContainsString('auto', $result);
$this->assertStringContainsString('= php_switch_scope(this_)', $result);
}
// ========================================================================
// StdContainerParser::getStdArrayDecl
// ========================================================================
public function testGetStdArrayDecl(): void
{
$result = $this->invoke('getStdArrayDecl', 'php::Int', [10]);
$this->assertEquals('php::StdArray<php::Int, 10>', $result);
}
public function testGetStdArrayDeclNested(): void
{
$result = $this->invoke('getStdArrayDecl', 'php::Int', [3, 4]);
$this->assertEquals('php::StdArray<php::StdArray<php::Int, 4>, 3>', $result);
}
public function testGetStdArrayDeclFloat(): void
{
$result = $this->invoke('getStdArrayDecl', 'php::Float', [5]);
$this->assertEquals('php::StdArray<php::Float, 5>', $result);
}
// ========================================================================
// StdContainerParser::getStdMapDecl
// ========================================================================
public function testGetStdMapDecl(): void
{
$result = $this->invoke('getStdMapDecl', 'std::map', 'php::Str', 'php::Int');
$this->assertEquals('std::map<php::Str, php::Int>', $result);
}
public function testGetStdMapDeclUnordered(): void
{
$result = $this->invoke('getStdMapDecl', 'std::unordered_map', 'php::Int', 'php::Str');
$this->assertEquals('std::unordered_map<php::Int, php::Str>', $result);
}
// ========================================================================
// StdContainerParser::getStdValueTypeBytes
// ========================================================================
public function testGetStdValueTypeBytes(): void
{
$this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', CompilerBase::TYPE_INT));
$this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', CompilerBase::TYPE_FLOAT));
$this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', CompilerBase::TYPE_BOOL));
}
}