Skip to content

Commit 4f58677

Browse files
test: test parameters type detection
1 parent f0604a0 commit 4f58677

File tree

5 files changed

+178
-16
lines changed

5 files changed

+178
-16
lines changed

src/Metadata/Resource/Factory/ParameterResourceMetadataCollectionFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ private function getDefaultParameters(Operation $operation, string $resourceClas
158158
$parameter = $parameter->withNativeType(Type::string());
159159
} elseif ('boolean' === ($parameter->getSchema()['type'] ?? null)) {
160160
$parameter = $parameter->withNativeType(Type::bool());
161+
} elseif ('integer' === ($parameter->getSchema()['type'] ?? null)) {
162+
$parameter = $parameter->withNativeType(Type::int());
163+
} elseif ('number' === ($parameter->getSchema()['type'] ?? null)) {
164+
$parameter = $parameter->withNativeType(Type::float());
161165
} else {
162166
$parameter = $parameter->withNativeType(Type::union(Type::string(), Type::list(Type::string())));
163167
}

src/Validator/Metadata/Resource/Factory/ParameterValidationResourceMetadataCollectionFactory.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Symfony\Component\Validator\Constraints\Collection;
2929
use Symfony\Component\Validator\Constraints\Count;
3030
use Symfony\Component\Validator\Constraints\DivisibleBy;
31+
use Symfony\Component\Validator\Constraints\Expression;
3132
use Symfony\Component\Validator\Constraints\GreaterThan;
3233
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
3334
use Symfony\Component\Validator\Constraints\Length;
@@ -190,7 +191,18 @@ private function addSchemaValidation(Parameter $parameter, ?array $schema = null
190191
}
191192

192193
if (isset($schema['type']) && 'array' === $schema['type']) {
193-
$assertions[] = new Type(type: 'array');
194+
$assertions[] = new Type(type: $schema['type']);
195+
}
196+
197+
// Allow null in case of optional parameter
198+
if (isset($schema['type']) && 'null' === $schema['type']) {
199+
// Header null values may be sent as array through Symfony
200+
$assertions[] = new Expression(expression: 'value in [null, "null", [null], ["null"]]');
201+
}
202+
203+
// Allow null in case of optional parameter
204+
if (isset($schema['type']) && 'boolean' === $schema['type']) {
205+
$assertions[] = new Expression(expression: 'value in [null, 0, 1, "0", "1", false, true, "false", "true"]');
194206
}
195207

196208
if (!$assertions) {

tests/Fixtures/TestBundle/ApiResource/WithParameter.php

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,94 @@
165165
'minimum' => 1,
166166
'maximum' => 5,
167167
],
168-
required: true,
168+
),
169+
],
170+
provider: [self::class, 'noopProvider']
171+
)]
172+
#[GetCollection(
173+
uriTemplate: 'header_float',
174+
parameters: [
175+
'Bar' => new HeaderParameter(
176+
schema: [
177+
'type' => 'number',
178+
'example' => 42.0,
179+
'minimum' => 1.0,
180+
'maximum' => 100.0,
181+
'multipleOf' => 0.01,
182+
],
183+
),
184+
],
185+
provider: [self::class, 'noopProvider']
186+
)]
187+
#[GetCollection(
188+
uriTemplate: 'header_boolean',
189+
parameters: [
190+
'Lorem' => new HeaderParameter(
191+
schema: [
192+
'type' => 'boolean',
193+
],
194+
),
195+
],
196+
provider: [self::class, 'noopProvider']
197+
)]
198+
#[GetCollection(
199+
uriTemplate: 'header_null',
200+
parameters: [
201+
'Ipsum' => new HeaderParameter(
202+
schema: [
203+
'type' => 'null',
204+
],
205+
),
206+
],
207+
provider: [self::class, 'noopProvider']
208+
)]
209+
#[GetCollection(
210+
uriTemplate: 'query_integer',
211+
parameters: [
212+
'Foo' => new QueryParameter(
213+
schema: [
214+
'type' => 'integer',
215+
'example' => 3,
216+
'minimum' => 1,
217+
'maximum' => 5,
218+
],
219+
),
220+
],
221+
provider: [self::class, 'noopProvider']
222+
)]
223+
#[GetCollection(
224+
uriTemplate: 'query_float',
225+
parameters: [
226+
'Bar' => new QueryParameter(
227+
schema: [
228+
'type' => 'number',
229+
'example' => 42.0,
230+
'minimum' => 1.0,
231+
'maximum' => 100.0,
232+
'multipleOf' => 0.01,
233+
],
234+
),
235+
],
236+
provider: [self::class, 'noopProvider']
237+
)]
238+
#[GetCollection(
239+
uriTemplate: 'query_boolean',
240+
parameters: [
241+
'Lorem' => new QueryParameter(
242+
schema: [
243+
'type' => 'boolean',
244+
],
245+
),
246+
],
247+
provider: [self::class, 'noopProvider']
248+
)]
249+
#[GetCollection(
250+
uriTemplate: 'query_null',
251+
parameters: [
252+
'Ipsum' => new QueryParameter(
253+
schema: [
254+
'type' => 'null',
255+
],
169256
),
170257
],
171258
provider: [self::class, 'noopProvider']

tests/Functional/Parameters/BooleanFilterTest.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,8 @@ public static function booleanFilterScenariosProvider(): \Generator
9898
#[DataProvider('booleanFilterNullAndEmptyScenariosProvider')]
9999
public function testBooleanFilterWithNullAndEmptyValues(string $url): void
100100
{
101-
$response = self::createClient()->request('GET', $url);
102-
$this->assertResponseIsSuccessful();
103-
104-
$responseData = $response->toArray();
105-
$filteredItems = $responseData['hydra:member'];
106-
107-
$expectedItemCount = 3;
108-
$this->assertCount($expectedItemCount, $filteredItems, \sprintf('Expected %d items for URL %s', $expectedItemCount, $url));
101+
self::createClient()->request('GET', $url);
102+
$this->assertResponseStatusCodeSame(422);
109103
}
110104

111105
public static function booleanFilterNullAndEmptyScenariosProvider(): \Generator

tests/Functional/Parameters/ParameterTest.php

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,18 +121,83 @@ public function testHeaderParameterRequired(): void
121121
}
122122

123123
#[DataProvider('provideHeaderValues')]
124-
public function testHeaderParameterInteger(string $value, int $expectedStatusCode): void
124+
public function testHeaderParameter(string $url, array $headers, int $expectedStatusCode): void
125125
{
126-
self::createClient()->request('GET', 'header_integer', ['headers' => ['Foo' => $value]]);
126+
self::createClient()->request('GET', $url, ['headers' => $headers]);
127127
$this->assertResponseStatusCodeSame($expectedStatusCode);
128128
}
129129

