cache = new GeneralCache($cacheDriver, $serializer); $this->clock = new SystemClock(); $this->fileSystemService = new FileSystemService(); $this->reflectionProvider = new CachedReflectionProvider(); $basePath = file_exists('/var/www/html/src') ? '/var/www/html' : dirname(__DIR__, 5); $this->pathProvider = new PathProvider($basePath); $this->discoveryContext = new DiscoveryContext( paths: [$this->pathProvider->getSourcePath()->toString()], scanType: ScanType::FULL, options: DiscoveryOptions::default(), startTime: $this->clock->now(), executionContext: null ); $this->cacheManager = new DiscoveryCacheManager( cache: $this->cache, clock: $this->clock, fileSystemService: $this->fileSystemService, logger: null, ttlHours: 24 ); // Perform discovery to create cache $configuration = new DiscoveryConfiguration( paths: [$this->pathProvider->getSourcePath()], useCache: true, enableMemoryMonitoring: false, memoryLimitMB: 128, maxFilesPerBatch: 100 ); $discoveryService = new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $configuration ); $this->discoveredRegistry = $discoveryService->discover(); // Store in cache $this->cacheManager->store($this->discoveryContext, $this->discoveredRegistry); }); test('discovery cache can be loaded', function () { $cachedRegistry = $this->cacheManager->get($this->discoveryContext); expect($cachedRegistry)->not->toBeNull() ->and($cachedRegistry)->toBeInstanceOf(DiscoveryRegistry::class); })->skip('Requires existing cache'); test('cached registry has content', function () { $cachedRegistry = $this->cacheManager->get($this->discoveryContext); if ($cachedRegistry === null) { $this->markTestSkipped('No cached registry found - run discovery first'); } expect($cachedRegistry->hasContent())->toBeTrue() ->and($cachedRegistry->isEmpty())->toBeFalse(); }); test('cached registry contains routes', function () { $cachedRegistry = $this->cacheManager->get($this->discoveryContext); if ($cachedRegistry === null) { $this->markTestSkipped('No cached registry found - run discovery first'); } $routeClass = Route::class; $routeAttributes = $cachedRegistry->attributes->get($routeClass); expect($routeAttributes)->toBeArray() ->and(count($routeAttributes))->toBeGreaterThan(0); }); test('route attributes are correctly deserialized', function () { $cachedRegistry = $this->cacheManager->get($this->discoveryContext); if ($cachedRegistry === null) { $this->markTestSkipped('No cached registry found - run discovery first'); } $routeClass = Route::class; $routeAttributes = $cachedRegistry->attributes->get($routeClass); if (empty($routeAttributes)) { $this->markTestSkipped('No routes found in cache'); } $firstRoute = $routeAttributes[0]; expect($firstRoute)->toBeInstanceOf(\App\Framework\Discovery\ValueObjects\DiscoveredAttribute::class) ->and($firstRoute->className)->toBeInstanceOf(\App\Framework\Core\ValueObjects\ClassName::class) ->and($firstRoute->attributeClass)->toBe($routeClass); }); test('route attributes can create route instances', function () { $cachedRegistry = $this->cacheManager->get($this->discoveryContext); if ($cachedRegistry === null) { $this->markTestSkipped('No cached registry found - run discovery first'); } $routeClass = Route::class; $routeAttributes = $cachedRegistry->attributes->get($routeClass); if (empty($routeAttributes)) { $this->markTestSkipped('No routes found in cache'); } $firstRoute = $routeAttributes[0]; expect($firstRoute)->toBeInstanceOf(\App\Framework\Discovery\ValueObjects\DiscoveredAttribute::class); // Try to create Route instance from arguments try { $routeInstance = new Route(...$firstRoute->arguments); expect($routeInstance)->toBeInstanceOf(Route::class); } catch (\Throwable $e) { $this->fail("Failed to create Route instance: {$e->getMessage()}"); } }); test('registry can be serialized and deserialized', function () { $cachedRegistry = $this->cacheManager->get($this->discoveryContext); if ($cachedRegistry === null) { $this->markTestSkipped('No cached registry found - run discovery first'); } $routeClass = Route::class; $originalRouteCount = count($cachedRegistry->attributes->get($routeClass)); // Serialize and deserialize $serialized = serialize($cachedRegistry); $deserialized = unserialize($serialized); expect($deserialized)->toBeInstanceOf(DiscoveryRegistry::class); $deserializedRouteCount = count($deserialized->attributes->get($routeClass)); expect($deserializedRouteCount)->toBe($originalRouteCount); }); test('cached registry content summary is accurate', function () { $cachedRegistry = $this->cacheManager->get($this->discoveryContext); if ($cachedRegistry === null) { $this->markTestSkipped('No cached registry found - run discovery first'); } $summary = $cachedRegistry->getContentSummary(); expect($summary)->toBeArray() ->and($summary)->toHaveKey('routes') ->and($summary)->toHaveKey('commands') ->and($summary)->toHaveKey('initializers'); // Verify route count matches actual count $routeClass = Route::class; $actualRouteCount = count($cachedRegistry->attributes->get($routeClass)); expect($summary['routes'])->toBe($actualRouteCount); }); test('all attribute types are accessible', function () { $cachedRegistry = $this->cacheManager->get($this->discoveryContext); if ($cachedRegistry === null) { $this->markTestSkipped('No cached registry found - run discovery first'); } $allTypes = $cachedRegistry->attributes->getAllTypes(); expect($allTypes)->toBeArray(); // Verify we can access each type foreach ($allTypes as $type) { $attributes = $cachedRegistry->attributes->get($type); $count = $cachedRegistry->attributes->getCount($type); expect($attributes)->toBeArray() ->and($count)->toBe(count($attributes)); } }); test('cache entry can be retrieved directly', function () { $cacheKey = $this->discoveryContext->getCacheKey(); $cacheResult = $this->cache->get($cacheKey); if (!$cacheResult->isHit) { $this->markTestSkipped('No cache entry found - run discovery first'); } $cachedData = $cacheResult->value; expect($cachedData)->not->toBeNull(); if (is_array($cachedData)) { expect($cachedData)->toHaveKey('registry'); } });