- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
198 lines
4.6 KiB
PHP
198 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\Discovery\Processing\ClassExtractor;
|
|
use App\Framework\Filesystem\File;
|
|
use App\Framework\Filesystem\FileSystemService;
|
|
|
|
beforeEach(function () {
|
|
$this->fileSystem = new FileSystemService();
|
|
$this->extractor = new ClassExtractor($this->fileSystem);
|
|
$this->tmpDir = '/var/www/html/tests/tmp';
|
|
|
|
if (! is_dir($this->tmpDir)) {
|
|
mkdir($this->tmpDir, 0777, true);
|
|
}
|
|
|
|
$this->createTestFile = function (string $filename, string $content): File {
|
|
$filepath = $this->tmpDir . '/' . $filename;
|
|
file_put_contents($filepath, $content);
|
|
|
|
$spl = new SplFileInfo($filepath);
|
|
|
|
return File::fromSplFileInfo($spl);
|
|
};
|
|
});
|
|
|
|
afterEach(function () {
|
|
// Clean up test files
|
|
if (is_dir($this->tmpDir)) {
|
|
$files = glob($this->tmpDir . '/*');
|
|
foreach ($files as $file) {
|
|
if (is_file($file)) {
|
|
unlink($file);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
describe('ClassExtractor', function () {
|
|
it('extracts classes from PHP file', function () {
|
|
$content = <<<'PHP'
|
|
<?php
|
|
|
|
namespace App\Test;
|
|
|
|
final readonly class TestClass
|
|
{
|
|
public function test(): void {}
|
|
}
|
|
PHP;
|
|
|
|
$file = ($this->createTestFile)('TestClass.php', $content);
|
|
$classes = $this->extractor->extractFromFile($file);
|
|
|
|
expect($classes)->toHaveCount(1);
|
|
expect($classes[0]->getFullyQualified())->toBe('App\Test\TestClass');
|
|
});
|
|
|
|
it('returns empty array for HTML template files without PHP tags', function () {
|
|
$content = <<<'HTML'
|
|
<layout name="layouts/main" />
|
|
|
|
<div class="section">
|
|
<h2>Dashboard</h2>
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<h3>Status</h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
HTML;
|
|
|
|
$file = ($this->createTestFile)('template.view.php', $content);
|
|
$classes = $this->extractor->extractFromFile($file);
|
|
|
|
expect($classes)->toHaveCount(0);
|
|
});
|
|
|
|
it('extracts multiple classes from file', function () {
|
|
$content = <<<'PHP'
|
|
<?php
|
|
|
|
namespace App\Test;
|
|
|
|
interface TestInterface {}
|
|
|
|
final readonly class TestClass implements TestInterface {}
|
|
|
|
trait TestTrait {}
|
|
|
|
enum TestEnum {
|
|
case CASE_ONE;
|
|
}
|
|
PHP;
|
|
|
|
$file = ($this->createTestFile)('Multiple.php', $content);
|
|
$classes = $this->extractor->extractFromFile($file);
|
|
|
|
expect($classes)->toHaveCount(4);
|
|
});
|
|
|
|
it('handles files with short PHP tags', function () {
|
|
$content = <<<'PHP'
|
|
<?= "test" ?>
|
|
<?php
|
|
|
|
class ShortTagTest {}
|
|
PHP;
|
|
|
|
$file = ($this->createTestFile)('ShortTag.php', $content);
|
|
$classes = $this->extractor->extractFromFile($file);
|
|
|
|
expect($classes)->toHaveCount(1);
|
|
});
|
|
|
|
it('extracts detailed class information', function () {
|
|
$content = <<<'PHP'
|
|
<?php
|
|
|
|
namespace App\Test;
|
|
|
|
final readonly class DetailedClass
|
|
{
|
|
public function method(): void {}
|
|
}
|
|
PHP;
|
|
|
|
$file = ($this->createTestFile)('Detailed.php', $content);
|
|
$detailed = $this->extractor->extractDetailedFromFile($file);
|
|
|
|
expect($detailed)->toHaveCount(1);
|
|
expect($detailed[0]['type'])->toBe('class');
|
|
expect($detailed[0]['name'])->toBe('DetailedClass');
|
|
expect($detailed[0]['namespace'])->toBe('App\Test');
|
|
expect($detailed[0]['fqn'])->toBe('App\Test\DetailedClass');
|
|
});
|
|
|
|
it('returns empty array for files with syntax errors', function () {
|
|
$content = <<<'PHP'
|
|
<?php
|
|
|
|
class InvalidClass {
|
|
// Missing closing brace
|
|
PHP;
|
|
|
|
$file = ($this->createTestFile)('Invalid.php', $content);
|
|
$classes = $this->extractor->extractFromFile($file);
|
|
|
|
expect($classes)->toHaveCount(0);
|
|
});
|
|
|
|
it('analyzes complete file structure', function () {
|
|
$content = <<<'PHP'
|
|
<?php
|
|
|
|
namespace App\Test;
|
|
|
|
use App\Framework\Core\Application;
|
|
|
|
final readonly class AnalysisTest
|
|
{
|
|
public function __construct(
|
|
private Application $app
|
|
) {}
|
|
}
|
|
PHP;
|
|
|
|
$file = ($this->createTestFile)('Analysis.php', $content);
|
|
$analysis = $this->extractor->analyzeFile($file);
|
|
|
|
expect($analysis)->toHaveKeys(['classes', 'functions', 'attributes', 'uses']);
|
|
expect($analysis['classes'])->toHaveCount(1);
|
|
expect($analysis['uses'])->toHaveCount(1);
|
|
});
|
|
|
|
it('does not extract from pure HTML without PHP tags', function () {
|
|
$content = <<<'HTML'
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Test</title>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>Title</h1>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
HTML;
|
|
|
|
$file = ($this->createTestFile)('pure.html', $content);
|
|
$classes = $this->extractor->extractFromFile($file);
|
|
|
|
expect($classes)->toHaveCount(0);
|
|
});
|
|
});
|