Passed
Push — master ( 1ccf8a...1e427b )
by Daniel
02:19
created

php$1 ➔ testProcessWorksWithMiddleware()   A

Complexity

Conditions 1

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 41
rs 9.264
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Usox\JsonSchemaApi;
6
7
use Exception;
8
use Mockery;
9
use Mockery\Adapter\Phpunit\MockeryTestCase;
10
use Mockery\MockInterface;
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ServerRequestInterface;
13
use Psr\Http\Message\StreamFactoryInterface;
14
use Psr\Http\Message\StreamInterface;
15
use Psr\Http\Server\RequestHandlerInterface;
16
use Psr\Log\LoggerInterface;
17
use Ramsey\Uuid\UuidFactoryInterface;
18
use Ramsey\Uuid\UuidInterface;
19
use stdClass;
20
use Teapot\StatusCode;
21
use Usox\JsonSchemaApi\Contract\MethodProviderInterface;
22
use Usox\JsonSchemaApi\Dispatch\MethodDispatcherInterface;
23
use Usox\JsonSchemaApi\Dispatch\RequestValidatorInterface;
24
use Usox\JsonSchemaApi\Exception\ApiException;
25
use Usox\JsonSchemaApi\Exception\ApiMethodException;
26
use Usox\JsonSchemaApi\Exception\ResponseMalformedException;
27
use Usox\JsonSchemaApi\Response\ResponseBuilderInterface;
28
29
class EndpointTest extends MockeryTestCase
30
{
31
    /** @var RequestValidatorInterface|MockInterface */
32
    private MockInterface $requestValidator;
33
34
    /** @var MethodDispatcherInterface|MockInterface */
35
    private MockInterface $methodDispatcher;
36
37
    /** @var ResponseBuilderInterface|MockInterface */
38
    private MockInterface $responseBuilder;
39
40
    /** @var UuidFactoryInterface|MockInterface */
41
    private MockInterface $uuidFactory;
42
43
    /** @var StreamFactoryInterface|MockInterface */
44
    private MockInterface $streamFactory;
45
46
    /** @var LoggerInterface|MockInterface */
47
    private MockInterface $logger;
48
    
49
    private Endpoint $subject;
50
    
51
    public function setUp(): void
52
    {
53
        $this->requestValidator = Mockery::mock(RequestValidatorInterface::class);
54
        $this->methodDispatcher = Mockery::mock(MethodDispatcherInterface::class);
55
        $this->responseBuilder = Mockery::mock(ResponseBuilderInterface::class);
56
        $this->uuidFactory = Mockery::mock(UuidFactoryInterface::class);
57
        $this->streamFactory = Mockery::mock(StreamFactoryInterface::class);
58
        $this->logger = Mockery::mock(LoggerInterface::class);
59
        
60
        $this->subject = new Endpoint(
61
            $this->requestValidator,
0 ignored issues
show
Bug introduced by
$this->requestValidator of type Mockery\MockInterface is incompatible with the type Usox\JsonSchemaApi\Dispa...questValidatorInterface expected by parameter $inputValidator of Usox\JsonSchemaApi\Endpoint::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

61
            /** @scrutinizer ignore-type */ $this->requestValidator,
Loading history...
62
            $this->methodDispatcher,
0 ignored issues
show
Bug introduced by
$this->methodDispatcher of type Mockery\MockInterface is incompatible with the type Usox\JsonSchemaApi\Dispa...thodDispatcherInterface expected by parameter $methodRetriever of Usox\JsonSchemaApi\Endpoint::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

62
            /** @scrutinizer ignore-type */ $this->methodDispatcher,
Loading history...
63
            $this->responseBuilder,
0 ignored issues
show
Bug introduced by
$this->responseBuilder of type Mockery\MockInterface is incompatible with the type Usox\JsonSchemaApi\Respo...esponseBuilderInterface expected by parameter $responseBuilder of Usox\JsonSchemaApi\Endpoint::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
            /** @scrutinizer ignore-type */ $this->responseBuilder,
Loading history...
64
            $this->uuidFactory,
0 ignored issues
show
Bug introduced by
$this->uuidFactory of type Mockery\MockInterface is incompatible with the type Ramsey\Uuid\UuidFactoryInterface expected by parameter $uuidFactory of Usox\JsonSchemaApi\Endpoint::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

64
            /** @scrutinizer ignore-type */ $this->uuidFactory,
Loading history...
65
            $this->streamFactory,
0 ignored issues
show
Bug introduced by
$this->streamFactory of type Mockery\MockInterface is incompatible with the type Psr\Http\Message\StreamFactoryInterface expected by parameter $streamFactory of Usox\JsonSchemaApi\Endpoint::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

65
            /** @scrutinizer ignore-type */ $this->streamFactory,
Loading history...
66
            $this->logger
0 ignored issues
show
Bug introduced by
$this->logger of type Mockery\MockInterface is incompatible with the type Psr\Log\LoggerInterface|null expected by parameter $logger of Usox\JsonSchemaApi\Endpoint::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

66
            /** @scrutinizer ignore-type */ $this->logger
Loading history...
67
        );
68
    }
69
    
70
    public function testServeReturnsHandlerOutput(): void
71
    {
72
        $request = Mockery::mock(ServerRequestInterface::class);
73
        $response = Mockery::mock(ResponseInterface::class);
74
        
75
        $parameter = new stdClass();
76
        $decodedInput = new stdClass();
77
        $decodedInput->parameter = $parameter;
78
        $responseData = ['some-response'];
79
        $processedResponse = ['some-processed-response'];
80
        
81
        $this->requestValidator->shouldReceive('validate')
82
            ->with($request)
83
            ->once()
84
            ->andReturn($decodedInput);
85
        
86
        $this->methodDispatcher->shouldReceive('dispatch')
87
            ->with($request, $decodedInput)
88
            ->once()
89
            ->andReturn($responseData);
90
        
91
        $this->responseBuilder->shouldReceive('buildResponse')
92
            ->with($responseData)
93
            ->once()
94
            ->andReturn($processedResponse);
95
        
96
        $this->createResponseExpectations(
97
            $response,
98
            $processedResponse,
99
            StatusCode::OK
100
        );
101
        
102
        static::assertSame(
103
            $response,
104
            $this->subject->serve($request, $response)
0 ignored issues
show
Bug introduced by
$request of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ServerRequestInterface expected by parameter $request of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
            $this->subject->serve(/** @scrutinizer ignore-type */ $request, $response)
Loading history...
Bug introduced by
$response of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ResponseInterface expected by parameter $response of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
            $this->subject->serve($request, /** @scrutinizer ignore-type */ $response)
Loading history...
105
        );
106
    }
107
108
    public function testServeCatchesApiMethodException(): void
109
    {
110
        $request = Mockery::mock(ServerRequestInterface::class);
111
        $response = Mockery::mock(ResponseInterface::class);
112
        $uuid = Mockery::mock(UuidInterface::class);
113
        
114
        $errorMessage = 'some-error';
115
        $errorCode = 666;
116
        $processedResponse = ['some-processed-response'];
117
        $uuidValue = 'some-uuid';
118
119
        $error = new class($errorMessage, $errorCode) extends ApiMethodException {};
120
121
        $this->requestValidator->shouldReceive('validate')
122
            ->with($request)
123
            ->once()
124
            ->andThrow($error);
125
126
        $this->responseBuilder->shouldReceive('buildErrorResponse')
127
            ->with($error, $uuid)
128
            ->once()
129
            ->andReturn($processedResponse);
130
        
131
        $this->uuidFactory->shouldReceive('uuid4')
132
            ->withNoArgs()
133
            ->once()
134
            ->andReturn($uuid);
135
        
136
        $uuid->shouldReceive('toString')
137
            ->withNoArgs()
138
            ->once()
139
            ->andReturn($uuidValue);
140
141
        $this->createResponseExpectations(
142
            $response,
143
            $processedResponse,
144
            StatusCode::BAD_REQUEST
145
        );
146
        
147
        $this->logger->shouldReceive('error')
148
            ->with(
149
                sprintf('%s (%d)', $errorMessage, $errorCode),
150
                Mockery::type('array')
151
            )
152
            ->once();
153
154
        static::assertSame(
155
            $response,
156
            $this->subject->serve($request, $response)
0 ignored issues
show
Bug introduced by
$request of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ServerRequestInterface expected by parameter $request of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

156
            $this->subject->serve(/** @scrutinizer ignore-type */ $request, $response)
Loading history...
Bug introduced by
$response of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ResponseInterface expected by parameter $response of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

156
            $this->subject->serve($request, /** @scrutinizer ignore-type */ $response)
Loading history...
157
        );
158
    }
159
160
    public function testServeCatchesApiException(): void
161
    {
162
        $request = Mockery::mock(ServerRequestInterface::class);
163
        $response = Mockery::mock(ResponseInterface::class);
164
        $uuid = Mockery::mock(UuidInterface::class);
165
166
        $errorMessage = 'some-error';
167
        $errorCode = 666;
168
        $processedResponse = ['some-processed-response'];
169
        $uuidValue = 'some-uuid';
170
171
        $error = new class($errorMessage, $errorCode) extends ApiException {};
172
173
        $this->requestValidator->shouldReceive('validate')
174
            ->with($request)
175
            ->once()
176
            ->andThrow($error);
177
178
        $this->responseBuilder->shouldReceive('buildErrorResponse')
179
            ->with($error, $uuid)
180
            ->once()
181
            ->andReturn($processedResponse);
182
183
        $this->uuidFactory->shouldReceive('uuid4')
184
            ->withNoArgs()
185
            ->once()
186
            ->andReturn($uuid);
187
188
        $uuid->shouldReceive('toString')
189
            ->withNoArgs()
190
            ->once()
191
            ->andReturn($uuidValue);
192
193
        $this->createResponseExpectations(
194
            $response,
195
            $processedResponse,
196
            StatusCode::BAD_REQUEST
197
        );
198
199
        $this->logger->shouldReceive('error')
200
            ->with(
201
                sprintf('%s (%d)', $errorMessage, $errorCode),
202
                Mockery::type('array')
203
            )
204
            ->once();
205
206
        static::assertSame(
207
            $response,
208
            $this->subject->serve($request, $response)
0 ignored issues
show
Bug introduced by
$request of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ServerRequestInterface expected by parameter $request of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

208
            $this->subject->serve(/** @scrutinizer ignore-type */ $request, $response)
Loading history...
Bug introduced by
$response of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ResponseInterface expected by parameter $response of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

208
            $this->subject->serve($request, /** @scrutinizer ignore-type */ $response)
Loading history...
209
        );
210
    }
211
212
    public function testServeCatchesGenericException(): void
213
    {
214
        $request = Mockery::mock(ServerRequestInterface::class);
215
        $response = Mockery::mock(ResponseInterface::class);
216
        $uuid = Mockery::mock(UuidInterface::class);
217
218
        $errorMessage = 'some-error';
219
        $errorCode = 666;
220
        $uuidValue = 'some-uuid';
221
222
        $error = new Exception($errorMessage, $errorCode);
223
224
        $this->requestValidator->shouldReceive('validate')
225
            ->with($request)
226
            ->once()
227
            ->andThrow($error);
228
229
        $this->uuidFactory->shouldReceive('uuid4')
230
            ->withNoArgs()
231
            ->once()
232
            ->andReturn($uuid);
233
234
        $uuid->shouldReceive('toString')
235
            ->withNoArgs()
236
            ->once()
237
            ->andReturn($uuidValue);
238
239
        $this->createResponseExpectations(
240
            $response,
241
            '',
242
            StatusCode::INTERNAL_SERVER_ERROR
243
        );
244
245
        $this->logger->shouldReceive('error')
246
            ->with(
247
                sprintf('%s (%d)', $errorMessage, $errorCode),
248
                Mockery::type('array')
249
            )
250
            ->once();
251
252
        static::assertSame(
253
            $response,
254
            $this->subject->serve($request, $response)
0 ignored issues
show
Bug introduced by
$response of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ResponseInterface expected by parameter $response of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

254
            $this->subject->serve($request, /** @scrutinizer ignore-type */ $response)
Loading history...
Bug introduced by
$request of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ServerRequestInterface expected by parameter $request of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

254
            $this->subject->serve(/** @scrutinizer ignore-type */ $request, $response)
Loading history...
255
        );
256
    }
257
258
    public function testServeCatchesInternalException(): void
259
    {
260
        $request = Mockery::mock(ServerRequestInterface::class);
261
        $response = Mockery::mock(ResponseInterface::class);
262
        $uuid = Mockery::mock(UuidInterface::class);
263
264
        $errorMessage = 'some-error';
265
        $errorCode = 666;
266
        $uuidValue = 'some-uuid';
267
        $context = ['some' => 'context'];
268
269
        $error = new ResponseMalformedException($errorMessage, $errorCode, null, $context);
270
271
        $this->requestValidator->shouldReceive('validate')
272
            ->with($request)
273
            ->once()
274
            ->andThrow($error);
275
276
        $this->uuidFactory->shouldReceive('uuid4')
277
            ->withNoArgs()
278
            ->once()
279
            ->andReturn($uuid);
280
281
        $uuid->shouldReceive('toString')
282
            ->withNoArgs()
283
            ->once()
284
            ->andReturn($uuidValue);
285
286
        $this->createResponseExpectations(
287
            $response,
288
            '',
289
            StatusCode::INTERNAL_SERVER_ERROR
290
        );
291
292
        $this->logger->shouldReceive('error')
293
            ->with(
294
                sprintf('%s (%d)', $errorMessage, $errorCode),
295
                Mockery::type('array')
296
            )
297
            ->once();
298
299
        static::assertSame(
300
            $response,
301
            $this->subject->serve($request, $response)
0 ignored issues
show
Bug introduced by
$response of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ResponseInterface expected by parameter $response of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

301
            $this->subject->serve($request, /** @scrutinizer ignore-type */ $response)
Loading history...
Bug introduced by
$request of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ServerRequestInterface expected by parameter $request of Usox\JsonSchemaApi\Endpoint::serve(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

301
            $this->subject->serve(/** @scrutinizer ignore-type */ $request, $response)
Loading history...
302
        );
303
    }
304
    
305
    public function testFactoryReturnsInstance(): void
306
    {
307
        static::assertInstanceOf(
308
            Endpoint::class,
309
            Endpoint::factory(
310
                Mockery::mock(MethodProviderInterface::class),
0 ignored issues
show
Bug introduced by
Mockery::mock(Usox\JsonS...oviderInterface::class) of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Usox\JsonSchemaApi\Contr...MethodProviderInterface expected by parameter $methodProvider of Usox\JsonSchemaApi\Endpoint::factory(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

310
                /** @scrutinizer ignore-type */ Mockery::mock(MethodProviderInterface::class),
Loading history...
311
                Mockery::mock(StreamFactoryInterface::class)
0 ignored issues
show
Bug introduced by
Mockery::mock(Psr\Http\M...actoryInterface::class) of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\StreamFactoryInterface|null expected by parameter $streamFactory of Usox\JsonSchemaApi\Endpoint::factory(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

311
                /** @scrutinizer ignore-type */ Mockery::mock(StreamFactoryInterface::class)
Loading history...
312
            )
313
        );
314
    }
315
316
    public function testProcessWorksWithMiddleware(): void
317
    {
318
        $request = Mockery::mock(ServerRequestInterface::class);
319
        $response = Mockery::mock(ResponseInterface::class);
320
        $requestHandler = Mockery::mock(RequestHandlerInterface::class);
321
322
        $parameter = new stdClass();
323
        $decodedInput = new stdClass();
324
        $decodedInput->parameter = $parameter;
325
        $responseData = ['some-response'];
326
        $processedResponse = ['some-processed-response'];
327
328
        $this->requestValidator->shouldReceive('validate')
329
            ->with($request)
330
            ->once()
331
            ->andReturn($decodedInput);
332
333
        $this->methodDispatcher->shouldReceive('dispatch')
334
            ->with($request, $decodedInput)
335
            ->once()
336
            ->andReturn($responseData);
337
338
        $this->responseBuilder->shouldReceive('buildResponse')
339
            ->with($responseData)
340
            ->once()
341
            ->andReturn($processedResponse);
342
343
        $this->createResponseExpectations(
344
            $response,
345
            $processedResponse,
346
            StatusCode::OK
347
        );
348
        
349
        $requestHandler->shouldReceive('handle')
350
            ->with($request)
351
            ->once()
352
            ->andReturn($response);
353
354
        static::assertSame(
355
            $response,
356
            $this->subject->process($request, $requestHandler)
0 ignored issues
show
Bug introduced by
$requestHandler of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Server\RequestHandlerInterface expected by parameter $handler of Usox\JsonSchemaApi\Endpoint::process(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

356
            $this->subject->process($request, /** @scrutinizer ignore-type */ $requestHandler)
Loading history...
Bug introduced by
$request of type Mockery\LegacyMockInterface|Mockery\MockInterface is incompatible with the type Psr\Http\Message\ServerRequestInterface expected by parameter $request of Usox\JsonSchemaApi\Endpoint::process(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

356
            $this->subject->process(/** @scrutinizer ignore-type */ $request, $requestHandler)
Loading history...
357
        );
358
    }
359
360
    /**
361
     * @param MockInterface $response
362
     * @param string|array<mixed, mixed> $responseData
363
     * @param int $statusCode
364
     */
365
    private function createResponseExpectations(
366
        MockInterface $response,
367
        $responseData,
368
        int $statusCode
369
    ): void {
370
        $stream = Mockery::mock(StreamInterface::class);
371
        
372
        $this->streamFactory->shouldReceive('createStream')
373
            ->with(json_encode($responseData))
374
            ->once()
375
            ->andReturn($stream);
376
        
377
        $response->shouldReceive('withHeader')
378
            ->with('Content-Type', 'application/json')
379
            ->once()
380
            ->andReturnSelf();
0 ignored issues
show
Bug introduced by
The method andReturnSelf() does not exist on Mockery\ExpectationInterface. Did you maybe mean andReturn()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

380
            ->/** @scrutinizer ignore-call */ andReturnSelf();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
381
        $response->shouldReceive('withStatus')
382
            ->with($statusCode)
383
            ->once()
384
            ->andReturnSelf();
385
        $response->shouldReceive('withBody')
386
            ->with($stream)
387
            ->once()
388
            ->andReturnSelf();
389
    }
390
}
391