Completed
Push — master ( e6c9d7...cc6bd7 )
by Grégoire
12:23
created

ShowMapperTest::testAddOptionRole()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 9.52
c 0
b 0
f 0
cc 1
nc 1
nop 0
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\Show;
15
16
use PHPUnit\Framework\TestCase;
17
use Sonata\AdminBundle\Admin\AdminInterface;
18
use Sonata\AdminBundle\Admin\BaseFieldDescription;
19
use Sonata\AdminBundle\Admin\FieldDescriptionCollection;
20
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
21
use Sonata\AdminBundle\Builder\ShowBuilderInterface;
22
use Sonata\AdminBundle\Model\ModelManagerInterface;
23
use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface;
24
use Sonata\AdminBundle\Show\ShowMapper;
25
use Sonata\AdminBundle\Tests\Fixtures\Admin\CleanAdmin;
26
use Sonata\AdminBundle\Translator\NoopLabelTranslatorStrategy;
27
28
/**
29
 * Test for ShowMapper.
30
 *
31
 * @author Andrej Hudec <[email protected]>
32
 */
33
class ShowMapperTest extends TestCase
34
{
35
    private const DEFAULT_GRANTED_ROLE = 'ROLE_ADMIN_BAZ';
36
37
    /**
38
     * @var ShowMapper
39
     */
40
    private $showMapper;
41
42
    /**
43
     * @var AdminInterface
44
     */
45
    private $admin;
46
47
    /**
48
     * @var ShowBuilderInterface
49
     */
50
    private $showBuilder;
51
52
    /**
53
     * @var FieldDescriptionCollection
54
     */
55
    private $fieldDescriptionCollection;
56
57
    /**
58
     * @var array
59
     */
60
    private $groups;
61
62
    /**
63
     * @var array
64
     */
65
    private $listShowFields;
66
67
    protected function setUp(): void
68
    {
69
        $this->showBuilder = $this->getMockForAbstractClass(ShowBuilderInterface::class);
70
        $this->fieldDescriptionCollection = new FieldDescriptionCollection();
71
        $this->admin = $this->getMockForAbstractClass(AdminInterface::class);
72
73
        $this->admin->expects($this->any())
74
            ->method('getLabel')
75
            ->willReturn('AdminLabel');
76
77
        $this->admin->expects($this->any())
78
            ->method('getShowTabs')
79
            ->willReturn([]);
80
81
        $this->groups = [];
82
        $this->listShowFields = [];
83
84
        $this->admin->expects($this->any())
85
            ->method('getShowGroups')
86
            ->willReturnCallback(function () {
87
                return $this->groups;
88
            });
89
90
        $this->admin->expects($this->any())
91
            ->method('setShowGroups')
92
            ->willReturnCallback(function ($showGroups): void {
93
                $this->groups = $showGroups;
94
            });
95
96
        $this->admin->expects($this->any())
97
            ->method('reorderShowGroup')
98
            ->willReturnCallback(function ($group, $keys): void {
99
                $this->groups[$group]['fields'] = array_merge(array_flip($keys), $this->groups[$group]['fields']);
100
            });
101
102
        $modelManager = $this->getMockForAbstractClass(ModelManagerInterface::class);
103
104
        $modelManager->expects($this->any())
105
            ->method('getNewFieldDescriptionInstance')
106
            ->willReturnCallback(function ($class, $name, array $options = []) {
107
                $fieldDescription = $this->getFieldDescriptionMock();
108
                $fieldDescription->setName($name);
109
                $fieldDescription->setOptions($options);
110
111
                return $fieldDescription;
112
            });
113
114
        $this->admin->expects($this->any())
115
            ->method('getModelManager')
116
            ->willReturn($modelManager);
117
118
        $labelTranslatorStrategy = new NoopLabelTranslatorStrategy();
119
120
        $this->admin->expects($this->any())
121
            ->method('getLabelTranslatorStrategy')
122
            ->willReturn($labelTranslatorStrategy);
123
124
        $this->admin->expects($this->any())
125
            ->method('hasShowFieldDescription')
126
            ->willReturnCallback(function ($name) {
127
                if (isset($this->listShowFields[$name])) {
128
                    return true;
129
                }
130
                $this->listShowFields[$name] = true;
131
132
                return false;
133
            });
134
135
        $this->showBuilder->expects($this->any())
136
            ->method('addField')
137
            ->willReturnCallback(static function ($list, $type, $fieldDescription, $admin): void {
0 ignored issues
show
Unused Code introduced by
The parameter $admin is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
138
                $list->add($fieldDescription);
139
            });
140
141
        $this->showMapper = new ShowMapper($this->showBuilder, $this->fieldDescriptionCollection, $this->admin);
142
    }
143
144
    public function testFluidInterface(): void
145
    {
146
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
147
148
        $this->assertSame($this->showMapper, $this->showMapper->add($fieldDescription));
149
        $this->assertSame($this->showMapper, $this->showMapper->remove('fooName'));
150
        $this->assertSame($this->showMapper, $this->showMapper->reorder([]));
151
    }
152
153
    public function testGet(): void
154
    {
155
        $this->assertFalse($this->showMapper->has('fooName'));
156
157
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
158
159
        $this->showMapper->add($fieldDescription);
160
        $this->assertSame($fieldDescription, $this->showMapper->get('fooName'));
161
    }
162
163
    public function testAdd(): void
164
    {
165
        $this->showMapper->add('fooName');
166
167
        $this->assertTrue($this->showMapper->has('fooName'));
168
169
        $fieldDescription = $this->showMapper->get('fooName');
170
171
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
172
        $this->assertSame('fooName', $fieldDescription->getName());
173
        $this->assertSame('fooName', $fieldDescription->getOption('label'));
174
    }
175
176
    public function testIfTrueApply(): void
177
    {
178
        $this->showMapper->ifTrue(true);
179
        $this->showMapper->add('fooName');
180
        $this->showMapper->ifEnd();
181
182
        $this->assertTrue($this->showMapper->has('fooName'));
183
        $fieldDescription = $this->showMapper->get('fooName');
184
185
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
186
        $this->assertSame('fooName', $fieldDescription->getName());
187
        $this->assertSame('fooName', $fieldDescription->getOption('label'));
188
    }
189
190
    public function testIfTrueNotApply(): void
191
    {
192
        $this->showMapper->ifTrue(false);
193
        $this->showMapper->add('fooName');
194
        $this->showMapper->ifEnd();
195
196
        $this->assertFalse($this->showMapper->has('fooName'));
197
    }
198
199
    public function testIfTrueCombination(): void
200
    {
201
        $this->showMapper->ifTrue(false);
202
        $this->showMapper->add('fooName');
203
        $this->showMapper->ifEnd();
204
        $this->showMapper->add('barName');
205
206
        $this->assertFalse($this->showMapper->has('fooName'));
207
        $this->assertTrue($this->showMapper->has('barName'));
208
        $fieldDescription = $this->showMapper->get('barName');
209
210
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
211
        $this->assertSame('barName', $fieldDescription->getName());
212
        $this->assertSame('barName', $fieldDescription->getOption('label'));
213
    }
214
215
    public function testIfFalseApply(): void
216
    {
217
        $this->showMapper->ifFalse(false);
218
        $this->showMapper->add('fooName');
219
        $this->showMapper->ifEnd();
220
221
        $this->assertTrue($this->showMapper->has('fooName'));
222
        $fieldDescription = $this->showMapper->get('fooName');
223
224
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
225
        $this->assertSame('fooName', $fieldDescription->getName());
226
        $this->assertSame('fooName', $fieldDescription->getOption('label'));
227
    }
228
229
    public function testIfFalseNotApply(): void
230
    {
231
        $this->showMapper->ifFalse(true);
232
        $this->showMapper->add('fooName');
233
        $this->showMapper->ifEnd();
234
235
        $this->assertFalse($this->showMapper->has('fooName'));
236
    }
237
238
    public function testIfFalseCombination(): void
239
    {
240
        $this->showMapper->ifFalse(true);
241
        $this->showMapper->add('fooName');
242
        $this->showMapper->ifEnd();
243
        $this->showMapper->add('barName');
244
245
        $this->assertFalse($this->showMapper->has('fooName'));
246
        $this->assertTrue($this->showMapper->has('barName'));
247
        $fieldDescription = $this->showMapper->get('barName');
248
249
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
250
        $this->assertSame('barName', $fieldDescription->getName());
251
        $this->assertSame('barName', $fieldDescription->getOption('label'));
252
    }
253
254
    public function testIfTrueNested(): void
255
    {
256
        $this->expectException(\RuntimeException::class);
257
        $this->expectExceptionMessage('Cannot nest ifTrue or ifFalse call');
258
259
        $this->showMapper->ifTrue(true);
260
        $this->showMapper->ifTrue(true);
261
    }
262
263
    public function testIfFalseNested(): void
264
    {
265
        $this->expectException(\RuntimeException::class);
266
        $this->expectExceptionMessage('Cannot nest ifTrue or ifFalse call');
267
268
        $this->showMapper->ifFalse(false);
269
        $this->showMapper->ifFalse(false);
270
    }
271
272
    public function testIfCombinationNested(): void
273
    {
274
        $this->expectException(\RuntimeException::class);
275
        $this->expectExceptionMessage('Cannot nest ifTrue or ifFalse call');
276
277
        $this->showMapper->ifTrue(true);
278
        $this->showMapper->ifFalse(false);
279
    }
280
281
    public function testIfFalseCombinationNested2(): void
282
    {
283
        $this->expectException(\RuntimeException::class);
284
        $this->expectExceptionMessage('Cannot nest ifTrue or ifFalse call');
285
286
        $this->showMapper->ifFalse(false);
287
        $this->showMapper->ifTrue(true);
288
    }
289
290
    public function testIfFalseCombinationNested3(): void
291
    {
292
        $this->expectException(\RuntimeException::class);
293
        $this->expectExceptionMessage('Cannot nest ifTrue or ifFalse call');
294
295
        $this->showMapper->ifFalse(true);
296
        $this->showMapper->ifTrue(false);
297
    }
298
299
    public function testIfFalseCombinationNested4(): void
300
    {
301
        $this->expectException(\RuntimeException::class);
302
        $this->expectExceptionMessage('Cannot nest ifTrue or ifFalse call');
303
304
        $this->showMapper->ifTrue(false);
305
        $this->showMapper->ifFalse(true);
306
    }
307
308
    public function testAddRemove(): void
309
    {
310
        $this->assertFalse($this->showMapper->has('fooName'));
311
312
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
313
314
        $this->showMapper->add($fieldDescription);
315
        $this->assertTrue($this->showMapper->has('fooName'));
316
317
        $this->showMapper->remove('fooName');
318
        $this->assertFalse($this->showMapper->has('fooName'));
319
    }
320
321
    public function testAddException(): void
322
    {
323
        $this->expectException(\RuntimeException::class, 'invalid state');
324
325
        $this->showMapper->add(12345);
326
    }
327
328
    public function testAddDuplicateFieldNameException(): void
329
    {
330
        $name = 'name';
331
        $this->expectException(\RuntimeException::class, sprintf('Duplicate field %s "name" in show mapper. Names should be unique.', $name));
332
333
        $this->showMapper->add($name);
334
        $this->showMapper->add($name);
335
    }
336
337
    public function testKeys(): void
338
    {
339
        $fieldDescription1 = $this->getFieldDescriptionMock('fooName1', 'fooLabel1');
340
        $fieldDescription2 = $this->getFieldDescriptionMock('fooName2', 'fooLabel2');
341
342
        $this->showMapper->add($fieldDescription1);
343
        $this->showMapper->add($fieldDescription2);
344
345
        $this->assertSame(['fooName1', 'fooName2'], $this->showMapper->keys());
346
    }
347
348
    public function testReorder(): void
349
    {
350
        $this->assertSame([], $this->admin->getShowGroups());
351
352
        $fieldDescription1 = $this->getFieldDescriptionMock('fooName1', 'fooLabel1');
353
        $fieldDescription2 = $this->getFieldDescriptionMock('fooName2', 'fooLabel2');
354
        $fieldDescription3 = $this->getFieldDescriptionMock('fooName3', 'fooLabel3');
355
        $fieldDescription4 = $this->getFieldDescriptionMock('fooName4', 'fooLabel4');
356
357
        $this->showMapper->with('Group1');
358
        $this->showMapper->add($fieldDescription1);
359
        $this->showMapper->add($fieldDescription2);
360
        $this->showMapper->add($fieldDescription3);
361
        $this->showMapper->add($fieldDescription4);
362
363
        $this->assertSame([
364
            'Group1' => [
365
                'collapsed' => false,
366
                'class' => false,
367
                'description' => false,
368
                'label' => 'Group1',
369
                'translation_domain' => null,
370
                'name' => 'Group1',
371
                'box_class' => 'box box-primary',
372
                'fields' => ['fooName1' => 'fooName1', 'fooName2' => 'fooName2', 'fooName3' => 'fooName3', 'fooName4' => 'fooName4'],
373
            ], ], $this->admin->getShowGroups());
374
375
        $this->showMapper->reorder(['fooName3', 'fooName2', 'fooName1', 'fooName4']);
376
377
        // print_r is used to compare order of items in associative arrays
378
        $this->assertSame(print_r([
379
            'Group1' => [
380
                'collapsed' => false,
381
                'class' => false,
382
                'description' => false,
383
                'label' => 'Group1',
384
                'translation_domain' => null,
385
                'name' => 'Group1',
386
                'box_class' => 'box box-primary',
387
                'fields' => ['fooName3' => 'fooName3', 'fooName2' => 'fooName2', 'fooName1' => 'fooName1', 'fooName4' => 'fooName4'],
388
            ], ], true), print_r($this->admin->getShowGroups(), true));
389
    }
390
391
    public function testGroupRemovingWithoutTab(): void
392
    {
393
        $this->cleanShowMapper();
394
395
        $this->showMapper->with('groupfoo1');
396
        $this->showMapper->removeGroup('groupfoo1');
397
398
        $this->assertSame([], $this->admin->getShowGroups());
399
    }
400
401
    public function testGroupRemovingWithTab(): void
402
    {
403
        $this->cleanShowMapper();
404
405
        $this->showMapper->tab('mytab')->with('groupfoo2');
406
        $this->showMapper->removeGroup('groupfoo2', 'mytab');
407
408
        $this->assertSame([], $this->admin->getShowGroups());
409
    }
410
411
    public function testGroupRemovingWithoutTabAndWithTabRemoving(): void
412
    {
413
        $this->cleanShowMapper();
414
415
        $this->showMapper->with('groupfoo3');
416
        $this->showMapper->removeGroup('groupfoo3', 'default', true);
417
418
        $this->assertSame([], $this->admin->getShowGroups());
419
        $this->assertSame([], $this->admin->getShowTabs());
420
    }
421
422
    public function testGroupRemovingWithTabAndWithTabRemoving(): void
423
    {
424
        $this->cleanShowMapper();
425
426
        $this->showMapper->tab('mytab2')->with('groupfoo4');
427
        $this->showMapper->removeGroup('groupfoo4', 'mytab2', true);
428
429
        $this->assertSame([], $this->admin->getShowGroups());
430
        $this->assertSame([], $this->admin->getShowTabs());
431
    }
432
433
    public function testEmptyFieldLabel(): void
434
    {
435
        $this->showMapper->add('foo', null, ['label' => false]);
436
437
        $this->assertFalse($this->showMapper->get('foo')->getOption('label'));
438
    }
439
440
    public function testAddOptionRole(): void
441
    {
442
        $this->cleanShowMapper();
443
444
        $this->showMapper->add('bar', 'bar');
445
446
        $this->assertTrue($this->showMapper->has('bar'));
447
448
        $this->showMapper->add('quux', 'bar', ['role' => 'ROLE_QUX']);
449
450
        $this->assertTrue($this->showMapper->has('bar'));
451
        $this->assertFalse($this->showMapper->has('quux'));
452
453
        $this->showMapper
454
            ->with('qux')
455
                ->add('foobar', 'bar', ['role' => self::DEFAULT_GRANTED_ROLE])
456
                ->add('foo', 'bar', ['role' => 'ROLE_QUX'])
457
                ->add('baz', 'bar')
458
            ->end();
459
460
        $this->assertArrayHasKey('qux', $this->admin->getShowGroups());
461
        $this->assertTrue($this->showMapper->has('foobar'));
462
        $this->assertFalse($this->showMapper->has('foo'));
463
        $this->assertTrue($this->showMapper->has('baz'));
464
    }
465
466
    private function cleanShowMapper(): void
467
    {
468
        $this->showBuilder = $this->getMockForAbstractClass(ShowBuilderInterface::class);
469
        $this->showBuilder->expects($this->any())
470
            ->method('addField')
471
            ->willReturnCallback(static function (FieldDescriptionCollection $list, ?string $type, FieldDescriptionInterface $fieldDescription, AdminInterface $admin): void {
0 ignored issues
show
Unused Code introduced by
The parameter $admin is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
472
                $list->add($fieldDescription);
473
            });
474
        $this->fieldDescriptionCollection = new FieldDescriptionCollection();
475
        $this->admin = new CleanAdmin('code', 'class', 'controller');
476
        $securityHandler = $this->createMock(SecurityHandlerInterface::class);
477
        $securityHandler
478
            ->expects($this->any())
479
            ->method('isGranted')
480
            ->willReturnCallback(static function (AdminInterface $admin, $attributes, $object = null): bool {
0 ignored issues
show
Unused Code introduced by
The parameter $object is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
481
                return self::DEFAULT_GRANTED_ROLE === $attributes;
482
            });
483
484
        $this->admin->setSecurityHandler($securityHandler);
485
486
        $this->showMapper = new ShowMapper($this->showBuilder, $this->fieldDescriptionCollection, $this->admin);
487
488
        $modelManager = $this->getMockForAbstractClass(ModelManagerInterface::class);
489
490
        $modelManager->expects($this->any())
491
            ->method('getNewFieldDescriptionInstance')
492
            ->willReturnCallback(function (string $class, string $name, array $options = []): FieldDescriptionInterface {
493
                $fieldDescription = $this->getFieldDescriptionMock();
494
                $fieldDescription->setName($name);
495
                $fieldDescription->setOptions($options);
496
497
                return $fieldDescription;
498
            });
499
500
        $this->admin->setModelManager($modelManager);
501
        $this->admin->setLabelTranslatorStrategy(new NoopLabelTranslatorStrategy());
502
    }
503
504
    private function getFieldDescriptionMock(?string $name = null, ?string $label = null): BaseFieldDescription
505
    {
506
        $fieldDescription = $this->getMockForAbstractClass(BaseFieldDescription::class);
507
508
        if (null !== $name) {
509
            $fieldDescription->setName($name);
510
        }
511
512
        if (null !== $label) {
513
            $fieldDescription->setOption('label', $label);
514
        }
515
516
        return $fieldDescription;
517
    }
518
}
519