Completed
Push — master ( 1c0828...c11e72 )
by Marko
04:18
created

ListMapperTest::getWrongIdentifierOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
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\Datagrid;
15
16
use PHPUnit\Framework\TestCase;
17
use Sonata\AdminBundle\Admin\AbstractAdmin;
18
use Sonata\AdminBundle\Admin\AdminInterface;
19
use Sonata\AdminBundle\Admin\BaseFieldDescription;
20
use Sonata\AdminBundle\Admin\FieldDescriptionCollection;
21
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
22
use Sonata\AdminBundle\Builder\ListBuilderInterface;
23
use Sonata\AdminBundle\Datagrid\ListMapper;
24
use Sonata\AdminBundle\Model\ModelManagerInterface;
25
use Sonata\AdminBundle\Translator\NoopLabelTranslatorStrategy;
26
27
/**
28
 * @author Andrej Hudec <[email protected]>
29
 */
30
class ListMapperTest extends TestCase
31
{
32
    private const DEFAULT_GRANTED_ROLE = 'ROLE_ADMIN_BAZ';
33
34
    /**
35
     * @var ListMapper
36
     */
37
    private $listMapper;
38
39
    /**
40
     * @var FieldDescriptionCollection
41
     */
42
    private $fieldDescriptionCollection;
43
44
    /**
45
     * @var AdminInterface
46
     */
47
    private $admin;
48
49
    protected function setUp(): void
50
    {
51
        $listBuilder = $this->createMock(ListBuilderInterface::class);
52
        $this->fieldDescriptionCollection = new FieldDescriptionCollection();
53
        $this->admin = $this->createMock(AbstractAdmin::class);
54
55
        $listBuilder->expects($this->any())
56
            ->method('addField')
57
            ->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...
58
                $list->add($fieldDescription);
59
            });
60
61
        $modelManager = $this->createMock(ModelManagerInterface::class);
62
63
        $modelManager->expects($this->any())
64
            ->method('getNewFieldDescriptionInstance')
65
            ->willReturnCallback(function ($class, $name, array $options = []) {
66
                $fieldDescription = $this->getFieldDescriptionMock();
67
                $fieldDescription->setName($name);
68
                $fieldDescription->setOptions($options);
69
70
                return $fieldDescription;
71
            });
72
73
        $this->admin->expects($this->any())
74
            ->method('getModelManager')
75
            ->willReturn($modelManager);
76
77
        $labelTranslatorStrategy = new NoopLabelTranslatorStrategy();
78
79
        $this->admin->expects($this->any())
80
            ->method('getLabelTranslatorStrategy')
81
            ->willReturn($labelTranslatorStrategy);
82
83
        $this->admin->expects($this->any())
84
            ->method('isGranted')
85
            ->willReturnCallback(static function (string $name, object $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...
86
                return self::DEFAULT_GRANTED_ROLE === $name;
87
            });
88
89
        $this->listMapper = new ListMapper($listBuilder, $this->fieldDescriptionCollection, $this->admin);
90
    }
91
92
    public function testFluidInterface(): void
93
    {
94
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
95
96
        $this->assertSame($this->listMapper, $this->listMapper->add($fieldDescription));
0 ignored issues
show
Documentation introduced by
$fieldDescription is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
97
        $this->assertSame($this->listMapper, $this->listMapper->remove('fooName'));
98
        $this->assertSame($this->listMapper, $this->listMapper->reorder([]));
99
    }
100
101
    public function testGet(): void
102
    {
103
        $this->assertFalse($this->listMapper->has('fooName'));
104
105
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
106
107
        $this->listMapper->add($fieldDescription);
0 ignored issues
show
Documentation introduced by
$fieldDescription is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
108
        $this->assertSame($fieldDescription, $this->listMapper->get('fooName'));
109
    }
110
111
    public function testAddIdentifier(): void
112
    {
113
        $this->assertFalse($this->listMapper->has('fooName'));
114
115
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
116
117
        $this->listMapper->addIdentifier($fieldDescription);
0 ignored issues
show
Documentation introduced by
$fieldDescription is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
118
        $this->assertTrue($this->listMapper->has('fooName'));
119
120
        $fieldDescription = $this->listMapper->get('fooName');
121
        $this->assertTrue($fieldDescription->getOption('identifier'));
122
    }
123
124
    public function testAddOptionIdentifier(): void
