Completed
Pull Request — master (#13)
by
unknown
03:54
created

ApiServiceTest   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 837
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 470
dl 0
loc 837
rs 10
c 0
b 0
f 0
wmc 24

19 Methods

Rating   Name   Duplication   Size   Complexity  
A itShouldPreferHttpsByDefault() 0 8 1
A getApiService() 0 11 1
A itCheckTheHostInApiSchema() 0 9 1
B itShouldNotReturnTheResponseOrAnyDataBecauseThereAreSomeViolationInResponse() 0 81 2
A dataProviderItShouldCreateRequestFromDefinition() 0 73 1
A dataProviderItShouldUseDefaultValues() 0 87 1
A itCreateABaseUriUsingTheOneProvidedInTheConfigArray() 0 7 1
A dataProviderItShouldThrowExceptionBecauseThereAreSomeError() 0 7 1
A itShouldReturnTheResponse() 0 62 1
A itShouldCreateRequestFromDefinition() 0 67 2
A itShouldUseDefaultValues() 0 71 3
A itShouldThrowExceptionBecauseThereAreSomeError() 0 21 1
A itCanMakeASynchronousCallWithoutDefaultValueAndParameters() 0 53 1
A itShouldCheckApiSchemaSchemes() 0 6 1
A itShouldNotCreateRequestBecauseSomeParameterWasNotDefined() 0 29 1
A setUp() 0 11 1
A itShouldPreferHttps() 0 8 1
A itOnlySupportHttpAndHttps() 0 9 1
A itShouldNotReturnTheResponseOrAnyDataBecauseThereAreSomeViolationInRequest() 0 73 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ElevenLabs\Api\Service\Tests;
6
7
use ElevenLabs\Api\Definition\Parameter;
8
use ElevenLabs\Api\Definition\Parameters;
9
use ElevenLabs\Api\Definition\RequestDefinition;
10
use ElevenLabs\Api\Definition\ResponseDefinition;
11
use ElevenLabs\Api\Schema;
12
use ElevenLabs\Api\Service\ApiService;
13
use ElevenLabs\Api\Service\Exception\RequestViolations;
14
use ElevenLabs\Api\Service\Exception\ResponseViolations;
15
use ElevenLabs\Api\Validator\ConstraintViolation;
16
use ElevenLabs\Api\Validator\MessageValidator;
17
use GuzzleHttp\Psr7\Request;
18
use Http\Client\HttpClient;
19
use Http\Message\MessageFactory;
20
use Http\Message\UriFactory;
21
use PHPUnit\Framework\MockObject\MockObject;
22
use PHPUnit\Framework\TestCase;
23
use Psr\Http\Message\ResponseInterface;
24
use Psr\Http\Message\StreamInterface;
25
use Psr\Http\Message\UriInterface;
26
use Rize\UriTemplate;
27
use Symfony\Component\Serializer\SerializerInterface;
28
29
/**
30
 * Class ApiServiceTest.
31
 */
32
class ApiServiceTest extends TestCase
33
{
34
    /** @var Schema|MockObject */
35
    private $schema;
36
37
    /** @var Schema|MockObject */
38
    private $uri;
39
40
    /** @var UriFactory|MockObject */
41
    private $uriFactory;
42
43
    /** @var UriTemplate|MockObject */
44
    private $uriTemplate;
45
46
    /** @var HttpClient|MockObject */
47
    private $httpClient;
48
49
    /** @var MessageFactory|MockObject */
50
    private $messageFactory;
51
52
    /** @var MessageValidator|MockObject */
53
    private $messageValidator;
54
55
    /** @var SerializerInterface|MockObject */
56
    private $serializer;
57
58
    /** @var array */
59
    private $config;
60
61
    public function setUp()
62
    {
63
        $this->uri = $this->createMock(UriInterface::class);
64
        $this->schema = $this->createMock(Schema::class);
65
        $this->uriFactory = $this->createMock(UriFactory::class);
66
        $this->uriTemplate = $this->createMock(UriTemplate::class);
67
        $this->httpClient = $this->createMock(HttpClient::class);
68
        $this->messageFactory = $this->createMock(MessageFactory::class);
69
        $this->messageValidator = $this->createMock(MessageValidator::class);
70
        $this->serializer = $this->createMock(SerializerInterface::class);
71
        $this->config = [];
72
    }
73
74
    /** @test */
75
    public function itShouldCheckApiSchemaSchemes()
76
    {
77
        $this->expectException(\LogicException::class);
78
        $this->expectExceptionMessage('You need to provide at least on scheme in your API Schema');
79
80
        $this->getApiService();
81
    }
82
83
    /** @test */
84
    public function itCheckTheHostInApiSchema()
85
    {
86
        $this->expectException(\LogicException::class);
87
        $this->expectExceptionMessage('The host in the API Schema should not be null');
88
89
        $this->schema->expects($this->exactly(2))->method('getSchemes')->willReturn(['https']);
90
        $this->schema->expects($this->once())->method('getHost')->willReturn('');
91
92
        $this->getApiService();
93
    }
94
95
    /** @test */
96
    public function itOnlySupportHttpAndHttps()
97
    {
98
        $this->expectException(\RuntimeException::class);
99
        $this->expectExceptionMessage('Cannot choose a proper scheme from the API Schema. Supported: https, http');
100
101
        $this->schema->expects($this->any())->method('getSchemes')->willReturn(['ftp']);
102
        $this->schema->expects($this->any())->method('getHost')->willReturn('domain.tld');
103
104
        $this->getApiService();
105
    }
106
107
    /** @test */
108
    public function itShouldPreferHttps()
109
    {
110
        $this->schema->expects($this->exactly(2))->method('getSchemes')->willReturn(['http', 'https']);
111
        $this->schema->expects($this->exactly(1))->method('getHost')->willReturn('domain.tld');
112
113
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://domain.tld')->willReturn($this->uri);
114
115
        $this->getApiService();
116
    }
117
118
    /** @test */
119
    public function itShouldPreferHttpsByDefault()
120
    {
121
        $this->schema->expects($this->exactly(2))->method('getSchemes')->willReturn(['http']);
122
        $this->schema->expects($this->exactly(1))->method('getHost')->willReturn('domain.tld');
123
124
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('http://domain.tld')->willReturn($this->uri);
125
126
        $this->getApiService();
127
    }
128
129
    /** @test */
130
    public function itCreateABaseUriUsingTheOneProvidedInTheConfigArray()
131
    {
132
        $this->config['baseUri'] = 'https://somewhere.tld';
133
134
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://somewhere.tld')->willReturn($this->uri);
135
136
        $this->getApiService();
137
    }
138
139
    /**
140
     * @test
141
     *
142
     * @dataProvider dataProviderItShouldUseDefaultValues
143
     *
144
     * @param array $requestParams
145
     * @param array $expected
146
     *
147
     * @throws \Assert\AssertionFailedException
148
     * @throws \ElevenLabs\Api\Service\Exception\ConstraintViolations
149
     * @throws \Http\Client\Exception
150
     */
151
    public function itShouldUseDefaultValues(array $requestParams, array $expected)
152
    {
153
        $requestParameters = [];
154
        foreach ($requestParams as $p) {
155
            $requestParameter = $this->getMockBuilder(Parameter::class)->disableOriginalConstructor()->getMock();
156
            $requestParameter->expects($this->once())->method('getLocation')->willReturn($p['location']);
157
            $requestParameter->expects($this->exactly(2))->method('getSchema')->willReturnCallback(function () use ($p) {
158
                $value = new \stdClass();
159
                $value->default = $p['default'];
160
161
                return $value;
162
            });
163
            if ("body" === $p['location']) {
164
                $this->serializer->expects($this->once())->method('serialize')->willReturn(json_encode($p['default']));
165
            } else {
166
                $this->serializer->expects($this->never())->method('serialize');
167
            }
168
            $requestParameters[$p['name']] = $requestParameter;
169
        }
170
        $this->uriTemplate->expects($this->any())->method('expand')->willReturnCallback(function ($pathTemplate, array $pathParameters) use ($expected) {
171
            $this->assertEquals('/foo/bar', $pathTemplate);
172
            $this->assertEquals($expected['path'], $pathParameters);
173
        });
174
175
        $params = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
176
        $params->expects($this->once())->method('getIterator')->willReturn($requestParameters);
177
        $params->expects($this->never())->method('getByName');
178
179
        $baseUri = $this->createMock(UriInterface::class);
180
        $baseUri->expects($this->once())->method('withPath')->willReturn($baseUri);
181
        $baseUri->expects($this->once())->method('withQuery')->willReturnCallback(function ($query) use ($baseUri, $expected) {
182
            $this->assertEquals($expected['query'], $query);
183
184
            return $baseUri;
185
        });
186
187
        $responseDefinition = $this->getMockBuilder(ResponseDefinition::class)->disableOriginalConstructor()->getMock();
188
        $responseDefinition->expects($this->once())->method('hasBodySchema')->willReturn(false);
189
190
        $requestDefinition = $this->getMockBuilder(RequestDefinition::class)->disableOriginalConstructor()->getMock();
191
        $requestDefinition->expects($this->once())->method('getContentTypes')->willReturn(['application/json']);
192
        $requestDefinition->expects($this->once())->method('getRequestParameters')->willReturn($params);
193
        $requestDefinition->expects($this->once())->method('getMethod')->willReturn('GET');
194
        $requestDefinition->expects($this->once())->method('getPathTemplate')->willReturn('/foo/bar');
195
        $requestDefinition->expects($this->once())->method('getResponseDefinition')->with(200)->willReturn($responseDefinition);
196
197
        $this->config['baseUri'] = 'https://somewhere.tld';
198
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://somewhere.tld')->willReturn($baseUri);
199
        $this->schema->expects($this->exactly(1))->method('getRequestDefinition')->with('operationId')->willReturn($requestDefinition);
200
        $this->messageFactory->expects($this->once())->method('createRequest')->willReturnCallback(function ($method, $uri, $headers, $body) use ($expected) {
201
            $this->assertEquals('GET', $method);
202
            $this->assertInstanceOf(UriInterface::class, $uri);
203
            $this->assertEquals($expected['headers'], $headers);
204
            $this->assertEquals($expected['body'], $body);
205
206
            $request = $this->getMockBuilder(Request::class)->disableOriginalConstructor()->getMock();
207
            $request->expects($this->once())->method('getHeaders')->willReturn([]);
208
209
            return $request;
210
        });
211
        $this->httpClient->expects($this->once())->method('sendRequest')->willReturnCallback(function ($request) {
212
            $this->assertInstanceOf(Request::class, $request);
213
214
            $response = $this->createMock(ResponseInterface::class);
215
            $response->expects($this->once())->method('getStatusCode')->willReturn(200);
216
217
            return $response;
218
        });
219
220
        $service = $this->getApiService();
221
        $service->call('operationId');
222
    }
223
224
    /**
225
     * @return array
226
     */
227
    public function dataProviderItShouldUseDefaultValues()
228
    {
229
        return [
230
            "path" => [
231
                [
232
                    [
233
                        'name' => 'foo',
234
                        'location' => 'path',
235
                        'value' => 'bar',
236
                        "default" => 'bar_default',
237
                    ],
238
                ],
239
                [
240
                    "path" => ['foo' => 'bar_default'],
241
                    "query" => null,
242
                    "headers" => ["Content-Type" => "application/json"],
243
                    'body' => null,
244
                ],
245
            ],
246
            "query" => [
247
                [
248
                    [
249
                        'name' => 'foo',
250
                        'location' => 'query',
251
                        'value' => 'bar',
252
                        "default" => 'bar_default',
253
                    ],
254
                ],
255
                [
256
                    "path" => [],
257
                    "query" => "foo=bar_default",
258
                    "headers" => ["Content-Type" => "application/json"],
259
                    'body' => null,
260
                ],
261
            ],
262
            "header" => [
263
                [
264
                    [
265
                        'name' => 'foo',
266
                        'location' => 'header',
267
                        'value' => 'bar',
268
                        "default" => 'bar_default',
269
                    ],
270
                ],
271
                [
272
                    "path" => [],
273
                    "query" => null,
274
                    "headers" => ["Content-Type" => "application/json", "foo" => "bar_default"],
275
                    'body' => null,
276
                ],
277
            ],
278
            "formData" => [
279
                [
280
                    [
281
                        'name' => 'foo',
282
                        'location' => 'formData',
283
                        'value' => 'bar',
284
                        "default" => 'bar_default',
285
                    ],
286
                    [
287
                        'name' => 'foo2',
288
                        'location' => 'formData',
289
                        'value' => 'bar2',
290
                        "default" => 'bar2_default',
291
                    ],
292
                ],
293
                [
294
                    "path" => [],
295
                    "query" => null,
296
                    "headers" => ["Content-Type" => "application/json"],
297
                    'body' => "foo=bar_default&foo2=bar2_default",
298
                ],
299
            ],
300
            "body" => [
301
                [
302
                    [
303
                        'name' => 'body',
304
                        'location' => 'body',
305
                        'value' => ['foo' => "bar", 'bar' => 'foo'],
306
                        "default" => ['foo' => "bar__default", 'bar' => 'foo__default'],
307
                    ],
308
                ],
309
                [
310
                    "path" => [],
311
                    "query" => null,
312
                    "headers" => ["Content-Type" => "application/json"],
313
                    'body' => json_encode(['foo' => "bar__default", 'bar' => 'foo__default']),
314
                ],
315
            ],
316
        ];
317
    }
318
319
    /**
320
     * @test
321
     *
322
     * @expectedException \InvalidArgumentException
323
     *
324
     * @expectedExceptionMessage foo is not a defined request parameter
325
     */
326
    public function itShouldNotCreateRequestBecauseSomeParameterWasNotDefined()
327
    {
328
        $this->uriTemplate->expects($this->never())->method('expand');
329
330
        $params = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
331
        $params->expects($this->once())->method('getIterator')->willReturn([]);
332
        $params->expects($this->once())->method('getByName')->willReturn(null);
333
334
        $baseUri = $this->createMock(UriInterface::class);
335
        $baseUri->expects($this->never())->method('withPath');
336
        $baseUri->expects($this->never())->method('withQuery');
337
338
        $requestDefinition = $this->getMockBuilder(RequestDefinition::class)->disableOriginalConstructor()->getMock();
339
        $requestDefinition->expects($this->once())->method('getContentTypes')->willReturn(['application/json']);
340
        $requestDefinition->expects($this->once())->method('getRequestParameters')->willReturn($params);
341
        $requestDefinition->expects($this->never())->method('getMethod');
342
        $requestDefinition->expects($this->never())->method('getPathTemplate');
343
        $requestDefinition->expects($this->never())->method('getResponseDefinition');
344
345
        $this->config['baseUri'] = 'https://somewhere.tld';
346
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://somewhere.tld')->willReturn($baseUri);
347
        $this->schema->expects($this->exactly(1))->method('getRequestDefinition')->with('operationId')->willReturn($requestDefinition);
348
        $this->messageFactory->expects($this->never())->method('createRequest');
349
        $this->httpClient->expects($this->never())->method('sendRequest');
350
        $this->messageValidator->expects($this->never())->method('validateResponse');
351
        $this->messageValidator->expects($this->never())->method('hasViolations');
352
353
        $service = $this->getApiService();
354
        $service->call('operationId', ['foo' => 'bar']);
355
    }
356
357
    /**
358
     * @test
359
     *
360
     * @dataProvider dataProviderItShouldCreateRequestFromDefinition
361
     *
362
     * @param array $localisations
363
     * @param array $requestParams
364
     * @param array $expected
365
     *
366
     * @throws \Assert\AssertionFailedException
367
     */
368
    public function itShouldCreateRequestFromDefinition(array $localisations, array $requestParams, array $expected)
369
    {
370
        $this->uriTemplate->expects($this->any())->method('expand')->willReturnCallback(function ($pathTemplate, array $pathParameters) use ($expected) {
371
            $this->assertEquals('/foo/bar', $pathTemplate);
372
            $this->assertEquals($expected['path'], $pathParameters);
373
        });
374
375
        $params = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
376
        $params->expects($this->once())->method('getIterator')->willReturn([]);
377
        $params->expects($this->any())->method('getByName')->willReturnCallback(function ($name) use ($localisations, $requestParams) {
378
            $param = $this->getMockBuilder(Parameter::class)->disableOriginalConstructor()->getMock();
379
            $param->expects($this->once())->method('getLocation')->willReturn($localisations[$name]);
380
            if ("body" === $localisations[$name]) {
381
                $this->serializer->expects($this->once())->method('serialize')->willReturn(json_encode($requestParams[$name]));
382
            } else {
383
                $this->serializer->expects($this->never())->method('serialize');
384
            }
385
386
            return $param;
387
        });
388
389
        $baseUri = $this->createMock(UriInterface::class);
390
        $baseUri->expects($this->once())->method('withPath')->willReturn($baseUri);
391
        $baseUri->expects($this->once())->method('withQuery')->willReturnCallback(function ($query) use ($baseUri, $expected) {
392
            $this->assertEquals($expected['query'], $query);
393
394
            return $baseUri;
395
        });
396
397
        $responseDefinition = $this->getMockBuilder(ResponseDefinition::class)->disableOriginalConstructor()->getMock();
398
        $responseDefinition->expects($this->once())->method('hasBodySchema')->willReturn(false);
399
400
        $requestDefinition = $this->getMockBuilder(RequestDefinition::class)->disableOriginalConstructor()->getMock();
401
        $requestDefinition->expects($this->once())->method('getContentTypes')->willReturn(['application/json']);
402
        $requestDefinition->expects($this->once())->method('getRequestParameters')->willReturn($params);
403
        $requestDefinition->expects($this->once())->method('getMethod')->willReturn('GET');
404
        $requestDefinition->expects($this->once())->method('getPathTemplate')->willReturn('/foo/bar');
405
        $requestDefinition->expects($this->once())->method('getResponseDefinition')->with(200)->willReturn($responseDefinition);
406
407
        $this->config['baseUri'] = 'https://somewhere.tld';
408
        $this->config['validateResponse'] = true;
409
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://somewhere.tld')->willReturn($baseUri);
410
        $this->schema->expects($this->exactly(1))->method('getRequestDefinition')->with('operationId')->willReturn($requestDefinition);
411
        $this->messageFactory->expects($this->once())->method('createRequest')->willReturnCallback(function ($method, $uri, $headers, $body) use ($expected) {
412
            $this->assertEquals('GET', $method);
413
            $this->assertInstanceOf(UriInterface::class, $uri);
414
            $this->assertEquals($expected['headers'], $headers);
415
            $this->assertEquals($expected['body'], $body);
416
417
            $request = $this->getMockBuilder(Request::class)->disableOriginalConstructor()->getMock();
418
            $request->expects($this->once())->method('getHeaders')->willReturn([]);
419
420
            return $request;
421
        });
422
        $this->httpClient->expects($this->once())->method('sendRequest')->willReturnCallback(function ($request) {
423
            $this->assertInstanceOf(Request::class, $request);
424
425
            $response = $this->createMock(ResponseInterface::class);
426
            $response->expects($this->once())->method('getStatusCode')->willReturn(200);
427
428
            return $response;
429
        });
430
        $this->messageValidator->expects($this->once())->method('validateResponse');
431
        $this->messageValidator->expects($this->exactly(2))->method('hasViolations')->willReturn(false);
432
433
        $service = $this->getApiService();
434
        $service->call('operationId', $requestParams);
435
    }
436
437
    /**
438
     * @return array
439
     */
440
    public function dataProviderItShouldCreateRequestFromDefinition()
441
    {
442
        return [
443
            "path" => [
444
                [
445
                    'foo' => 'path',
446
                ],
447
                [
448
                    'foo' => 'bar',
449
                ],
450
                [
451
                    "path" => ['foo' => 'bar'],
452
                    "query" => null,
453
                    "headers" => ["Content-Type" => "application/json"],
454
                    'body' => null,
455
                ],
456
            ],
457
            "query" => [
458
                [
459
                    'foo' => 'query',
460
                ],
461
                [
462
                    'foo' => 'bar',
463
                ],
464
                [
465
                    "path" => [],
466
                    "query" => "foo=bar",
467
                    "headers" => ["Content-Type" => "application/json"],
468
                    'body' => null,
469
                ],
470
            ],
471
            "header" => [
472
                [
473
                    'foo' => 'header',
474
                ],
475
                [
476
                    'foo' => 'bar',
477
                ],
478
                [
479
                    "path" => [],
480
                    "query" => null,
481
                    "headers" => ["Content-Type" => "application/json", "foo" => "bar"],
482
                    'body' => null,
483
                ],
484
            ],
485
            "formData" => [
486
                [
487
                    'foo' => 'formData',
488
                    "foo2" => 'formData',
489
                ],
490
                [
491
                    'foo' => 'bar',
492
                    "foo2" => 'bar2',
493
                ],
494
                [
495
                    "path" => [],
496
                    "query" => null,
497
                    "headers" => ["Content-Type" => "application/json"],
498
                    'body' => "foo=bar&foo2=bar2",
499
                ],
500
            ],
501
            "body" => [
502
                [
503
                    'body' => 'body',
504
                ],
505
                [
506
                    'body' => ['foo' => "bar", 'bar' => 'foo'],
507
                ],
508
                [
509
                    "path" => [],
510
                    "query" => null,
511
                    "headers" => ["Content-Type" => "application/json"],
512
                    'body' => json_encode(['foo' => "bar", 'bar' => 'foo']),
513
                ],
514
            ],
515
        ];
516
    }
517
518
    /**
519
     * @test
520
     *
521
     * @throws \Assert\AssertionFailedException
522
     * @throws \ElevenLabs\Api\Service\Exception\ConstraintViolations
523
     * @throws \Http\Client\Exception
524
     */
525
    public function itCanMakeASynchronousCallWithoutDefaultValueAndParameters()
526
    {
527
        $params = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
528
        $params->expects($this->once())->method('getIterator')->willReturn([]);
529
        $params->expects($this->never())->method('getByName');
530
531
        $baseUri = $this->createMock(UriInterface::class);
532
        $baseUri->expects($this->once())->method('withPath')->willReturn($baseUri);
533
        $baseUri->expects($this->once())->method('withQuery')->willReturn($baseUri);
534
535
        $responseDefinition = $this->getMockBuilder(ResponseDefinition::class)->disableOriginalConstructor()->getMock();
536
        $responseDefinition->expects($this->once())->method('hasBodySchema')->willReturn(true);
537
538
        $requestDefinition = $this->getMockBuilder(RequestDefinition::class)->disableOriginalConstructor()->getMock();
539
        $requestDefinition->expects($this->once())->method('getContentTypes')->willReturn(['application/json']);
540
        $requestDefinition->expects($this->once())->method('getRequestParameters')->willReturn($params);
541
        $requestDefinition->expects($this->once())->method('getMethod')->willReturn('GET');
542
        $requestDefinition->expects($this->once())->method('getPathTemplate')->willReturn('/foo/bar');
543
        $requestDefinition->expects($this->once())->method('getResponseDefinition')->with(200)->willReturn($responseDefinition);
544
545
        $this->config['baseUri'] = 'https://somewhere.tld';
546
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://somewhere.tld')->willReturn($baseUri);
547
        $this->schema->expects($this->exactly(1))->method('getRequestDefinition')->with('operationId')->willReturn($requestDefinition);
548
        $this->messageFactory->expects($this->once())->method('createRequest')->willReturnCallback(function ($method, $uri, $headers, $body) {
549
            $this->assertEquals('GET', $method);
550
            $this->assertInstanceOf(UriInterface::class, $uri);
551
            $this->assertEquals(['Content-Type' => "application/json"], $headers);
552
            $this->assertNull($body);
553
554
            $request = $this->getMockBuilder(Request::class)->disableOriginalConstructor()->getMock();
555
556
            return $request;
557
        });
558
        $this->httpClient->expects($this->once())->method('sendRequest')->willReturnCallback(function ($request) {
559
            $this->assertInstanceOf(Request::class, $request);
560
561
            $stream =  $this->createMock(StreamInterface::class);
562
            $stream->expects($this->once())->method('__toString')->willReturn('body');
563
564
            $response = $this->createMock(ResponseInterface::class);
565
            $response->expects($this->once())->method('getStatusCode')->willReturn(200);
566
            $response->expects($this->once())->method('getBody')->willReturn($stream);
567
            $response->expects($this->once())->method('getHeaderLine')->with('Content-Type')->willReturn('application/json');
568
569
            return $response;
570
        });
571
        $this->serializer->expects($this->once())->method('deserialize')->willReturn(["items" => ['foo', 'bar']]);
572
        $this->messageValidator->expects($this->never())->method('validateResponse');
573
        $this->messageValidator->expects($this->exactly(1))->method('hasViolations')->willReturn(false);
574
575
        $service = $this->getApiService();
576
        $data = $service->call('operationId');
577
        $this->assertSame(['items' => ['foo', 'bar']], $data);
578
    }
579
580
    /**
581
     * @test
582
     *
583
     * @dataProvider dataProviderItShouldThrowExceptionBecauseThereAreSomeError
584
     *
585
     * @param array $config
586
     *
587
     * @expectedException \Assert\AssertionFailedException
588
     *
589
     * @throws \ElevenLabs\Api\Service\Exception\ConstraintViolations
590
     * @throws \Http\Client\Exception
591
     */
592
    public function itShouldThrowExceptionBecauseThereAreSomeError(array $config)
593
    {
594
        $this->uriTemplate->expects($this->never())->method('expand');
595
596
        $params = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
597
        $params->expects($this->never())->method('getIterator');
598
        $params->expects($this->never())->method('getByName');
599
600
        $responseDefinition = $this->getMockBuilder(ResponseDefinition::class)->disableOriginalConstructor()->getMock();
601
        $responseDefinition->expects($this->never())->method('hasBodySchema');
602
603
        $this->config['baseUri'] = 'https://somewhere.tld';
604
        $this->config = array_merge($this->config, $config);
605
        $this->uriFactory->expects($this->never())->method('createUri')->with('https://somewhere.tld');
606
        $this->schema->expects($this->never())->method('getRequestDefinition')->with('operationId');
607
        $this->messageFactory->expects($this->never())->method('createRequest');
608
        $this->httpClient->expects($this->never())->method('sendRequest');
609
610
        $service = $this->getApiService();
611
        $response = $service->call('operationId', ['foo' => 'bar']);
612
        $this->assertInstanceOf(ResponseInterface::class, $response);
613
    }
614
615
    /**
616
     * @return array
617
     */
618
    public function dataProviderItShouldThrowExceptionBecauseThereAreSomeError(): array
619
    {
620
        return [
621
            [['returnResponse' => 'foo']],
622
            [['validateRequest' => 'foo']],
623
            [['validateResponse' => 'foo']],
624
            [['baseUri' => 42]],
625
        ];
626
    }
627
628
    /** @test */
629
    public function itShouldReturnTheResponse()
630
    {
631
        $this->uriTemplate->expects($this->once())->method('expand')->willReturnCallback(function ($pathTemplate, array $pathParameters) {
632
            $this->assertEquals('/foo/bar', $pathTemplate);
633
            $this->assertEquals([], $pathParameters);
634
        });
635
636
        $params = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
637
        $params->expects($this->once())->method('getIterator')->willReturn([]);
638
        $params->expects($this->once())->method('getByName')->willReturnCallback(function ($name) {
639
            $this->assertEquals("foo", $name);
640
            $param = $this->getMockBuilder(Parameter::class)->disableOriginalConstructor()->getMock();
641
            $param->expects($this->once())->method('getLocation')->willReturn('query');
642
643
            return $param;
644
        });
645
646
        $baseUri = $this->createMock(UriInterface::class);
647
        $baseUri->expects($this->once())->method('withPath')->willReturn($baseUri);
648
        $baseUri->expects($this->once())->method('withQuery')->willReturnCallback(function ($query) use ($baseUri) {
649
            $this->assertEquals('foo=bar', $query);
650
651
            return $baseUri;
652
        });
653
654
        $responseDefinition = $this->getMockBuilder(ResponseDefinition::class)->disableOriginalConstructor()->getMock();
655
        $responseDefinition->expects($this->never())->method('hasBodySchema');
656
657
        $requestDefinition = $this->getMockBuilder(RequestDefinition::class)->disableOriginalConstructor()->getMock();
658
        $requestDefinition->expects($this->once())->method('getContentTypes')->willReturn(['application/json']);
659
        $requestDefinition->expects($this->once())->method('getRequestParameters')->willReturn($params);
660
        $requestDefinition->expects($this->once())->method('getMethod')->willReturn('GET');
661
        $requestDefinition->expects($this->once())->method('getPathTemplate')->willReturn('/foo/bar');
662
        $requestDefinition->expects($this->once())->method('getResponseDefinition')->with(200)->willReturn($responseDefinition);
663
664
        $this->config['baseUri'] = 'https://somewhere.tld';
665
        $this->config['returnResponse'] = true;
666
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://somewhere.tld')->willReturn($baseUri);
667
        $this->schema->expects($this->exactly(1))->method('getRequestDefinition')->with('operationId')->willReturn($requestDefinition);
668
        $this->messageFactory->expects($this->once())->method('createRequest')->willReturnCallback(function ($method, $uri, $headers, $body) {
669
            $this->assertEquals('GET', $method);
670
            $this->assertInstanceOf(UriInterface::class, $uri);
671
            $this->assertEquals(['Content-Type' => 'application/json'], $headers);
672
            $this->assertNull($body);
673
674
            $request = $this->getMockBuilder(Request::class)->disableOriginalConstructor()->getMock();
675
676
            return $request;
677
        });
678
        $this->httpClient->expects($this->once())->method('sendRequest')->willReturnCallback(function ($request) {
679
            $this->assertInstanceOf(Request::class, $request);
680
681
            $response = $this->createMock(ResponseInterface::class);
682
            $response->expects($this->once())->method('getStatusCode')->willReturn(200);
683
            $response->expects($this->never())->method('getBody');
684
685
            return $response;
686
        });
687
688
        $service = $this->getApiService();
689
        $response = $service->call('operationId', ['foo' => 'bar']);
690
        $this->assertInstanceOf(ResponseInterface::class, $response);
691
    }
692
693
    /** @test */
694
    public function itShouldNotReturnTheResponseOrAnyDataBecauseThereAreSomeViolationInRequest()
695
    {
696
        $this->uriTemplate->expects($this->once())->method('expand')->willReturnCallback(function ($pathTemplate, array $pathParameters) {
697
            $this->assertEquals('/foo/bar', $pathTemplate);
698
            $this->assertEquals([], $pathParameters);
699
        });
700
701
        $params = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
702
        $params->expects($this->once())->method('getIterator')->willReturn([]);
703
        $params->expects($this->once())->method('getByName')->willReturnCallback(function ($name) {
704
            $this->assertEquals('foo', $name);
705
            $param = $this->getMockBuilder(Parameter::class)->disableOriginalConstructor()->getMock();
706
            $param->expects($this->once())->method('getLocation')->willReturn('query');
707
708
            return $param;
709
        });
710
711
        $baseUri = $this->createMock(UriInterface::class);
712
        $baseUri->expects($this->once())->method('withPath')->willReturnCallback(function ($path) use ($baseUri) {
713
            $this->assertEquals("", $path);
714
715
            return $baseUri;
716
        });
717
        $baseUri->expects($this->once())->method('withQuery')->willReturnCallback(function ($query) use ($baseUri) {
718
            $this->assertEquals("foo=bar", $query);
719
720
            return $baseUri;
721
        });
722
723
        $requestDefinition = $this->getMockBuilder(RequestDefinition::class)->disableOriginalConstructor()->getMock();
724
        $requestDefinition->expects($this->once())->method('getContentTypes')->willReturn(['application/json']);
725
        $requestDefinition->expects($this->once())->method('getRequestParameters')->willReturn($params);
726
        $requestDefinition->expects($this->once())->method('getMethod')->willReturn('GET');
727
        $requestDefinition->expects($this->once())->method('getPathTemplate')->willReturn('/foo/bar');
728
        $requestDefinition->expects($this->never())->method('getResponseDefinition');
729
730
        $this->config['baseUri'] = 'https://somewhere.tld';
731
        $this->config['validateResponse'] = true;
732
        $this->config['validateRequest'] = true;
733
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://somewhere.tld')->willReturn($baseUri);
734
        $this->schema->expects($this->exactly(1))->method('getRequestDefinition')->with('operationId')->willReturn($requestDefinition);
735
        $this->messageFactory->expects($this->once())->method('createRequest')->willReturnCallback(function ($method, $uri, $headers, $body) {
736
            $this->assertEquals('GET', $method);
737
            $this->assertInstanceOf(UriInterface::class, $uri);
738
            $this->assertEquals(['Content-Type' => 'application/json'], $headers);
739
            $this->assertNull($body);
740
741
            $request = $this->getMockBuilder(Request::class)->disableOriginalConstructor()->getMock();
742
743
            return $request;
744
        });
745
        $this->httpClient->expects($this->never())->method('sendRequest');
746
        $this->messageValidator->expects($this->never())->method('validateResponse');
747
        $this->messageValidator->expects($this->once())->method('hasViolations')->willReturn(true);
748
        $this->messageValidator->expects($this->once())->method('getViolations')->willReturnCallback(function () {
749
            $violation = $this->getMockBuilder(ConstraintViolation::class)->disableOriginalConstructor()->getMock();
750
            $violation->expects($this->once())->method('getProperty')->willReturn('foo');
751
            $violation->expects($this->once())->method('getMessage')->willReturn('required');
752
            $violation->expects($this->once())->method('getConstraint')->willReturn('bar');
753
            $violation->expects($this->once())->method('getLocation')->willReturn('query');
754
755
            return [$violation];
756
        });
757
758
        try {
759
            $service = $this->getApiService();
760
            $service->call('operationId', ['foo' => 'bar']);
761
        } catch (RequestViolations $e) {
762
            $this->assertEquals("Request constraint violations:\n[property]: foo\n[message]: required\n[constraint]: bar\n[location]: query\n\n", $e->getMessage());
763
764
            return;
765
        }
766
        $this->fail("This test must throw a RequestViolations Exception");
767
    }
768
769
    /** @test */
770
    public function itShouldNotReturnTheResponseOrAnyDataBecauseThereAreSomeViolationInResponse()
771
    {
772
        $this->uriTemplate->expects($this->once())->method('expand')->willReturnCallback(function ($pathTemplate, array $pathParameters) {
773
            $this->assertEquals('/foo/bar', $pathTemplate);
774
            $this->assertEquals([], $pathParameters);
775
        });
776
777
        $params = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
778
        $params->expects($this->once())->method('getIterator')->willReturn([]);
779
        $params->expects($this->once())->method('getByName')->willReturnCallback(function ($name) {
780
            $this->assertEquals('foo', $name);
781
            $param = $this->getMockBuilder(Parameter::class)->disableOriginalConstructor()->getMock();
782
            $param->expects($this->once())->method('getLocation')->willReturn('query');
783
784
            return $param;
785
        });
786
787
        $baseUri = $this->createMock(UriInterface::class);
788
        $baseUri->expects($this->once())->method('withPath')->willReturnCallback(function ($path) use ($baseUri) {
789
            $this->assertEquals("", $path);
790
791
            return $baseUri;
792
        });
793
        $baseUri->expects($this->once())->method('withQuery')->willReturnCallback(function ($query) use ($baseUri) {
794
            $this->assertEquals("foo=bar", $query);
795
796
            return $baseUri;
797
        });
798
799
        $requestDefinition = $this->getMockBuilder(RequestDefinition::class)->disableOriginalConstructor()->getMock();
800
        $requestDefinition->expects($this->once())->method('getContentTypes')->willReturn(['application/json']);
801
        $requestDefinition->expects($this->once())->method('getRequestParameters')->willReturn($params);
802
        $requestDefinition->expects($this->once())->method('getMethod')->willReturn('GET');
803
        $requestDefinition->expects($this->once())->method('getPathTemplate')->willReturn('/foo/bar');
804
        $requestDefinition->expects($this->never())->method('getResponseDefinition');
805
806
        $this->config['baseUri'] = 'https://somewhere.tld';
807
        $this->config['validateResponse'] = true;
808
        $this->config['validateRequest'] = false;
809
        $this->uriFactory->expects($this->exactly(1))->method('createUri')->with('https://somewhere.tld')->willReturn($baseUri);
810
        $this->schema->expects($this->exactly(1))->method('getRequestDefinition')->with('operationId')->willReturn($requestDefinition);
811
        $this->messageFactory->expects($this->once())->method('createRequest')->willReturnCallback(function ($method, $uri, $headers, $body) {
812
            $this->assertEquals('GET', $method);
813
            $this->assertInstanceOf(UriInterface::class, $uri);
814
            $this->assertEquals(['Content-Type' => 'application/json'], $headers);
815
            $this->assertNull($body);
816
817
            $request = $this->getMockBuilder(Request::class)->disableOriginalConstructor()->getMock();
818
819
            return $request;
820
        });
821
        $this->httpClient->expects($this->once())->method('sendRequest')->willReturnCallback(function ($request) {
822
            $this->assertInstanceOf(Request::class, $request);
823
824
            $response = $this->createMock(ResponseInterface::class);
825
            $response->expects($this->never())->method('getStatusCode');
826
            $response->expects($this->never())->method('getBody');
827
828
            return $response;
829
        });
830
        $this->messageValidator->expects($this->once())->method('validateResponse');
831
        $this->messageValidator->expects($this->once())->method('hasViolations')->willReturn(true);
832
        $this->messageValidator->expects($this->once())->method('getViolations')->willReturnCallback(function () {
833
            $violation = $this->getMockBuilder(ConstraintViolation::class)->disableOriginalConstructor()->getMock();
834
            $violation->expects($this->once())->method('getProperty')->willReturn('foo');
835
            $violation->expects($this->once())->method('getMessage')->willReturn('required');
836
            $violation->expects($this->once())->method('getConstraint')->willReturn('bar');
837
            $violation->expects($this->once())->method('getLocation')->willReturn('query');
838
839
            return [$violation];
840
        });
841
842
        try {
843
            $service = $this->getApiService();
844
            $service->call('operationId', ['foo' => 'bar']);
845
        } catch (ResponseViolations $e) {
846
            $this->assertEquals("Request constraint violations:\n[property]: foo\n[message]: required\n[constraint]: bar\n[location]: query\n\n", $e->getMessage());
847
848
            return;
849
        }
850
        $this->fail("This test must throw a ResponseViolations Exception");
851
    }
852
853
    /**
854
     * @throws \Assert\AssertionFailedException
855
     *
856
     * @return ApiService
857
     */
858
    private function getApiService(): ApiService
859
    {
860
        return new ApiService(
861
            $this->uriFactory,
862
            $this->uriTemplate,
863
            $this->httpClient,
864
            $this->messageFactory,
865
            $this->schema,
866
            $this->messageValidator,
867
            $this->serializer,
868
            $this->config
869
        );
870
    }
871
}
872