Completed
Push — master ( ad3b69...02c092 )
by John
09:08 queued 05:48
created

canUseXRouterForDiKeyInPath()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 22
Code Lines 16

Duplication

Lines 22
Ratio 100 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 22
loc 22
rs 9.2
cc 2
eloc 16
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\Routing;
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\ScalarSchema;
17
use KleijnWeb\PhpApi\Descriptions\Description\Schema\Schema;
18
use KleijnWeb\SwaggerBundle\Routing\OpenApiRouteLoader;
19
use Symfony\Component\Routing\Route;
20
21
/**
22
 * @author John Kleijn <[email protected]>
23
 */
24
class SwaggerRouteLoaderTest extends \PHPUnit_Framework_TestCase
25
{
26
    const DOCUMENT_PATH = '/totally/non-existent/path';
27
28
    /**
29
     * @var \PHPUnit_Framework_MockObject_MockObject
30
     */
31
    private $repositoryMock;
32
33
    /**
34
     * @var \PHPUnit_Framework_MockObject_MockObject
35
     */
36
    private $decriptionMock;
37
38
    /**
39
     * @var OpenApiRouteLoader
40
     */
41
    private $loader;
42
43
    /**
44
     * Create mocks
45
     */
46
    protected function setUp()
47
    {
48
        $this->decriptionMock = $this
49
            ->getMockBuilder(Description::class)
50
            ->disableOriginalConstructor()
51
            ->getMock();
52
53
        /** @var Repository $repository */
54
        $this->repositoryMock = $repository = $this
55
            ->getMockBuilder(Repository::class)
56
            ->disableOriginalConstructor()
57
            ->getMock();
58
59
        $this->repositoryMock
60
            ->expects($this->any())
61
            ->method('get')
62
            ->willReturn($this->decriptionMock);
63
64
        $this->loader = new OpenApiRouteLoader($repository);
65
    }
66
67
    /**
68
     * @test
69
     */
70
    public function supportSwaggerAsRouteTypeOnly()
71
    {
72
        $this->assertFalse($this->loader->supports('/a/b/c'));
73
        $this->assertTrue($this->loader->supports('/a/b/c', 'swagger'));
74
    }
75
76
    /**
77
     * @test
78
     */
79 View Code Duplication
    public function canLoadMultipleDocuments()
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...
80
    {
81
        $this->decriptionMock
82
            ->expects($this->any())
83
            ->method('getPaths')
84
            ->willReturn([]);
85
86
        $this->loader->load(self::DOCUMENT_PATH);
87
        $this->loader->load(self::DOCUMENT_PATH . '2');
88
    }
89
90
    /**
91
     * @test
92
     */
93
    public function loadingMultipleDocumentWillPreventRouteKeyCollisions()
94
    {
95
        $this->decriptionMock
96
            ->expects($this->any())
97
            ->method('getPaths')
98
            ->willReturn([
99
                new Path('/a', [new Operation('', '/a', 'get')]),
100
            ]);
101
102
        $routes1 = $this->loader->load(self::DOCUMENT_PATH);
103
        $routes2 = $this->loader->load(self::DOCUMENT_PATH . '2');
104
        $this->assertSame(count($routes1), count(array_diff_key($routes1->all(), $routes2->all())));
105
    }
106
107
    /**
108
     * @test
109
     * @expectedException \RuntimeException
110
     */
111 View Code Duplication
    public function cannotTryToLoadSameDocumentMoreThanOnce()
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...
112
    {
113
        $this->decriptionMock
114
            ->expects($this->any())
115
            ->method('getPaths')
116
            ->willReturn([]);
117
118
        $this->loader->load(self::DOCUMENT_PATH);
119
        $this->loader->load(self::DOCUMENT_PATH);
120
    }
121
122
    /**
123
     * @test
124
     */
125 View Code Duplication
    public function willReturnRouteCollection()
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...
126
    {
127
        $this->decriptionMock
128
            ->expects($this->any())
129
            ->method('getPaths')
130
            ->willReturn([]);
131
132
        $routes = $this->loader->load(self::DOCUMENT_PATH);
133
        $this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $routes);
134
    }
