Skip to content

Commit b2cfabc

Browse files
committed
test: add unit tests for ConsoleOutput and ConsoleCoverageRenderer
1 parent 3e1cca8 commit b2cfabc

2 files changed

Lines changed: 378 additions & 0 deletions

File tree

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Studio\OpenApiContractTesting\Tests\Unit;
6+
7+
use PHPUnit\Framework\Attributes\Test;
8+
use PHPUnit\Framework\TestCase;
9+
use Studio\OpenApiContractTesting\PHPUnit\ConsoleCoverageRenderer;
10+
use Studio\OpenApiContractTesting\PHPUnit\ConsoleOutput;
11+
12+
class ConsoleCoverageRendererTest extends TestCase
13+
{
14+
#[Test]
15+
public function render_returns_empty_string_for_empty_results(): void
16+
{
17+
$this->assertSame('', ConsoleCoverageRenderer::render([]));
18+
}
19+
20+
#[Test]
21+
public function render_default_mode_shows_covered_list_and_uncovered_count(): void
22+
{
23+
$results = [
24+
'front' => [
25+
'covered' => ['GET /v1/pets', 'POST /v1/pets'],
26+
'uncovered' => ['DELETE /v1/pets/{petId}', 'GET /v1/pets/{petId}'],
27+
'total' => 4,
28+
'coveredCount' => 2,
29+
],
30+
];
31+
32+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
33+
34+
$this->assertStringContainsString('OpenAPI Contract Test Coverage', $output);
35+
$this->assertStringContainsString('[front] 2/4 endpoints (50%)', $output);
36+
$this->assertStringContainsString('Covered:', $output);
37+
$this->assertStringContainsString(' ✓ GET /v1/pets', $output);
38+
$this->assertStringContainsString(' ✓ POST /v1/pets', $output);
39+
$this->assertStringContainsString('Uncovered: 2 endpoints', $output);
40+
$this->assertStringNotContainsString('', $output);
41+
}
42+
43+
#[Test]
44+
public function render_all_mode_shows_both_covered_and_uncovered_lists(): void
45+
{
46+
$results = [
47+
'front' => [
48+
'covered' => ['GET /v1/pets', 'POST /v1/pets'],
49+
'uncovered' => ['DELETE /v1/pets/{petId}', 'GET /v1/pets/{petId}'],
50+
'total' => 4,
51+
'coveredCount' => 2,
52+
],
53+
];
54+
55+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::ALL);
56+
57+
$this->assertStringContainsString('Covered:', $output);
58+
$this->assertStringContainsString(' ✓ GET /v1/pets', $output);
59+
$this->assertStringContainsString(' ✓ POST /v1/pets', $output);
60+
$this->assertStringContainsString('Uncovered:', $output);
61+
$this->assertStringContainsString(' ✗ DELETE /v1/pets/{petId}', $output);
62+
$this->assertStringContainsString(' ✗ GET /v1/pets/{petId}', $output);
63+
$this->assertStringNotContainsString('Uncovered: 2 endpoints', $output);
64+
}
65+
66+
#[Test]
67+
public function render_uncovered_only_mode_shows_uncovered_list_and_covered_count(): void
68+
{
69+
$results = [
70+
'front' => [
71+
'covered' => ['GET /v1/pets', 'POST /v1/pets'],
72+
'uncovered' => ['DELETE /v1/pets/{petId}', 'GET /v1/pets/{petId}'],
73+
'total' => 4,
74+
'coveredCount' => 2,
75+
],
76+
];
77+
78+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::UNCOVERED_ONLY);
79+
80+
$this->assertStringContainsString('Covered: 2 endpoints', $output);
81+
$this->assertStringNotContainsString('', $output);
82+
$this->assertStringContainsString('Uncovered:', $output);
83+
$this->assertStringContainsString(' ✗ DELETE /v1/pets/{petId}', $output);
84+
$this->assertStringContainsString(' ✗ GET /v1/pets/{petId}', $output);
85+
}
86+
87+
#[Test]
88+
public function render_full_coverage_default_mode_shows_no_uncovered_section(): void
89+
{
90+
$results = [
91+
'front' => [
92+
'covered' => ['GET /v1/pets', 'POST /v1/pets'],
93+
'uncovered' => [],
94+
'total' => 2,
95+
'coveredCount' => 2,
96+
],
97+
];
98+
99+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
100+
101+
$this->assertStringContainsString('[front] 2/2 endpoints (100%)', $output);
102+
$this->assertStringContainsString(' ✓ GET /v1/pets', $output);
103+
$this->assertStringNotContainsString('Uncovered', $output);
104+
}
105+
106+
#[Test]
107+
public function render_full_coverage_all_mode_shows_no_uncovered_section(): void
108+
{
109+
$results = [
110+
'front' => [
111+
'covered' => ['GET /v1/pets', 'POST /v1/pets'],
112+
'uncovered' => [],
113+
'total' => 2,
114+
'coveredCount' => 2,
115+
],
116+
];
117+
118+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::ALL);
119+
120+
$this->assertStringContainsString(' ✓ GET /v1/pets', $output);
121+
$this->assertStringNotContainsString('Uncovered', $output);
122+
}
123+
124+
#[Test]
125+
public function render_zero_coverage_default_mode_shows_uncovered_count(): void
126+
{
127+
$results = [
128+
'front' => [
129+
'covered' => [],
130+
'uncovered' => ['GET /v1/pets', 'POST /v1/pets'],
131+
'total' => 2,
132+
'coveredCount' => 0,
133+
],
134+
];
135+
136+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
137+
138+
$this->assertStringContainsString('[front] 0/2 endpoints (0%)', $output);
139+
$this->assertStringNotContainsString('Covered:', $output);
140+
$this->assertStringContainsString('Uncovered: 2 endpoints', $output);
141+
}
142+
143+
#[Test]
144+
public function render_zero_coverage_uncovered_only_mode_shows_uncovered_list(): void
145+
{
146+
$results = [
147+
'front' => [
148+
'covered' => [],
149+
'uncovered' => ['GET /v1/pets', 'POST /v1/pets'],
150+
'total' => 2,
151+
'coveredCount' => 0,
152+
],
153+
];
154+
155+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::UNCOVERED_ONLY);
156+
157+
$this->assertStringContainsString('[front] 0/2 endpoints (0%)', $output);
158+
$this->assertStringNotContainsString('Covered:', $output);
159+
$this->assertStringContainsString('Uncovered:', $output);
160+
$this->assertStringContainsString(' ✗ GET /v1/pets', $output);
161+
$this->assertStringContainsString(' ✗ POST /v1/pets', $output);
162+
}
163+
164+
#[Test]
165+
public function render_multiple_specs(): void
166+
{
167+
$results = [
168+
'front' => [
169+
'covered' => ['GET /v1/pets'],
170+
'uncovered' => ['POST /v1/pets'],
171+
'total' => 2,
172+
'coveredCount' => 1,
173+
],
174+
'admin' => [
175+
'covered' => ['GET /v1/users'],
176+
'uncovered' => [],
177+
'total' => 1,
178+
'coveredCount' => 1,
179+
],
180+
];
181+
182+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
183+
184+
$this->assertStringContainsString('[front] 1/2 endpoints (50%)', $output);
185+
$this->assertStringContainsString('[admin] 1/1 endpoints (100%)', $output);
186+
}
187+
188+
#[Test]
189+
public function render_defaults_to_default_mode(): void
190+
{
191+
$results = [
192+
'front' => [
193+
'covered' => ['GET /v1/pets'],
194+
'uncovered' => ['POST /v1/pets'],
195+
'total' => 2,
196+
'coveredCount' => 1,
197+
],
198+
];
199+
200+
$withExplicitDefault = ConsoleCoverageRenderer::render($results, ConsoleOutput::DEFAULT);
201+
$withImplicitDefault = ConsoleCoverageRenderer::render($results);
202+
203+
$this->assertSame($withExplicitDefault, $withImplicitDefault);
204+
}
205+
206+
#[Test]
207+
public function render_header_and_separators_are_present(): void
208+
{
209+
$results = [
210+
'front' => [
211+
'covered' => ['GET /v1/pets'],
212+
'uncovered' => [],
213+
'total' => 1,
214+
'coveredCount' => 1,
215+
],
216+
];
217+
218+
$output = ConsoleCoverageRenderer::render($results);
219+
220+
$this->assertStringContainsString('OpenAPI Contract Test Coverage', $output);
221+
$this->assertStringContainsString('==================================================', $output);
222+
$this->assertStringContainsString('--------------------------------------------------', $output);
223+
}
224+
225+
#[Test]
226+
public function render_spec_with_zero_endpoints(): void
227+
{
228+
$results = [
229+
'empty' => [
230+
'covered' => [],
231+
'uncovered' => [],
232+
'total' => 0,
233+
'coveredCount' => 0,
234+
],
235+
];
236+
237+
$output = ConsoleCoverageRenderer::render($results, ConsoleOutput::ALL);
238+
239+
$this->assertStringContainsString('[empty] 0/0 endpoints (0%)', $output);
240+
$this->assertStringNotContainsString('Covered', $output);
241+
$this->assertStringNotContainsString('Uncovered', $output);
242+
}
243+
}

