Completed
Pull Request — master (#131)
by Bart
02:39 queued 54s
created

FieldTest::getMockFieldDefinition()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 14
nc 1
nop 1
1
<?php
2
3
namespace NerdsAndCompany\Schematic\Converters\Base;
4
5
use Craft;
6
use craft\base\Field as FieldModel;
7
use craft\fields\Categories as CategoriesField;
8
use craft\fields\PlainText as PlainTextField;
9
use Codeception\Test\Unit;
10
11
/**
12
 * Class FieldTest.
13
 *
14
 * @author    Nerds & Company
15
 * @copyright Copyright (c) 2015-2017, Nerds & Company
16
 * @license   MIT
17
 *
18
 * @see      http://www.nerds.company
19
 */
20
class FieldTest extends Unit
21
{
22
    /**
23
     * @var Field
24
     */
25
    private $converter;
26
27
    /**
28
     * Set the converter.
29
     *
30
     * @SuppressWarnings(PHPMD.CamelCaseMethodName)
31
     * phpcs:disable PSR2.Methods.MethodDeclaration.Underscore
32
     */
33
    protected function _before()
34
    {
35
        $this->converter = new Field();
36
    }
37
38
    //==============================================================================================================
39
    //=================================================  TESTS  ====================================================
40
    //==============================================================================================================
41
42
    /**
43
     * @dataProvider provideFields
44
     *
45
     * @param FieldModel $field
46
     * @param array      $definition
47
     */
48
    public function testGetRecordDefinition(FieldModel $field, array $definition)
49
    {
50
        if ($field instanceof CategoriesField) {
51
            $mockCategoryGroup = $this->getMockCategoryGroup(1);
52
53
            Craft::$app->categories->expects($this->any())
54
                                   ->method('getGroupById')
55
                                   ->with($field->group->id)
56
                                   ->willReturn($mockCategoryGroup);
57
        }
58
59
        $result = $this->converter->getRecordDefinition($field);
60
61
        $this->assertSame($definition, $result);
62
    }
63
64
    /**
65
     * @dataProvider provideFields
66
     *
67
     * @param FieldModel $field
68
     * @param array      $definition
69
     * @param string     $groupStatus existing|new|invalid
70
     */
71
    public function testSaveRecord(FieldModel $field, array $definition, string $groupStatus)
72
    {
73
        Craft::$app->fields->expects($this->exactly(1))
74
                            ->method('getAllGroups')
75
                            ->willReturn([$this->getMockFieldGroup(1)]);
76
77
        Craft::$app->fields->expects($this->exactly('existing' == $groupStatus ? 0 : 1))
78
                          ->method('saveGroup')
79
                          ->willReturn('invalid' !== $groupStatus);
80
81
        Craft::$app->fields->expects($this->exactly(1))
82
                          ->method('saveField')
83
                          ->with($field)
84
                          ->willReturn(true);
85
86
        $result = $this->converter->saveRecord($field, $definition);
87
88
        $this->assertTrue($result);
89
    }
90
91
    /**
92
     * @dataProvider provideFields
93
     *
94
     * @param FieldModel $field
95
     */
96
    public function testDeleteRecord(FieldModel $field)
97
    {
98
        Craft::$app->fields->expects($this->exactly(1))
99
                            ->method('deleteField')
100
                            ->with($field);
101
102
        $this->converter->deleteRecord($field);
103
    }
104
105
    /**
106
     * @dataProvider provideFields
107
     *
108
     * @param FieldModel $field
109
     * @param array      $definition
110
     */
111
    public function testSetRecordAttributes(FieldModel $field, array $definition)
112
    {
113
        $newField = new PlainTextField();
114
115
        if ($field instanceof CategoriesField) {
116
            $newField = new CategoriesField();
117
            $mockCategoryGroup = $this->getMockCategoryGroup(1);
118
119
            Craft::$app->categories->expects($this->any())
120
                                   ->method('getGroupByHandle')
121
                                   ->with('categoryGroupHandle'.$field->group->id)
122
                                   ->willReturn($mockCategoryGroup);
123
        }
124
125
        $this->converter->setRecordAttributes($newField, $definition, []);
126
127
        $this->assertSame($field->name, $newField->name);
128
        $this->assertSame($field->handle, $newField->handle);
129
130
        if ($field instanceof CategoriesField) {
131
            $this->assertSame($field->source, $newField->source);
132
        }
133
    }
134
135
    //==============================================================================================================
136
    //==============================================  PROVIDERS  ===================================================
137
    //==============================================================================================================
138
139
    /**
140
     * @return array
141
     */
142
    public function provideFields()
143
    {
144
        $mockField1 = $this->getMockField(1, 1);
145
        $mockField2 = $this->getMockField(1, 2);
146
        $mockField3 = $this->getMockCategoriesField(1, 1);
147
148
        return [
149
            'valid field existing group' => [
150
                'field' => $mockField1,
151
                'definition' => $this->getMockFieldDefinition($mockField1),
152
                'groupStatus' => 'existing',
153
            ],
154
            'valid field new group' => [
155
                'field' => $mockField2,
156
                'definition' => $this->getMockFieldDefinition($mockField2),
157
                'groupStatus' => 'new',
158
            ],
159
            'valid field invalid group' => [
160
                'field' => $mockField2,
161
                'definition' => $this->getMockFieldDefinition($mockField2),
162
                'groupStatus' => 'invalid',
163
            ],
164
            'categories field existing group' => [
165
                'field' => $mockField3,
166
                'definition' => $this->getMockCategoriesFieldDefinition($mockField3),
0 ignored issues
show
Compatibility introduced by
$mockField3 of type object<craft\base\Field> is not a sub-type of object<craft\fields\Categories>. It seems like you assume a child class of the class craft\base\Field to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
167
                'groupStatus' => 'existing',
168
            ],
169
        ];
170
    }
171
172
    //==============================================================================================================
173
    //================================================  HELPERS  ===================================================
174
    //==============================================================================================================
175
176
    /**
177
     * @param FieldModel $mockField
178
     *
179
     * @return array
180
     */
181
    private function getMockFieldDefinition(FieldModel $mockField)
182
    {
183
        return [
184
            'class' => get_class($mockField),
185
            'attributes' => [
186
                'name' => 'fieldName'.$mockField->id,
187
                'handle' => 'fieldHandle'.$mockField->id,
188
                'instructions' => null,
189
                'translationMethod' => 'none',
190
                'translationKeyFormat' => null,
191
                'oldHandle' => null,
192
                'columnPrefix' => null,
193
                'required' => false,
194
                'sortOrder' => null,
195
            ],
196
            'group' => $mockField->group->name,
197
        ];
198
    }
199
200
    /**
201
     * @param CategoriesField $mockField
202
     *
203
     * @return array
204
     */
205
    private function getMockCategoriesFieldDefinition(CategoriesField $mockField)
206
    {
207
        $fieldDefinition = $this->getMockFieldDefinition($mockField);
208
209
        $fieldDefinition['attributes'] = array_merge([
210
            'branchLimit' => null,
211
            'sources' => '*',
212
            'source' => 'group:categoryGroupHandle1',
213
            'targetSiteId' => null,
214
            'viewMode' => null,
215
            'limit' => null,
216
            'selectionLabel' => null,
217
            'localizeRelations' => false,
218
            'allowMultipleSources' => true,
219
            'allowLimit' => true,
220
        ], $fieldDefinition['attributes']);
221
222
        return $fieldDefinition;
223
    }
224
225
    /**
226
     * @param int $fieldId
227
     * @param int $groupId
228
     *
229
     * @return Mock|FieldModel
230
     */
231
    private function getMockField(int $fieldId, int $groupId)
232
    {
233
        $mockField = $this->getMockBuilder(FieldModel::class)
234
                           ->setMethods(['getGroup'])
235
                           ->disableOriginalConstructor()
236
                           ->getMock();
237
238
        $this->setMockFieldAttributes($mockField, $fieldId, $groupId);
0 ignored issues
show
Documentation introduced by
$mockField is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\base\Field>.

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...
239
240
        return $mockField;
241
    }
242
243
    /**
244
     * @param int $fieldId
245
     * @param int $groupId
246
     *
247
     * @return Mock|Categories
248
     */
249
    private function getMockCategoriesField(int $fieldId, int $groupId)
250
    {
251
        $mockField = $this->getMockBuilder(CategoriesField::class)
252
                          ->setMethods(['getGroup'])
253
                          ->disableOriginalConstructor()
254
                          ->getMock();
255
256
        $this->setMockFieldAttributes($mockField, $fieldId, $groupId);
0 ignored issues
show
Documentation introduced by
$mockField is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\base\Field>.

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...
257
258
        $mockField->source = 'group:'.$groupId;
259
260
        return $mockField;
261
    }
262
263
    /**
264
     * @param Mock|FieldModel $mockField
265
     * @param int             $fieldId
266
     * @param int             $groupId
267
     */
268
    private function setMockFieldAttributes(FieldModel &$mockField, int $fieldId, int $groupId)
269
    {
270
        $mockField->id = $fieldId;
271
        $mockField->groupId = $fieldId;
272
        $mockField->handle = 'fieldHandle'.$fieldId;
273
        $mockField->name = 'fieldName'.$fieldId;
274
275
        $mockField->expects($this->any())
276
                  ->method('getGroup')
277
                  ->willReturn($this->getMockFieldGroup($groupId));
278
    }
279
280
    /**
281
     * Get a mock field group.
282
     *
283
     * @param int $groupId
284
     *
285
     * @return Mock|FieldGroup
286
     */
287
    private function getMockFieldGroup(int $groupId)
288
    {
289
        $mockGroup = $this->getMockBuilder(FieldGroup::class)
290
                          ->disableOriginalConstructor()
291
                          ->getMock();
292
293
        $mockGroup->id = $groupId;
294
        $mockGroup->name = 'fieldGroup'.$groupId;
295
296
        return $mockGroup;
297
    }
298
299
    /**
300
     * @param int $groupId
301
     *
302
     * @return Mock|CategoryGroup
303
     */
304
    private function getMockCategoryGroup(int $groupId)
305
    {
306
        $mockCategoryGroup = $this->getMockBuilder(CategoryGroup::class)
307
                                  ->disableOriginalConstructor()
308
                                  ->getMock();
309
310
        $mockCategoryGroup->id = $groupId;
311
        $mockCategoryGroup->handle = 'categoryGroupHandle'.$groupId;
312
313
        return $mockCategoryGroup;
314
315
        Craft::$app->categories->expects($this->any())
0 ignored issues
show
Unused Code introduced by
\Craft::$app->categories...rn($mockCategoryGroup); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
316
                               ->method('getGroupByHandle')
317
                               ->with('categoryGroupHandle'.$groupId)
318
                               ->willReturn($mockCategoryGroup);
319
    }
320
}
321