135
136
    /**
137
     * @test
138
     */
139 View Code Duplication
    public function routeCollectionWillContainOneRouteForEveryPathAndMethod()
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...
140
    {
141
        $this->decriptionMock
142
            ->expects($this->any())
143
            ->method('getPaths')
144
            ->willReturn([
145
                new Path('/a', [new Operation(uniqid(), '/a', 'get'), new Operation(uniqid(), '/a', 'post')]),
146
                new Path('/b', [new Operation(uniqid(), '/b', 'get')]),
147
            ]);
148
149
        $routes = $this->loader->load(self::DOCUMENT_PATH);
150
151
        $this->assertCount(3, $routes);
152
    }
153
154
    /**
155
     * @test
156
     */
157 View Code Duplication
    public function routeCollectionWillIncludeSeparateRoutesForSubPaths()
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...
158
    {
159
        $this->decriptionMock
160
            ->expects($this->any())
161
            ->method('getPaths')
162
            ->willReturn([
163
                new Path('/a', [new Operation(uniqid(), '/a', 'get')]),
164
                new Path('/a/b', [new Operation(uniqid(), '/a/b', 'get')]),
165
                new Path('/a/b/c', [new Operation(uniqid(), '/a/b/c', 'get')]),
166
            ]);
167
168
169
        $routes = $this->loader->load(self::DOCUMENT_PATH);
170
171
        $this->assertCount(3, $routes);
172
    }
173
174
    /**
175
     * @test
176
     */
177
    public function canUseOperationIdAsControllerKey()
178
    {
179
        $expected = 'my.controller.key:methodName';
180
181
        $this->decriptionMock
182
            ->expects($this->any())
183
            ->method('getPaths')
184
            ->willReturn([
185
                new Path('/a', [
186
                    new Operation('/a:get', '/a', 'get'),
187
                    new Operation($expected, '/a', 'post')
188
                ]),
189
                new Path('/b', [new Operation('/b:get', '/b', 'get')]),
190
            ]);
191
192
        $routes = $this->loader->load(self::DOCUMENT_PATH);
193
194
        $actual = $routes->get('swagger.path.a.methodName');
195
        $this->assertNotNull($actual);
196
        $this->assertSame($expected, $actual->getDefault('_controller'));
197
    }
198
199
    /**
200
     * @test
201
     */
202
    public function canUseXRouterMethodToOverrideMethod()
203
    {
204
        $extensions = ['router-controller-method' => 'myMethodName'];
205
206
        $this->decriptionMock
207
            ->expects($this->any())
208
            ->method('getPaths')
209
            ->willReturn([
210
                new Path('/a', [
211
                    new Operation('/a:get', '/a', 'get'),
212
                    new Operation('/a:post', '/a', 'post', [], null, [], $extensions)
213
                ]),
214
                new Path('/b', [new Operation('/b:get', '/b', 'get')]),
215
            ]);
216
217
        $routes = $this->loader->load(self::DOCUMENT_PATH);
218
219
        $actual = $routes->get('swagger.path.a.myMethodName');
220
        $this->assertNotNull($actual);
221
    }
222
223
    /**
224
     * @test
225
     */
226
    public function canUseXRouterControllerForDiKeyInOperation()