tests/Unit/ConsoleOutputTest.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Studio\OpenApiContractTesting\Tests\Unit;
6+
7+
use PHPUnit\Framework\Attributes\Test;
8+
use PHPUnit\Framework\TestCase;
9+
use Studio\OpenApiContractTesting\PHPUnit\ConsoleOutput;
10+
11+
use function putenv;
12+
13+
class ConsoleOutputTest extends TestCase
14+
{
15+
protected function setUp(): void
16+
{
17+
parent::setUp();
18+
19+
// Clear the environment variable before each test
20+
putenv('OPENAPI_CONSOLE_OUTPUT');
21+
}
22+
23+
protected function tearDown(): void
24+
{
25+
putenv('OPENAPI_CONSOLE_OUTPUT');
26+
27+
parent::tearDown();
28+
}
29+
30+
#[Test]
31+
public function resolve_returns_default_when_parameter_is_null(): void
32+
{
33+
$this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve(null));
34+
}
35+
36+
#[Test]
37+
public function resolve_returns_default_when_parameter_is_empty_string(): void
38+
{
39+
$this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve(''));
40+
}
41+
42+
#[Test]
43+
public function resolve_returns_default_when_parameter_is_whitespace(): void
44+
{
45+
$this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve(' '));
46+
}
47+
48+
#[Test]
49+
public function resolve_returns_all_from_parameter(): void
50+
{
51+
$this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('all'));
52+
}
53+
54+
#[Test]
55+
public function resolve_returns_uncovered_only_from_parameter(): void
56+
{
57+
$this->assertSame(ConsoleOutput::UNCOVERED_ONLY, ConsoleOutput::resolve('uncovered_only'));
58+
}
59+
60+
#[Test]
61+
public function resolve_returns_default_from_parameter(): void
62+
{
63+
$this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve('default'));
64+
}
65+
66+
#[Test]
67+
public function resolve_is_case_insensitive_for_parameter(): void
68+
{
69+
$this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('ALL'));
70+
$this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('All'));
71+
$this->assertSame(ConsoleOutput::UNCOVERED_ONLY, ConsoleOutput::resolve('UNCOVERED_ONLY'));
72+
$this->assertSame(ConsoleOutput::UNCOVERED_ONLY, ConsoleOutput::resolve('Uncovered_Only'));
73+
}
74+
75+
#[Test]
76+
public function resolve_trims_whitespace_from_parameter(): void
77+
{
78+
$this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve(' all '));
79+
}
80+
81+
#[Test]
82+
public function resolve_returns_default_for_invalid_parameter(): void
83+
{
84+
$this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve('invalid'));
85+
$this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve('covered_only'));
86+
}
87+
88+
#[Test]
89+
public function resolve_env_overrides_parameter(): void
90+
{
91+
putenv('OPENAPI_CONSOLE_OUTPUT=uncovered_only');
92+
93+
$this->assertSame(ConsoleOutput::UNCOVERED_ONLY, ConsoleOutput::resolve('all'));
94+
}
95+
96+
#[Test]
97+
public function resolve_env_is_case_insensitive(): void
98+
{
99+
putenv('OPENAPI_CONSOLE_OUTPUT=ALL');
100+
101+
$this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve(null));
102+
}
103+
104+
#[Test]
105+
public function resolve_env_trims_whitespace(): void
106+
{
107+
putenv('OPENAPI_CONSOLE_OUTPUT= all ');
108+
109+
$this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve(null));
110+
}
111+
112+
#[Test]
113+
public function resolve_invalid_env_falls_back_to_default(): void
114+
{
115+
putenv('OPENAPI_CONSOLE_OUTPUT=invalid');
116+
117+
$this->assertSame(ConsoleOutput::DEFAULT, ConsoleOutput::resolve('all'));
118+
}
119+
120+
#[Test]
121+
public function resolve_empty_env_uses_parameter(): void
122+
{
123+
putenv('OPENAPI_CONSOLE_OUTPUT=');
124+
125+
$this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('all'));
126+
}
127+
128+
#[Test]
129+
public function resolve_whitespace_only_env_uses_parameter(): void
130+
{
131+
putenv('OPENAPI_CONSOLE_OUTPUT= ');
132+
133+
$this->assertSame(ConsoleOutput::ALL, ConsoleOutput::resolve('all'));
134+
}
135+
}

0 commit comments

Comments
 (0)