Completed
Push — 3.x ( 24debf...05b755 )
by Grégoire
03:31
created

DefaultRouteGeneratorTest   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 357
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 4
dl 0
loc 357
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 7 1
A testGenerate() 0 11 1
B testGenerateUrl() 0 48 5
A getGenerateUrlTests() 0 14 1
A testGenerateUrlWithException() 0 21 1
B testGenerateUrlChild() 0 68 6
A getGenerateUrlChildTests() 0 8 1
B testGenerateUrlParentFieldDescription() 0 55 4
A getGenerateUrlParentFieldDescriptionTests() 0 8 1
B testGenerateUrlLoadCache() 0 82 5
A getGenerateUrlLoadCacheTests() 0 6 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\AdminBundle\Tests\Route;
15
16
use PHPUnit\Framework\TestCase;
17
use Sonata\AdminBundle\Admin\AdminInterface;
18
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
19
use Sonata\AdminBundle\Route\DefaultRouteGenerator;
20
use Sonata\AdminBundle\Route\RouteCollection;
21
use Sonata\AdminBundle\Route\RoutesCache;
22
use Symfony\Component\Filesystem\Filesystem;
23
use Symfony\Component\HttpFoundation\ParameterBag;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\Routing\RouterInterface;
26
27
class DefaultRouteGeneratorTest extends TestCase
28
{
29
    private const ROUTER_DOMAIN = 'http://sonata-project';
30
31
    protected $cacheTempFolder;
32
33
    public function setUp(): void
34
    {
35
        $this->cacheTempFolder = sys_get_temp_dir().'/sonata_test_route';
36
37
        $filesystem = new Filesystem();
38
        $filesystem->remove($this->cacheTempFolder);
39
    }
40
41
    public function testGenerate(): void
42
    {
43
        $router = $this->getMockForAbstractClass(RouterInterface::class);
44
        $router->expects($this->once())->method('generate')->willReturn('/foo/bar');
45
46
        $cache = new RoutesCache($this->cacheTempFolder, true);
47
48
        $generator = new DefaultRouteGenerator($router, $cache);
49
50
        $this->assertSame('/foo/bar', $generator->generate('foo_bar'));
51
    }
52
53
    /**
54
     * @dataProvider getGenerateUrlTests
55
     */
56
    public function testGenerateUrl(
57
        string $expected,
58
        string $name,
59
        array $parameters,
60
        int $referenceType = RouterInterface::ABSOLUTE_PATH
61
    ): void {
62
        $childCollection = new RouteCollection('base.Code.Foo|base.Code.Bar', 'admin_acme_child', '/foo/', 'BundleName:ControllerName');
63
        $childCollection->add('bar');
64
65
        $collection = new RouteCollection('base.Code.Foo', 'admin_acme', '/', 'BundleName:ControllerName');
66
        $collection->add('foo');
67
        $collection->addCollection($childCollection);
0 ignored issues
show
Documentation introduced by
$childCollection is of type object<Sonata\AdminBundle\Route\RouteCollection>, but the function expects a object<self>.

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...
68
69
        $admin = $this->getMockForAbstractClass(AdminInterface::class);
70
        $admin->method('isChild')->willReturn(false);
71
        $admin->method('getCode')->willReturn('base.Code.Foo');
72
        $admin->expects($this->once())->method('hasParentFieldDescription')->willReturn(false);
73
        $admin->expects($this->once())->method('hasRequest')->willReturn(true);
74
        $admin->method('getUniqid')->willReturn('foo_uniqueid');
75
        $admin->method('getCode')->willReturn('foo_code');
76
        $admin->expects($this->once())->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
77
        $admin->method('getRoutes')->willReturn($collection);
78
        $admin->method('getExtensions')->willReturn([]);
79
80
        $router = $this->getMockForAbstractClass(RouterInterface::class);
81
        $router->expects($this->once())
82
            ->method('generate')
83
            ->willReturnCallback(static function (string $name, array $parameters = [], int $referenceType = RouterInterface::ABSOLUTE_PATH): string {
84
                $params = '';
85
                $domain = RouterInterface::ABSOLUTE_URL === $referenceType ? self::ROUTER_DOMAIN : '';
86
                if (!empty($parameters)) {
87
                    $params .= '?'.http_build_query($parameters);
88
                }
89
90
                switch ($name) {
91
                    case 'admin_acme_foo':
92
                        return $domain.'/foo'.$params;
93
                    case 'admin_acme_child_bar':
94
                        return $domain.'/foo/bar'.$params;
95
                }
96
            });
97
98
        $cache = new RoutesCache($this->cacheTempFolder, true);
99
100
        $generator = new DefaultRouteGenerator($router, $cache);
101
102
        $this->assertSame($expected, $generator->generateUrl($admin, $name, $parameters, $referenceType));
0 ignored issues
show
Documentation introduced by
$referenceType is of type integer, but the function expects a boolean.

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...
103
    }
104
105
    public function getGenerateUrlTests(): array
106
    {
107
        return [
108
            ['/foo?abc=a123&efg=e456&default_param=default_val', 'foo', ['default_param' => 'default_val']],
109
            ['/foo/bar?abc=a123&efg=e456&default_param=default_val', 'base.Code.Bar.bar', ['default_param' => 'default_val']],
110
            ['/foo/bar?abc=a123&efg=e456&default_param=default_val', 'base.Code.Bar.bar', ['default_param' => 'default_val'], RouterInterface::ABSOLUTE_PATH],
111
            [
112
                self::ROUTER_DOMAIN.'/foo/bar?abc=a123&efg=e456&default_param=default_val',
113
                'base.Code.Bar.bar',
114
                ['default_param' => 'default_val'],
115
                RouterInterface::ABSOLUTE_URL,
116
            ],
117
        ];
118
    }
119
120
    public function testGenerateUrlWithException(): void
121
    {
122
        $this->expectException(\RuntimeException::class);
123
        $this->expectExceptionMessage('unable to find the route `base.Code.Route.foo`');
124
125
        $admin = $this->getMockForAbstractClass(AdminInterface::class);
126
        $admin->method('isChild')->willReturn(false);
127
        $admin->method('getCode')->willReturn('base.Code.Route');
128
        $admin->expects($this->once())->method('hasParentFieldDescription')->willReturn(false);
129
        $admin->expects($this->once())->method('hasRequest')->willReturn(true);
130
        $admin->expects($this->once())->method('getPersistentParameters')->willReturn([]);
131
        $admin->expects($this->exactly(2))->method('getRoutes')->willReturn(new RouteCollection('base.Code.Route', 'baseRouteName', 'baseRoutePattern', 'BundleName:ControllerName'));
132
        $admin->method('getExtensions')->willReturn([]);
133
134
        $router = $this->getMockForAbstractClass(RouterInterface::class);
135
136
        $cache = new RoutesCache($this->cacheTempFolder, true);
137
138
        $generator = new DefaultRouteGenerator($router, $cache);
139
        $generator->generateUrl($admin, 'foo', []);
140
    }
141
142
    /**
143
     * @dataProvider getGenerateUrlChildTests
144
     */
145
    public function testGenerateUrlChild(string $type, string $expected, string $name, array $parameters): void
146
    {
147
        $childCollection = new RouteCollection('base.Code.Parent|base.Code.Child', 'admin_acme_child', '/foo/', 'BundleName:ControllerName');
148
        $childCollection->add('bar');
149
150
        $collection = new RouteCollection('base.Code.Parent', 'admin_acme', '/', 'BundleName:ControllerName');
151
        $collection->add('foo');
152
        $collection->addCollection($childCollection);
0 ignored issues
show
Documentation introduced by
$childCollection is of type object<Sonata\AdminBundle\Route\RouteCollection>, but the function expects a object<self>.

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...
153
154
        $admin = $this->getMockForAbstractClass(AdminInterface::class);
155
        $admin->method('isChild')->willReturn(true);
156
        $admin->method('getCode')->willReturn('base.Code.Child');
157
        $admin->method('getBaseCodeRoute')->willReturn('base.Code.Parent|base.Code.Child');
158
        $admin->method('getIdParameter')->willReturn('id');
159
        $admin->method('hasParentFieldDescription')->willReturn(false);
160
        $admin->method('hasRequest')->willReturn(true);
161
        $admin->method('getUniqid')->willReturn('foo_uniqueid');
162
        $admin->method('getCode')->willReturn('foo_code');
163
        $admin->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
164
        $admin->method('getRoutes')->willReturn($childCollection);
165
        $admin->method('getExtensions')->willReturn([]);
166
167
        $parentAdmin = $this->getMockForAbstractClass(AdminInterface::class);
168
        $parentAdmin->method('getIdParameter')->willReturn('childId');
169
        $parentAdmin->method('getRoutes')->willReturn($collection);
170
        $parentAdmin->method('getCode')->willReturn('base.Code.Parent');
171
        $parentAdmin->method('getExtensions')->willReturn([]);
172
173
        // no request attached in this test, so this will not be used
174
        $parentAdmin->expects($this->never())->method('getPersistentParameters')->willReturn(['from' => 'parent']);
175
176
        $request = $this->createMock(Request::class);
177
        $request->attributes = $this->createMock(ParameterBag::class);
178
        $request->attributes->method('has')->willReturn(true);
179
        $request->attributes
180
            ->method('get')
181
            ->willReturnCallback(static function (string $key): string {
182
                if ('childId' === $key) {
183
                    return '987654';
184
                }
185
            });
186
187
        $admin->method('getRequest')->willReturn($request);
188
        $admin->method('getParent')->willReturn($parentAdmin);
189
190
        $router = $this->getMockForAbstractClass(RouterInterface::class);
191
        $router->expects($this->once())
192
            ->method('generate')
193
            ->willReturnCallback(static function (string $name, array $parameters = []) {
194
                $params = '';
195
                if (!empty($parameters)) {
196
                    $params .= '?'.http_build_query($parameters);
197
                }
198
199
                switch ($name) {
200
                    case 'admin_acme_foo':
201
                        return '/foo'.$params;
202
                    case 'admin_acme_child_bar':
203
                        return '/foo/bar'.$params;
204
                }
205
            });
206
207
        $cache = new RoutesCache($this->cacheTempFolder, true);
208
209
        $generator = new DefaultRouteGenerator($router, $cache);
210
211
        $this->assertSame($expected, $generator->generateUrl('child' === $type ? $admin : $parentAdmin, $name, $parameters));
212
    }
213
214
    public function getGenerateUrlChildTests(): array
215
    {
216
        return [
217
            ['parent', '/foo?id=123&default_param=default_val', 'foo', ['id' => 123, 'default_param' => 'default_val']],
218
            ['parent', '/foo/bar?id=123&default_param=default_val', 'base.Code.Child.bar', ['id' => 123, 'default_param' => 'default_val']],
219
            ['child', '/foo/bar?abc=a123&efg=e456&default_param=default_val&childId=987654', 'bar', ['id' => 123, 'default_param' => 'default_val']],
220
        ];
221
    }
222
223
    /**
224
     * @dataProvider getGenerateUrlParentFieldDescriptionTests
225
     */
226
    public function testGenerateUrlParentFieldDescription(string $expected, string $name, array $parameters): void
227
    {
228
        $childCollection = new RouteCollection('base.Code.Parent|base.Code.Child', 'admin_acme_child', '/foo/', 'BundleName:ControllerName');
229
        $childCollection->add('bar');
230
231
        $collection = new RouteCollection('base.Code.Parent', 'admin_acme', '/', 'BundleName:ControllerName');
232
        $collection->add('foo');
233
        $collection->addCollection($childCollection);
0 ignored issues
show
Documentation introduced by
$childCollection is of type object<Sonata\AdminBundle\Route\RouteCollection>, but the function expects a object<self>.

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...
234
235
        $admin = $this->getMockForAbstractClass(AdminInterface::class);
236
        $admin->method('isChild')->willReturn(false);
237
        $admin->method('getCode')->willReturn('base.Code.Parent');
238
        // embeded admin (not nested ...)
239
        $admin->expects($this->once())->method('hasParentFieldDescription')->willReturn(true);
240
        $admin->expects($this->once())->method('hasRequest')->willReturn(true);
241
        $admin->method('getUniqid')->willReturn('foo_uniqueid');
242
        $admin->method('getCode')->willReturn('foo_code');
243
        $admin->expects($this->once())->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
244
        $admin->method('getExtensions')->willReturn([]);
245
        $admin->method('getRoutes')->willReturn($collection);
246
247
        $router = $this->getMockForAbstractClass(RouterInterface::class);
248
        $router->expects($this->once())
249
            ->method('generate')
250
            ->willReturnCallback(static function (string $name, array $parameters = []): string {
251
                $params = '';
252
                if (!empty($parameters)) {
253
                    $params .= '?'.http_build_query($parameters);
254
                }
255
256
                switch ($name) {
257
                    case 'admin_acme_foo':
258
                        return '/foo'.$params;
259
                    case 'admin_acme_child_bar':
260
                        return '/foo/bar'.$params;
261
                }
262
            });
263
264
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
265
        $fieldDescription->expects($this->once())->method('getOption')->willReturn([]);
266
267
        $parentAdmin = $this->getMockForAbstractClass(AdminInterface::class);
268
        $parentAdmin->method('getUniqid')->willReturn('parent_foo_uniqueid');
269
        $parentAdmin->method('getCode')->willReturn('parent_foo_code');
270
        $parentAdmin->method('getExtensions')->willReturn([]);
271
272
        $fieldDescription->method('getAdmin')->willReturn($parentAdmin);
273
        $admin->method('getParentFieldDescription')->willReturn($fieldDescription);
274
275
        $cache = new RoutesCache($this->cacheTempFolder, true);
276
277
        $generator = new DefaultRouteGenerator($router, $cache);
278
279
        $this->assertSame($expected, $generator->generateUrl($admin, $name, $parameters));
280
    }
281
282
    public function getGenerateUrlParentFieldDescriptionTests(): array
283
    {
284
        return [
285
            ['/foo?abc=a123&efg=e456&default_param=default_val&uniqid=foo_uniqueid&code=base.Code.Parent&pcode=parent_foo_code&puniqid=parent_foo_uniqueid', 'foo', ['default_param' => 'default_val']],
286
            // this second test does not make sense as we cannot have embeded admin with nested admin....
287
            ['/foo/bar?abc=a123&efg=e456&default_param=default_val&uniqid=foo_uniqueid&code=base.Code.Parent&pcode=parent_foo_code&puniqid=parent_foo_uniqueid', 'base.Code.Child.bar', ['default_param' => 'default_val']],
288
        ];
289
    }
290
291
    /**
292
     * @dataProvider getGenerateUrlLoadCacheTests
293
     */
294
    public function testGenerateUrlLoadCache(string $expected, string $name, array $parameters): void
295
    {
296
        $childCollection = new RouteCollection('base.Code.Parent|base.Code.Child', 'admin_acme_child', '/foo', 'BundleName:ControllerName');
297
        $childCollection->add('bar');
298
299
        $collection = new RouteCollection('base.Code.Parent', 'admin_acme', '/', 'BundleName:ControllerName');
300
        $collection->add('foo');
301
        $collection->addCollection($childCollection);
0 ignored issues
show
Documentation introduced by
$childCollection is of type object<Sonata\AdminBundle\Route\RouteCollection>, but the function expects a object<self>.

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...
302
303
        $standaloneCollection = new RouteCollection('base.Code.Child', 'admin_acme_child_standalone', '/', 'BundleName:ControllerName');
304
        $standaloneCollection->add('bar');
305
306
        $admin = $this->getMockForAbstractClass(AdminInterface::class);
307
        $admin->method('isChild')->willReturn(true);
308
        $admin->method('getCode')->willReturn('base.Code.Child');
309
        $admin->method('getBaseCodeRoute')->willReturn('base.Code.Parent|base.Code.Child');
310
        $admin->method('getIdParameter')->willReturn('id');
311
        $admin->method('hasParentFieldDescription')->willReturn(false);
312
        $admin->method('hasRequest')->willReturn(true);
313
        $admin->method('getUniqid')->willReturn('foo_uniqueid');
314
        $admin->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
315
        $admin->method('getRoutes')->willReturn($childCollection);
316
        $admin->method('getExtensions')->willReturn([]);
317
318
        $parentAdmin = $this->getMockForAbstractClass(AdminInterface::class);
319
        $parentAdmin->method('getIdParameter')->willReturn('childId');
320
        $parentAdmin->method('getRoutes')->willReturn($collection);
321
        $parentAdmin->method('getCode')->willReturn('base.Code.Parent');
322
        $parentAdmin->method('getExtensions')->willReturn([]);
323
324
        // no request attached in this test, so this will not be used
325
        $parentAdmin->expects($this->never())->method('getPersistentParameters')->willReturn(['from' => 'parent']);
326
327
        $request = $this->createMock(Request::class);
328
        $request->attributes = $this->createMock(ParameterBag::class);
329
        $request->attributes->method('has')->willReturn(true);
330
        $request->attributes
331
            ->method('get')
332
            ->willReturnCallback(static function (string $key): string {
333
                if ('childId' === $key) {
334
                    return '987654';
335
                }
336
            });
337
338
        $admin->method('getRequest')->willReturn($request);
339
        $admin->method('getParent')->willReturn($parentAdmin);
340
341
        $standaloneAdmin = $this->getMockForAbstractClass(AdminInterface::class);
342
        $standaloneAdmin->method('isChild')->willReturn(false);
343
        $standaloneAdmin->method('getCode')->willReturn('base.Code.Child');
344
        $standaloneAdmin->expects($this->once())->method('hasParentFieldDescription')->willReturn(false);
345
        $standaloneAdmin->expects($this->once())->method('hasRequest')->willReturn(true);
346
        $standaloneAdmin->method('getUniqid')->willReturn('foo_uniqueid');
347
        $standaloneAdmin->expects($this->once())->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
348
        $standaloneAdmin->method('getRoutes')->willReturn($standaloneCollection);
349
        $standaloneAdmin->method('getExtensions')->willReturn([]);
350
351
        $router = $this->getMockForAbstractClass(RouterInterface::class);
352
        $router->expects($this->exactly(2))
353
            ->method('generate')
354
            ->willReturnCallback(static function (string $name, array $parameters = []): string {
355
                $params = '';
356
                if (!empty($parameters)) {
357
                    $params .= '?'.http_build_query($parameters);
358
                }
359
360
                switch ($name) {
361
                    case 'admin_acme_child_bar':
362
                        return '/foo/bar'.$params;
363
                    case 'admin_acme_child_standalone_bar':
364
                        return '/bar'.$params;
365
                }
366
            });
367
368
        $cache = new RoutesCache($this->cacheTempFolder, true);
369
370
        $generator = new DefaultRouteGenerator($router, $cache);
371
372
        // Generate once to populate cache
373
        $generator->generateUrl($admin, 'bar', $parameters);
374
        $this->assertSame($expected, $generator->generateUrl($standaloneAdmin, $name, $parameters));
375
    }
376
377
    public function getGenerateUrlLoadCacheTests(): array
378
    {
379
        return [
380
            ['/bar?abc=a123&efg=e456&id=123&default_param=default_val', 'bar', ['id' => 123, 'default_param' => 'default_val']],
381
        ];
382
    }
383
}
384