cache = new GeneralCache($cacheDriver, $serializer); $this->clock = new SystemClock(); $this->pathProvider = new PathProvider('/home/michael/dev/michaelschiemer'); $this->reflectionProvider = new CachedReflectionProvider(); $this->configuration = new DiscoveryConfiguration( paths: ['/home/michael/dev/michaelschiemer/tests/fixtures'], useCache: false, // Disable cache for tests enableMemoryMonitoring: false, memoryLimitMB: 64, maxFilesPerBatch: 100 ); // Clear cache between tests $this->cache->clear(); }); it('can be instantiated with required dependencies', function () { $service = new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $this->configuration ); expect($service)->toBeInstanceOf(UnifiedDiscoveryService::class); }); it('performs discovery and returns DiscoveryRegistry', function () { $service = new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $this->configuration ); $registry = $service->discover(); expect($registry)->toBeInstanceOf(DiscoveryRegistry::class); expect($registry->attributes)->toBeInstanceOf(\App\Framework\Discovery\Results\AttributeRegistry::class); expect($registry->interfaces)->toBeInstanceOf(\App\Framework\Discovery\Results\InterfaceRegistry::class); }); it('handles empty scan paths gracefully', function () { $emptyConfig = new DiscoveryConfiguration( paths: [], useCache: false, enableMemoryMonitoring: false, memoryLimitMB: 64, maxFilesPerBatch: 100 ); $service = new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $emptyConfig ); $registry = $service->discover(); expect($registry)->toBeInstanceOf(DiscoveryRegistry::class); // Empty paths should still return a valid registry, just empty expect($registry->attributes->getAll())->toBeArray(); }); it('supports incremental discovery', function () { $service = new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $this->configuration ); $registry = $service->incrementalDiscover(); expect($registry)->toBeInstanceOf(DiscoveryRegistry::class); }); it('validates configuration on instantiation', function () { $invalidConfig = new DiscoveryConfiguration( paths: ['/nonexistent/path'], useCache: false, enableMemoryMonitoring: false, memoryLimitMB: -1, // Invalid memory limit maxFilesPerBatch: 0 // Invalid batch size ); expect(function () { new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $invalidConfig ); })->toThrow(\InvalidArgumentException::class); }); it('handles memory management configuration', function () { $memoryConfig = new DiscoveryConfiguration( paths: ['/home/michael/dev/michaelschiemer/src'], useCache: false, enableMemoryMonitoring: true, memoryLimitMB: 32, // 32MB limit maxFilesPerBatch: 50 ); $service = new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $memoryConfig ); expect($service)->toBeInstanceOf(UnifiedDiscoveryService::class); // Should not throw memory errors with management enabled $registry = $service->discover(); expect($registry)->toBeInstanceOf(DiscoveryRegistry::class); }); it('respects chunk size in configuration', function () { $smallChunkConfig = new DiscoveryConfiguration( paths: ['/home/michael/dev/michaelschiemer/tests'], useCache: false, enableMemoryMonitoring: false, memoryLimitMB: 64, maxFilesPerBatch: 5 // Very small batches ); $service = new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $smallChunkConfig ); $registry = $service->discover(); expect($registry)->toBeInstanceOf(DiscoveryRegistry::class); // Should handle small chunks without issues }); it('handles file system errors gracefully', function () { $invalidPathConfig = new DiscoveryConfiguration( paths: ['/completely/nonexistent/path'], useCache: false, enableMemoryMonitoring: false, memoryLimitMB: 64, maxFilesPerBatch: 100 ); $service = new UnifiedDiscoveryService( pathProvider: $this->pathProvider, cache: $this->cache, clock: $this->clock, reflectionProvider: $this->reflectionProvider, configuration: $invalidPathConfig ); // Should not throw but return empty registry $registry = $service->discover(); expect($registry)->toBeInstanceOf(DiscoveryRegistry::class); }); });