227
    {
228
        $diKey      = 'my.x_router.controller';
229
        $expected   = "$diKey:post";
230
        $extensions = ['router-controller' => $diKey];
231
        $this->decriptionMock
232
            ->expects($this->any())
233
            ->method('getPaths')
234
            ->willReturn([
235
                new Path('/a', [
236
                    new Operation('/a:get', '/a', 'get'),
237
                    new Operation('/a:post', '/a', 'post', [], null, [], $extensions)
238
                ]),
239
                new Path('/b', [new Operation('/b:get', '/b', 'get')]),
240
            ]);
241
242
        $routes = $this->loader->load(self::DOCUMENT_PATH);
243
244
        $actual = $routes->get('swagger.path.a.post');
245
        $this->assertNotNull($actual);
246
        $this->assertSame($expected, $actual->getDefault('_controller'));
247
    }
248
249
    /**
250
     * @test
251
     */
252 View Code Duplication
    public function canUseXRouterControllerForDiKeyInPath()
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...
253
    {
254
        $diKey    = 'my.x_router.controller';
255
        $expected = "$diKey:post";
256
        $this->decriptionMock
257
            ->expects($this->any())
258
            ->method('getPaths')
259
            ->willReturn([new Path('/a', [new Operation('/a:post', '/a', 'post')])]);
260
261
        $this->decriptionMock
262
            ->expects($this->atLeast(1))
263
            ->method('getExtension')
264
            ->willReturnCallback(function (string $name) use ($diKey) {
265
                return $name == 'router-controller' ? $diKey : null;
266
            });
267
268
        $routes = $this->loader->load(self::DOCUMENT_PATH);
269
270
        $actual = $routes->get('swagger.path.a.post');
271
        $this->assertNotNull($actual);
272
        $this->assertSame($expected, $actual->getDefault('_controller'));
273
    }
274
275
    /**
276
     * @test
277
     */
278 View Code Duplication
    public function canUseXRouterForDiKeyInPath()
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...
279
    {
280
        $router   = 'my.x_router';
281
        $expected = "$router.a:post";
282
        $this->decriptionMock
283
            ->expects($this->any())
284
            ->method('getPaths')
285
            ->willReturn([new Path('/a', [new Operation('/a:post', '/a', 'post')])]);
286
287
        $this->decriptionMock
288
            ->expects($this->atLeast(1))
289
            ->method('getExtension')
290
            ->willReturnCallback(function (string $name) use ($router) {
291
                return $name == 'router' ? $router : null;
292
            });
293
294
        $routes = $this->loader->load(self::DOCUMENT_PATH);
295
296
        $actual = $routes->get('swagger.path.a.post');
297
        $this->assertNotNull($actual);
298
        $this->assertSame($expected, $actual->getDefault('_controller'));
299
    }
300
301
    /**
302
     * @test
303
     */
304
    public function routeCollectionWillIncludeSeparateRoutesForSubPathMethodCombinations()
305
    {
306
        $this->decriptionMock
307
            ->expects($this->any())
308
            ->method('getPaths')
309
            ->willReturn([
310
                new Path('/a', [
311
                    new Operation('/a:get', '/a', 'get'),
312
                ]),
313
                new Path('/a/b', [
314
                    new Operation('/a/b:get', '/a/b', 'get'),
315
                    new Operation('/a/b:post', '/a/b', 'post')
316
                ]),
317
                new Path('/a/b/c', [new Operation('/a/b/c:get', '/a/b/c', 'get')]),
318
            ]);
319
320
        $routes = $this->loader->load(self::DOCUMENT_PATH);
321
322
        $this->assertCount(4, $routes);
323
    }
324
325
    /**
326
     * @test
327
     */
328
    public function routeCollectionWillContainPathFromDescription()