125
    {
126
        $this->assertFalse($this->listMapper->has('fooName'));
127
        $this->assertFalse($this->listMapper->has('barName'));
128
        $this->assertFalse($this->listMapper->has('bazName'));
129
130
        $this->listMapper->add('barName');
131
        $this->assertNull($this->listMapper->get('barName')->getOption('identifier'));
132
        $this->listMapper->add('fooName', null, ['identifier' => true]);
133
        $this->assertTrue($this->listMapper->has('fooName'));
134
        $this->assertTrue($this->listMapper->get('fooName')->getOption('identifier'));
135
        $this->listMapper->add('bazName', null, ['identifier' => false]);
136
        $this->assertTrue($this->listMapper->has('bazName'));
137
        $this->assertFalse($this->listMapper->get('bazName')->getOption('identifier'));
138
    }
139
140
    /**
141
     * @dataProvider getWrongIdentifierOptions
142
     */
143
    public function testAddOptionIdentifierWithWrongValue(bool $expected, $value): void
144
    {
145
        $this->assertFalse($this->listMapper->has('fooName'));
146
147
        $this->expectException(\InvalidArgumentException::class);
148
        $this->expectExceptionMessageRegExp('{^Value for "identifier" option must be boolean, [^ ]+ given\.$}');
149
150
        $this->listMapper->add('fooName', null, ['identifier' => $value]);
151
    }
152
153
    public function getWrongIdentifierOptions(): iterable
154
    {
155
        return [
156
            [true, 1],
157
            [true, 'string'],
158
            [true, new \stdClass()],
159
            [true, [null]],
160
            [false, 0],
161
            [false, null],
162
            [false, ''],
163
            [false, '0'],
164
            [false, []],
165
        ];
166
    }
167
168
    public function testAdd(): void
169
    {
170
        $this->listMapper->add('fooName');
171
        $this->listMapper->add('fooNameLabelBar', null, ['label' => 'Foo Bar']);
172
        $this->listMapper->add('fooNameLabelFalse', null, ['label' => false]);
173
174
        $this->assertTrue($this->listMapper->has('fooName'));
175
176
        $fieldDescription = $this->listMapper->get('fooName');
177
        $fieldLabelBar = $this->listMapper->get('fooNameLabelBar');
178
        $fieldLabelFalse = $this->listMapper->get('fooNameLabelFalse');
179
180
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
181
        $this->assertSame('fooName', $fieldDescription->getName());
182
        $this->assertSame('fooName', $fieldDescription->getOption('label'));
183
        $this->assertSame('Foo Bar', $fieldLabelBar->getOption('label'));
184
        $this->assertFalse($fieldLabelFalse->getOption('label'));
185
    }
186
187
    public function testAddViewInlineAction(): void
188
    {
189
        $this->assertFalse($this->listMapper->has('_action'));
190
        $this->listMapper->add('_action', 'actions', ['actions' => ['show' => []]]);
191
192
        $this->assertTrue($this->listMapper->has('_action'));
193
194
        $fieldDescription = $this->listMapper->get('_action');
195
196
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
197
        $this->assertSame('_action', $fieldDescription->getName());
198
        $this->assertCount(1, $fieldDescription->getOption('actions'));
199
        $this->assertSame(['show' => []], $fieldDescription->getOption('actions'));
200
    }
201
202
    public function testAddRemove(): void
203
    {
204
        $this->assertFalse($this->listMapper->has('fooName'));
205
206
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
207
208
        $this->listMapper->add($fieldDescription);
0 ignored issues
show
Documentation introduced by
$fieldDescription is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
209
        $this->assertTrue($this->listMapper->has('fooName'));
210
211
        $this->listMapper->remove('fooName');
212
        $this->assertFalse($this->listMapper->has('fooName'));
213
    }
214
215
    public function testAddDuplicateNameException(): void
216
    {
217
        $tmpNames = [];
218
        $this->admin->expects($this->any())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

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...
219
            ->method('hasListFieldDescription')
220
            ->willReturnCallback(static function ($name) use (&$tmpNames) {
221
                if (isset($tmpNames[$name])) {
222
                    return true;
223
                }
224
                $tmpNames[$name] = $name;
225
226
                return false;
227
            });
228
229
        $this->expectException(\RuntimeException::class, 'Duplicate field name "fooName" in list mapper. Names should be unique.');
230
231
        $this->listMapper->add('fooName');
232
        $this->listMapper->add('fooName');
233
    }
234
235
    public function testAddWrongTypeException(): void
236
    {
237
        $this->expectException(\RuntimeException::class, 'Unknown field name in list mapper. Field name should be either of FieldDescriptionInterface interface or string.');
238
239
        $this->listMapper->add(12345);
240
    }
241
242
    public function testAutoAddVirtualOption(): void
243
    {
244
        foreach (['actions', 'batch', 'select'] as $type) {
245
            $this->listMapper->add('_'.$type, $type);
246
        }
247
248
        foreach ($this->fieldDescriptionCollection->getElements() as $field) {
249
            $this->assertTrue(
250
                $field->isVirtual(),
251
                'Failed asserting that FieldDescription with type "'.$field->getType().'" is tagged with virtual flag.'
252
            );
253
        }
254
    }
255
256
    public function testKeys(): void
257
    {
258
        $fieldDescription1 = $this->getFieldDescriptionMock('fooName1', 'fooLabel1');
259
        $fieldDescription2 = $this->getFieldDescriptionMock('fooName2', 'fooLabel2');
260
261
        $this->listMapper->add($fieldDescription1);
0 ignored issues
show
Documentation introduced by
$fieldDescription1 is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
262
        $this->listMapper->add($fieldDescription2);
0 ignored issues
show
Documentation introduced by
$fieldDescription2 is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
263
264
        $this->assertSame(['fooName1', 'fooName2'], $this->listMapper->keys());
265
    }
266
267
    public function testReorder(): void
268
    {
269
        $fieldDescription1 = $this->getFieldDescriptionMock('fooName1', 'fooLabel1');
270
        $fieldDescription2 = $this->getFieldDescriptionMock('fooName2', 'fooLabel2');
271
        $fieldDescription3 = $this->getFieldDescriptionMock('fooName3', 'fooLabel3');
272
        $fieldDescription4 = $this->getFieldDescriptionMock('fooName4', 'fooLabel4');
273
274
        $this->listMapper->add($fieldDescription1);
0 ignored issues
show
Documentation introduced by
$fieldDescription1 is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
275
        $this->listMapper->add($fieldDescription2);
0 ignored issues
show
Documentation introduced by
$fieldDescription2 is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
276
        $this->listMapper->add($fieldDescription3);
0 ignored issues
show
Documentation introduced by
$fieldDescription3 is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
277
        $this->listMapper->add($fieldDescription4);
0 ignored issues
show
Documentation introduced by
$fieldDescription4 is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
278
279
        $this->assertSame([
280
            'fooName1' => $fieldDescription1,
281
            'fooName2' => $fieldDescription2,
282
            'fooName3' => $fieldDescription3,
283
            'fooName4' => $fieldDescription4,
284
        ], $this->fieldDescriptionCollection->getElements());
285
286
        $this->listMapper->reorder(['fooName3', 'fooName2', 'fooName1', 'fooName4']);
287
288
        // print_r is used to compare order of items in associative arrays
289
        $this->assertSame(print_r([
290
            'fooName3' => $fieldDescription3,
291
            'fooName2' => $fieldDescription2,
292
            'fooName1' => $fieldDescription1,
293
            'fooName4' => $fieldDescription4,
294
        ], true), print_r($this->fieldDescriptionCollection->getElements(), true));
295
    }
296
297
    public function testAddOptionRole(): void
298
    {
299
        $this->listMapper->add('bar', 'bar');
300
301
        $this->assertTrue($this->listMapper->has('bar'));
302
303
        $this->listMapper->add('quux', 'bar', ['role' => 'ROLE_QUX']);
304
305
        $this->assertTrue($this->listMapper->has('bar'));
306
        $this->assertFalse($this->listMapper->has('quux'));
307
308
        $this->listMapper
309
            ->add('foobar', 'bar', ['role' => self::DEFAULT_GRANTED_ROLE])
310
            ->add('foo', 'bar', ['role' => 'ROLE_QUX'])
311
            ->add('baz', 'bar');
312
313
        $this->assertTrue($this->listMapper->has('foobar'));
314
        $this->assertFalse($this->listMapper->has('foo'));
315
        $this->assertTrue($this->listMapper->has('baz'));
316
    }
317
318
    private function getFieldDescriptionMock(?string $name = null, ?string $label = null): BaseFieldDescription
319
    {
320
        $fieldDescription = $this->getMockForAbstractClass(BaseFieldDescription::class);
321
322
        if (null !== $name) {
323
            $fieldDescription->setName($name);
324
        }
325
326
        if (null !== $label) {
327
            $fieldDescription->setOption('label', $label);
328
        }
329
330
        return $fieldDescription;
331
    }
332
}
333