Completed
Push — master ( 67bb58...4e1c5d )
by Grégoire
03:35
created

testGroupMenuProviderWithoutChecker()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 36
rs 9.344
c 0
b 0
f 0
cc 1
nc 1
nop 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\Menu\Provider;
15
16
use Knp\Menu\FactoryInterface;
17
use Knp\Menu\ItemInterface;
18
use Knp\Menu\MenuFactory;
19
use Knp\Menu\MenuItem;
20
use Knp\Menu\Provider\MenuProviderInterface;
21
use PHPUnit\Framework\MockObject\MockObject;
22
use PHPUnit\Framework\TestCase;
23
use Sonata\AdminBundle\Admin\AbstractAdmin;
24
use Sonata\AdminBundle\Admin\Pool;
25
use Sonata\AdminBundle\Menu\Provider\GroupMenuProvider;
26
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
27
28
class GroupMenuProviderTest extends TestCase
29
{
30
    /**
31
     * @var MockObject|Pool
32
     */
33
    private $pool;
34
    /**
35
     * @var MockObject|MenuProviderInterface
36
     */
37
    private $provider;
38
    /**
39
     * @var MockObject|FactoryInterface
40
     */
41
    private $factory;
42
43
    /**
44
     * @var MockObject
45
     */
46
    private $checker;
47
48
    protected function setUp(): void
49
    {
50
        $this->pool = $this->getMockBuilder(Pool::class)->disableOriginalConstructor()->getMock();
51
        $this->checker = $this
52
            ->getMockBuilder(AuthorizationCheckerInterface::class)
53
            ->setMethods(['isGranted'])
54
            ->disableOriginalConstructor()
55
            ->getMock();
56
57
        $this->factory = new MenuFactory();
58
59
        $this->provider = new GroupMenuProvider($this->factory, $this->pool, $this->checker);
60
    }
61
62
    public function testGroupMenuProviderName(): void
63
    {
64
        $this->assertTrue($this->provider->has('sonata_group_menu'));
65
    }
66
67
    /**
68
     * @dataProvider getAdminGroups
69
     */
70
    public function testGetMenuProviderWithCheckerGrantedGroupRoles(array $adminGroups): void
71
    {
72
        $this->pool
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\Pool>.

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

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

Loading history...
73
            ->method('getInstance')
74
            ->with($this->equalTo('sonata_admin_foo_service'))
75
            ->willReturn($this->getAdminMock());
76
77
        $this->checker
78
            ->method('isGranted')
79
            ->willReturn(false);
80
81
        $menu = $this->provider->get(
82
            'providerFoo',
83
            [
84
                'name' => 'foo',
85
                'group' => $adminGroups,
86
            ]
87
        );
88
89
        $this->assertInstanceOf(ItemInterface::class, $menu);
90
        $this->assertSame('foo', $menu->getName());
91
92
        $children = $menu->getChildren();
93
94
        $this->assertCount(1, $children);
95
        $this->assertArrayHasKey('foo_admin_label', $children);
96
        $this->assertArrayNotHasKey('route_label', $children);
97
        $this->assertInstanceOf(MenuItem::class, $menu['foo_admin_label']);
98
        $this->assertSame('foo_admin_label', $menu['foo_admin_label']->getLabel());
99
100
        $extras = $menu['foo_admin_label']->getExtras();
101
        $this->assertArrayHasKey('label_catalogue', $extras);
102
        $this->assertSame($extras['label_catalogue'], 'SonataAdminBundle');
103
    }
104
105
    public function unanimousGrantCheckerMock(array $args): bool
106
    {
107
        if ($args === ['foo', 'bar']) {
108
            return false;
109
        }
110
111
        if ($args === ['foo'] || $args === ['bar'] || $args === ['baz']) {
112
            return true;
113
        }
114
115
        return false;
116
    }
117
118
    public function unanimousGrantCheckerNoBazMock(array $args): bool
119
    {
120
        if ($args === ['foo', 'bar'] || $args === ['baz']) {
121
            return false;
122
        }
123
124
        if ($args === ['foo'] || $args === ['bar']) {
125
            return true;
126
        }
127
128
        return false;
129
    }
130
131
    /**
132
     * @dataProvider getAdminGroupsMultipleRoles
133
     */
134
    public function testGetMenuProviderWithCheckerGrantedMultipleGroupRoles(
135
        array $adminGroups
136
    ): void {
137
        $this->checker
138
            ->method('isGranted')
139
            ->willReturnCallback([$this, 'unanimousGrantCheckerMock']);
140
141
        $menu = $this->provider->get(
142
            'providerFoo',
143
            [
144
                'name' => 'foo',
145
                'group' => $adminGroups,
146
            ]
147
        );
148
149
        $this->assertInstanceOf(ItemInterface::class, $menu);
150
151
        $children = $menu->getChildren();
152
153
        $this->assertCount(4, $children);
154
    }
155
156
    /**
157
     * @dataProvider getAdminGroupsMultipleRoles
158
     */
159
    public function testGetMenuProviderWithCheckerGrantedGroupAndItemRoles(
160
        array $adminGroups
161
    ): void {
162
        $this->checker
163
            ->method('isGranted')
164
            ->willReturnCallback([$this, 'unanimousGrantCheckerNoBazMock']);
165
166
        $menu = $this->provider->get(
167
            'providerFoo',
168
            [
169
                'name' => 'foo',
170
                'group' => $adminGroups,
171
            ]
172
        );
173
        $isBazItem = $adminGroups['roles'] === ['baz'];
174
175
        $this->assertInstanceOf(ItemInterface::class, $menu);
176
        $this->assertSame(!$isBazItem, $menu->isDisplayed());
177
178
        $children = $menu->getChildren();
179
        $this->assertCount($isBazItem ? 0 : 3, $children);
180
    }
181
182
    /**
183
     * @dataProvider getAdminGroupsMultipleRolesOnTop
184
     */
185
    public function testGetMenuProviderWithCheckerGrantedMultipleGroupRolesOnTop(
186
        array $adminGroups
187
    ): void {
188
        $this->checker
189
            ->method('isGranted')
190
            ->willReturnCallback([$this, 'unanimousGrantCheckerMock']);
191
192
        $menu = $this->provider->get(
193
            'providerFoo',
194
            [
195
                'name' => 'foo',
196
                'group' => $adminGroups,
197
            ]
198
        );
199
        $this->assertInstanceOf(ItemInterface::class, $menu);
200
201
        $this->assertTrue($menu->isDisplayed());
202
    }
203
204
    /**
205
     * @dataProvider getAdminGroups
206
     */
207
    public function testGetMenuProviderWithAdmin(array $adminGroups): void
208
    {
209
        $this->pool
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\Pool>.

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

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

Loading history...
210
            ->method('getInstance')
211
            ->with($this->equalTo('sonata_admin_foo_service'))
212
            ->willReturn($this->getAdminMock());
213
214
        $this->checker
215
            ->method('isGranted')
216
            ->willReturn(true);
217
218
        $menu = $this->provider->get(
219
            'providerFoo',
220
            [
221
                'name' => 'foo',
222
                'group' => $adminGroups,
223
            ]
224
        );
225
226
        $this->assertInstanceOf(ItemInterface::class, $menu);
227
        $this->assertSame('foo', $menu->getName());
228
229
        $children = $menu->getChildren();
230
231
        $this->assertCount(2, $children);
232
        $this->assertArrayHasKey('foo_admin_label', $children);
233
        $this->assertArrayHasKey('route_label', $children);
234
        $this->assertInstanceOf(MenuItem::class, $menu['foo_admin_label']);
235
        $this->assertSame('foo_admin_label', $menu['foo_admin_label']->getLabel());
236
237
        $extras = $menu['foo_admin_label']->getExtras();
238
        $this->assertArrayHasKey('label_catalogue', $extras);
239
        $this->assertSame($extras['label_catalogue'], 'SonataAdminBundle');
240
241
        $extras = $menu['route_label']->getExtras();
242
        $this->assertArrayHasKey('label_catalogue', $extras);
243
        $this->assertSame($extras['label_catalogue'], 'SonataAdminBundle');
244
    }
245
246
    /**
247
     * @dataProvider getAdminGroups
248
     */
249
    public function testGetKnpMenuWithListRoute(array $adminGroups): void
250
    {
251
        $this->pool
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\Pool>.

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

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

Loading history...
252
            ->method('getInstance')
253
            ->with($this->equalTo('sonata_admin_foo_service'))
254
            ->willReturn($this->getAdminMock(false));
255
256
        $this->checker
257
            ->method('isGranted')
258
            ->willReturn(true);
259
260
        $menu = $this->provider->get(
261
            'providerFoo',
262
            [
263
                'name' => 'foo',
264
                'group' => $adminGroups,
265
            ]
266
        );
267
268
        $this->assertInstanceOf(ItemInterface::class, $menu);
269
        $this->assertArrayNotHasKey('foo_admin_label', $menu->getChildren());
270
        $this->assertArrayHasKey('route_label', $menu->getChildren());
271
        $this->assertCount(1, $menu->getChildren());
272
    }
273
274
    /**
275
     * @dataProvider getAdminGroups
276
     */
277
    public function testGetKnpMenuWithGrantedList(array $adminGroups): void
278
    {
279
        $this->pool
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\Pool>.

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

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

Loading history...
280
            ->method('getInstance')
281
            ->with($this->equalTo('sonata_admin_foo_service'))
282
            ->willReturn($this->getAdminMock(true, false));
283
284
        $this->checker
285
            ->method('isGranted')
286
            ->willReturn(true);
287
288
        $menu = $this->provider->get(
289
            'providerFoo',
290
            [
291
                'name' => 'foo',
292
                'group' => $adminGroups,
293
            ]
294
        );
295
296
        $this->assertInstanceOf(ItemInterface::class, $menu);
297
        $this->assertArrayNotHasKey('foo_admin_label', $menu->getChildren());
298
        $this->assertArrayHasKey('route_label', $menu->getChildren());
299
        $this->assertCount(1, $menu->getChildren());
300
    }
301
302
    /**
303
     * @dataProvider getAdminGroupsWithOnTopOption
304
     */
305
    public function testGetMenuProviderOnTopOptions(array $adminGroupsOnTopOption): void
306
    {
307
        $this->pool
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\Pool>.

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

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

Loading history...
308
            ->method('getInstance')
309
            ->with($this->equalTo('sonata_admin_foo_service'))
310
            ->willReturn($this->getAdminMock(true, false));
311
312
        $menu = $this->provider->get(
313
            'providerFoo',
314
            [
315
                'name' => 'foo',
316
                'group' => $adminGroupsOnTopOption,
317
            ]
318
        );
319
320
        $this->assertInstanceOf(ItemInterface::class, $menu);
321
        $this->assertCount(0, $menu->getChildren());
322
    }
323
324
    /**
325
     * @dataProvider getAdminGroups
326
     */
327
    public function testGetMenuProviderKeepOpenOption(array $adminGroups): void
328
    {
329
        $this->pool
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\Pool>.

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

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

Loading history...
330
            ->method('getInstance')
331
            ->with($this->equalTo('sonata_admin_foo_service'))
332
            ->willReturn($this->getAdminMock());
333
334
        $this->checker
335
            ->method('isGranted')
336
            ->willReturn(true);
337
338
        $adminGroups['keep_open'] = true;
339
340
        $menu = $this->provider->get(
341
            'providerFoo',
342
            [
343
                'name' => 'foo',
344
                'group' => $adminGroups,
345
            ]
346
        );
347
348
        $this->assertInstanceOf(ItemInterface::class, $menu);
349
        $this->assertSame('keep-open', $menu->getAttribute('class'));
350
        $this->assertTrue($menu->getExtra('keep_open'));
351
    }
352
353
    /**
354
     * @return array
355
     */
356
    public function getAdminGroups()
357
    {
358
        return [
359
            [
360
                'bar' => [
361
                    'label' => 'foo',
362
                    'icon' => '<i class="fa fa-edit"></i>',
363
                    'label_catalogue' => 'SonataAdminBundle',
364
                    'items' => [
365
                        [
366
                            'admin' => 'sonata_admin_foo_service',
367
                            'label' => 'fooLabel',
368
                            'route_absolute' => true,
369
                        ],
370
                        [
371
                            'admin' => '',
372
                            'label' => 'route_label',
373
                            'route' => 'FooRoute',
374
                            'route_params' => ['foo' => 'bar'],
375
                            'route_absolute' => true,
376
                            'roles' => [],
377
                        ],
378
                    ],
379
                    'item_adds' => [],
380
                    'roles' => ['foo'],
381
                ],
382
            ],
383
        ];
384
    }
385
386
    /**
387
     * @return array
388
     */
389
    public function getAdminGroupsMultipleRoles()
390
    {
391
        return [
392
            [
393
                // group for all roles, children with different roles
394
                [
395
                    'label' => 'foo',
396
                    'icon' => '<i class="fa fa-edit"></i>',
397
                    'label_catalogue' => 'SonataAdminBundle',
398
                    'items' => [
399
                        [
400
                            'admin' => '',
401
                            'label' => 'route_label1',
402
                            'route' => 'FooRoute1',
403
                            'route_params' => ['foo' => 'bar'],
404
                            'route_absolute' => true,
405
                            'roles' => ['foo', 'bar'],
406
                        ],
407
                        [
408
                            'admin' => '',
409
                            'label' => 'route_label2',
410
                            'route' => 'FooRoute2',
411
                            'route_params' => ['foo' => 'bar'],
412
                            'route_absolute' => true,
413
                            'roles' => ['foo'],
414
                        ],
415
                        [
416
                            'admin' => '',
417
                            'label' => 'route_label3',
418
                            'route' => 'FooRoute3',
419
                            'route_params' => ['foo' => 'bar'],
420
                            'route_absolute' => true,
421
                            'roles' => ['bar'],
422
                        ],
423
                        [
424
                            'admin' => '',
425
                            'label' => 'route_label4',
426
                            'route' => 'FooRoute4',
427
                            'route_params' => ['foo' => 'bar'],
428
                            'route_absolute' => true,
429
                            'roles' => ['baz'],
430
                        ],
431
                    ],
432
                    'roles' => ['foo', 'bar'],
433
                    'item_adds' => [],
434
                ],
435
            ], [
436
                // group for one role, children with different roles
437
                [
438
                    'label' => 'foo',
439
                    'icon' => '<i class="fa fa-edit"></i>',
440
                    'label_catalogue' => 'SonataAdminBundle',
441
                    'items' => [
442
                        [
443
                            'admin' => '',
444
                            'label' => 'route_label1',
445
                            'route' => 'FooRoute1',
446
                            'route_params' => ['foo' => 'bar'],
447
                            'route_absolute' => true,
448
                            'roles' => ['foo', 'bar'],
449
                        ],
450
                        [
451
                            'admin' => '',
452
                            'label' => 'route_label2',
453
                            'route' => 'FooRoute2',
454
                            'route_params' => ['foo' => 'bar'],
455
                            'route_absolute' => true,
456
                            'roles' => ['foo'],
457
                        ],
458
                        [
459
                            'admin' => '',
460
                            'label' => 'route_label3',
461
                            'route' => 'FooRoute3',
462
                            'route_params' => ['foo' => 'bar'],
463
                            'route_absolute' => true,
464
                            'roles' => ['bar'],
465
                        ],
466
                        [
467
                            'admin' => '',
468
                            'label' => 'route_label4',
469
                            'route' => 'FooRoute4',
470
                            'route_params' => ['foo' => 'bar'],
471
                            'route_absolute' => true,
472
                            'roles' => ['baz'],
473
                        ],
474
                    ],
475
                    'roles' => ['baz'],
476
                    'item_adds' => [],
477
                ],
478
            ],
479
        ];
480
    }
481
482
    /**
483
     * @return array
484
     */
485
    public function getAdminGroupsMultipleRolesOnTop()
486
    {
487
        return [
488
            [
489
                [
490
                    'label' => 'foo1',
491
                    'icon' => '<i class="fa fa-edit"></i>',
492
                    'label_catalogue' => 'SonataAdminBundle',
493
                    'items' => [
494
                        [
495
                            'admin' => '',
496
                            'label' => 'route_label1',
497
                            'route' => 'FooRoute1',
498
                            'route_params' => ['foo' => 'bar'],
499
                            'route_absolute' => true,
500
                        ],
501
                    ],
502
                    'item_adds' => [],
503
                    'roles' => ['foo', 'bar'],
504
                    'on_top' => true,
505
                ],
506
            ], [
507
                [
508
                    'label' => 'foo2',
509
                    'icon' => '<i class="fa fa-edit"></i>',
510
                    'label_catalogue' => 'SonataAdminBundle',
511
                    'items' => [
512
                        [
513
                            'admin' => '',
514
                            'label' => 'route_label2',
515
                            'route' => 'FooRoute2',
516
                            'route_params' => ['foo' => 'bar'],
517
                            'route_absolute' => true,
518
                        ],
519
                    ],
520
                    'item_adds' => [],
521
                    'roles' => ['foo'],
522
                    'on_top' => true,
523
                ],
524
            ], [
525
                [
526
                    'label' => 'foo3',
527
                    'icon' => '<i class="fa fa-edit"></i>',
528
                    'label_catalogue' => 'SonataAdminBundle',
529
                    'items' => [
530
                        [
531
                            'admin' => '',
532
                            'label' => 'route_label3',
533
                            'route' => 'FooRoute3',
534
                            'route_params' => ['foo' => 'bar'],
535
                            'route_absolute' => true,
536
                        ],
537
                    ],
538
                    'item_adds' => [],
539
                    'roles' => ['bar'],
540
                    'on_top' => true,
541
                ],
542
            ],
543
        ];
544
    }
545
546
    /**
547
     * @return array
548
     */
549
    public function getAdminGroupsWithOnTopOption()
550
    {
551
        return [
552
            [
553
                'foo' => [
554
                    'label' => 'foo_on_top',
555
                    'icon' => '<i class="fa fa-edit"></i>',
556
                    'label_catalogue' => 'SonataAdminBundle',
557
                    'on_top' => true,
558
                    'items' => [
559
                        [
560
                            'admin' => 'sonata_admin_foo_service',
561
                            'label' => 'fooLabel',
562
                            'route_absolute' => true,
563
                            'route_params' => [],
564
                        ],
565
                    ],
566
                    'item_adds' => [],
567
                    'roles' => [],
568
                ],
569
            ],
570
        ];
571
    }
572
573
    private function getAdminMock(bool $hasRoute = true, bool $isGranted = true): AbstractAdmin
574
    {
575
        $admin = $this->createMock(AbstractAdmin::class);
576
        $admin->expects($this->once())
577
            ->method('hasRoute')
578
            ->with($this->equalTo('list'))
579
            ->willReturn($hasRoute);
580
581
        $admin
582
            ->method('hasAccess')
583
            ->with($this->equalTo('list'))
584
            ->willReturn($isGranted);
585
586
        $admin
587
            ->method('getLabel')
588
            ->willReturn('foo_admin_label');
589
590
        $admin
591
            ->method('generateMenuUrl')
592
            ->willReturn([]);
593
594
        $admin
595
            ->method('getTranslationDomain')
596
            ->willReturn('SonataAdminBundle');
597
598
        return $admin;
599
    }
600
}
601