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\PhpApi\Hydrator\ObjectHydrator; |
22
|
|
|
use KleijnWeb\SwaggerBundle\EventListener\Request\RequestMeta; |
23
|
|
|
use KleijnWeb\SwaggerBundle\EventListener\Request\RequestProcessor; |
24
|
|
|
use KleijnWeb\SwaggerBundle\Exception\MalformedContentException; |
25
|
|
|
use KleijnWeb\SwaggerBundle\Exception\ValidationException; |
26
|
|
|
use Symfony\Component\HttpFoundation\ParameterBag; |
27
|
|
|
use Symfony\Component\HttpFoundation\Request; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @author John Kleijn <[email protected]> |
31
|
|
|
*/ |
32
|
|
|
class RequestProcessorTest extends \PHPUnit_Framework_TestCase |
33
|
|
|
{ |
34
|
|
|
/** |
35
|
|
|
* @var \PHPUnit_Framework_MockObject_MockObject |
36
|
|
|
*/ |
37
|
|
|
private $repositoryMock; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var \PHPUnit_Framework_MockObject_MockObject |
41
|
|
|
*/ |
42
|
|
|
private $validatorMock; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var \PHPUnit_Framework_MockObject_MockObject |
46
|
|
|
*/ |
47
|
|
|
private $hydratorMock; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var \PHPUnit_Framework_MockObject_MockObject |
51
|
|
|
*/ |
52
|
|
|
private $parametersAssemblerMock; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* Create mocks |
56
|
|
|
*/ |
57
|
|
|
protected function setUp() |
58
|
|
|
{ |
59
|
|
|
/** @var Repository $repository */ |
60
|
|
|
$this->repositoryMock = $repository = $this |
|
|
|
|
61
|
|
|
->getMockBuilder(Repository::class) |
62
|
|
|
->disableOriginalConstructor() |
63
|
|
|
->getMock(); |
64
|
|
|
|
65
|
|
|
/** @var Repository $repository */ |
66
|
|
|
$this->validatorMock = $validator = $this |
|
|
|
|
67
|
|
|
->getMockBuilder(SchemaValidator::class) |
68
|
|
|
->disableOriginalConstructor() |
69
|
|
|
->getMock(); |
70
|
|
|
|
71
|
|
|
/** @var RequestParameterAssembler $hydrator */ |
72
|
|
|
$this->parametersAssemblerMock = $parametersAssembler = $this |
|
|
|
|
73
|
|
|
->getMockBuilder(RequestParameterAssembler::class) |
74
|
|
|
->disableOriginalConstructor() |
75
|
|
|
->getMock(); |
76
|
|
|
|
77
|
|
|
/** @var ObjectHydrator $hydrator */ |
78
|
|
|
$this->hydratorMock = $hydrator = $this |
|
|
|
|
79
|
|
|
->getMockBuilder(ObjectHydrator::class) |
80
|
|
|
->disableOriginalConstructor() |
81
|
|
|
->getMock(); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @test |
86
|
|
|
*/ |
87
|
|
|
public function willThrowExceptionIfRequestDoesNotHaveDocumentUri() |
88
|
|
|
{ |
89
|
|
|
$processor = $this->createProcessor(); |
90
|
|
|
|
91
|
|
|
$this->setExpectedException(\UnexpectedValueException::class); |
|
|
|
|
92
|
|
|
$processor->process(new Request()); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @test |
97
|
|
|
*/ |
98
|
|
View Code Duplication |
public function willThrowExceptionWhenContentIsNotJson() |
|
|
|
|
99
|
|
|
{ |
100
|
|
|
$processor = $this->createProcessor(); |
101
|
|
|
|
102
|
|
|
$this->setExpectedException(MalformedContentException::class); |
|
|
|
|
103
|
|
|
|
104
|
|
|
$processor->process( |
105
|
|
|
$this->createRequest( |
106
|
|
|
[ |
107
|
|
|
RequestMeta::ATTRIBUTE_URI => '/uri', |
108
|
|
|
RequestMeta::ATTRIBUTE_PATH => '/path', |
109
|
|
|
], |
110
|
|
|
'not json' |
111
|
|
|
) |
112
|
|
|
); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @test |
117
|
|
|
*/ |
118
|
|
View Code Duplication |
public function willAssembleParameters() |
|
|
|
|
119
|
|
|
{ |
120
|
|
|
$processor = $this->createProcessor(); |
121
|
|
|
$this->parametersAssemblerMock->expects($this->once())->method('assemble'); |
122
|
|
|
|
123
|
|
|
$processor->process( |
124
|
|
|
$this->createRequest( |
125
|
|
|
[ |
126
|
|
|
RequestMeta::ATTRIBUTE_URI => '/uri', |
127
|
|
|
RequestMeta::ATTRIBUTE_PATH => '/path', |
128
|
|
|
] |
129
|
|
|
) |
130
|
|
|
); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* @test |
135
|
|
|
*/ |
136
|
|
|
public function willUpdateAttributes() |
137
|
|
|
{ |
138
|
|
|
$processor = $this->createProcessor(); |
139
|
|
|
$coercedAttributes = (object)[ |
140
|
|
|
'foo' => 'bar', |
141
|
|
|
]; |
142
|
|
|
|
143
|
|
|
$this->parametersAssemblerMock->expects($this->once())->method('assemble')->willReturn($coercedAttributes); |
144
|
|
|
|
145
|
|
|
$request = $this->createRequest( |
146
|
|
|
[ |
147
|
|
|
RequestMeta::ATTRIBUTE_URI => '/uri', |
148
|
|
|
RequestMeta::ATTRIBUTE_PATH => '/path', |
149
|
|
|
] |
150
|
|
|
); |
151
|
|
|
|
152
|
|
|
$processor->process($request); |
153
|
|
|
|
154
|
|
|
$this->assertTrue($request->attributes->has(RequestMeta::ATTRIBUTE_URI)); |
155
|
|
|
$this->assertTrue($request->attributes->has(RequestMeta::ATTRIBUTE_PATH)); |
156
|
|
|
$this->assertTrue($request->attributes->has('foo')); |
157
|
|
|
$this->assertSame('bar', $request->attributes->get('foo')); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* @test |
162
|
|
|
*/ |
163
|
|
|
public function canDecodeJsonBody() |
164
|
|
|
{ |
165
|
|
|
$body = (object)['foo' => 'bar']; |
166
|
|
|
|
167
|
|
|
$processor = $this->createProcessor(); |
168
|
|
|
|
169
|
|
|
$this->parametersAssemblerMock |
170
|
|
|
->expects($this->once()) |
171
|
|
|
->method('assemble') |
172
|
|
|
->willReturnCallback( |
173
|
|
|
function ( |
174
|
|
|
Operation $operation, |
175
|
|
|
array $query, |
176
|
|
|
array $attributes, |
177
|
|
|
array $headers, |
178
|
|
|
\stdClass $body |
179
|
|
|
) { |
180
|
|
|
return (object)['theBody' => $body]; |
181
|
|
|
} |
182
|
|
|
); |
183
|
|
|
|
184
|
|
|
$request = $this->createRequest( |
185
|
|
|
[ |
186
|
|
|
RequestMeta::ATTRIBUTE_URI => '/uri', |
187
|
|
|
RequestMeta::ATTRIBUTE_PATH => '/path', |
188
|
|
|
], |
189
|
|
|
json_encode($body) |
190
|
|
|
); |
191
|
|
|
|
192
|
|
|
$processor->process($request); |
193
|
|
|
|
194
|
|
|
$this->assertEquals($body, $request->attributes->get('theBody')); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* @test |
199
|
|
|
*/ |
200
|
|
|
public function canHydrateJsonBody() |
201
|
|
|
{ |
202
|
|
|
$body = (object)['theBody' => 'bar']; |
203
|
|
|
|
204
|
|
|
$processor = $this->createProcessor(true, true); |
205
|
|
|
|
206
|
|
|
$parameter = new Parameter('theBody', true, new ObjectSchema((object)[]), Parameter::IN_BODY); |
207
|
|
|
$descriptionMock = $this->getMockBuilder(Description::class)->disableOriginalConstructor()->getMock(); |
208
|
|
|
$descriptionMock->expects($this->once())->method('getRequestBodyParameter')->willReturn($parameter); |
209
|
|
|
|
210
|
|
|
$this->repositoryMock->expects($this->once())->method('get')->willReturn($descriptionMock); |
211
|
|
|
|
212
|
|
|
$this->parametersAssemblerMock |
213
|
|
|
->expects($this->once()) |
214
|
|
|
->method('assemble') |
215
|
|
|
->willReturnCallback( |
216
|
|
|
function ( |
217
|
|
|
Operation $operation, |
218
|
|
|
array $query, |
219
|
|
|
array $attributes, |
220
|
|
|
array $headers, |
221
|
|
|
\stdClass $body |
222
|
|
|
) { |
223
|
|
|
return (object)['theBody' => $body]; |
224
|
|
|
} |
225
|
|
|
); |
226
|
|
|
|
227
|
|
|
$dto = new \ArrayObject; |
228
|
|
|
|
229
|
|
|
$this->hydratorMock |
230
|
|
|
->expects($this->once()) |
231
|
|
|
->method('hydrate') |
232
|
|
|
->with($body, $this->isInstanceOf(Schema::class)) |
233
|
|
|
->willReturnCallback( |
234
|
|
|
function () use ($dto) { |
235
|
|
|
return $dto; |
236
|
|
|
} |
237
|
|
|
); |
238
|
|
|
|
239
|
|
|
$request = $this->createRequest( |
240
|
|
|
[ |
241
|
|
|
RequestMeta::ATTRIBUTE_URI => '/uri', |
242
|
|
|
RequestMeta::ATTRIBUTE_PATH => '/path', |
243
|
|
|
], |
244
|
|
|
json_encode($body) |
245
|
|
|
); |
246
|
|
|
|
247
|
|
|
$processor->process($request); |
248
|
|
|
|
249
|
|
|
$this->assertSame($dto, $request->attributes->get('theBody')); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* @test |
254
|
|
|
*/ |
255
|
|
|
public function willSetRequestMetaAttribute() |
256
|
|
|
{ |
257
|
|
|
$processor = $this->createProcessor(); |
258
|
|
|
$coercedAttributes = (object)[ |
259
|
|
|
'foo' => 'bar', |
260
|
|
|
]; |
261
|
|
|
|
262
|
|
|
$this->parametersAssemblerMock->expects($this->once())->method('assemble')->willReturn($coercedAttributes); |
263
|
|
|
|
264
|
|
|
$request = $this->createRequest( |
265
|
|
|
[ |
266
|
|
|
RequestMeta::ATTRIBUTE_URI => '/uri', |
267
|
|
|
RequestMeta::ATTRIBUTE_PATH => '/path', |
268
|
|
|
] |
269
|
|
|
); |
270
|
|
|
|
271
|
|
|
$processor->process($request); |
272
|
|
|
|
273
|
|
|
$this->assertTrue($request->attributes->has(RequestMeta::ATTRIBUTE)); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* @test |
278
|
|
|
*/ |
279
|
|
View Code Duplication |
public function willThrowExceptionIfRequestIsNotValid() |
|
|
|
|
280
|
|
|
{ |
281
|
|
|
$processor = $this->createProcessor(false, false); |
282
|
|
|
|
283
|
|
|
$this->setExpectedException(ValidationException::class); |
|
|
|
|
284
|
|
|
|
285
|
|
|
$processor->process( |
286
|
|
|
$this->createRequest( |
287
|
|
|
[ |
288
|
|
|
RequestMeta::ATTRIBUTE_URI => '/uri', |
289
|
|
|
RequestMeta::ATTRIBUTE_PATH => '/path', |
290
|
|
|
] |
291
|
|
|
) |
292
|
|
|
); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* @test |
297
|
|
|
*/ |
298
|
|
|
public function willPassNullToValidatorWhenOperationAndRequestHaveNoParams() |
299
|
|
|
{ |
300
|
|
|
$processor = $this->createProcessor(); |
301
|
|
|
|
302
|
|
|
$descriptionMock = $this->getMockBuilder(Description::class)->disableOriginalConstructor()->getMock(); |
303
|
|
|
$pathMock = $this->getMockBuilder(Path::class)->disableOriginalConstructor()->getMock(); |
304
|
|
|
$descriptionMock->expects($this->once())->method('getPath')->willReturn($pathMock); |
305
|
|
|
$operationMock = $this->getMockBuilder(Operation::class)->disableOriginalConstructor()->getMock(); |
306
|
|
|
$pathMock->expects($this->once())->method('getOperation')->willReturn($operationMock); |
307
|
|
|
$operationMock->expects($this->once())->method('hasParameters')->willReturn(false); |
308
|
|
|
|
309
|
|
|
$this->repositoryMock->expects($this->once())->method('get')->willReturn($descriptionMock); |
310
|
|
|
$this->parametersAssemblerMock->expects($this->once())->method('assemble')->willReturn((object)[]); |
311
|
|
|
|
312
|
|
|
$this->validatorMock->expects($this->once())->method('validate')->with( |
313
|
|
|
$this->isInstanceOf(Schema::class), |
314
|
|
|
null |
315
|
|
|
); |
316
|
|
|
|
317
|
|
|
$processor->process( |
318
|
|
|
$this->createRequest( |
319
|
|
|
[ |
320
|
|
|
RequestMeta::ATTRIBUTE_URI => '/uri', |
321
|
|
|
RequestMeta::ATTRIBUTE_PATH => '/path', |
322
|
|
|
] |
323
|
|
|
) |
324
|
|
|
); |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
/** |
328
|
|
|
* @param bool $useHydrator |
329
|
|
|
* @param null|bool $forcedValidationResult |
330
|
|
|
* |
331
|
|
|
* @return RequestProcessor |
332
|
|
|
*/ |
333
|
|
|
private function createProcessor(bool $useHydrator = false, $forcedValidationResult = true): RequestProcessor |
334
|
|
|
{ |
335
|
|
|
if (null !== $forcedValidationResult) { |
336
|
|
|
$this->validatorMock |
337
|
|
|
->expects($this->any()) |
338
|
|
|
->method('validate') |
339
|
|
|
->willReturn(new ValidationResult($forcedValidationResult)); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** @var Repository $repository */ |
343
|
|
|
$repository = $this->repositoryMock; |
344
|
|
|
/** @var SchemaValidator $validator */ |
345
|
|
|
$validator = $this->validatorMock; |
346
|
|
|
/** @var RequestParameterAssembler $parametersAssembler */ |
347
|
|
|
$parametersAssembler = $this->parametersAssemblerMock; |
348
|
|
|
/** @var ObjectHydrator $hydrator */ |
349
|
|
|
$hydrator = $this->hydratorMock; |
350
|
|
|
|
351
|
|
|
return new RequestProcessor( |
352
|
|
|
$repository, |
353
|
|
|
$validator, |
354
|
|
|
$parametersAssembler, |
355
|
|
|
($useHydrator ? $hydrator : null) |
356
|
|
|
); |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* @param array $attributes |
361
|
|
|
* |
362
|
|
|
* @param string $content |
363
|
|
|
* |
364
|
|
|
* @return Request |
365
|
|
|
*/ |
366
|
|
|
private function createRequest(array $attributes, string $content = ''): Request |
367
|
|
|
{ |
368
|
|
|
return new class($attributes, $content) extends Request |
|
|
|
|
369
|
|
|
{ |
370
|
|
|
/** |
371
|
|
|
* @param array $attributes |
372
|
|
|
* @param array $content |
373
|
|
|
*/ |
374
|
|
|
public function __construct(array $attributes, $content) |
375
|
|
|
{ |
376
|
|
|
parent::__construct(); |
377
|
|
|
$this->attributes = new ParameterBag($attributes); |
378
|
|
|
$this->content = $content; |
|
|
|
|
379
|
|
|
} |
380
|
|
|
}; |
381
|
|
|
} |
382
|
|
|
} |
383
|
|
|
|
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.