parent
0c2a25ea52
commit
d73d077a7a
13 changed files with 1185 additions and 0 deletions
@ -0,0 +1,114 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\ArgInfo; |
||||
|
||||
class ArgInfoTest extends TestCase |
||||
{ |
||||
public function testDefaultBooleanProperties(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
// Set required string properties first (they have no defaults) |
||||
$arg->name = ''; |
||||
$arg->type = ''; |
||||
|
||||
// default values for implicitly-initialized fields |
||||
$this->assertEquals('', $arg->default); |
||||
$this->assertNull($arg->defaultValue); |
||||
$this->assertEquals('', $arg->class); |
||||
$this->assertFalse($arg->byRef); |
||||
$this->assertFalse($arg->variadic); |
||||
$this->assertFalse($arg->nullable); |
||||
$this->assertFalse($arg->property); |
||||
$this->assertFalse($arg->unsafePtr); |
||||
} |
||||
|
||||
public function testNameAndType(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$arg->name = 'value'; |
||||
$arg->type = 'php::Int'; |
||||
|
||||
$this->assertEquals('value', $arg->name); |
||||
$this->assertEquals('php::Int', $arg->type); |
||||
} |
||||
|
||||
public function testDefaultValues(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$arg->default = '0'; |
||||
|
||||
$this->assertEquals('0', $arg->default); |
||||
} |
||||
|
||||
public function testClass(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$arg->class = 'DateTime'; |
||||
|
||||
$this->assertEquals('DateTime', $arg->class); |
||||
} |
||||
|
||||
public function testByRef(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$this->assertFalse($arg->byRef); |
||||
|
||||
$arg->byRef = true; |
||||
$this->assertTrue($arg->byRef); |
||||
} |
||||
|
||||
public function testVariadic(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$this->assertFalse($arg->variadic); |
||||
|
||||
$arg->variadic = true; |
||||
$this->assertTrue($arg->variadic); |
||||
} |
||||
|
||||
public function testNullable(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$this->assertFalse($arg->nullable); |
||||
|
||||
$arg->nullable = true; |
||||
$this->assertTrue($arg->nullable); |
||||
} |
||||
|
||||
public function testProperty(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$this->assertFalse($arg->property); |
||||
|
||||
$arg->property = true; |
||||
$this->assertTrue($arg->property); |
||||
} |
||||
|
||||
public function testUnsafePtr(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$this->assertFalse($arg->unsafePtr); |
||||
|
||||
$arg->unsafePtr = true; |
||||
$this->assertTrue($arg->unsafePtr); |
||||
} |
||||
|
||||
public function testAllFlagsCombined(): void |
||||
{ |
||||
$arg = new ArgInfo(); |
||||
$arg->name = 'args'; |
||||
$arg->type = 'php::Var'; |
||||
$arg->variadic = true; |
||||
$arg->byRef = true; |
||||
$arg->nullable = true; |
||||
|
||||
$this->assertEquals('args', $arg->name); |
||||
$this->assertEquals('php::Var', $arg->type); |
||||
$this->assertTrue($arg->variadic); |
||||
$this->assertTrue($arg->byRef); |
||||
$this->assertTrue($arg->nullable); |
||||
} |
||||
} |
||||
@ -0,0 +1,113 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Context; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Context\FunctionContext; |
||||
use PhpAot\Php\Context\ScopeContext; |
||||
|
||||
class FunctionContextTest extends TestCase |
||||
{ |
||||
public function testConstructInitializesAllProperties(): void |
||||
{ |
||||
$ctx = new FunctionContext(); |
||||
|
||||
$this->assertEmpty($ctx->objects); |
||||
$this->assertEmpty($ctx->stdArrays); |
||||
$this->assertEmpty($ctx->stdContainers); |
||||
$this->assertEmpty($ctx->localVars); |
||||
$this->assertEmpty($ctx->staticVars); |
||||
$this->assertEmpty($ctx->globalVars); |
||||
$this->assertEmpty($ctx->ceWrappers); |
||||
$this->assertEmpty($ctx->arguments); |
||||
$this->assertEmpty($ctx->beforeStmtLines); |
||||
$this->assertEmpty($ctx->afterStmtLines); |
||||
$this->assertEmpty($ctx->objectProps); |
||||
$this->assertEmpty($ctx->scopeLayouts); |
||||
|
||||
$this->assertSame(0, $ctx->tmpVarIndex); |
||||
$this->assertSame(0, $ctx->scopeLevel); |
||||
$this->assertFalse($ctx->inLoop); |
||||
$this->assertFalse($ctx->inClosure); |
||||
$this->assertFalse($ctx->inAssignExpr); |
||||
} |
||||
|
||||
public function testEnterScopeIncrementsLevel(): void |
||||
{ |
||||
$ctx = new FunctionContext(); |
||||
$this->assertSame(0, $ctx->scopeLevel); |
||||
|
||||
$ctx->enterScope(); |
||||
$this->assertSame(1, $ctx->scopeLevel); |
||||
$this->assertArrayHasKey(0, $ctx->scopeLayouts); |
||||
$this->assertInstanceOf(ScopeContext::class, $ctx->scopeLayouts[0]); |
||||
|
||||
$ctx->enterScope(); |
||||
$this->assertSame(2, $ctx->scopeLevel); |
||||
$this->assertArrayHasKey(0, $ctx->scopeLayouts); |
||||
$this->assertArrayHasKey(1, $ctx->scopeLayouts); |
||||
} |
||||
|
||||
public function testLeaveScopeDecrementsLevel(): void |
||||
{ |
||||
$ctx = new FunctionContext(); |
||||
$ctx->enterScope(); |
||||
$ctx->enterScope(); |
||||
$this->assertSame(2, $ctx->scopeLevel); |
||||
|
||||
$ctx->leaveScope(); |
||||
$this->assertSame(1, $ctx->scopeLevel); |
||||
|
||||
$ctx->leaveScope(); |
||||
$this->assertSame(0, $ctx->scopeLevel); |
||||
} |
||||
|
||||
public function testMutableProperties(): void |
||||
{ |
||||
$ctx = new FunctionContext(); |
||||
|
||||
$ctx->inLoop = true; |
||||
$this->assertTrue($ctx->inLoop); |
||||
|
||||
$ctx->inClosure = true; |
||||
$this->assertTrue($ctx->inClosure); |
||||
|
||||
$ctx->inAssignExpr = true; |
||||
$this->assertTrue($ctx->inAssignExpr); |
||||
|
||||
$ctx->tmpVarIndex = 5; |
||||
$this->assertSame(5, $ctx->tmpVarIndex); |
||||
} |
||||
|
||||
public function testLocalVarsManipulation(): void |
||||
{ |
||||
$ctx = new FunctionContext(); |
||||
$ctx->localVars['x'] = 'php::Int'; |
||||
$ctx->localVars['name'] = 'php::Str'; |
||||
|
||||
$this->assertArrayHasKey('x', $ctx->localVars); |
||||
$this->assertArrayHasKey('name', $ctx->localVars); |
||||
$this->assertEquals('php::Int', $ctx->localVars['x']); |
||||
$this->assertEquals('php::Str', $ctx->localVars['name']); |
||||
} |
||||
|
||||
public function testObjectsMap(): void |
||||
{ |
||||
$ctx = new FunctionContext(); |
||||
$ctx->objects['obj1'] = 'stdClass'; |
||||
$ctx->objects['obj2'] = 'DateTime'; |
||||
|
||||
$this->assertCount(2, $ctx->objects); |
||||
$this->assertEquals('stdClass', $ctx->objects['obj1']); |
||||
} |
||||
|
||||
public function testBeforeAfterStmtLines(): void |
||||
{ |
||||
$ctx = new FunctionContext(); |
||||
$ctx->beforeStmtLines[] = 'int x = 1;'; |
||||
$ctx->afterStmtLines[] = 'x = 0;'; |
||||
|
||||
$this->assertCount(1, $ctx->beforeStmtLines); |
||||
$this->assertCount(1, $ctx->afterStmtLines); |
||||
} |
||||
} |
||||
@ -0,0 +1,15 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Context; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Context\ScopeContext; |
||||
|
||||
class ScopeContextTest extends TestCase |
||||
{ |
||||
public function testCanInstantiate(): void |
||||
{ |
||||
$scope = new ScopeContext(); |
||||
$this->assertInstanceOf(ScopeContext::class, $scope); |
||||
} |
||||
} |
||||
@ -0,0 +1,133 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Entity; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Entity\ClassDef; |
||||
use PhpAot\Php\Entity\MethodDef; |
||||
use PhpAot\Php\Entity\PropertyDef; |
||||
use PhpAot\Php\Entity\ConstantDef; |
||||
use PhpAot\Php\Entity\FunctionDef; |
||||
use PhpParser\Modifiers; |
||||
|
||||
class ClassDefTest extends TestCase |
||||
{ |
||||
public function testConstructDefaults(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$this->assertEquals('Foo', $class->name); |
||||
$this->assertEquals('', $class->namespace); |
||||
$this->assertSame(Modifiers::PUBLIC, $class->flags); |
||||
$this->assertEquals('', $class->extends); |
||||
$this->assertEmpty($class->implements); |
||||
$this->assertEmpty($class->methods); |
||||
$this->assertEmpty($class->properties); |
||||
$this->assertEmpty($class->constants); |
||||
$this->assertFalse($class->enum); |
||||
$this->assertFalse($class->requireCtor); |
||||
$this->assertFalse($class->inheritedFromInternalClass); |
||||
$this->assertNull($class->trait); |
||||
} |
||||
|
||||
public function testConstructWithNamespace(): void |
||||
{ |
||||
$class = new ClassDef('Bar', Modifiers::PUBLIC, 'App\\Lib'); |
||||
$this->assertEquals('Bar', $class->name); |
||||
$this->assertEquals('App\\Lib', $class->namespace); |
||||
} |
||||
|
||||
public function testPropertyContextIsInitialized(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$this->assertNotNull($class->propertyContext); |
||||
$this->assertInstanceOf(\PhpAot\Php\Context\FunctionContext::class, $class->propertyContext); |
||||
} |
||||
|
||||
public function testGetNamespacedNameInheritedFromClassLikeDef(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC, 'A\\B'); |
||||
$this->assertEquals('A_B_Foo', $class->getNamespacedName(true)); |
||||
$this->assertEquals('A\\B\\Foo', $class->getNamespacedName(false)); |
||||
} |
||||
|
||||
public function testAddAndHasMethod(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$method = new MethodDef(Modifiers::PUBLIC, 'bar'); |
||||
|
||||
$this->assertFalse($class->hasMethod('bar')); |
||||
|
||||
$class->addMethod($method); |
||||
$this->assertTrue($class->hasMethod('bar')); |
||||
$this->assertTrue($class->hasMethod('BAR')); // case-insensitive |
||||
$this->assertSame($method, $class->getMethod('bar')); |
||||
} |
||||
|
||||
public function testGetMethodCaseInsensitive(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$method = new MethodDef(Modifiers::PUBLIC, 'MyMethod'); |
||||
|
||||
$class->addMethod($method); |
||||
$this->assertSame($method, $class->getMethod('mymethod')); |
||||
$this->assertSame($method, $class->getMethod('MYMETHOD')); |
||||
} |
||||
|
||||
public function testHasMethodNotFound(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$this->assertFalse($class->hasMethod('nonexistent')); |
||||
} |
||||
|
||||
public function testHasProperty(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$prop = new PropertyDef('name', Modifiers::PUBLIC, 'php::Str'); |
||||
$class->properties['name'] = $prop; |
||||
|
||||
$this->assertTrue($class->hasProperty('name')); |
||||
$this->assertFalse($class->hasProperty('missing')); |
||||
$this->assertSame($prop, $class->getProperty('name')); |
||||
} |
||||
|
||||
public function testHasConstant(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$const = new ConstantDef('VERSION', Modifiers::PUBLIC, 'php::Str', '"1.0"'); |
||||
$class->constants['VERSION'] = $const; |
||||
|
||||
$this->assertTrue($class->hasConstant('VERSION')); |
||||
$this->assertFalse($class->hasConstant('MISSING')); |
||||
$this->assertSame($const, $class->getConstant('VERSION')); |
||||
} |
||||
|
||||
public function testIsAbstract(): void |
||||
{ |
||||
$abstractClass = new ClassDef('AbstractFoo', Modifiers::ABSTRACT); |
||||
$this->assertTrue($abstractClass->isAbstract()); |
||||
|
||||
$concreteClass = new ClassDef('ConcreteFoo', Modifiers::PUBLIC); |
||||
$this->assertFalse($concreteClass->isAbstract()); |
||||
} |
||||
|
||||
public function testRequireCtorAndEnumDefaults(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$this->assertFalse($class->requireCtor); |
||||
$this->assertFalse($class->enum); |
||||
} |
||||
|
||||
public function testTraitAliasesAndIgnoredDefaults(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$this->assertEmpty($class->traitAliases); |
||||
$this->assertEmpty($class->traitIgnored); |
||||
} |
||||
|
||||
public function testImplementsAndExtendsDefaults(): void |
||||
{ |
||||
$class = new ClassDef('Foo', Modifiers::PUBLIC); |
||||
$this->assertEmpty($class->implements); |
||||
$this->assertEquals('', $class->extends); |
||||
} |
||||
} |
||||
@ -0,0 +1,47 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Entity; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Entity\ClassLikeDef; |
||||
use PhpAot\Php\Entity\ClassDef; |
||||
use PhpAot\Php\Entity\InterfaceDef; |
||||
use PhpParser\Modifiers; |
||||
|
||||
class ClassLikeDefTest extends TestCase |
||||
{ |
||||
public function testConstructWithoutNamespace(): void |
||||
{ |
||||
$def = new ClassLikeDef('Foo'); |
||||
$this->assertEquals('Foo', $def->name); |
||||
$this->assertEquals('', $def->namespace); |
||||
$this->assertEquals('', $def->extends); |
||||
} |
||||
|
||||
public function testConstructWithNamespace(): void |
||||
{ |
||||
$def = new ClassLikeDef('Foo', 'App\\Bar'); |
||||
$this->assertEquals('Foo', $def->name); |
||||
$this->assertEquals('App\\Bar', $def->namespace); |
||||
} |
||||
|
||||
public function testGetNamespacedNameWithoutNamespace(): void |
||||
{ |
||||
$def = new ClassLikeDef('Foo'); |
||||
$this->assertEquals('Foo', $def->getNamespacedName()); |
||||
$this->assertEquals('Foo', $def->getNamespacedName(false)); |
||||
} |
||||
|
||||
public function testGetNamespacedNameSymbolic(): void |
||||
{ |
||||
$def = new ClassLikeDef('Foo', 'App\\Bar'); |
||||
// symbolic: backslashes → underscores → App_Bar_Foo |
||||
$this->assertEquals('App_Bar_Foo', $def->getNamespacedName(true)); |
||||
} |
||||
|
||||
public function testGetNamespacedNameNonSymbolic(): void |
||||
{ |
||||
$def = new ClassLikeDef('Foo', 'App\\Bar'); |
||||
$this->assertEquals('App\\Bar\\Foo', $def->getNamespacedName(false)); |
||||
} |
||||
} |
||||
@ -0,0 +1,68 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Entity; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Entity\ConstantDef; |
||||
use PhpParser\Modifiers; |
||||
|
||||
class ConstantDefTest extends TestCase |
||||
{ |
||||
public function testConstruct(): void |
||||
{ |
||||
$const = new ConstantDef('MAX_SIZE', Modifiers::PUBLIC, 'php::Int', '1024L'); |
||||
|
||||
$this->assertEquals('MAX_SIZE', $const->name); |
||||
$this->assertSame(Modifiers::PUBLIC, $const->flags); |
||||
$this->assertEquals('php::Int', $const->type); |
||||
$this->assertEquals('1024L', $const->value); |
||||
$this->assertEquals('', $const->arrayExpr); |
||||
$this->assertEquals('', $const->class); |
||||
$this->assertNull($const->valueExpr); |
||||
} |
||||
|
||||
public function testConstructWithStringValue(): void |
||||
{ |
||||
$const = new ConstantDef('APP_NAME', Modifiers::PUBLIC, 'php::Str', 'php::Str{"MyApp"}'); |
||||
|
||||
$this->assertEquals('APP_NAME', $const->name); |
||||
$this->assertEquals('php::Str', $const->type); |
||||
$this->assertEquals('php::Str{"MyApp"}', $const->value); |
||||
} |
||||
|
||||
public function testClassProperty(): void |
||||
{ |
||||
$const = new ConstantDef('PI', Modifiers::PUBLIC, 'php::Float', '3.14'); |
||||
$this->assertEquals('', $const->class); |
||||
|
||||
$const->class = 'Math'; |
||||
$this->assertEquals('Math', $const->class); |
||||
} |
||||
|
||||
public function testArrayExprProperty(): void |
||||
{ |
||||
$const = new ConstantDef('ITEMS', Modifiers::PUBLIC, 'php::Array', '[]'); |
||||
$this->assertEquals('', $const->arrayExpr); |
||||
|
||||
$const->arrayExpr = 'zval arr; array_init(&arr);'; |
||||
$this->assertEquals('zval arr; array_init(&arr);', $const->arrayExpr); |
||||
} |
||||
|
||||
public function testValueExprProperty(): void |
||||
{ |
||||
$const = new ConstantDef('VALUE', Modifiers::PUBLIC, 'php::Int', '1L'); |
||||
$this->assertNull($const->valueExpr); |
||||
} |
||||
|
||||
public function testDifferentVisibilityFlags(): void |
||||
{ |
||||
$publicConst = new ConstantDef('A', Modifiers::PUBLIC, 'php::Int', '1'); |
||||
$this->assertSame(Modifiers::PUBLIC, $publicConst->flags); |
||||
|
||||
$protectedConst = new ConstantDef('B', Modifiers::PROTECTED, 'php::Int', '2'); |
||||
$this->assertSame(Modifiers::PROTECTED, $protectedConst->flags); |
||||
|
||||
$privateConst = new ConstantDef('C', Modifiers::PRIVATE, 'php::Int', '3'); |
||||
$this->assertSame(Modifiers::PRIVATE, $privateConst->flags); |
||||
} |
||||
} |
||||
@ -0,0 +1,115 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Entity; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Entity\FunctionDef; |
||||
use PhpAot\Php\ArgInfo; |
||||
|
||||
class FunctionDefTest extends TestCase |
||||
{ |
||||
public function testConstruct(): void |
||||
{ |
||||
$fn = new FunctionDef('test', 'void', ''); |
||||
|
||||
$this->assertEquals('test', $fn->name); |
||||
$this->assertEquals('void', $fn->returnType); |
||||
$this->assertEquals('', $fn->namespace); |
||||
$this->assertFalse($fn->method); |
||||
$this->assertFalse($fn->stub); |
||||
$this->assertEmpty($fn->argInfoList); |
||||
$this->assertEquals(0, $fn->argCountRequired); |
||||
$this->assertEquals('', $fn->params); |
||||
$this->assertEquals('', $fn->returnClass); |
||||
} |
||||
|
||||
public function testConstructWithNamespace(): void |
||||
{ |
||||
$fn = new FunctionDef('run', 'php::Int', 'App\\Lib'); |
||||
|
||||
$this->assertEquals('run', $fn->name); |
||||
$this->assertEquals('php::Int', $fn->returnType); |
||||
$this->assertEquals('App\\Lib', $fn->namespace); |
||||
} |
||||
|
||||
public function testGetNamespacedNameWithoutNamespace(): void |
||||
{ |
||||
$fn = new FunctionDef('main', 'void', ''); |
||||
$this->assertEquals('main', $fn->getNamespacedName()); |
||||
} |
||||
|
||||
public function testGetNamespacedNameWithNamespace(): void |
||||
{ |
||||
$fn = new FunctionDef('run', 'void', 'App\\Lib'); |
||||
$this->assertEquals('App\\Lib\\run', $fn->getNamespacedName()); |
||||
} |
||||
|
||||
public function testHasVariadicArgEmptyList(): void |
||||
{ |
||||
$fn = new FunctionDef('test', 'void', ''); |
||||
$this->assertFalse($fn->hasVariadicArg()); |
||||
} |
||||
|
||||
public function testHasVariadicArgFalse(): void |
||||
{ |
||||
$fn = new FunctionDef('test', 'void', ''); |
||||
|
||||
$arg1 = new ArgInfo(); |
||||
$arg1->name = 'x'; |
||||
$arg1->type = 'php::Int'; |
||||
$arg1->variadic = false; |
||||
|
||||
$fn->argInfoList = [$arg1]; |
||||
$this->assertFalse($fn->hasVariadicArg()); |
||||
} |
||||
|
||||
public function testHasVariadicArgTrue(): void |
||||
{ |
||||
$fn = new FunctionDef('test', 'void', ''); |
||||
|
||||
$arg1 = new ArgInfo(); |
||||
$arg1->name = 'args'; |
||||
$arg1->type = 'php::Var'; |
||||
$arg1->variadic = true; |
||||
|
||||
$fn->argInfoList = [$arg1]; |
||||
$this->assertTrue($fn->hasVariadicArg()); |
||||
} |
||||
|
||||
public function testHasVariadicArgLastOnly(): void |
||||
{ |
||||
$fn = new FunctionDef('test', 'void', ''); |
||||
|
||||
$arg1 = new ArgInfo(); |
||||
$arg1->name = 'x'; |
||||
$arg1->type = 'php::Int'; |
||||
$arg1->variadic = false; |
||||
|
||||
$arg2 = new ArgInfo(); |
||||
$arg2->name = 'rest'; |
||||
$arg2->type = 'php::Var'; |
||||
$arg2->variadic = true; |
||||
|
||||
$fn->argInfoList = [$arg1, $arg2]; |
||||
$this->assertTrue($fn->hasVariadicArg()); |
||||
} |
||||
|
||||
public function testMethodFlag(): void |
||||
{ |
||||
$fn = new FunctionDef('handle', 'void', ''); |
||||
$this->assertFalse($fn->method); |
||||
|
||||
$fn->method = true; |
||||
$this->assertTrue($fn->method); |
||||
} |
||||
|
||||
public function testParamsAndReturnClassSettable(): void |
||||
{ |
||||
$fn = new FunctionDef('test', 'php::Object', ''); |
||||
$fn->params = 'php::Int x, php::Str y'; |
||||
$fn->returnClass = 'DateTime'; |
||||
|
||||
$this->assertEquals('php::Int x, php::Str y', $fn->params); |
||||
$this->assertEquals('DateTime', $fn->returnClass); |
||||
} |
||||
} |
||||
@ -0,0 +1,42 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Entity; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Entity\InterfaceDef; |
||||
|
||||
class InterfaceDefTest extends TestCase |
||||
{ |
||||
public function testConstructWithoutNamespace(): void |
||||
{ |
||||
$iface = new InterfaceDef('JsonSerializable'); |
||||
|
||||
$this->assertEquals('JsonSerializable', $iface->name); |
||||
$this->assertEquals('', $iface->namespace); |
||||
$this->assertEquals('', $iface->extends); |
||||
} |
||||
|
||||
public function testConstructWithNamespace(): void |
||||
{ |
||||
$iface = new InterfaceDef('Renderable', 'App\\Contracts'); |
||||
|
||||
$this->assertEquals('Renderable', $iface->name); |
||||
$this->assertEquals('App\\Contracts', $iface->namespace); |
||||
} |
||||
|
||||
public function testGetNamespacedName(): void |
||||
{ |
||||
$iface = new InterfaceDef('Logger', 'App\\Contracts'); |
||||
|
||||
$this->assertEquals('App_Contracts_Logger', $iface->getNamespacedName(true)); |
||||
$this->assertEquals('App\\Contracts\\Logger', $iface->getNamespacedName(false)); |
||||
} |
||||
|
||||
public function testExtendsCanBeSet(): void |
||||
{ |
||||
$iface = new InterfaceDef('Child'); |
||||
$iface->extends = 'Parent'; |
||||
|
||||
$this->assertEquals('Parent', $iface->extends); |
||||
} |
||||
} |
||||
@ -0,0 +1,51 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Entity; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Entity\MethodDef; |
||||
use PhpAot\Php\Entity\FunctionDef; |
||||
use PhpParser\Modifiers; |
||||
|
||||
class MethodDefTest extends TestCase |
||||
{ |
||||
public function testConstruct(): void |
||||
{ |
||||
$method = new MethodDef(Modifiers::PUBLIC, 'handle'); |
||||
|
||||
$this->assertEquals('handle', $method->name); |
||||
$this->assertSame(Modifiers::PUBLIC, $method->flags); |
||||
$this->assertNull($method->functionDef); |
||||
$this->assertFalse($method->hasDynamicCall); |
||||
} |
||||
|
||||
public function testGetReturnType(): void |
||||
{ |
||||
$method = new MethodDef(Modifiers::PUBLIC, 'getValue'); |
||||
$fn = new FunctionDef('getValue', 'php::Int', ''); |
||||
$method->functionDef = $fn; |
||||
|
||||
$this->assertEquals('php::Int', $method->getReturnType()); |
||||
} |
||||
|
||||
public function testGetReturnTypeVoid(): void |
||||
{ |
||||
$method = new MethodDef(Modifiers::PROTECTED, 'execute'); |
||||
$fn = new FunctionDef('execute', 'void', ''); |
||||
$method->functionDef = $fn; |
||||
|
||||
$this->assertEquals('void', $method->getReturnType()); |
||||
} |
||||
|
||||
public function testFlags(): void |
||||
{ |
||||
$publicMethod = new MethodDef(Modifiers::PUBLIC, 'pub'); |
||||
$this->assertSame(Modifiers::PUBLIC, $publicMethod->flags); |
||||
|
||||
$protectedMethod = new MethodDef(Modifiers::PROTECTED, 'prot'); |
||||
$this->assertSame(Modifiers::PROTECTED, $protectedMethod->flags); |
||||
|
||||
$privateMethod = new MethodDef(Modifiers::PRIVATE, 'priv'); |
||||
$this->assertSame(Modifiers::PRIVATE, $privateMethod->flags); |
||||
} |
||||
} |
||||
@ -0,0 +1,82 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests\Entity; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Entity\PropertyDef; |
||||
use PhpParser\Modifiers; |
||||
|
||||
class PropertyDefTest extends TestCase |
||||
{ |
||||
public function testConstructWithDefaults(): void |
||||
{ |
||||
$prop = new PropertyDef('count', Modifiers::PUBLIC, 'php::Int'); |
||||
|
||||
$this->assertEquals('count', $prop->name); |
||||
$this->assertSame(Modifiers::PUBLIC, $prop->flags); |
||||
$this->assertEquals('php::Int', $prop->type); |
||||
$this->assertNull($prop->default); |
||||
$this->assertFalse($prop->nullable); |
||||
$this->assertEquals('', $prop->class); |
||||
} |
||||
|
||||
public function testConstructWithDefaultValue(): void |
||||
{ |
||||
$prop = new PropertyDef('count', Modifiers::PUBLIC, 'php::Int', '0'); |
||||
|
||||
$this->assertEquals('0', $prop->default); |
||||
} |
||||
|
||||
public function testConstructWithNullable(): void |
||||
{ |
||||
$prop = new PropertyDef('name', Modifiers::PUBLIC, 'php::Str', null, true); |
||||
|
||||
$this->assertTrue($prop->nullable); |
||||
} |
||||
|
||||
public function testIsPrivate(): void |
||||
{ |
||||
$privateProp = new PropertyDef('secret', Modifiers::PRIVATE, 'php::Str'); |
||||
$this->assertTrue($privateProp->isPrivate()); |
||||
$this->assertFalse($privateProp->isProtected()); |
||||
$this->assertFalse($privateProp->isPublic()); |
||||
} |
||||
|
||||
public function testIsProtected(): void |
||||
{ |
||||
$protectedProp = new PropertyDef('value', Modifiers::PROTECTED, 'php::Int'); |
||||
$this->assertFalse($protectedProp->isPrivate()); |
||||
$this->assertTrue($protectedProp->isProtected()); |
||||
$this->assertFalse($protectedProp->isPublic()); |
||||
} |
||||
|
||||
public function testIsPublic(): void |
||||
{ |
||||
$publicProp = new PropertyDef('name', Modifiers::PUBLIC, 'php::Str'); |
||||
$this->assertFalse($publicProp->isPrivate()); |
||||
$this->assertFalse($publicProp->isProtected()); |
||||
$this->assertTrue($publicProp->isPublic()); |
||||
|
||||
// PUBLIC flag is 0, so no-flag properties are also public |
||||
$impliedPublic = new PropertyDef('name', 0, 'php::Str'); |
||||
$this->assertTrue($impliedPublic->isPublic()); |
||||
} |
||||
|
||||
public function testIsStatic(): void |
||||
{ |
||||
$staticProp = new PropertyDef('counter', Modifiers::PUBLIC | Modifiers::STATIC, 'php::Int'); |
||||
$this->assertTrue($staticProp->isStatic()); |
||||
|
||||
$instanceProp = new PropertyDef('counter', Modifiers::PUBLIC, 'php::Int'); |
||||
$this->assertFalse($instanceProp->isStatic()); |
||||
} |
||||
|
||||
public function testClassProperty(): void |
||||
{ |
||||
$prop = new PropertyDef('data', Modifiers::PUBLIC, 'php::Var'); |
||||
$this->assertEquals('', $prop->class); |
||||
|
||||
$prop->class = 'App\\Entity\\User'; |
||||
$this->assertEquals('App\\Entity\\User', $prop->class); |
||||
} |
||||
} |
||||
@ -0,0 +1,151 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Exception\DynamicCall; |
||||
use PhpAot\Php\Exception\PlaceHolder; |
||||
use PhpAot\Php\Exception\Redo; |
||||
use PhpAot\Php\Exception\Skip; |
||||
use PhpAot\Php\Exception\SyntaxError; |
||||
use PhpAot\Php\Exception\TestError; |
||||
use PhpAot\Php\Exception\Unsupported; |
||||
use PhpAot\Php\Constants; |
||||
|
||||
class ExceptionTest extends TestCase |
||||
{ |
||||
public function testDynamicCall(): void |
||||
{ |
||||
$e = new DynamicCall('Dynamic call error'); |
||||
$this->assertInstanceOf(\RuntimeException::class, $e); |
||||
$this->assertEquals('Dynamic call error', $e->getMessage()); |
||||
} |
||||
|
||||
public function testPlaceHolder(): void |
||||
{ |
||||
$e = new PlaceHolder('Placeholder error'); |
||||
$this->assertInstanceOf(\RuntimeException::class, $e); |
||||
$this->assertEquals('Placeholder error', $e->getMessage()); |
||||
} |
||||
|
||||
public function testRedo(): void |
||||
{ |
||||
$e = new Redo('Redo compilation'); |
||||
$this->assertInstanceOf(\RuntimeException::class, $e); |
||||
$this->assertStringContainsString('Redo', $e->getMessage()); |
||||
} |
||||
|
||||
public function testSkip(): void |
||||
{ |
||||
$e = new Skip('Skip this file'); |
||||
$this->assertInstanceOf(\RuntimeException::class, $e); |
||||
$this->assertStringContainsString('Skip', $e->getMessage()); |
||||
} |
||||
|
||||
public function testSyntaxError(): void |
||||
{ |
||||
$e = new SyntaxError('Unexpected token'); |
||||
$this->assertInstanceOf(\RuntimeException::class, $e); |
||||
$this->assertStringContainsString('Unexpected', $e->getMessage()); |
||||
} |
||||
|
||||
public function testTestError(): void |
||||
{ |
||||
$e = new TestError('Test assertion failed'); |
||||
$this->assertInstanceOf(\RuntimeException::class, $e); |
||||
$this->assertStringContainsString('Test assertion', $e->getMessage()); |
||||
} |
||||
|
||||
public function testUnsupported(): void |
||||
{ |
||||
$e = new Unsupported('Unsupported syntax'); |
||||
$this->assertInstanceOf(\RuntimeException::class, $e); |
||||
$this->assertStringContainsString('Unsupported', $e->getMessage()); |
||||
} |
||||
|
||||
public function testCustomErrorCodes(): void |
||||
{ |
||||
$e = new TestError('Error 42', 42); |
||||
$this->assertEquals(42, $e->getCode()); |
||||
} |
||||
|
||||
public function testCatchByBaseRuntimeException(): void |
||||
{ |
||||
// All exceptions can be caught by their parent RuntimeException |
||||
$errors = [ |
||||
new DynamicCall('test'), |
||||
new PlaceHolder('test'), |
||||
new Redo('test'), |
||||
new Skip('test'), |
||||
new SyntaxError('test'), |
||||
new TestError('test'), |
||||
new Unsupported('test'), |
||||
]; |
||||
|
||||
foreach ($errors as $e) { |
||||
try { |
||||
throw $e; |
||||
} catch (\RuntimeException $caught) { |
||||
$this->assertSame($e, $caught); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public function testConstantsReservedNames(): void |
||||
{ |
||||
$this->assertIsArray(Constants::CPP_RESERVED_NAMES); |
||||
$this->assertContains('class', Constants::CPP_RESERVED_NAMES); |
||||
$this->assertContains('namespace', Constants::CPP_RESERVED_NAMES); |
||||
$this->assertContains('int', Constants::CPP_RESERVED_NAMES); |
||||
$this->assertContains('void', Constants::CPP_RESERVED_NAMES); |
||||
} |
||||
|
||||
public function testConstantsUnsupportedFunctions(): void |
||||
{ |
||||
$this->assertIsArray(Constants::UNSUPPORTED_FUNCTIONS); |
||||
$this->assertContains('extract', Constants::UNSUPPORTED_FUNCTIONS); |
||||
} |
||||
|
||||
public function testConstantsCompilerOptions(): void |
||||
{ |
||||
$options = Constants::COMPILER_OPTIONS; |
||||
$this->assertIsArray($options); |
||||
$this->assertArrayHasKey('optimize', $options); |
||||
$this->assertArrayHasKey('output', $options); |
||||
$this->assertArrayHasKey('help', $options); |
||||
$this->assertArrayHasKey('debug', $options); |
||||
$this->assertArrayHasKey('job', $options); |
||||
$this->assertArrayHasKey('mode', $options); |
||||
} |
||||
|
||||
public function testCompilerOptionOptimizeDefaults(): void |
||||
{ |
||||
$opt = Constants::COMPILER_OPTIONS['optimize']; |
||||
$this->assertEquals('O', $opt['prefix']); |
||||
$this->assertIsInt($opt['defaultValue']); |
||||
$this->assertEquals(0, $opt['defaultValue']); |
||||
} |
||||
|
||||
public function testCompilerOptionModeDefaults(): void |
||||
{ |
||||
$opt = Constants::COMPILER_OPTIONS['mode']; |
||||
$this->assertEquals('bin', $opt['defaultValue']); |
||||
} |
||||
|
||||
public function testCompilerOptionNoValueFlags(): void |
||||
{ |
||||
$noValueFlags = ['help', 'version', 'no-literal-strings', 'force', 'debug', 'no-console']; |
||||
foreach ($noValueFlags as $flag) { |
||||
$this->assertArrayHasKey($flag, Constants::COMPILER_OPTIONS); |
||||
$this->assertTrue(Constants::COMPILER_OPTIONS[$flag]['noValue'] ?? false); |
||||
} |
||||
} |
||||
|
||||
public function testMsvcSuppressedWarnings(): void |
||||
{ |
||||
$warnings = Constants::MSVC_SUPPRESSED_WARNINGS; |
||||
$this->assertIsArray($warnings); |
||||
$this->assertArrayHasKey('4244', $warnings); |
||||
$this->assertArrayHasKey('4127', $warnings); |
||||
} |
||||
} |
||||
@ -0,0 +1,183 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\FileScanner; |
||||
|
||||
class FileScannerTest extends TestCase |
||||
{ |
||||
// ======================================================================== |
||||
// Extension type detection |
||||
// ======================================================================== |
||||
|
||||
public function testIsPhpFile(): void |
||||
{ |
||||
$this->assertTrue(FileScanner::isPhpFile('/path/to/file.php')); |
||||
$this->assertFalse(FileScanner::isPhpFile('/path/to/file.cc')); |
||||
$this->assertFalse(FileScanner::isPhpFile('/path/to/file.c')); |
||||
$this->assertFalse(FileScanner::isPhpFile('/path/to/file.py')); |
||||
} |
||||
|
||||
public function testIsCppFile(): void |
||||
{ |
||||
$this->assertTrue(FileScanner::isCppFile('/path/to/file.cc')); |
||||
$this->assertTrue(FileScanner::isCppFile('/path/to/file.cpp')); |
||||
$this->assertTrue(FileScanner::isCppFile('/path/to/file.cxx')); |
||||
$this->assertFalse(FileScanner::isCppFile('/path/to/file.c')); |
||||
$this->assertFalse(FileScanner::isCppFile('/path/to/file.php')); |
||||
} |
||||
|
||||
public function testIsNativeSourceFile(): void |
||||
{ |
||||
// C++ files |
||||
$this->assertTrue(FileScanner::isNativeSourceFile('/path/to/file.cc')); |
||||
$this->assertTrue(FileScanner::isNativeSourceFile('/path/to/file.cpp')); |
||||
$this->assertTrue(FileScanner::isNativeSourceFile('/path/to/file.cxx')); |
||||
// C files |
||||
$this->assertTrue(FileScanner::isNativeSourceFile('/path/to/file.c')); |
||||
// Assembly files |
||||
$this->assertTrue(FileScanner::isNativeSourceFile('/path/to/file.s')); |
||||
$this->assertTrue(FileScanner::isNativeSourceFile('/path/to/file.S')); |
||||
// Objective-C files |
||||
$this->assertTrue(FileScanner::isNativeSourceFile('/path/to/file.m')); |
||||
$this->assertTrue(FileScanner::isNativeSourceFile('/path/to/file.mm')); |
||||
// Not native source |
||||
$this->assertFalse(FileScanner::isNativeSourceFile('/path/to/file.php')); |
||||
$this->assertFalse(FileScanner::isNativeSourceFile('/path/to/file.py')); |
||||
$this->assertFalse(FileScanner::isNativeSourceFile('/path/to/file.h')); |
||||
$this->assertFalse(FileScanner::isNativeSourceFile('/path/to/file.hpp')); |
||||
} |
||||
|
||||
// ======================================================================== |
||||
// getFileName / getFileExt |
||||
// ======================================================================== |
||||
|
||||
public function testGetFileName(): void |
||||
{ |
||||
$this->assertEquals('hello', FileScanner::getFileName('/path/to/hello.php')); |
||||
$this->assertEquals('helper', FileScanner::getFileName('/path/to/helper.c')); |
||||
$this->assertEquals('main', FileScanner::getFileName('/path/to/main.cc')); |
||||
} |
||||
|
||||
public function testGetFileNameWithMultipleDots(): void |
||||
{ |
||||
$this->assertEquals('my.test', FileScanner::getFileName('/path/to/my.test.php')); |
||||
} |
||||
|
||||
public function testGetFileExt(): void |
||||
{ |
||||
$this->assertEquals('php', FileScanner::getFileExt('/path/to/file.php')); |
||||
$this->assertEquals('c', FileScanner::getFileExt('/path/to/file.c')); |
||||
$this->assertEquals('cc', FileScanner::getFileExt('/path/to/file.cc')); |
||||
$this->assertEquals('S', FileScanner::getFileExt('/path/to/file.S')); |
||||
} |
||||
|
||||
// ======================================================================== |
||||
// Constants |
||||
// ======================================================================== |
||||
|
||||
public function testPhpExtConstant(): void |
||||
{ |
||||
$this->assertEquals(['php'], FileScanner::PHP_EXT); |
||||
} |
||||
|
||||
public function testCppExtConstant(): void |
||||
{ |
||||
$this->assertContains('cc', FileScanner::CPP_EXT); |
||||
$this->assertContains('cpp', FileScanner::CPP_EXT); |
||||
$this->assertContains('cxx', FileScanner::CPP_EXT); |
||||
} |
||||
|
||||
public function testCextConstant(): void |
||||
{ |
||||
$this->assertEquals(['c'], FileScanner::C_EXT); |
||||
} |
||||
|
||||
public function testAsmExtConstant(): void |
||||
{ |
||||
$this->assertContains('s', FileScanner::ASM_EXT); |
||||
$this->assertContains('S', FileScanner::ASM_EXT); |
||||
} |
||||
|
||||
public function testObjcExtConstant(): void |
||||
{ |
||||
$this->assertEquals(['m'], FileScanner::OBJC_EXT); |
||||
} |
||||
|
||||
public function testObjcxxExtConstant(): void |
||||
{ |
||||
$this->assertEquals(['mm'], FileScanner::OBJCXX_EXT); |
||||
} |
||||
|
||||
public function testNativeSrcExtConstant(): void |
||||
{ |
||||
$expected = ['cpp', 'cxx', 'cc', 'c', 's', 'S', 'm', 'mm']; |
||||
sort($expected); |
||||
$actual = FileScanner::NATIVE_SRC_EXT; |
||||
sort($actual); |
||||
$this->assertEquals($expected, $actual); |
||||
} |
||||
|
||||
// ======================================================================== |
||||
// Scan method |
||||
// ======================================================================== |
||||
|
||||
public function testScanDirectory(): void |
||||
{ |
||||
$tmpDir = sys_get_temp_dir() . '/file_scanner_test_' . uniqid(); |
||||
mkdir($tmpDir, 0777, true); |
||||
mkdir($tmpDir . '/sub', 0777, true); |
||||
|
||||
touch($tmpDir . '/main.php'); |
||||
touch($tmpDir . '/helper.c'); |
||||
touch($tmpDir . '/math.S'); |
||||
touch($tmpDir . '/module.cc'); |
||||
touch($tmpDir . '/lib.m'); |
||||
touch($tmpDir . '/ignored.py'); |
||||
touch($tmpDir . '/README.md'); |
||||
touch($tmpDir . '/sub/nested.cpp'); |
||||
|
||||
$scanner = new FileScanner($tmpDir); |
||||
$files = $scanner->scan(); |
||||
|
||||
// Python and Markdown should not be included |
||||
$this->assertContains($tmpDir . '/main.php', $files); |
||||
$this->assertContains($tmpDir . '/helper.c', $files); |
||||
$this->assertContains($tmpDir . '/math.S', $files); |
||||
$this->assertContains($tmpDir . '/module.cc', $files); |
||||
$this->assertContains($tmpDir . '/lib.m', $files); |
||||
$this->assertContains($tmpDir . '/sub/nested.cpp', $files); |
||||
$this->assertNotContains($tmpDir . '/ignored.py', $files); |
||||
$this->assertNotContains($tmpDir . '/README.md', $files); |
||||
|
||||
// Clean up |
||||
unlink($tmpDir . '/main.php'); |
||||
unlink($tmpDir . '/helper.c'); |
||||
unlink($tmpDir . '/math.S'); |
||||
unlink($tmpDir . '/module.cc'); |
||||
unlink($tmpDir . '/lib.m'); |
||||
unlink($tmpDir . '/ignored.py'); |
||||
unlink($tmpDir . '/README.md'); |
||||
unlink($tmpDir . '/sub/nested.cpp'); |
||||
rmdir($tmpDir . '/sub'); |
||||
rmdir($tmpDir); |
||||
} |
||||
|
||||
public function testConstructorRejectsNonexistentDir(): void |
||||
{ |
||||
$this->expectException(\InvalidArgumentException::class); |
||||
new FileScanner('/nonexistent/path'); |
||||
} |
||||
|
||||
public function testGetDirectory(): void |
||||
{ |
||||
$tmpDir = sys_get_temp_dir() . '/file_scanner_getdir_' . uniqid(); |
||||
mkdir($tmpDir, 0777, true); |
||||
|
||||
$scanner = new FileScanner($tmpDir); |
||||
$this->assertEquals($tmpDir, $scanner->getDirectory()); |
||||
|
||||
rmdir($tmpDir); |
||||
} |
||||
} |
||||
@ -0,0 +1,71 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Tests; |
||||
|
||||
use PHPUnit\Framework\TestCase; |
||||
use PhpAot\Php\Symbol; |
||||
use PhpAot\Php\CompilerBase; |
||||
|
||||
class SymbolTest extends TestCase |
||||
{ |
||||
public function testGetStaticProperty(): void |
||||
{ |
||||
$this->assertEquals('php::getStaticProperty', Symbol::getStaticProperty()); |
||||
} |
||||
|
||||
public function testSetStaticProperty(): void |
||||
{ |
||||
$this->assertEquals('php::setStaticProperty', Symbol::setStaticProperty()); |
||||
} |
||||
|
||||
public function testInstanceOf(): void |
||||
{ |
||||
$this->assertEquals('php::instanceOf', Symbol::instanceOf()); |
||||
} |
||||
|
||||
public function testConcat(): void |
||||
{ |
||||
$this->assertEquals('php::concat', Symbol::concat()); |
||||
} |
||||
|
||||
public function testConstant(): void |
||||
{ |
||||
$this->assertEquals('php::constant', Symbol::constant()); |
||||
} |
||||
|
||||
public function testGetClassEntrySafe(): void |
||||
{ |
||||
$this->assertEquals('php::getClassEntrySafe', Symbol::getClassEntrySafe()); |
||||
} |
||||
|
||||
public function testArgList(): void |
||||
{ |
||||
$this->assertEquals('php::ArgList', Symbol::argList()); |
||||
} |
||||
|
||||
public function testGetCalledCe(): void |
||||
{ |
||||
$result = Symbol::getCalledCe(); |
||||
$this->assertStringContainsString(CompilerBase::PREFIX, $result); |
||||
$this->assertStringContainsString('get_called_ce', $result); |
||||
} |
||||
|
||||
public function testGetCalledClass(): void |
||||
{ |
||||
$result = Symbol::getCalledClass(); |
||||
$this->assertStringContainsString(CompilerBase::PREFIX, $result); |
||||
$this->assertStringContainsString('get_called_class', $result); |
||||
} |
||||
|
||||
public function testSafeIndex(): void |
||||
{ |
||||
$result = Symbol::safeIndex('0', '10'); |
||||
$this->assertEquals('php::safeIndex(0, 10)', $result); |
||||
} |
||||
|
||||
public function testSafeIndexWithVariables(): void |
||||
{ |
||||
$result = Symbol::safeIndex('i', 'count'); |
||||
$this->assertEquals('php::safeIndex(i, count)', $result); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue