These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php declare(strict_types=1); |
||
2 | /* |
||
3 | * This file is part of the KleijnWeb\SwaggerBundle package. |
||
4 | * |
||
5 | * For the full copyright and license information, please view the LICENSE |
||
6 | * file that was distributed with this source code. |
||
7 | */ |
||
8 | |||
9 | namespace KleijnWeb\SwaggerBundle\Tests\EventListener\Request; |
||
10 | |||
11 | use KleijnWeb\PhpApi\Descriptions\Description\Description; |
||
12 | use KleijnWeb\PhpApi\Descriptions\Description\Operation; |
||
13 | use KleijnWeb\PhpApi\Descriptions\Description\Parameter; |
||
14 | use KleijnWeb\PhpApi\Descriptions\Description\Path; |
||
15 | use KleijnWeb\PhpApi\Descriptions\Description\Repository; |
||
16 | use KleijnWeb\PhpApi\Descriptions\Description\Schema\ObjectSchema; |
||
17 | use KleijnWeb\PhpApi\Descriptions\Description\Schema\Schema; |
||
18 | use KleijnWeb\PhpApi\Descriptions\Description\Schema\Validator\SchemaValidator; |
||
19 | use KleijnWeb\PhpApi\Descriptions\Description\Schema\Validator\ValidationResult; |
||
20 | use KleijnWeb\PhpApi\Descriptions\Request\RequestParameterAssembler; |
||
21 | use KleijnWeb\SwaggerBundle\Hydrator\ObjectHydrator; |
||
22 | use KleijnWeb\PhpApi\RoutingBundle\Routing\RequestMeta; |
||
23 | use KleijnWeb\SwaggerBundle\EventListener\Request\RequestProcessor; |
||
24 | use KleijnWeb\SwaggerBundle\Exception\MalformedContentException; |
||
25 | use KleijnWeb\SwaggerBundle\Exception\ValidationException; |
||
26 | use PHPUnit\Framework\TestCase; |
||
27 | use Symfony\Component\HttpFoundation\ParameterBag; |
||
28 | use Symfony\Component\HttpFoundation\Request; |
||
29 | |||
30 | /** |
||
31 | * @author John Kleijn <[email protected]> |
||
32 | */ |
||
33 | class RequestProcessorTest extends TestCase |
||
34 | { |
||
35 | /** |
||
36 | * @var \PHPUnit_Framework_MockObject_MockObject |
||
37 | */ |
||
38 | private $repositoryMock; |
||
39 | |||
40 | /** |
||
41 | * @var \PHPUnit_Framework_MockObject_MockObject |
||
42 | */ |
||
43 | private $validatorMock; |
||
44 | |||
45 | /** |
||
46 | * @var \PHPUnit_Framework_MockObject_MockObject |
||
47 | */ |
||
48 | private $hydratorMock; |
||
49 | |||
50 | /** |
||
51 | * @var \PHPUnit_Framework_MockObject_MockObject |
||
52 | */ |
||
53 | private $parametersAssemblerMock; |
||
54 | |||
55 | /** |
||
56 | * Create mocks |
||
57 | */ |
||
58 | protected function setUp() |
||
59 | { |
||
60 | /** @var Repository $repository */ |
||
61 | $this->repositoryMock = $repository = $this |
||
62 | ->getMockBuilder(Repository::class) |
||
63 | ->disableOriginalConstructor() |
||
64 | ->getMock(); |
||
65 | |||
66 | /** @var Repository $repository */ |
||
67 | $this->validatorMock = $validator = $this |
||
68 | ->getMockBuilder(SchemaValidator::class) |
||
69 | ->disableOriginalConstructor() |
||
70 | ->getMock(); |
||
71 | |||
72 | /** @var RequestParameterAssembler $hydrator */ |
||
73 | $this->parametersAssemblerMock = $parametersAssembler = $this |
||
74 | ->getMockBuilder(RequestParameterAssembler::class) |
||
75 | ->disableOriginalConstructor() |
||
76 | ->getMock(); |
||
77 | |||
78 | /** @var ObjectHydrator $hydrator */ |
||
79 | $this->hydratorMock = $hydrator = $this |
||
80 | ->getMockBuilder(ObjectHydrator::class) |
||
81 | ->disableOriginalConstructor() |
||
82 | ->getMock(); |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * @test |
||
87 | */ |
||
88 | public function willThrowExceptionIfRequestDoesNotHaveDocumentUri() |
||
89 | { |
||
90 | $processor = $this->createProcessor(); |
||
91 | |||
92 | $this->expectException(\UnexpectedValueException::class); |
||
93 | $processor->process(new Request()); |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * @test |
||
98 | */ |
||
99 | View Code Duplication | public function willThrowExceptionWhenContentIsNotJson() |
|
100 | { |
||
101 | $processor = $this->createProcessor(); |
||
102 | |||
103 | $this->expectException(MalformedContentException::class); |
||
104 | |||
105 | $processor->process( |
||
106 | $this->createRequest( |
||
107 | [ |
||
108 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
109 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
110 | ], |
||
111 | 'not json' |
||
112 | ) |
||
113 | ); |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * @test |
||
118 | */ |
||
119 | View Code Duplication | public function willAssembleParameters() |
|
120 | { |
||
121 | $processor = $this->createProcessor(); |
||
122 | $this->parametersAssemblerMock->expects($this->once())->method('assemble'); |
||
123 | |||
124 | $processor->process( |
||
125 | $this->createRequest( |
||
126 | [ |
||
127 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
128 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
129 | ] |
||
130 | ) |
||
131 | ); |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * @test |
||
136 | */ |
||
137 | public function willUpdateAttributes() |
||
138 | { |
||
139 | $processor = $this->createProcessor(); |
||
140 | $coercedAttributes = (object)[ |
||
141 | 'foo' => 'bar', |
||
142 | ]; |
||
143 | |||
144 | $this->parametersAssemblerMock->expects($this->once())->method('assemble')->willReturn($coercedAttributes); |
||
145 | |||
146 | $request = $this->createRequest( |
||
147 | [ |
||
148 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
149 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
150 | ] |
||
151 | ); |
||
152 | |||
153 | $processor->process($request); |
||
154 | |||
155 | $this->assertTrue($request->attributes->has(RequestMeta::ATTRIBUTE_URI)); |
||
156 | $this->assertTrue($request->attributes->has(RequestMeta::ATTRIBUTE_PATH)); |
||
157 | $this->assertTrue($request->attributes->has('foo')); |
||
158 | $this->assertSame('bar', $request->attributes->get('foo')); |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * @test |
||
163 | */ |
||
164 | public function canDecodeJsonBody() |
||
165 | { |
||
166 | $body = (object)['foo' => 'bar']; |
||
167 | |||
168 | $processor = $this->createProcessor(); |
||
169 | |||
170 | $this->parametersAssemblerMock |
||
171 | ->expects($this->once()) |
||
172 | ->method('assemble') |
||
173 | ->willReturnCallback( |
||
174 | function ( |
||
175 | Operation $operation, |
||
176 | array $query, |
||
177 | array $attributes, |
||
178 | array $headers, |
||
179 | \stdClass $body |
||
180 | ) { |
||
181 | return (object)['theBody' => $body]; |
||
182 | } |
||
183 | ); |
||
184 | |||
185 | $request = $this->createRequest( |
||
186 | [ |
||
187 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
188 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
189 | ], |
||
190 | json_encode($body) |
||
191 | ); |
||
192 | |||
193 | $processor->process($request); |
||
194 | |||
195 | $this->assertEquals($body, $request->attributes->get('theBody')); |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * @test |
||
200 | */ |
||
201 | public function canHydrateJsonBody() |
||
202 | { |
||
203 | $body = (object)['theBody' => 'bar']; |
||
204 | |||
205 | $processor = $this->createProcessor(true, true); |
||
206 | |||
207 | $parameter = new Parameter('theBody', true, new ObjectSchema((object)[]), Parameter::IN_BODY); |
||
208 | $descriptionMock = $this->getMockBuilder(Description::class)->disableOriginalConstructor()->getMock(); |
||
209 | $descriptionMock->expects($this->once())->method('getRequestBodyParameter')->willReturn($parameter); |
||
210 | |||
211 | $this->repositoryMock->expects($this->once())->method('get')->willReturn($descriptionMock); |
||
212 | |||
213 | $this->parametersAssemblerMock |
||
214 | ->expects($this->once()) |
||
215 | ->method('assemble') |
||
216 | ->willReturnCallback( |
||
217 | function ( |
||
218 | Operation $operation, |
||
219 | array $query, |
||
220 | array $attributes, |
||
221 | array $headers, |
||
222 | \stdClass $body |
||
223 | ) { |
||
224 | return (object)['theBody' => $body]; |
||
225 | } |
||
226 | ); |
||
227 | |||
228 | $dto = new \ArrayObject; |
||
229 | |||
230 | $this->hydratorMock |
||
231 | ->expects($this->once()) |
||
232 | ->method('hydrate') |
||
233 | ->with($body, $this->isInstanceOf(Schema::class)) |
||
234 | ->willReturnCallback( |
||
235 | function () use ($dto) { |
||
236 | return $dto; |
||
237 | } |
||
238 | ); |
||
239 | |||
240 | $request = $this->createRequest( |
||
241 | [ |
||
242 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
243 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
244 | ], |
||
245 | json_encode($body) |
||
246 | ); |
||
247 | |||
248 | $processor->process($request); |
||
249 | |||
250 | $this->assertSame($dto, $request->attributes->get('theBody')); |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * @test |
||
255 | */ |
||
256 | public function willSetRequestMetaAttribute() |
||
257 | { |
||
258 | $processor = $this->createProcessor(); |
||
259 | $coercedAttributes = (object)[ |
||
260 | 'foo' => 'bar', |
||
261 | ]; |
||
262 | |||
263 | $this->parametersAssemblerMock->expects($this->once())->method('assemble')->willReturn($coercedAttributes); |
||
264 | |||
265 | $request = $this->createRequest( |
||
266 | [ |
||
267 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
268 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
269 | ] |
||
270 | ); |
||
271 | |||
272 | $processor->process($request); |
||
273 | |||
274 | $this->assertTrue($request->attributes->has(RequestMeta::ATTRIBUTE)); |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * @test |
||
279 | */ |
||
280 | View Code Duplication | public function willThrowExceptionIfRequestIsNotValid() |
|
0 ignored issues
–
show
|
|||
281 | { |
||
282 | $processor = $this->createProcessor(false, false); |
||
283 | |||
284 | $this->expectException(ValidationException::class); |
||
285 | |||
286 | $processor->process( |
||
287 | $this->createRequest( |
||
288 | [ |
||
289 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
290 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
291 | ] |
||
292 | ) |
||
293 | ); |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * @test |
||
298 | */ |
||
299 | public function willThrowExceptionIfRequestBodyIsNotValid() |
||
300 | { |
||
301 | $this->hydratorMock->expects($this->never()) |
||
302 | ->method('hydrate'); |
||
303 | |||
304 | $processor = $this->createProcessor(true, false); |
||
305 | $this->expectException(ValidationException::class); |
||
306 | |||
307 | $processor->process( |
||
308 | $this->createRequest( |
||
309 | [ |
||
310 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
311 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
312 | ], |
||
313 | json_encode([]) |
||
314 | ) |
||
315 | ); |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * @test |
||
320 | */ |
||
321 | public function willPassNullToValidatorWhenOperationAndRequestHaveNoParams() |
||
322 | { |
||
323 | $processor = $this->createProcessor(); |
||
324 | |||
325 | $descriptionMock = $this->getMockBuilder(Description::class)->disableOriginalConstructor()->getMock(); |
||
326 | $pathMock = $this->getMockBuilder(Path::class)->disableOriginalConstructor()->getMock(); |
||
327 | $descriptionMock->expects($this->once())->method('getPath')->willReturn($pathMock); |
||
328 | $operationMock = $this->getMockBuilder(Operation::class)->disableOriginalConstructor()->getMock(); |
||
329 | $pathMock->expects($this->once())->method('getOperation')->willReturn($operationMock); |
||
330 | $operationMock->expects($this->once())->method('hasParameters')->willReturn(false); |
||
331 | |||
332 | $this->repositoryMock->expects($this->once())->method('get')->willReturn($descriptionMock); |
||
333 | $this->parametersAssemblerMock->expects($this->once())->method('assemble')->willReturn((object)[]); |
||
334 | |||
335 | $this->validatorMock->expects($this->once())->method('validate')->with( |
||
336 | $this->isInstanceOf(Schema::class), |
||
337 | null |
||
338 | ); |
||
339 | |||
340 | $processor->process( |
||
341 | $this->createRequest( |
||
342 | [ |
||
343 | RequestMeta::ATTRIBUTE_URI => '/uri', |
||
344 | RequestMeta::ATTRIBUTE_PATH => '/path', |
||
345 | ] |
||
346 | ) |
||
347 | ); |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * @param bool $useHydrator |
||
352 | * @param null|bool $forcedValidationResult |
||
353 | * |
||
354 | * @return RequestProcessor |
||
355 | */ |
||
356 | private function createProcessor(bool $useHydrator = false, $forcedValidationResult = true): RequestProcessor |
||
357 | { |
||
358 | if (null !== $forcedValidationResult) { |
||
359 | $this->validatorMock |
||
360 | ->expects($this->any()) |
||
361 | ->method('validate') |
||
362 | ->willReturn(new ValidationResult($forcedValidationResult)); |
||
363 | } |
||
364 | |||
365 | /** @var Repository $repository */ |
||
366 | $repository = $this->repositoryMock; |
||
367 | /** @var SchemaValidator $validator */ |
||
368 | $validator = $this->validatorMock; |
||
369 | /** @var RequestParameterAssembler $parametersAssembler */ |
||
370 | $parametersAssembler = $this->parametersAssemblerMock; |
||
371 | /** @var ObjectHydrator $hydrator */ |
||
372 | $hydrator = $this->hydratorMock; |
||
373 | |||
374 | return new RequestProcessor( |
||
375 | $repository, |
||
376 | $validator, |
||
377 | $parametersAssembler, |
||
378 | ($useHydrator ? $hydrator : null) |
||
379 | ); |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * @param array $attributes |
||
384 | * |
||
385 | * @param string $content |
||
386 | * |
||
387 | * @return Request |
||
388 | */ |
||
389 | private function createRequest(array $attributes, string $content = ''): Request |
||
390 | { |
||
391 | return new class($attributes, $content) extends Request |
||
392 | { |
||
393 | /** |
||
394 | * @param array $attributes |
||
395 | * @param array $content |
||
396 | */ |
||
397 | public function __construct(array $attributes, $content) |
||
398 | { |
||
399 | parent::__construct(); |
||
400 | $this->attributes = new ParameterBag($attributes); |
||
401 | $this->content = $content; |
||
0 ignored issues
–
show
It seems like
$content of type array is incompatible with the declared type string|resource|false|null of property $content .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..
Loading history...
|
|||
402 | } |
||
403 | }; |
||
404 | } |
||
405 | } |
||
406 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.