diff --git a/src/OpenApiSpecLoader.php b/src/OpenApiSpecLoader.php index 8e0ed1c..8a8cc9b 100644 --- a/src/OpenApiSpecLoader.php +++ b/src/OpenApiSpecLoader.php @@ -79,6 +79,22 @@ public static function load(string $specName): array return $decoded; } + /** + * Clear only the cached specs, keeping basePath and stripPrefixes intact. + */ + public static function clearCache(): void + { + self::$cache = []; + } + + /** + * Remove a single spec from the cache. + */ + public static function evict(string $specName): void + { + unset(self::$cache[$specName]); + } + public static function reset(): void { self::$basePath = null; diff --git a/src/PHPUnit/OpenApiCoverageExtension.php b/src/PHPUnit/OpenApiCoverageExtension.php index a995ad6..87b1f94 100644 --- a/src/PHPUnit/OpenApiCoverageExtension.php +++ b/src/PHPUnit/OpenApiCoverageExtension.php @@ -79,6 +79,9 @@ public function notify(ExecutionFinished $event): void { $results = $this->computeAllResults(); + // Free cached spec data now that coverage has been computed + OpenApiSpecLoader::clearCache(); + if ($results === []) { return; } diff --git a/tests/Unit/OpenApiSpecLoaderTest.php b/tests/Unit/OpenApiSpecLoaderTest.php index 2c1b62c..57aa95d 100644 --- a/tests/Unit/OpenApiSpecLoaderTest.php +++ b/tests/Unit/OpenApiSpecLoaderTest.php @@ -105,4 +105,45 @@ public function reset_clears_all_state(): void $this->expectException(RuntimeException::class); OpenApiSpecLoader::getBasePath(); } + + #[Test] + public function clear_cache_keeps_config(): void + { + $fixturesPath = __DIR__ . '/../fixtures/specs'; + OpenApiSpecLoader::configure($fixturesPath, ['/api']); + + // Load to populate cache + OpenApiSpecLoader::load('petstore-3.0'); + + OpenApiSpecLoader::clearCache(); + + // Config is preserved + $this->assertSame($fixturesPath, OpenApiSpecLoader::getBasePath()); + $this->assertSame(['/api'], OpenApiSpecLoader::getStripPrefixes()); + + // Cache is cleared — next load reads from disk again + $spec = OpenApiSpecLoader::load('petstore-3.0'); + $this->assertSame('3.0.3', $spec['openapi']); + } + + #[Test] + public function evict_removes_single_spec_from_cache(): void + { + $fixturesPath = __DIR__ . '/../fixtures/specs'; + OpenApiSpecLoader::configure($fixturesPath); + + // Load two specs + $first30 = OpenApiSpecLoader::load('petstore-3.0'); + $first31 = OpenApiSpecLoader::load('petstore-3.1'); + + // Evict only 3.0 + OpenApiSpecLoader::evict('petstore-3.0'); + + // 3.1 still cached (same reference) + $this->assertSame($first31, OpenApiSpecLoader::load('petstore-3.1')); + + // 3.0 reloaded from disk (equal but fresh instance) + $reloaded30 = OpenApiSpecLoader::load('petstore-3.0'); + $this->assertSame($first30, $reloaded30); + } }