Completed
Push — master ( c56c3c...fbb14f )
by Grégoire
16s queued 11s
created

DefaultRouteGeneratorTest::testGenerateUrl()   B

Complexity

Conditions 5
Paths 1

Size

Total Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 48
rs 8.8234
c 0
b 0
f 0
cc 5
nc 1
nop 4
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('getBaseCodeRoute')->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->expects($this->once())->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
76
        $admin->method('getRoutes')->willReturn($collection);
77
        $admin->method('getExtensions')->willReturn([]);
78
        $admin->method('getCode')->willReturn($name);
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('getBaseCodeRoute')->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
        $admin->method('getCode')->willReturn('Code');
134
135
        $router = $this->getMockForAbstractClass(RouterInterface::class);
136
137
        $cache = new RoutesCache($this->cacheTempFolder, true);
138
139
        $generator = new DefaultRouteGenerator($router, $cache);
140
        $generator->generateUrl($admin, 'foo', []);
141
    }
142
143
    /**
144
     * @dataProvider getGenerateUrlChildTests
145
     */
146
    public function testGenerateUrlChild(string $type, string $expected, string $name, array $parameters): void
147
    {
148
        $childCollection = new RouteCollection('base.Code.Parent|base.Code.Child', 'admin_acme_child', '/foo/', 'BundleName:ControllerName');
149
        $childCollection->add('bar');
150
151
        $collection = new RouteCollection('base.Code.Parent', 'admin_acme', '/', 'BundleName:ControllerName');
152
        $collection->add('foo');
153
        $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...
154
155
        $admin = $this->getMockForAbstractClass(AdminInterface::class);
156
        $admin->method('isChild')->willReturn(true);
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('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
163
        $admin->method('getRoutes')->willReturn($childCollection);
164
        $admin->method('getExtensions')->willReturn([]);
165
166
        $parentAdmin = $this->getMockForAbstractClass(AdminInterface::class);
167
        $parentAdmin->method('getIdParameter')->willReturn('childId');
168
        $parentAdmin->method('getRoutes')->willReturn($collection);
169
        $parentAdmin->method('getBaseCodeRoute')->willReturn('base.Code.Parent');
170
        $parentAdmin->method('getExtensions')->willReturn([]);
171
        $parentAdmin->method('getCode')->willReturn($name);
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
        $admin->method('getCode')->willReturn($name);
190
191
        $router = $this->getMockForAbstractClass(RouterInterface::class);
192
        $router->expects($this->once())
193
            ->method('generate')
194
            ->willReturnCallback(static function (string $name, array $parameters = []) {
195
                $params = '';
196
                if (!empty($parameters)) {
197
                    $params .= '?'.http_build_query($parameters);
198
                }
199
200
                switch ($name) {
201
                    case 'admin_acme_foo':
202
                        return '/foo'.$params;
203
                    case 'admin_acme_child_bar':
204
                        return '/foo/bar'.$params;
205
                }
206
            });
207
208
        $cache = new RoutesCache($this->cacheTempFolder, true);
209
210
        $generator = new DefaultRouteGenerator($router, $cache);
211
212
        $this->assertSame($expected, $generator->generateUrl('child' === $type ? $admin : $parentAdmin, $name, $parameters));
213
    }
214
215
    public function getGenerateUrlChildTests(): array
216
    {
217
        return [
218
            ['parent', '/foo?id=123&default_param=default_val', 'foo', ['id' => 123, 'default_param' => 'default_val']],
219
            ['parent', '/foo/bar?id=123&default_param=default_val', 'base.Code.Child.bar', ['id' => 123, 'default_param' => 'default_val']],
220
            ['child', '/foo/bar?abc=a123&efg=e456&default_param=default_val&childId=987654', 'bar', ['id' => 123, 'default_param' => 'default_val']],
221
        ];
222
    }
223
224
    /**
225
     * @dataProvider getGenerateUrlParentFieldDescriptionTests
226
     */
227
    public function testGenerateUrlParentFieldDescription(string $expected, string $name, array $parameters): void
228
    {
229
        $childCollection = new RouteCollection('base.Code.Parent|base.Code.Child', 'admin_acme_child', '/foo/', 'BundleName:ControllerName');
230
        $childCollection->add('bar');
231
232
        $collection = new RouteCollection('base.Code.Parent', 'admin_acme', '/', 'BundleName:ControllerName');
233
        $collection->add('foo');
234
        $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...
235
236
        $admin = $this->getMockForAbstractClass(AdminInterface::class);
237
        $admin->method('isChild')->willReturn(false);
238
        $admin->method('getCode')->willReturn('base.Code.Parent');
239
        $admin->method('getBaseCodeRoute')->willReturn('base.Code.Parent');
240
        // embeded admin (not nested ...)
241
        $admin->expects($this->once())->method('hasParentFieldDescription')->willReturn(true);
242
        $admin->expects($this->once())->method('hasRequest')->willReturn(true);
243
        $admin->expects($this->any())->method('getUniqid')->willReturn('foo_uniqueid');
244
        $admin->expects($this->once())->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
245
        $admin->method('getExtensions')->willReturn([]);
246
        $admin->method('getRoutes')->willReturn($collection);
247
248
        $router = $this->getMockForAbstractClass(RouterInterface::class);
249
        $router->expects($this->once())
250
            ->method('generate')
251
            ->willReturnCallback(static function (string $name, array $parameters = []): string {
252
                $params = '';
253
                if (!empty($parameters)) {
254
                    $params .= '?'.http_build_query($parameters);
255
                }
256
257
                switch ($name) {
258
                    case 'admin_acme_foo':
259
                        return '/foo'.$params;
260
                    case 'admin_acme_child_bar':
261
                        return '/foo/bar'.$params;
262
                }
263
            });
264
265
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
266
        $fieldDescription->expects($this->once())->method('getOption')->willReturn([]);
267
268
        $parentAdmin = $this->getMockForAbstractClass(AdminInterface::class);
269
        $parentAdmin->method('getUniqid')->willReturn('parent_foo_uniqueid');
270
        $parentAdmin->method('getCode')->willReturn('parent_foo_code');
271
        $parentAdmin->method('getExtensions')->willReturn([]);
272
273
        $fieldDescription->method('getAdmin')->willReturn($parentAdmin);
274
        $admin->method('getParentFieldDescription')->willReturn($fieldDescription);
275
276
        $cache = new RoutesCache($this->cacheTempFolder, true);
277
278
        $generator = new DefaultRouteGenerator($router, $cache);
279
280
        $this->assertSame($expected, $generator->generateUrl($admin, $name, $parameters));
281
    }
282
283
    public function getGenerateUrlParentFieldDescriptionTests(): array
284
    {
285
        return [
286
            ['/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']],
287
            // this second test does not make sense as we cannot have embeded admin with nested admin....
288
            ['/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']],
289
        ];