329
    {
330
        $paths = [
331
            new Path('/a', [new Operation('/a:get', '/a', 'get'),]),
332
            new Path('/a/b', [new Operation('/a/b:get', '/a/b', 'get'),]),
333
            new Path('/a/b/c', [new Operation('/a/b/c:get', '/a/b/c', 'get')]),
334
            new Path('/d/f/g', [new Operation('/d/f/g:get', '/d/f/g', 'get')]),
335
            new Path('/1/2/3', [new Operation('/1/2/3:get', '/1/2/3', 'get')]),
336
            new Path('/foo/{bar}/{blah}', [new Operation('/foo/{bar}/{blah}:get', '/foo/{bar}/{blah}', 'get')]),
337
            new Path('/z', [new Operation('/z:get', '/z', 'get'),]),
338
        ];
339
340
        $this->decriptionMock
341
            ->expects($this->any())
342
            ->method('getPaths')
343
            ->willReturn($paths);
344
345
        $routes = $this->loader->load(self::DOCUMENT_PATH);
346
347
        $descriptionPaths = array_map(function (Path $path) {
348
            return $path->getPath();
349
        }, $paths);
350
        sort($descriptionPaths);
351
352
        $routePaths = array_map(function (Route $route) {
353
            return $route->getPath();
354
        }, $routes->getIterator()->getArrayCopy());
355
356
        sort($routePaths);
357
        $this->assertSame($descriptionPaths, $routePaths);
358
    }
359
360
    /**
361
     * @test
362
     */
363
    public function willAddRequirementsForIntegerPathParams()
364
    {
365
        $parameter = new Parameter(
366
            'foo',
367
            true,
368
            new ScalarSchema((object)['type' => Schema::TYPE_INT]),
369
            Parameter::IN_PATH
370
        );
371
372
        $this->decriptionMock
373
            ->expects($this->any())
374
            ->method('getPaths')
375
            ->willReturn([new Path('/a', [new Operation('/a:get', '/a', 'get', [$parameter])])]);
376
377
        $routes = $this->loader->load(self::DOCUMENT_PATH);
378
        $actual = $routes->get('swagger.path.a.get');
379
        $this->assertNotNull($actual);
380
        $requirements = $actual->getRequirements();
381
        $this->assertNotNull($requirements);
382
383
        $this->assertSame($requirements['foo'], '\d+');
384
    }
385
386
    /**
387
     * @test
388
     */
389
    public function willAddRequirementsForStringPatternParams()
390
    {
391
        $expected        = '\d{2}hello';
392
        $parameter = new Parameter(
393
            'aString',
394
            true,
395
            new ScalarSchema((object)[
396
                'type' => Schema::TYPE_STRING,
397
                'pattern' => $expected
398
            ]),
399
            Parameter::IN_PATH
400
        );
401
402
        $this->decriptionMock
403
            ->expects($this->any())
404
            ->method('getPaths')
405
            ->willReturn([new Path('/a', [new Operation('/a:get', '/a', 'get', [$parameter])])]);
406
407
        $routes = $this->loader->load(self::DOCUMENT_PATH);
408
        $actual = $routes->get('swagger.path.a.get');
409
        $this->assertNotNull($actual);
410
        $requirements = $actual->getRequirements();
411
        $this->assertNotNull($requirements);
412
413
        $this->assertSame($expected, $requirements['aString']);
414
    }
415
416
    /**
417
     * @test
418
     */
419
    public function willAddRequirementsForStringEnumParams()
420
    {
421
        $enum            = ['a', 'b', 'c'];
422
        $expected        = '(a|b|c)';
423
        $parameter = new Parameter(
424
            'aString',
425
            true,
426
            new ScalarSchema((object)[
427
                'type' => Schema::TYPE_STRING,
428
                'enum' => $enum
429
            ]),
430
            Parameter::IN_PATH
431
        );
432
433
        $this->decriptionMock
434
            ->expects($this->any())
435
            ->method('getPaths')
436
            ->willReturn([new Path('/a', [new Operation('/a:get', '/a', 'get', [$parameter])])]);
437
438
        $routes = $this->loader->load(self::DOCUMENT_PATH);
439
        $actual = $routes->get('swagger.path.a.get');
440
        $this->assertNotNull($actual);
441
        $requirements = $actual->getRequirements();
442
        $this->assertNotNull($requirements);
443
444
        $this->assertSame($expected, $requirements['aString']);
445
    }
446
}
447