fix: Gitea Traefik routing and connection pool optimization
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
This commit is contained in:
912
tests/debug/test_token_classification.php
Normal file
912
tests/debug/test_token_classification.php
Normal file
@@ -0,0 +1,912 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
use App\Framework\Tokenizer\PhpTokenizer;
|
||||
use App\Framework\Tokenizer\ValueObjects\Token;
|
||||
use App\Framework\Tokenizer\ValueObjects\TokenType;
|
||||
|
||||
/**
|
||||
* Test script for token classification
|
||||
* Tests various PHP structures and compares expected vs actual token types
|
||||
*/
|
||||
|
||||
final class TokenClassificationTest
|
||||
{
|
||||
private PhpTokenizer $tokenizer;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->tokenizer = new PhpTokenizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all test cases
|
||||
*/
|
||||
public function runAll(): void
|
||||
{
|
||||
$testCases = $this->getTestCases();
|
||||
$total = count($testCases);
|
||||
$passed = 0;
|
||||
$failed = 0;
|
||||
|
||||
echo "=== Token Classification Test Suite ===\n\n";
|
||||
echo "Running {$total} test cases...\n\n";
|
||||
|
||||
foreach ($testCases as $index => $testCase) {
|
||||
echo str_repeat('=', 80) . "\n";
|
||||
echo "Test Case " . ($index + 1) . ": {$testCase['name']}\n";
|
||||
echo str_repeat('=', 80) . "\n\n";
|
||||
|
||||
$result = $this->runTestCase($testCase);
|
||||
|
||||
if ($result['passed']) {
|
||||
$passed++;
|
||||
echo "✅ PASSED\n\n";
|
||||
} else {
|
||||
$failed++;
|
||||
echo "❌ FAILED\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo str_repeat('=', 80) . "\n";
|
||||
echo "Summary: {$passed}/{$total} passed, {$failed}/{$total} failed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a single test case
|
||||
*/
|
||||
private function runTestCase(array $testCase): array
|
||||
{
|
||||
$code = $testCase['code'];
|
||||
$expected = $testCase['expected'];
|
||||
$expectedMetadata = $testCase['expectedMetadata'] ?? null;
|
||||
|
||||
echo "Code:\n";
|
||||
$codeLines = explode("\n", $code);
|
||||
foreach ($codeLines as $i => $line) {
|
||||
echo sprintf(" %2d: %s\n", $i + 1, $line);
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Tokenize the code
|
||||
$tokens = $this->tokenizer->tokenize($code);
|
||||
|
||||
// Build actual token map
|
||||
$actual = $this->buildTokenMap($tokens);
|
||||
|
||||
// Compare expected vs actual
|
||||
$differences = $this->compareTokens($expected, $actual);
|
||||
|
||||
// Check metadata if expected
|
||||
$metadataDifferences = [];
|
||||
if ($expectedMetadata !== null) {
|
||||
$metadataDifferences = $this->compareMetadata($tokens, $expectedMetadata);
|
||||
}
|
||||
|
||||
// Display expected tokens
|
||||
echo "Expected Tokens:\n";
|
||||
foreach ($expected as $lineNum => $lineTokens) {
|
||||
foreach ($lineTokens as $tokenValue => $expectedType) {
|
||||
echo sprintf(" Line %d: '%s' → %s\n", $lineNum, $tokenValue, $expectedType);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Display actual tokens
|
||||
echo "Actual Tokens:\n";
|
||||
foreach ($actual as $lineNum => $lineTokens) {
|
||||
foreach ($lineTokens as $tokenValue => $actualType) {
|
||||
echo sprintf(" Line %d: '%s' → %s\n", $lineNum, $tokenValue, $actualType->value);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Display differences
|
||||
if (empty($differences) && empty($metadataDifferences)) {
|
||||
echo "Differences: None - All tokens and metadata match!\n";
|
||||
return ['passed' => true, 'differences' => []];
|
||||
}
|
||||
|
||||
echo "Differences:\n";
|
||||
foreach ($differences as $diff) {
|
||||
if ($diff['match']) {
|
||||
echo sprintf(" ✅ Line %d: '%s' → %s (correct)\n",
|
||||
$diff['line'],
|
||||
$diff['token'],
|
||||
$diff['expected']
|
||||
);
|
||||
} else {
|
||||
echo sprintf(" ❌ Line %d: '%s' → Expected %s, got %s\n",
|
||||
$diff['line'],
|
||||
$diff['token'],
|
||||
$diff['expected'],
|
||||
$diff['actual']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Display metadata differences
|
||||
if (!empty($metadataDifferences)) {
|
||||
echo "\nMetadata Differences:\n";
|
||||
foreach ($metadataDifferences as $diff) {
|
||||
if ($diff['match']) {
|
||||
echo sprintf(" ✅ Line %d: '%s' → %s (correct)\n",
|
||||
$diff['line'],
|
||||
$diff['token'],
|
||||
$diff['expected']
|
||||
);
|
||||
} else {
|
||||
echo sprintf(" ❌ Line %d: '%s' → Expected %s, got %s\n",
|
||||
$diff['line'],
|
||||
$diff['token'],
|
||||
$diff['expected'],
|
||||
$diff['actual']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$allDifferences = array_merge($differences, $metadataDifferences);
|
||||
return [
|
||||
'passed' => empty(array_filter($allDifferences, fn($d) => !$d['match'])),
|
||||
'differences' => $allDifferences
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build token map from TokenCollection
|
||||
*/
|
||||
private function buildTokenMap($tokens): array
|
||||
{
|
||||
$map = [];
|
||||
|
||||
foreach ($tokens as $token) {
|
||||
$line = $token->line;
|
||||
$value = trim($token->value);
|
||||
|
||||
// Skip whitespace-only tokens and PHP tags
|
||||
if ($token->type === TokenType::WHITESPACE ||
|
||||
$token->type === TokenType::PHP_TAG ||
|
||||
empty($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($map[$line])) {
|
||||
$map[$line] = [];
|
||||
}
|
||||
|
||||
// Use token value as key, token type as value
|
||||
$map[$line][$value] = $token->type;
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare metadata for tokens
|
||||
*/
|
||||
private function compareMetadata($tokens, array $expectedMetadata): array
|
||||
{
|
||||
$differences = [];
|
||||
|
||||
// Build token lookup by line and value
|
||||
$tokenLookup = [];
|
||||
foreach ($tokens as $token) {
|
||||
$line = $token->line;
|
||||
$value = trim($token->value);
|
||||
|
||||
if (empty($value) || $token->type === TokenType::WHITESPACE || $token->type === TokenType::PHP_TAG) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($tokenLookup[$line])) {
|
||||
$tokenLookup[$line] = [];
|
||||
}
|
||||
|
||||
$tokenLookup[$line][$value] = $token;
|
||||
}
|
||||
|
||||
// Compare expected metadata
|
||||
foreach ($expectedMetadata as $lineNum => $lineMetadata) {
|
||||
foreach ($lineMetadata as $tokenValue => $expectedMeta) {
|
||||
$token = $tokenLookup[$lineNum][$tokenValue] ?? null;
|
||||
|
||||
if ($token === null) {
|
||||
$differences[] = [
|
||||
'line' => $lineNum,
|
||||
'token' => $tokenValue,
|
||||
'expected' => json_encode($expectedMeta),
|
||||
'actual' => 'TOKEN_NOT_FOUND',
|
||||
'match' => false
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
$actualMeta = $token->metadata;
|
||||
|
||||
// Check each expected metadata property
|
||||
foreach ($expectedMeta as $property => $expectedValue) {
|
||||
$actualValue = $actualMeta?->$property ?? null;
|
||||
|
||||
if ($property === 'isBuiltIn') {
|
||||
$actualValue = $actualMeta?->isBuiltIn ?? false;
|
||||
}
|
||||
|
||||
$match = $actualValue === $expectedValue;
|
||||
|
||||
if (!$match) {
|
||||
$differences[] = [
|
||||
'line' => $lineNum,
|
||||
'token' => $tokenValue,
|
||||
'expected' => "{$property}: " . ($expectedValue === true ? 'true' : ($expectedValue === false ? 'false' : $expectedValue)),
|
||||
'actual' => "{$property}: " . ($actualValue === true ? 'true' : ($actualValue === false ? 'false' : ($actualValue ?? 'null'))),
|
||||
'match' => false
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $differences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare expected and actual tokens
|
||||
*/
|
||||
private function compareTokens(array $expected, array $actual): array
|
||||
{
|
||||
$differences = [];
|
||||
$allLines = array_unique(array_merge(array_keys($expected), array_keys($actual)));
|
||||
|
||||
foreach ($allLines as $lineNum) {
|
||||
$expectedTokens = $expected[$lineNum] ?? [];
|
||||
$actualTokens = $actual[$lineNum] ?? [];
|
||||
|
||||
// Check all expected tokens
|
||||
foreach ($expectedTokens as $tokenValue => $expectedTypeName) {
|
||||
$expectedType = TokenType::tryFrom($expectedTypeName);
|
||||
$actualType = $actualTokens[$tokenValue] ?? null;
|
||||
|
||||
$differences[] = [
|
||||
'line' => $lineNum,
|
||||
'token' => $tokenValue,
|
||||
'expected' => $expectedTypeName,
|
||||
'actual' => $actualType?->value ?? 'NOT_FOUND',
|
||||
'match' => $actualType === $expectedType
|
||||
];
|
||||
}
|
||||
|
||||
// Check for unexpected tokens (optional - could be verbose)
|
||||
foreach ($actualTokens as $tokenValue => $actualType) {
|
||||
if (!isset($expectedTokens[$tokenValue])) {
|
||||
// This token wasn't expected - could log as info
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $differences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all test cases
|
||||
*/
|
||||
private function getTestCases(): array
|
||||
{
|
||||
return array_merge(
|
||||
// Test Cases for Classes
|
||||
$this->getClassTestCases(),
|
||||
// Test Cases for Enums
|
||||
$this->getEnumTestCases(),
|
||||
// Test Cases for Attributes
|
||||
$this->getAttributeTestCases(),
|
||||
// Test Cases for Methods and Properties
|
||||
$this->getMethodPropertyTestCases(),
|
||||
// Test Cases for Metadata
|
||||
$this->getMetadataTestCases()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test cases for classes
|
||||
*/
|
||||
private function getClassTestCases(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'Simple Class',
|
||||
'code' => '<?php class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Final Class',
|
||||
'code' => '<?php final class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'final' => 'keyword_modifier',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Abstract Class',
|
||||
'code' => '<?php abstract class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'abstract' => 'keyword_modifier',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Readonly Class',
|
||||
'code' => '<?php readonly class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'readonly' => 'keyword_modifier',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Class with Extends',
|
||||
'code' => '<?php class Child extends Parent {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'class' => 'keyword_other',
|
||||
'Child' => 'class_name',
|
||||
'extends' => 'keyword_other',
|
||||
'Parent' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Class with Implements',
|
||||
'code' => '<?php class MyClass implements MyInterface {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
'implements' => 'keyword_other',
|
||||
'MyInterface' => 'interface_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Class with Multiple Modifiers',
|
||||
'code' => '<?php final readonly class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'final' => 'keyword_modifier',
|
||||
'readonly' => 'keyword_modifier',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Class with Extends and Implements',
|
||||
'code' => '<?php class Child extends Parent implements MyInterface {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'class' => 'keyword_other',
|
||||
'Child' => 'class_name',
|
||||
'extends' => 'keyword_other',
|
||||
'Parent' => 'class_name',
|
||||
'implements' => 'keyword_other',
|
||||
'MyInterface' => 'interface_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test cases for enums
|
||||
*/
|
||||
private function getEnumTestCases(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'Pure Enum',
|
||||
'code' => '<?php enum Status {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'enum' => 'keyword_other',
|
||||
'Status' => 'enum_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Backed Enum (String)',
|
||||
'code' => '<?php enum Status: string {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'enum' => 'keyword_other',
|
||||
'Status' => 'enum_name',
|
||||
':' => 'operator',
|
||||
'string' => 'keyword_type',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Backed Enum (Int)',
|
||||
'code' => '<?php enum Status: int {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'enum' => 'keyword_other',
|
||||
'Status' => 'enum_name',
|
||||
':' => 'operator',
|
||||
'int' => 'keyword_type',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Enum with Implements',
|
||||
'code' => '<?php enum Status implements MyInterface {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'enum' => 'keyword_other',
|
||||
'Status' => 'enum_name',
|
||||
'implements' => 'keyword_other',
|
||||
'MyInterface' => 'interface_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Final Enum',
|
||||
'code' => '<?php final enum Status {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'final' => 'keyword_modifier',
|
||||
'enum' => 'keyword_other',
|
||||
'Status' => 'enum_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Backed Enum with Implements',
|
||||
'code' => '<?php enum Status: string implements MyInterface {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'enum' => 'keyword_other',
|
||||
'Status' => 'enum_name',
|
||||
':' => 'operator',
|
||||
'string' => 'keyword_type',
|
||||
'implements' => 'keyword_other',
|
||||
'MyInterface' => 'interface_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test cases for attributes
|
||||
*/
|
||||
private function getAttributeTestCases(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'Simple Attribute',
|
||||
'code' => '<?php #[Route] class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'#' => 'attribute',
|
||||
'[' => 'bracket',
|
||||
'Route' => 'attribute_name',
|
||||
']' => 'bracket',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Attribute with Parameter',
|
||||
'code' => '<?php #[Route(\'/api\')] class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'#' => 'attribute',
|
||||
'[' => 'bracket',
|
||||
'Route' => 'attribute_name',
|
||||
'(' => 'parenthesis',
|
||||
'\'/api\'' => 'string_literal',
|
||||
')' => 'parenthesis',
|
||||
']' => 'bracket',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Attribute with Named Parameters',
|
||||
'code' => '<?php #[Route(path: \'/api\', method: \'GET\')] class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'#' => 'attribute',
|
||||
'[' => 'bracket',
|
||||
'Route' => 'attribute_name',
|
||||
'(' => 'parenthesis',
|
||||
'path' => 'attribute_name',
|
||||
':' => 'operator',
|
||||
'\'/api\'' => 'string_literal',
|
||||
',' => 'punctuation',
|
||||
'method' => 'attribute_name',
|
||||
':' => 'operator',
|
||||
'\'GET\'' => 'string_literal',
|
||||
')' => 'parenthesis',
|
||||
']' => 'bracket',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Multiple Attributes',
|
||||
'code' => '<?php #[Route, Auth] class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'#' => 'attribute',
|
||||
'[' => 'bracket',
|
||||
'Route' => 'attribute_name',
|
||||
',' => 'punctuation',
|
||||
'Auth' => 'attribute_name',
|
||||
']' => 'bracket',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Attribute with Multiple Parameters',
|
||||
'code' => '<?php #[Route(\'/api\', \'POST\')] class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'#' => 'attribute',
|
||||
'[' => 'bracket',
|
||||
'Route' => 'attribute_name',
|
||||
'(' => 'parenthesis',
|
||||
'\'/api\'' => 'string_literal',
|
||||
',' => 'punctuation',
|
||||
'\'POST\'' => 'string_literal',
|
||||
')' => 'parenthesis',
|
||||
']' => 'bracket',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Attribute with Class Parameter',
|
||||
'code' => '<?php #[Route(MyClass::class)] class MyClass {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'#' => 'attribute',
|
||||
'[' => 'bracket',
|
||||
'Route' => 'attribute_name',
|
||||
'(' => 'parenthesis',
|
||||
'MyClass' => 'class_name',
|
||||
'::' => 'operator',
|
||||
'class' => 'keyword_other',
|
||||
')' => 'parenthesis',
|
||||
']' => 'bracket',
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Attribute on Method',
|
||||
'code' => '<?php class MyClass { #[Route] public function test() {} }',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
'{' => 'brace',
|
||||
],
|
||||
2 => [
|
||||
'#' => 'attribute',
|
||||
'[' => 'bracket',
|
||||
'Route' => 'attribute_name',
|
||||
']' => 'bracket',
|
||||
'public' => 'keyword_modifier',
|
||||
'function' => 'keyword_other',
|
||||
'test' => 'method_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test cases for methods and properties
|
||||
*/
|
||||
private function getMethodPropertyTestCases(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'Static Method Call',
|
||||
'code' => '<?php MyClass::staticMethod();',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'MyClass' => 'class_name',
|
||||
'::' => 'operator',
|
||||
'staticMethod' => 'static_method_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Instance Method Call',
|
||||
'code' => '<?php $obj->instanceMethod();',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'$obj' => 'variable',
|
||||
'->' => 'operator',
|
||||
'instanceMethod' => 'instance_method_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Property Access',
|
||||
'code' => '<?php $obj->property;',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'$obj' => 'variable',
|
||||
'->' => 'operator',
|
||||
'property' => 'instance_property_name',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Static Property Access',
|
||||
'code' => '<?php MyClass::$staticProperty;',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'MyClass' => 'class_name',
|
||||
'::' => 'operator',
|
||||
'$staticProperty' => 'variable',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Constructor Call',
|
||||
'code' => '<?php new MyClass();',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'new' => 'keyword_other',
|
||||
'MyClass' => 'constructor_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Method Definition',
|
||||
'code' => '<?php public function myMethod() {}',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'public' => 'keyword_modifier',
|
||||
'function' => 'keyword_other',
|
||||
'myMethod' => 'function_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Method Definition in Class',
|
||||
'code' => '<?php class MyClass { public function myMethod() {} }',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
'{' => 'brace',
|
||||
],
|
||||
2 => [
|
||||
'public' => 'keyword_modifier',
|
||||
'function' => 'keyword_other',
|
||||
'myMethod' => 'method_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Constructor Definition',
|
||||
'code' => '<?php class MyClass { public function __construct() {} }',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
'{' => 'brace',
|
||||
],
|
||||
2 => [
|
||||
'public' => 'keyword_modifier',
|
||||
'function' => 'keyword_other',
|
||||
'__construct' => 'constructor_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Static Method Definition',
|
||||
'code' => '<?php class MyClass { public static function staticMethod() {} }',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'class' => 'keyword_other',
|
||||
'MyClass' => 'class_name',
|
||||
'{' => 'brace',
|
||||
],
|
||||
2 => [
|
||||
'public' => 'keyword_modifier',
|
||||
'static' => 'keyword_modifier',
|
||||
'function' => 'keyword_other',
|
||||
'staticMethod' => 'method_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Nullsafe Operator Method Call',
|
||||
'code' => '<?php $obj?->method();',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'$obj' => 'variable',
|
||||
'?->' => 'operator',
|
||||
'method' => 'instance_method_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test cases for metadata
|
||||
*/
|
||||
private function getMetadataTestCases(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'Built-in Function Call',
|
||||
'code' => '<?php count($array);',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'count' => 'function_name',
|
||||
'$array' => 'variable',
|
||||
],
|
||||
],
|
||||
'expectedMetadata' => [
|
||||
1 => [
|
||||
'count' => [
|
||||
'functionName' => 'count',
|
||||
'isBuiltIn' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Built-in Function strlen',
|
||||
'code' => '<?php strlen($str);',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'strlen' => 'function_name',
|
||||
'$str' => 'variable',
|
||||
],
|
||||
],
|
||||
'expectedMetadata' => [
|
||||
1 => [
|
||||
'strlen' => [
|
||||
'functionName' => 'strlen',
|
||||
'isBuiltIn' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Built-in Function array_map',
|
||||
'code' => '<?php array_map($callback, $array);',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'array_map' => 'function_name',
|
||||
'$callback' => 'variable',
|
||||
'$array' => 'variable',
|
||||
],
|
||||
],
|
||||
'expectedMetadata' => [
|
||||
1 => [
|
||||
'array_map' => [
|
||||
'functionName' => 'array_map',
|
||||
'isBuiltIn' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'User Function Call',
|
||||
'code' => '<?php myFunction();',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'myFunction' => 'function_name',
|
||||
'(' => 'parenthesis',
|
||||
')' => 'parenthesis',
|
||||
],
|
||||
],
|
||||
'expectedMetadata' => [
|
||||
1 => [
|
||||
'myFunction' => [
|
||||
'functionName' => 'myFunction',
|
||||
'isBuiltIn' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Static Method Call with Metadata',
|
||||
'code' => '<?php MyClass::staticMethod();',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'MyClass' => 'class_name',
|
||||
'::' => 'operator',
|
||||
'staticMethod' => 'static_method_name',
|
||||
],
|
||||
],
|
||||
'expectedMetadata' => [
|
||||
1 => [
|
||||
'MyClass' => [
|
||||
'className' => 'MyClass',
|
||||
],
|
||||
'staticMethod' => [
|
||||
'functionName' => 'staticMethod',
|
||||
'className' => 'MyClass',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Instance Method Call with Metadata',
|
||||
'code' => '<?php $obj->instanceMethod();',
|
||||
'expected' => [
|
||||
1 => [
|
||||
'$obj' => 'variable',
|
||||
'->' => 'operator',
|
||||
'instanceMethod' => 'instance_method_name',
|
||||
],
|
||||
],
|
||||
'expectedMetadata' => [
|
||||
1 => [
|
||||
'instanceMethod' => [
|
||||
'functionName' => 'instanceMethod',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Run tests if executed directly
|
||||
if (php_sapi_name() === 'cli') {
|
||||
$test = new TokenClassificationTest();
|
||||
$test->runAll();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user