diff --git a/README.md b/README.md
index 42b96b3..e95d2b8 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,7 @@ Add the coverage extension to your `phpunit.xml`:
| `strip_prefixes` | No | `[]` | Comma-separated prefixes to strip from request paths (e.g., `/api`) |
| `specs` | No | `front` | Comma-separated spec names for coverage tracking |
| `output_file` | No | — | File path to write Markdown coverage report (relative paths resolve from `getcwd()`) |
+| `console_output` | No | `default` | Console output mode: `default`, `all`, or `uncovered_only` (overridden by `OPENAPI_CONSOLE_OUTPUT` env var) |
*Not required if you call `OpenApiSpecLoader::configure()` manually.
@@ -163,7 +164,11 @@ For Laravel, set the `max_errors` key in `config/openapi-contract-testing.php`.
## Coverage Report
-After running tests, the PHPUnit extension prints a coverage report:
+After running tests, the PHPUnit extension prints a coverage report. The output format is controlled by the `console_output` parameter (or `OPENAPI_CONSOLE_OUTPUT` environment variable).
+
+### `default` mode (default)
+
+Shows covered endpoints individually and uncovered as a count:
```
OpenAPI Contract Test Coverage
@@ -179,6 +184,56 @@ Covered:
Uncovered: 41 endpoints
```
+### `all` mode
+
+Shows both covered and uncovered endpoints individually:
+
+```
+OpenAPI Contract Test Coverage
+==================================================
+
+[front] 12/45 endpoints (26.7%)
+--------------------------------------------------
+Covered:
+ ✓ GET /v1/pets
+ ✓ POST /v1/pets
+ ✓ GET /v1/pets/{petId}
+ ✓ DELETE /v1/pets/{petId}
+Uncovered:
+ ✗ PUT /v1/pets/{petId}
+ ✗ GET /v1/owners
+ ...
+```
+
+### `uncovered_only` mode
+
+Shows uncovered endpoints individually and covered as a count — useful for large APIs where you want to focus on missing coverage:
+
+```
+OpenAPI Contract Test Coverage
+==================================================
+
+[front] 12/45 endpoints (26.7%)
+--------------------------------------------------
+Covered: 12 endpoints
+Uncovered:
+ ✗ PUT /v1/pets/{petId}
+ ✗ GET /v1/owners
+ ...
+```
+
+You can set the mode via `phpunit.xml`:
+
+```xml
+
+```
+
+Or via environment variable (takes priority over `phpunit.xml`):
+
+```bash
+OPENAPI_CONSOLE_OUTPUT=uncovered_only vendor/bin/phpunit
+```
+
## CI Integration
### GitHub Actions Step Summary
@@ -201,6 +256,15 @@ Use the `output_file` parameter to write a Markdown report to a file. This is us
```
+You can also use the `OPENAPI_CONSOLE_OUTPUT` environment variable in CI to show uncovered endpoints in the job log:
+
+```yaml
+- name: Run tests (show uncovered endpoints)
+ run: vendor/bin/phpunit
+ env:
+ OPENAPI_CONSOLE_OUTPUT: uncovered_only
+```
+
Example GitHub Actions workflow step to post the report as a PR comment:
```yaml
diff --git a/src/PHPUnit/ConsoleCoverageRenderer.php b/src/PHPUnit/ConsoleCoverageRenderer.php
new file mode 100644
index 0000000..e39f8ce
--- /dev/null
+++ b/src/PHPUnit/ConsoleCoverageRenderer.php
@@ -0,0 +1,94 @@
+ $results
+ */
+ public static function render(array $results, ConsoleOutput $consoleOutput = ConsoleOutput::DEFAULT): string
+ {
+ if ($results === []) {
+ return '';
+ }
+
+ $output = "\n\n";
+ $output .= "OpenAPI Contract Test Coverage\n";
+ $output .= str_repeat('=', 50) . "\n";
+
+ foreach ($results as $spec => $result) {
+ $percentage = self::percentage($result['coveredCount'], $result['total']);
+
+ $output .= "\n[{$spec}] {$result['coveredCount']}/{$result['total']} endpoints ({$percentage}%)\n";
+ $output .= str_repeat('-', 50) . "\n";
+
+ $output .= self::renderCovered($result, $consoleOutput);
+ $output .= self::renderUncovered($result, $consoleOutput);
+ }
+
+ $output .= "\n";
+
+ return $output;
+ }
+
+ /**
+ * @param CoverageResult $result
+ */
+ private static function renderCovered(array $result, ConsoleOutput $consoleOutput): string
+ {
+ if ($result['covered'] === []) {
+ return '';
+ }
+
+ if ($consoleOutput === ConsoleOutput::UNCOVERED_ONLY) {
+ return "Covered: {$result['coveredCount']} endpoints\n";
+ }
+
+ $output = "Covered:\n";
+
+ foreach ($result['covered'] as $endpoint) {
+ $output .= " ✓ {$endpoint}\n";
+ }
+
+ return $output;
+ }
+
+ /**
+ * @param CoverageResult $result
+ */
+ private static function renderUncovered(array $result, ConsoleOutput $consoleOutput): string
+ {
+ if ($result['uncovered'] === []) {
+ return '';
+ }
+
+ $uncoveredCount = count($result['uncovered']);
+
+ if ($consoleOutput === ConsoleOutput::DEFAULT) {
+ return "Uncovered: {$uncoveredCount} endpoints\n";
+ }
+
+ $output = "Uncovered:\n";
+
+ foreach ($result['uncovered'] as $endpoint) {
+ $output .= " ✗ {$endpoint}\n";
+ }
+
+ return $output;
+ }
+
+ private static function percentage(int $covered, int $total): float|int
+ {
+ return $total > 0 ? round($covered / $total * 100, 1) : 0;
+ }
+}
diff --git a/src/PHPUnit/ConsoleOutput.php b/src/PHPUnit/ConsoleOutput.php
new file mode 100644
index 0000000..aca7096
--- /dev/null
+++ b/src/PHPUnit/ConsoleOutput.php
@@ -0,0 +1,51 @@
+ parameter > DEFAULT.
+ */
+ public static function resolve(?string $parameterValue): self
+ {
+ $envValue = getenv('OPENAPI_CONSOLE_OUTPUT');
+
+ if ($envValue !== false && trim($envValue) !== '') {
+ $resolved = self::tryFrom(mb_strtolower(trim($envValue)));
+
+ if ($resolved === null) {
+ fwrite(STDERR, "[OpenAPI Coverage] WARNING: Invalid OPENAPI_CONSOLE_OUTPUT value '{$envValue}'. Valid values: default, all, uncovered_only. Falling back to 'default'.\n");
+ }
+
+ return $resolved ?? self::DEFAULT;
+ }
+
+ if ($parameterValue !== null && trim($parameterValue) !== '') {
+ $resolved = self::tryFrom(mb_strtolower(trim($parameterValue)));
+
+ if ($resolved === null) {
+ fwrite(STDERR, "[OpenAPI Coverage] WARNING: Invalid console_output parameter '{$parameterValue}'. Valid values: default, all, uncovered_only. Falling back to 'default'.\n");
+ }
+
+ return $resolved ?? self::DEFAULT;
+ }
+
+ return self::DEFAULT;
+ }
+}
diff --git a/src/PHPUnit/OpenApiCoverageExtension.php b/src/PHPUnit/OpenApiCoverageExtension.php
index 662ea8a..a995ad6 100644
--- a/src/PHPUnit/OpenApiCoverageExtension.php
+++ b/src/PHPUnit/OpenApiCoverageExtension.php
@@ -23,8 +23,6 @@
use function fwrite;
use function getcwd;
use function getenv;
-use function round;
-use function str_repeat;
use function str_starts_with;
final class OpenApiCoverageExtension implements Extension
@@ -59,15 +57,20 @@ public function bootstrap(Configuration $configuration, Facade $facade, Paramete
}
}
+ $consoleOutput = ConsoleOutput::resolve(
+ $parameters->has('console_output') ? $parameters->get('console_output') : null,
+ );
+
$githubSummaryPath = getenv('GITHUB_STEP_SUMMARY') ?: null;
- $facade->registerSubscriber(new class ($specs, $outputFile, $githubSummaryPath) implements ExecutionFinishedSubscriber {
+ $facade->registerSubscriber(new class ($specs, $outputFile, $consoleOutput, $githubSummaryPath) implements ExecutionFinishedSubscriber {
/**
* @param string[] $specs
*/
public function __construct(
private readonly array $specs,
private readonly ?string $outputFile,
+ private readonly ConsoleOutput $consoleOutput,
private readonly ?string $githubSummaryPath,
) {}
@@ -80,7 +83,7 @@ public function notify(ExecutionFinished $event): void
return;
}
- $this->printReport($results);
+ echo ConsoleCoverageRenderer::render($results, $this->consoleOutput);
if ($this->outputFile !== null || $this->githubSummaryPath !== null) {
$this->writeMarkdownReport($results);
@@ -122,39 +125,6 @@ private function computeAllResults(): array
return $results;
}
- /**
- * @param array $results
- */
- private function printReport(array $results): void
- {
- echo "\n\n";
- echo "OpenAPI Contract Test Coverage\n";
- echo str_repeat('=', 50) . "\n";
-
- foreach ($results as $spec => $result) {
- $percentage = self::percentage($result['coveredCount'], $result['total']);
-
- echo "\n[{$spec}] {$result['coveredCount']}/{$result['total']} endpoints ({$percentage}%)\n";
- echo str_repeat('-', 50) . "\n";
-
- if ($result['covered'] !== []) {
- echo "Covered:\n";
-
- foreach ($result['covered'] as $endpoint) {
- echo " ✓ {$endpoint}\n";
- }
- }
-
- $uncoveredCount = $result['total'] - $result['coveredCount'];
-
- if ($uncoveredCount > 0) {
- echo "Uncovered: {$uncoveredCount} endpoints\n";
- }
- }
-
- echo "\n";
- }
-
/**
* @param array $results
*/
@@ -178,11 +148,6 @@ private function writeMarkdownReport(array $results): void
}
}
}
-
- private static function percentage(int $covered, int $total): float|int
- {
- return $total > 0 ? round($covered / $total * 100, 1) : 0;
- }
});
}
}
diff --git a/tests/Unit/ConsoleCoverageRendererTest.php b/tests/Unit/ConsoleCoverageRendererTest.php
new file mode 100644
index 0000000..6967c0a
--- /dev/null
+++ b/tests/Unit/ConsoleCoverageRendererTest.php
@@ -0,0 +1,299 @@
+assertSame('', ConsoleCoverageRenderer::render([]));
+ }
+
+ #[Test]
+ public function render_default_mode_shows_covered_list_and_uncovered_count(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'uncovered' => ['DELETE /v1/pets/{petId}', 'GET /v1/pets/{petId}'],
+ 'total' => 4,
+ 'coveredCount' => 2,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
+
+ $this->assertStringContainsString('OpenAPI Contract Test Coverage', $output);
+ $this->assertStringContainsString('[front] 2/4 endpoints (50%)', $output);
+ $this->assertStringContainsString('Covered:', $output);
+ $this->assertStringContainsString(' ✓ GET /v1/pets', $output);
+ $this->assertStringContainsString(' ✓ POST /v1/pets', $output);
+ $this->assertStringContainsString('Uncovered: 2 endpoints', $output);
+ $this->assertStringNotContainsString(' ✗', $output);
+ }
+
+ #[Test]
+ public function render_all_mode_shows_both_covered_and_uncovered_lists(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'uncovered' => ['DELETE /v1/pets/{petId}', 'GET /v1/pets/{petId}'],
+ 'total' => 4,
+ 'coveredCount' => 2,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::ALL);
+
+ $this->assertStringContainsString('Covered:', $output);
+ $this->assertStringContainsString(' ✓ GET /v1/pets', $output);
+ $this->assertStringContainsString(' ✓ POST /v1/pets', $output);
+ $this->assertStringContainsString('Uncovered:', $output);
+ $this->assertStringContainsString(' ✗ DELETE /v1/pets/{petId}', $output);
+ $this->assertStringContainsString(' ✗ GET /v1/pets/{petId}', $output);
+ $this->assertStringNotContainsString('Uncovered: 2 endpoints', $output);
+ }
+
+ #[Test]
+ public function render_uncovered_only_mode_shows_uncovered_list_and_covered_count(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'uncovered' => ['DELETE /v1/pets/{petId}', 'GET /v1/pets/{petId}'],
+ 'total' => 4,
+ 'coveredCount' => 2,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::UNCOVERED_ONLY);
+
+ $this->assertStringContainsString('Covered: 2 endpoints', $output);
+ $this->assertStringNotContainsString(' ✓', $output);
+ $this->assertStringContainsString('Uncovered:', $output);
+ $this->assertStringContainsString(' ✗ DELETE /v1/pets/{petId}', $output);
+ $this->assertStringContainsString(' ✗ GET /v1/pets/{petId}', $output);
+ }
+
+ #[Test]
+ public function render_full_coverage_default_mode_shows_no_uncovered_section(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'uncovered' => [],
+ 'total' => 2,
+ 'coveredCount' => 2,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
+
+ $this->assertStringContainsString('[front] 2/2 endpoints (100%)', $output);
+ $this->assertStringContainsString(' ✓ GET /v1/pets', $output);
+ $this->assertStringNotContainsString('Uncovered', $output);
+ }
+
+ #[Test]
+ public function render_full_coverage_all_mode_shows_no_uncovered_section(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'uncovered' => [],
+ 'total' => 2,
+ 'coveredCount' => 2,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::ALL);
+
+ $this->assertStringContainsString(' ✓ GET /v1/pets', $output);
+ $this->assertStringNotContainsString('Uncovered', $output);
+ }
+
+ #[Test]
+ public function render_zero_coverage_default_mode_shows_uncovered_count(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => [],
+ 'uncovered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'total' => 2,
+ 'coveredCount' => 0,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
+
+ $this->assertStringContainsString('[front] 0/2 endpoints (0%)', $output);
+ $this->assertStringNotContainsString('Covered:', $output);
+ $this->assertStringContainsString('Uncovered: 2 endpoints', $output);
+ }
+
+ #[Test]
+ public function render_zero_coverage_uncovered_only_mode_shows_uncovered_list(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => [],
+ 'uncovered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'total' => 2,
+ 'coveredCount' => 0,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::UNCOVERED_ONLY);
+
+ $this->assertStringContainsString('[front] 0/2 endpoints (0%)', $output);
+ $this->assertStringNotContainsString('Covered:', $output);
+ $this->assertStringContainsString('Uncovered:', $output);
+ $this->assertStringContainsString(' ✗ GET /v1/pets', $output);
+ $this->assertStringContainsString(' ✗ POST /v1/pets', $output);
+ }
+
+ #[Test]
+ public function render_multiple_specs(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets'],
+ 'uncovered' => ['POST /v1/pets'],
+ 'total' => 2,
+ 'coveredCount' => 1,
+ ],
+ 'admin' => [
+ 'covered' => ['GET /v1/users'],
+ 'uncovered' => [],
+ 'total' => 1,
+ 'coveredCount' => 1,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
+
+ $this->assertStringContainsString('[front] 1/2 endpoints (50%)', $output);
+ $this->assertStringContainsString('[admin] 1/1 endpoints (100%)', $output);
+ }
+
+ #[Test]
+ public function render_defaults_to_default_mode(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets'],
+ 'uncovered' => ['POST /v1/pets'],
+ 'total' => 2,
+ 'coveredCount' => 1,
+ ],
+ ];
+
+ $withExplicitDefault = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
+ $withImplicitDefault = ConsoleCoverageRenderer::render($results);
+
+ $this->assertSame($withExplicitDefault, $withImplicitDefault);
+ }
+
+ #[Test]
+ public function render_header_and_separators_are_present(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets'],
+ 'uncovered' => [],
+ 'total' => 1,
+ 'coveredCount' => 1,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results);
+
+ $this->assertStringContainsString('OpenAPI Contract Test Coverage', $output);
+ $this->assertStringContainsString('==================================================', $output);
+ $this->assertStringContainsString('--------------------------------------------------', $output);
+ }
+
+ #[Test]
+ public function render_zero_coverage_all_mode_shows_uncovered_list_only(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => [],
+ 'uncovered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'total' => 2,
+ 'coveredCount' => 0,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::ALL);
+
+ $this->assertStringContainsString('[front] 0/2 endpoints (0%)', $output);
+ $this->assertStringNotContainsString('Covered', $output);
+ $this->assertStringContainsString('Uncovered:', $output);
+ $this->assertStringContainsString(' ✗ GET /v1/pets', $output);
+ }
+
+ #[Test]
+ public function render_full_coverage_uncovered_only_mode_shows_covered_count_only(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets', 'POST /v1/pets'],
+ 'uncovered' => [],
+ 'total' => 2,
+ 'coveredCount' => 2,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::UNCOVERED_ONLY);
+
+ $this->assertStringContainsString('Covered: 2 endpoints', $output);
+ $this->assertStringNotContainsString(' ✓', $output);
+ $this->assertStringNotContainsString('Uncovered', $output);
+ }
+
+ #[Test]
+ public function render_percentage_rounds_to_one_decimal_place(): void
+ {
+ $results = [
+ 'front' => [
+ 'covered' => ['GET /v1/pets'],
+ 'uncovered' => ['POST /v1/pets', 'DELETE /v1/pets/{petId}'],
+ 'total' => 3,
+ 'coveredCount' => 1,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results);
+
+ $this->assertStringContainsString('[front] 1/3 endpoints (33.3%)', $output);
+ }
+
+ #[Test]
+ public function render_spec_with_zero_endpoints(): void
+ {
+ $results = [
+ 'empty' => [
+ 'covered' => [],
+ 'uncovered' => [],
+ 'total' => 0,
+ 'coveredCount' => 0,
+ ],
+ ];
+
+ $output = ConsoleCoverageRenderer::render($results, ConsoleOutput::ALL);
+
+ $this->assertStringContainsString('[empty] 0/0 endpoints (0%)', $output);
+ $this->assertStringNotContainsString('Covered', $output);
+ $this->assertStringNotContainsString('Uncovered', $output);
+ }
+}
diff --git a/tests/Unit/ConsoleOutputTest.php b/tests/Unit/ConsoleOutputTest.php
new file mode 100644
index 0000000..6883157
--- /dev/null
+++ b/tests/Unit/ConsoleOutputTest.php
@@ -0,0 +1,135 @@
+assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve(null));
+ }
+
+ #[Test]
+ public function resolve_returns_default_when_parameter_is_empty_string(): void
+ {
+ $this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve(''));
+ }
+
+ #[Test]
+ public function resolve_returns_default_when_parameter_is_whitespace(): void
+ {
+ $this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve(' '));
+ }
+
+ #[Test]
+ public function resolve_returns_all_from_parameter(): void
+ {
+ $this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('all'));
+ }
+
+ #[Test]
+ public function resolve_returns_uncovered_only_from_parameter(): void
+ {
+ $this->assertSame(ConsoleOutput::UNCOVERED_ONLY, ConsoleOutput::resolve('uncovered_only'));
+ }
+
+ #[Test]
+ public function resolve_returns_default_from_parameter(): void
+ {
+ $this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve('default'));
+ }
+
+ #[Test]
+ public function resolve_is_case_insensitive_for_parameter(): void
+ {
+ $this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('ALL'));
+ $this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('All'));
+ $this->assertSame(ConsoleOutput::UNCOVERED_ONLY, ConsoleOutput::resolve('UNCOVERED_ONLY'));
+ $this->assertSame(ConsoleOutput::UNCOVERED_ONLY, ConsoleOutput::resolve('Uncovered_Only'));
+ }
+
+ #[Test]
+ public function resolve_trims_whitespace_from_parameter(): void
+ {
+ $this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve(' all '));
+ }
+
+ #[Test]
+ public function resolve_returns_default_for_invalid_parameter(): void
+ {
+ $this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve('invalid'));
+ $this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve('covered_only'));
+ }
+
+ #[Test]
+ public function resolve_env_overrides_parameter(): void
+ {
+ putenv('OPENAPI_CONSOLE_OUTPUT=uncovered_only');
+
+ $this->assertSame(ConsoleOutput::UNCOVERED_ONLY, ConsoleOutput::resolve('all'));
+ }
+
+ #[Test]
+ public function resolve_env_is_case_insensitive(): void
+ {
+ putenv('OPENAPI_CONSOLE_OUTPUT=ALL');
+
+ $this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve(null));
+ }
+
+ #[Test]
+ public function resolve_env_trims_whitespace(): void
+ {
+ putenv('OPENAPI_CONSOLE_OUTPUT= all ');
+
+ $this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve(null));
+ }
+
+ #[Test]
+ public function resolve_invalid_env_falls_back_to_default(): void
+ {
+ putenv('OPENAPI_CONSOLE_OUTPUT=invalid');
+
+ $this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve('all'));
+ }
+
+ #[Test]
+ public function resolve_empty_env_uses_parameter(): void
+ {
+ putenv('OPENAPI_CONSOLE_OUTPUT=');
+
+ $this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('all'));
+ }
+
+ #[Test]
+ public function resolve_whitespace_only_env_uses_parameter(): void
+ {
+ putenv('OPENAPI_CONSOLE_OUTPUT= ');
+
+ $this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('all'));
+ }
+}