parent
b46f62da30
commit
9d6e8bdc4d
5 changed files with 188 additions and 8 deletions
@ -0,0 +1,126 @@ |
||||
<?php |
||||
/** |
||||
* This file is part of TypePHP(AOT). |
||||
* |
||||
* @link https://www.swoole.com/aot/ |
||||
* @contact service@swoole.com |
||||
*/ |
||||
|
||||
use PhpParser\Modifiers; |
||||
use TypePhp\CompilerTest; |
||||
use TypePhp\Exception\TestError; |
||||
|
||||
/** |
||||
* @internal |
||||
* @coversNothing |
||||
*/ |
||||
final class EnumDeclarationRulesTest extends PHPUnit\Framework\TestCase |
||||
{ |
||||
private string $testRoot; |
||||
|
||||
protected function setUp(): void |
||||
{ |
||||
$this->testRoot = sys_get_temp_dir() . '/typephp-enum-rules-' . bin2hex(random_bytes(8)); |
||||
mkdir($this->testRoot, 0777, true); |
||||
} |
||||
|
||||
protected function tearDown(): void |
||||
{ |
||||
if (!is_dir($this->testRoot)) { |
||||
return; |
||||
} |
||||
$iterator = new RecursiveIteratorIterator( |
||||
new RecursiveDirectoryIterator($this->testRoot, FilesystemIterator::SKIP_DOTS), |
||||
RecursiveIteratorIterator::CHILD_FIRST, |
||||
); |
||||
foreach ($iterator as $entry) { |
||||
$entry->isDir() ? rmdir($entry->getPathname()) : unlink($entry->getPathname()); |
||||
} |
||||
rmdir($this->testRoot); |
||||
} |
||||
|
||||
public function testDuplicateCaseIsRejectedDuringPrepare(): void |
||||
{ |
||||
$compiler = $this->compilerFor(<<<'PHP' |
||||
<?php |
||||
enum Suit { case Hearts; case Hearts; } |
||||
function main(): void {} |
||||
PHP); |
||||
|
||||
$this->expectException(TestError::class); |
||||
$this->expectExceptionMessage('Cannot redefine class constant Suit::Hearts'); |
||||
$compiler->prepareFile($this->testRoot . '/program.php'); |
||||
} |
||||
|
||||
/** @dataProvider caseConstantClashProvider */ |
||||
public function testCaseAndClassConstantCannotShareAName(string $members): void |
||||
{ |
||||
$compiler = $this->compilerFor("<?php\nenum Suit { {$members} }\nfunction main(): void {}\n");
|
||||
|
||||
$this->expectException(TestError::class); |
||||
$this->expectExceptionMessage('Cannot redefine class constant Suit::Hearts'); |
||||
$compiler->prepareFile($this->testRoot . '/program.php'); |
||||
} |
||||
|
||||
public static function caseConstantClashProvider(): iterable |
||||
{ |
||||
yield 'case then constant' => ['case Hearts; public const Hearts = 1;']; |
||||
yield 'constant then case' => ['public const Hearts = 1; case Hearts;']; |
||||
} |
||||
|
||||
public function testCaseNamesRemainCaseSensitive(): void |
||||
{ |
||||
$compiler = $this->compilerFor(<<<'PHP' |
||||
<?php |
||||
enum Suit { case Hearts; case hearts; } |
||||
function main(): void {} |
||||
PHP); |
||||
$file = $this->testRoot . '/program.php'; |
||||
$compiler->prepareFile($file); |
||||
$compiler->convertFile($file); |
||||
|
||||
self::assertSame(['Hearts' => null, 'hearts' => null], $compiler->getClassDef('Suit')?->enumCases); |
||||
} |
||||
|
||||
public function testEnumIsImplicitlyFinal(): void |
||||
{ |
||||
$compiler = $this->compilerFor(<<<'PHP' |
||||
<?php |
||||
enum Suit { case Hearts; } |
||||
function main(): void {} |
||||
PHP); |
||||
$compiler->prepareFile($this->testRoot . '/program.php'); |
||||
|
||||
$enum = $compiler->getClassDef('Suit'); |
||||
self::assertNotNull($enum); |
||||
self::assertNotSame(0, $enum->flags & Modifiers::FINAL); |
||||
} |
||||
|
||||
public function testClassCannotExtendEnum(): void |
||||
{ |
||||
$compiler = $this->compilerFor(<<<'PHP' |
||||
<?php |
||||
enum Suit { case Hearts; } |
||||
class InvalidSuit extends Suit {} |
||||
function main(): void {} |
||||
PHP); |
||||
$file = $this->testRoot . '/program.php'; |
||||
$compiler->prepareFile($file); |
||||
|
||||
$this->expectException(TestError::class); |
||||
$this->expectExceptionMessage('cannot extend final class `Suit`'); |
||||
$compiler->convertFile($file); |
||||
} |
||||
|
||||
private function compilerFor(string $source): CompilerTest |
||||
{ |
||||
$file = $this->testRoot . '/program.php'; |
||||
file_put_contents($file, $source); |
||||
|
||||
global $translator; |
||||
$compiler = CompilerTest::create($this->testRoot); |
||||
$translator = $compiler; |
||||
$compiler->addFiles([$file]); |
||||
return $compiler; |
||||
} |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
--TEST-- |
||||
Enums are final and case names remain case-sensitive |
||||
--FILE-- |
||||
<?php |
||||
|
||||
enum Suit |
||||
{ |
||||
case Hearts; |
||||
case hearts; |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$reflection = new ReflectionClass(Suit::class); |
||||
var_dump($reflection->isFinal()); |
||||
foreach (Suit::cases() as $case) { |
||||
var_dump($case->name); |
||||
} |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
bool(true) |
||||
string(6) "Hearts" |
||||
string(6) "hearts" |
||||
Loading…
Reference in new issue