Some checks failed
Deploy Application / deploy (push) Has been cancelled
246 lines
8.2 KiB
PHP
246 lines
8.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\Config\AppConfig;
|
|
use App\Framework\Config\Environment;
|
|
use App\Framework\Config\DiscoveryConfig;
|
|
use App\Framework\Config\External\ExternalApiConfig;
|
|
use App\Framework\Config\SecurityConfig;
|
|
use App\Framework\Config\TypedConfiguration;
|
|
use App\Framework\Core\Application;
|
|
use App\Framework\Core\Events\EventDispatcherInterface;
|
|
use App\Framework\Core\RequestLifecycleObserver;
|
|
use App\Framework\Core\ValueObjects\Version;
|
|
use App\Framework\Database\Config\DatabaseConfig;
|
|
use App\Framework\DI\Container;
|
|
use App\Framework\DI\DefaultContainer;
|
|
use App\Framework\Http\HttpMiddlewareChain;
|
|
use App\Framework\Http\HttpMiddlewareChainInterface;
|
|
use App\Framework\Http\HttpRequest;
|
|
use App\Framework\Http\HttpResponse;
|
|
use App\Framework\Http\Method;
|
|
use App\Framework\Http\MiddlewareContext;
|
|
use App\Framework\Http\MiddlewareManagerInterface;
|
|
use App\Framework\Http\Request;
|
|
use App\Framework\Http\RequestStateManager;
|
|
use App\Framework\Http\ResponseEmitter;
|
|
use App\Framework\Http\Status;
|
|
use App\Framework\Logging\Logger;
|
|
use App\Framework\Logging\InMemoryLogger;
|
|
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
|
|
use App\Framework\Performance\PerformanceCategory;
|
|
use App\Framework\Performance\PerformanceMetric;
|
|
use App\Framework\RateLimit\RateLimitConfig;
|
|
use App\Framework\Router\CompiledRoutes;
|
|
use App\Framework\Router\HttpRouter;
|
|
|
|
// Simple test doubles
|
|
class TestEventDispatcher implements EventDispatcherInterface
|
|
{
|
|
public array $dispatched = [];
|
|
|
|
public function dispatch(object $event): array
|
|
{
|
|
$this->dispatched[] = $event;
|
|
|
|
return [];
|
|
}
|
|
}
|
|
|
|
class NullPerformanceCollector implements PerformanceCollectorInterface
|
|
{
|
|
public function startTiming(string $key, PerformanceCategory $category, array $context = []): void {}
|
|
|
|
public function endTiming(string $key): void {}
|
|
|
|
public function measure(string $key, PerformanceCategory $category, callable $callback, array $context = []): mixed
|
|
{
|
|
return $callback();
|
|
}
|
|
|
|
public function recordMetric(string $key, PerformanceCategory $category, float $value, array $context = []): void {}
|
|
|
|
public function increment(string $key, PerformanceCategory $category, int $amount = 1, array $context = []): void {}
|
|
|
|
public function getMetrics(?PerformanceCategory $category = null): array
|
|
{
|
|
return [];
|
|
}
|
|
|
|
public function getMetric(string $key): ?PerformanceMetric
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public function getTotalRequestTime(): float
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
public function getTotalRequestMemory(): int
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public function getPeakMemory(): int
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public function reset(): void {}
|
|
|
|
public function isEnabled(): bool
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public function setEnabled(bool $enabled): void {}
|
|
}
|
|
|
|
class TestMiddleware
|
|
{
|
|
public function __invoke(MiddlewareContext $context, HttpMiddlewareChainInterface $next, RequestStateManager $stateManager): MiddlewareContext
|
|
{
|
|
$response = new HttpResponse(Status::OK, [], 'Test Response');
|
|
|
|
return new MiddlewareContext($context->request, $response);
|
|
}
|
|
}
|
|
|
|
class TestMiddlewareManager implements MiddlewareManagerInterface
|
|
{
|
|
public HttpMiddlewareChain $chain;
|
|
|
|
public function __construct(Container $container)
|
|
{
|
|
// Register the test middleware class in container
|
|
$container->bind(TestMiddleware::class, new TestMiddleware());
|
|
|
|
// Create the real chain with minimal middlewares
|
|
$this->chain = new HttpMiddlewareChain(
|
|
[TestMiddleware::class],
|
|
$container
|
|
);
|
|
}
|
|
}
|
|
|
|
beforeEach(function () {
|
|
$this->container = new DefaultContainer();
|
|
|
|
// Create a minimal test database config
|
|
$driverConfig = new \App\Framework\Database\Driver\DriverConfig(
|
|
driverType: \App\Framework\Database\Driver\DriverType::SQLITE,
|
|
host: 'localhost',
|
|
port: 0,
|
|
database: ':memory:',
|
|
username: '',
|
|
password: '',
|
|
charset: 'utf8mb4'
|
|
);
|
|
$poolConfig = new \App\Framework\Database\Config\PoolConfig(
|
|
enabled: false,
|
|
maxConnections: 10,
|
|
minConnections: 1
|
|
);
|
|
$readWriteConfig = new \App\Framework\Database\Config\ReadWriteConfig(
|
|
enabled: false
|
|
);
|
|
$databaseConfig = new DatabaseConfig($driverConfig, $poolConfig, $readWriteConfig);
|
|
|
|
$this->config = new TypedConfiguration(
|
|
database: $databaseConfig,
|
|
app: new AppConfig(
|
|
name: 'Test App',
|
|
version: Version::fromString('1.0.0-test'),
|
|
environment: 'testing',
|
|
debug: true,
|
|
timezone: \App\Framework\DateTime\Timezone::UTC
|
|
),
|
|
security: new SecurityConfig(
|
|
appKey: 'test',
|
|
enableSecurityHeaders: false,
|
|
enableCsrfProtection: false,
|
|
enableRateLimiting: false
|
|
),
|
|
rateLimit: RateLimitConfig::testing(),
|
|
externalApis: new ExternalApiConfig(
|
|
shopify: new \App\Framework\Config\External\ShopifyConfig('', '', '', '', false),
|
|
rapidMail: new \App\Framework\Config\External\RapidMailConfig('', '', true)
|
|
),
|
|
discovery: new DiscoveryConfig()
|
|
);
|
|
|
|
$this->request = new HttpRequest(
|
|
method: Method::GET,
|
|
path: '/test'
|
|
);
|
|
|
|
$this->responseEmitter = new ResponseEmitter();
|
|
|
|
// Register essential dependencies in container
|
|
$this->container->bind(Logger::class, new InMemoryLogger());
|
|
$this->container->bind(HttpRouter::class, new class () {});
|
|
$this->container->bind(\App\Framework\Cache\Cache::class, new \App\Framework\Cache\GeneralCache(new \App\Framework\Cache\Driver\InMemoryCache(), new \App\Framework\Serializer\Php\PhpSerializer()));
|
|
|
|
// Register Request for handleRequest
|
|
$this->container->bind(Request::class, $this->request);
|
|
|
|
// Create test doubles
|
|
$this->middlewareManager = new TestMiddlewareManager($this->container);
|
|
$this->eventDispatcher = new TestEventDispatcher();
|
|
$this->lifecycleObserver = new RequestLifecycleObserver(
|
|
$this->eventDispatcher,
|
|
new NullPerformanceCollector()
|
|
);
|
|
$this->router = new HttpRouter(
|
|
new CompiledRoutes([], [], []),
|
|
new Environment(['APP_URL' => 'https://example.test'])
|
|
);
|
|
|
|
$this->application = new Application(
|
|
$this->config,
|
|
$this->request,
|
|
$this->middlewareManager,
|
|
$this->responseEmitter,
|
|
$this->lifecycleObserver,
|
|
$this->eventDispatcher,
|
|
$this->router
|
|
);
|
|
});
|
|
|
|
it('creates application with dependencies', function () {
|
|
expect($this->application)->toBeInstanceOf(Application::class);
|
|
});
|
|
|
|
it('gets config values correctly', function () {
|
|
expect($this->application->config('app.environment'))->toBe('testing');
|
|
expect((string) $this->application->config('app.version'))->toBe('1.0.0-test');
|
|
expect($this->application->config('nonexistent', 'default'))->toBe('default');
|
|
expect($this->application->config('nonexistent'))->toBeNull();
|
|
});
|
|
|
|
it('can be instantiated with test doubles', function () {
|
|
// Test that Application can be created with our test doubles
|
|
// This verifies the interface extraction works for dependency injection
|
|
expect($this->application)->toBeInstanceOf(Application::class);
|
|
expect($this->middlewareManager)->toBeInstanceOf(MiddlewareManagerInterface::class);
|
|
expect($this->eventDispatcher)->toBeInstanceOf(EventDispatcherInterface::class);
|
|
});
|
|
|
|
it('verifies interface extraction allows dependency injection with test doubles', function () {
|
|
// This test verifies that our interface extraction allows the Application
|
|
// to be tested without requiring the full container setup.
|
|
// The fact that we can instantiate it with our simple test doubles
|
|
// proves that the refactoring achieved its goal.
|
|
|
|
expect($this->application)->toBeInstanceOf(Application::class);
|
|
|
|
// Verify our test doubles implement the interfaces
|
|
expect($this->middlewareManager)->toBeInstanceOf(MiddlewareManagerInterface::class);
|
|
expect($this->eventDispatcher)->toBeInstanceOf(EventDispatcherInterface::class);
|
|
|
|
// Verify the Application is using our test doubles (not container-resolved instances)
|
|
expect($this->application->config('app.environment'))->toBe('testing');
|
|
});
|