Completed
Push — master ( f730e7...231cf5 )
by John
03:07
created

willPassNullToValidatorWhenOperationAndRequestHaveNoParams()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 28
rs 8.8571
cc 1
eloc 17
nc 1
nop 0
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
0 ignored issues
show
Unused Code introduced by
$repository is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

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.

Loading history...
61
            ->getMockBuilder(Repository::class)
62
            ->disableOriginalConstructor()
63
            ->getMock();
64
65
        /** @var Repository $repository */
66
        $this->validatorMock = $validator = $this
0 ignored issues
show
Unused Code introduced by
$validator is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

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.

Loading history...
67
            ->getMockBuilder(SchemaValidator::class)
68
            ->disableOriginalConstructor()
69
            ->getMock();
70
71
        /** @var RequestParameterAssembler $hydrator */
72
        $this->parametersAssemblerMock = $parametersAssembler = $this
0 ignored issues
show
Unused Code introduced by
$parametersAssembler is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

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.

Loading history...
73
            ->getMockBuilder(RequestParameterAssembler::class)
74
            ->disableOriginalConstructor()
75
            ->getMock();
76
77
        /** @var ObjectHydrator $hydrator */
78
        $this->hydratorMock = $hydrator = $this
0 ignored issues
show
Unused Code introduced by
$hydrator is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

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.

Loading history...
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);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
92
        $processor->process(new Request());
93
    }
94
95
    /**
96
     * @test
97
     */
98 View Code Duplication
    public function willThrowExceptionWhenContentIsNotJson()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
99
    {
100
        $processor = $this->createProcessor();
101
102
        $this->setExpectedException(MalformedContentException::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
280
    {
281
        $processor = $this->createProcessor(false, false);
282
283
        $this->setExpectedException(ValidationException::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
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
0 ignored issues
show
Documentation introduced by
$content is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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;
0 ignored issues
show
Documentation Bug introduced by
It seems like $content of type array is incompatible with the declared type string 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...
379
            }
380
        };
381
    }
382
}
383