130130
public static function provideHeaderValues(): iterable
131131
{
132-
yield 'valid integer' => ['3', 200];
133-
yield 'too high' => ['6', 422];
134-
yield 'too low' => ['0', 422];
135-
yield 'invalid integer' => ['string', 422];
132+
// header_integer
133+
yield 'missing header header_integer' => ['header_integer', [], 200];
134+
yield 'valid integer header_integer' => ['header_integer', ['Foo' => '3'], 200];
135+
yield 'too high header_integer' => ['header_integer', ['Foo' => '6'], 422];
136+
yield 'too low header_integer' => ['header_integer', ['Foo' => '0'], 422];
137+
yield 'invalid integer header_integer' => ['header_integer', ['Foo' => 'string'], 422];
138+
139+
// header_float
140+
yield 'missing header header_float' => ['header_float', [], 200];
141+
yield 'valid float header_float' => ['header_float', ['Bar' => '3.5'], 200];
142+
yield 'valid integer header_float' => ['header_float', ['Bar' => '3'], 200];
143+
yield 'too high header_float' => ['header_float', ['Bar' => '600'], 422];
144+
yield 'too low header_float' => ['header_float', ['Bar' => '0'], 422];
145+
yield 'invalid number header_float' => ['header_float', ['Bar' => 'string'], 422];
146+
147+
// header_boolean
148+
yield 'missing header header_boolean' => ['header_boolean', [], 200];
149+
yield 'valid boolean false header_boolean' => ['header_boolean', ['Lorem' => 'false'], 200];
150+
yield 'valid boolean true header_boolean' => ['header_boolean', ['Lorem' => 'true'], 200];
151+
yield 'valid boolean 0 header_boolean' => ['header_boolean', ['Lorem' => 0], 200];
152+
yield 'valid boolean 0 string header_boolean' => ['header_boolean', ['Lorem' => '0'], 200];
153+
yield 'valid boolean 1 header_boolean' => ['header_boolean', ['Lorem' => 1], 200];
154+
yield 'valid boolean 1 string header_boolean' => ['header_boolean', ['Lorem' => '1'], 200];
155+
yield 'invalid boolean header_boolean' => ['header_boolean', ['Lorem' => 'string'], 422];
156+
157+
// header_null
158+
yield 'missing header header_null' => ['header_null', [], 200];
159+
yield 'valid null header_null' => ['header_null', ['Ipsum' => null], 200];
160+
yield 'valid null string header_null' => ['header_null', ['Ipsum' => 'null'], 200];
161+
yield 'invalid null header_null' => ['header_null', ['Ipsum' => 'string'], 422];
162+
}
163+
164+
#[DataProvider('provideQueryValues')]
165+
public function testQueryParameter(string $url, array $query, int $expectedStatusCode): void
166+
{
167+
self::createClient()->request('GET', $url, ['query' => $query]);
168+
$this->assertResponseStatusCodeSame($expectedStatusCode);
169+
}
170+
171+
public static function provideQueryValues(): iterable
172+
{
173+
// query_integer
174+
yield 'valid integer query_integer' => ['query_integer', ['Foo' => '3'], 200];
175+
yield 'too high query_integer' => ['query_integer', ['Foo' => '6'], 422];
176+
yield 'too low query_integer' => ['query_integer', ['Foo' => '0'], 422];
177+
yield 'invalid integer query_integer' => ['query_integer', ['Foo' => 'string'], 422];
178+
179+
// query_float
180+
yield 'valid float query_float' => ['query_float', ['Bar' => '3.5'], 200];
181+
yield 'valid integer query_float' => ['query_float', ['Bar' => '3'], 200];
182+
yield 'too high query_float' => ['query_float', ['Bar' => '600'], 422];
183+
yield 'too low query_float' => ['query_float', ['Bar' => '0'], 422];
184+
yield 'invalid number query_float' => ['query_float', ['Bar' => 'string'], 422];
185+
186+
// query_boolean
187+
yield 'valid boolean false query_boolean' => ['query_boolean', ['Lorem' => false], 200];
188+
yield 'valid boolean false string query_boolean' => ['query_boolean', ['Lorem' => 'false'], 200];
189+
yield 'valid boolean true query_boolean' => ['query_boolean', ['Lorem' => true], 200];
190+
yield 'valid boolean true string query_boolean' => ['query_boolean', ['Lorem' => 'true'], 200];
191+
yield 'valid boolean 0 query_boolean' => ['query_boolean', ['Lorem' => 0], 200];
192+
yield 'valid boolean 0 string query_boolean' => ['query_boolean', ['Lorem' => '0'], 200];
193+
yield 'valid boolean 1 query_boolean' => ['query_boolean', ['Lorem' => 1], 200];
194+
yield 'valid boolean 1 string query_boolean' => ['query_boolean', ['Lorem' => '1'], 200];
195+
yield 'invalid boolean query_boolean' => ['query_boolean', ['Lorem' => 'string'], 422];
196+
197+
// query_null
198+
yield 'valid null query_null' => ['query_null', ['Ipsum' => null], 200];
199+
yield 'valid null string query_null' => ['query_null', ['Ipsum' => 'null'], 200];
200+
yield 'invalid null query_null' => ['query_null', ['Ipsum' => 'string'], 422];
136201
}
137202

138203
#[DataProvider('provideCountryValues')]

0 commit comments

Comments
 (0)