Skip to content

Commit 0c01d40

Browse files
test: unit tests for backed enum resources
1 parent 76af4ef commit 0c01d40

File tree

4 files changed

+362
-0
lines changed

4 files changed

+362
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6264;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\Get;
18+
use ApiPlatform\Metadata\GetCollection;
19+
20+
#[ApiResource(normalizationContext: ['groups' => ['get']])]
21+
#[GetCollection(provider: Availability::class.'::getCases')]
22+
#[Get(provider: Availability::class.'::getCase')]
23+
enum Availability: int
24+
{
25+
use BackedEnumTrait;
26+
27+
case Available = 0;
28+
case Cancelled = 10;
29+
case Postponed = 200;
30+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6264;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\Get;
18+
use ApiPlatform\Metadata\GetCollection;
19+
20+
#[ApiResource(normalizationContext: ['groups' => ['get']])]
21+
#[GetCollection(provider: AvailabilityStatus::class.'::getCases')]
22+
#[Get(provider: AvailabilityStatus::class.'::getCase')]
23+
enum AvailabilityStatus: string
24+
{
25+
use BackedEnumTrait;
26+
27+
case Pending = 'pending';
28+
case Reviewed = 'reviewed';
29+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6264;
15+
16+
use ApiPlatform\Metadata\Operation;
17+
use Symfony\Component\Serializer\Attribute\Groups;
18+
19+
trait BackedEnumTrait
20+
{
21+
public static function values(): array
22+
{
23+
return array_map(static fn (\BackedEnum $feature) => $feature->value, self::cases());
24+
}
25+
26+
public function getId(): string
27+
{
28+
return $this->name;
29+
}
30+
31+
#[Groups(['get'])]
32+
public function getValue(): string|int
33+
{
34+
return $this->value;
35+
}
36+
37+
public static function getCases(): array
38+
{
39+
return self::cases();
40+
}
41+
42+
public static function getCase(Operation $operation, array $uriVariables): ?self
43+
{
44+
return array_reduce(self::cases(), static fn ($c, \BackedEnum $case) => $case->name === $uriVariables['id'] ? $case : $c, null);
45+
}
46+
}
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Functional;
15+
16+
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
17+
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6264\Availability;
18+
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6264\AvailabilityStatus;
19+
use Symfony\Component\HttpClient\HttpOptions;
20+
21+
final class BackedEnumResourceTest extends ApiTestCase
22+
{
23+
public static function providerEnumItemsJson(): iterable
24+
{
25+
// String cases
26+
foreach (Availability::cases() as $case) {
27+
yield ['/availabilities/'.$case->name, 'application/json', ['value' => $case->value]];
28+
29+
yield ['/availabilities/'.$case->name, 'application/vnd.api+json', [
30+
'data' => [
31+
'id' => '/availabilities/'.$case->name,
32+
'type' => 'Availability',
33+
'attributes' => [
34+
'value' => $case->value,
35+
],
36+
],
37+
]];
38+
39+
yield ['/availabilities/'.$case->name, 'application/hal+json', [
40+
'_links' => [
41+
'self' => [
42+
'href' => '/availabilities/'.$case->name,
43+
],
44+
],
45+
'value' => $case->value,
46+
]];
47+
48+
yield ['/availabilities/'.$case->name, 'application/ld+json', [
49+
'@context' => '/contexts/Availability',
50+
'@id' => '/availabilities/'.$case->name,
51+
'@type' => 'Availability',
52+
'value' => $case->value,
53+
]];
54+
}
55+
56+
// Integer cases
57+
foreach (AvailabilityStatus::cases() as $case) {
58+
yield ['/availability_statuses/'.$case->name, 'application/json', ['value' => $case->value]];
59+
60+
yield ['/availability_statuses/'.$case->name, 'application/vnd.api+json', [
61+
'data' => [
62+
'id' => '/availability_statuses/'.$case->name,
63+
'type' => 'AvailabilityStatus',
64+
'attributes' => [
65+
'value' => $case->value,
66+
],
67+
],
68+
]];
69+
70+
yield ['/availability_statuses/'.$case->name, 'application/hal+json', [
71+
'_links' => [
72+
'self' => [
73+
'href' => '/availability_statuses/'.$case->name,
74+
],
75+
],
76+
'value' => $case->value,
77+
]];
78+
79+
yield ['/availability_statuses/'.$case->name, 'application/ld+json', [
80+
'@context' => '/contexts/AvailabilityStatus',
81+
'@id' => '/availability_statuses/'.$case->name,
82+
'@type' => 'AvailabilityStatus',
83+
'value' => $case->value,
84+
]];
85+
}
86+
}
87+
88+
/** @dataProvider providerEnumItemsJson */
89+
public function testItemJson(string $uri, string $mimeType, array $expected): void
90+
{
91+
self::createClient()->request('GET', $uri, ['headers' => ['Accept' => $mimeType]]);
92+
93+
$this->assertResponseIsSuccessful();
94+
$this->assertJsonEquals($expected);
95+
}
96+
97+
public static function providerEnumItemsGraphQl(): iterable
98+
{
99+
// String cases
100+
$query = <<<'GRAPHQL'
101+
query GetAvailability($identifier: ID!) {
102+
availability(id: $identifier) {
103+
value
104+
}
105+
}
106+
GRAPHQL;
107+
foreach (Availability::cases() as $case) {
108+
yield [$query, ['identifier' => '/availabilities/'.$case->name], ['data' => ['availability' => ['value' => $case->value]]]];
109+
}
110+
111+
// Integer cases
112+
$query = <<<'GRAPHQL'
113+
query GetAvailabilityStatus($identifier: ID!) {
114+
availabilityStatus(id: $identifier) {
115+
value
116+
}
117+
}
118+
GRAPHQL;
119+
foreach (AvailabilityStatus::cases() as $case) {
120+
yield [$query, ['identifier' => '/availability_statuses/'.$case->name], ['data' => ['availability_status' => ['value' => $case->value]]]];
121+
}
122+
}
123+
124+
/** @dataProvider providerEnumItemsGraphQl */
125+
public function testItemGraphql(string $query, array $variables, array $expected): void
126+
{
127+
$options = (new HttpOptions())
128+
->setJson(['query' => $query, 'variables' => $variables])
129+
->setHeaders(['Content-Type' => 'application/json']);
130+
self::createClient()->request('POST', '/graphql', $options->toArray());
131+
132+
$this->assertResponseIsSuccessful();
133+
$this->assertJsonEquals($expected);
134+
}
135+
136+
public function testCollectionJson(): void
137+
{
138+
self::createClient()->request('GET', '/availabilities', ['headers' => ['Accept' => 'application/json']]);
139+
140+
$this->assertResponseIsSuccessful();
141+
$this->assertJsonEquals([
142+
['value' => 0],
143+
['value' => 10],
144+
['value' => 200],
145+
]);
146+
}
147+
148+
public function testCollectionJsonApi(): void
149+
{
150+
self::createClient()->request('GET', '/availabilities', ['headers' => ['Accept' => 'application/vnd.api+json']]);
151+
152+
$this->assertResponseIsSuccessful();
153+
$this->assertJsonEquals([
154+
'links' => [
155+
'self' => '/availabilities',
156+
],
157+
'meta' => [
158+
'totalItems' => 3,
159+
],
160+
'data' => [
161+
[
162+
'id' => '/availabilities/Available',
163+
'type' => 'Availability',
164+
'attributes' => [
165+
'value' => 0,
166+
],
167+
],
168+
[
169+
'id' => '/availabilities/Cancelled',
170+
'type' => 'Availability',
171+
'attributes' => [
172+
'value' => 10,
173+
],
174+
],
175+
[
176+
'id' => '/availabilities/Postponed',
177+
'type' => 'Availability',
178+
'attributes' => [
179+
'value' => 200,
180+
],
181+
],
182+
],
183+
]);
184+
}
185+
186+
public function testCollectionHal(): void
187+
{
188+
self::createClient()->request('GET', '/availabilities', ['headers' => ['Accept' => 'application/hal+json']]);
189+
190+
$this->assertResponseIsSuccessful();
191+
$this->assertJsonEquals([
192+
'_links' => [
193+
'self' => [
194+
'href' => '/availabilities',
195+
],
196+
'item' => [
197+
['href' => '/availabilities/Available'],
198+
['href' => '/availabilities/Cancelled'],
199+
['href' => '/availabilities/Postponed'],
200+
],
201+
],
202+
'totalItems' => 3,
203+
'_embedded' => [
204+
'item' => [
205+
[
206+
'_links' => [
207+
'self' => ['href' => '/availabilities/Available'],
208+
],
209+
'value' => 0,
210+
],
211+
[
212+
'_links' => [
213+
'self' => ['href' => '/availabilities/Cancelled'],
214+
],
215+
'value' => 10,
216+
],
217+
[
218+
'_links' => [
219+
'self' => ['href' => '/availabilities/Postponed'],
220+
],
221+
'value' => 200,
222+
],
223+
],
224+
],
225+
]);
226+
}
227+
228+
public function testCollectionJsonLd(): void
229+
{
230+
self::createClient()->request('GET', '/availabilities', ['headers' => ['Accept' => 'application/ld+json']]);
231+
232+
$this->assertResponseIsSuccessful();
233+
$this->assertJsonEquals([
234+
'@context' => '/contexts/Availability',
235+
'@id' => '/availabilities',
236+
'@type' => 'hydra:Collection',
237+
'hydra:totalItems' => 3,
238+
'hydra:member' => [
239+
[
240+
'@id' => '/availabilities/Available',
241+
'@type' => 'Availability',
242+
'value' => 0,
243+
],
244+
[
245+
'@id' => '/availabilities/Cancelled',
246+
'@type' => 'Availability',
247+
'value' => 10,
248+
],
249+
[
250+
'@id' => '/availabilities/Postponed',
251+
'@type' => 'Availability',
252+
'value' => 200,
253+
],
254+
],
255+
]);
256+
}
257+
}

0 commit comments

Comments
 (0)