290
    }
291
292
    /**
293
     * @dataProvider getGenerateUrlLoadCacheTests
294
     */
295
    public function testGenerateUrlLoadCache(string $expected, string $name, array $parameters): void
296
    {
297
        $childCollection = new RouteCollection('base.Code.Parent|base.Code.Child', 'admin_acme_child', '/foo', 'BundleName:ControllerName');
298
        $childCollection->add('bar');
299
300
        $collection = new RouteCollection('base.Code.Parent', 'admin_acme', '/', 'BundleName:ControllerName');
301
        $collection->add('foo');
302
        $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...
303
304
        $standaloneCollection = new RouteCollection('base.Code.Child', 'admin_acme_child_standalone', '/', 'BundleName:ControllerName');
305
        $standaloneCollection->add('bar');
306
307
        $admin = $this->getMockForAbstractClass(AdminInterface::class);
308
        $admin->method('isChild')->willReturn(true);
309
        $admin->method('getCode')->willReturn('base.Code.Child');
310
        $admin->method('getBaseCodeRoute')->willReturn('base.Code.Parent|base.Code.Child');
311
        $admin->method('getIdParameter')->willReturn('id');
312
        $admin->method('hasParentFieldDescription')->willReturn(false);
313
        $admin->method('hasRequest')->willReturn(true);
314
        $admin->method('getUniqid')->willReturn('foo_uniqueid');
315
        $admin->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
316
        $admin->method('getRoutes')->willReturn($childCollection);
317
        $admin->method('getExtensions')->willReturn([]);
318
319
        $parentAdmin = $this->getMockForAbstractClass(AdminInterface::class);
320
        $parentAdmin->method('getIdParameter')->willReturn('childId');
321
        $parentAdmin->method('getRoutes')->willReturn($collection);
322
        $parentAdmin->method('getCode')->willReturn('base.Code.Parent');
323
        $parentAdmin->method('getExtensions')->willReturn([]);
324
325
        // no request attached in this test, so this will not be used
326
        $parentAdmin->expects($this->never())->method('getPersistentParameters')->willReturn(['from' => 'parent']);
327
328
        $request = $this->createMock(Request::class);
329
        $request->attributes = $this->createMock(ParameterBag::class);
330
        $request->attributes->method('has')->willReturn(true);
331
        $request->attributes
332
            ->method('get')
333
            ->willReturnCallback(static function (string $key): string {
334
                if ('childId' === $key) {
335
                    return '987654';
336
                }
337
            });
338
339
        $admin->method('getRequest')->willReturn($request);
340
        $admin->method('getParent')->willReturn($parentAdmin);
341
342
        $standaloneAdmin = $this->getMockForAbstractClass(AdminInterface::class);
343
        $standaloneAdmin->method('isChild')->willReturn(false);
344
        $standaloneAdmin->method('getBaseCodeRoute')->willReturn('base.Code.Child');
345
        $standaloneAdmin->expects($this->once())->method('hasParentFieldDescription')->willReturn(false);
346
        $standaloneAdmin->expects($this->once())->method('hasRequest')->willReturn(true);
347
        $standaloneAdmin->method('getUniqid')->willReturn('foo_uniqueid');
348
        $standaloneAdmin->expects($this->once())->method('getPersistentParameters')->willReturn(['abc' => 'a123', 'efg' => 'e456']);
349
        $standaloneAdmin->method('getRoutes')->willReturn($standaloneCollection);
350
        $standaloneAdmin->method('getExtensions')->willReturn([]);
351
        $standaloneAdmin->method('getCode')->willReturn('Code');
352
353
        $router = $this->getMockForAbstractClass(RouterInterface::class);
354
        $router->expects($this->exactly(2))
355
            ->method('generate')
356
            ->willReturnCallback(static function (string $name, array $parameters = []): string {
357
                $params = '';
358
                if (!empty($parameters)) {
359
                    $params .= '?'.http_build_query($parameters);
360
                }
361
362
                switch ($name) {
363
                    case 'admin_acme_child_bar':
364
                        return '/foo/bar'.$params;
365
                    case 'admin_acme_child_standalone_bar':
366
                        return '/bar'.$params;
367
                }
368
            });
369
370
        $cache = new RoutesCache($this->cacheTempFolder, true);
371
372
        $generator = new DefaultRouteGenerator($router, $cache);
373
374
        // Generate once to populate cache
375
        $generator->generateUrl($admin, 'bar', $parameters);
376
        $this->assertSame($expected, $generator->generateUrl($standaloneAdmin, $name, $parameters));
377
    }
378
379
    public function getGenerateUrlLoadCacheTests(): array
380
    {
381
        return [
382
            ['/bar?abc=a123&efg=e456&id=123&default_param=default_val', 'bar', ['id' => 123, 'default_param' => 'default_val']],
383
        ];
384
    }
385
}
386