Completed
Pull Request — master (#114)
by Bart
02:14
created

GlobalSetsTest::provideValidGlobalSets()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 19
nc 1
nop 0
1
<?php
2
3
namespace NerdsAndCompany\Schematic\Services;
4
5
use Craft;
6
use craft\elements\GlobalSet;
7
use craft\models\FieldLayout;
8
use craft\models\Site;
9
use craft\services\Fields;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, NerdsAndCompany\Schematic\Services\Fields.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use Codeception\Test\Unit;
11
use NerdsAndCompany\Schematic\Schematic;
12
13
/**
14
 * Class GlobalSetsTest.
15
 *
16
 * @author    Nerds & Company
17
 * @copyright Copyright (c) 2015-2017, Nerds & Company
18
 * @license   MIT
19
 *
20
 * @see      http://www.nerds.company
21
 */
22
class GlobalSetsTest extends Unit
23
{
24
    /**
25
     * @var GlobalSets
26
     */
27
    private $service;
28
29
    /**
30
     * Set the service.
31
     *
32
     * @SuppressWarnings(PHPMD.CamelCaseMethodName)
33
     */
34
    protected function _before()
35
    {
36
        Craft::$app->sites->expects($this->any())
37
                  ->method('getSiteByHandle')
38
                  ->willReturn($this->getMockSite());
39
40
        $this->service = new GlobalSets();
41
    }
42
43
    //==============================================================================================================
44
    //=================================================  TESTS  ====================================================
45
    //==============================================================================================================
46
47
    /**
48
     * @dataProvider provideValidGlobalSets
49
     *
50
     * @param GlobalSetModel[] $sets
51
     * @param array            $expectedResult
52
     */
53
    public function testSuccessfulExport(array $sets, array $expectedResult = [])
54
    {
55
        $this->expectList($sets);
56
57
        $actualResult = $this->service->export();
58
59
        $this->assertSame($expectedResult, $actualResult);
60
    }
61
62
    /**
63
     * @dataProvider provideValidGlobalSetDefinitions
64
     *
65
     * @param array $setDefinitions
66
     */
67
    public function testSuccessfulImport(array $setDefinitions, array $existingSets, int $saveCount)
68
    {
69
        $this->expectList($existingSets);
70
        $this->expectSaves($saveCount);
71
        $this->expectDeletes(0);
72
73
        $this->service->import($setDefinitions);
74
    }
75
76
    /**
77
     * @dataProvider provideValidGlobalSetDefinitions
78
     *
79
     * @param array $setDefinitions
80
     */
81
    public function testImportWithForceOption(array $setDefinitions, array $existingSets, int $saveCount, int $deleteCount)
82
    {
83
        Schematic::$force = true;
84
        $this->expectList($existingSets);
85
        $this->expectSaves($saveCount);
86
        $this->expectDeletes($deleteCount);
87
88
        $this->service->import($setDefinitions);
89
    }
90
91
    //==============================================================================================================
92
    //==============================================  PROVIDERS  ===================================================
93
    //==============================================================================================================
94
95
    /**
96
     * @return array
97
     */
98
    public function provideValidGlobalSets()
99
    {
100
        $mockGlobalSet1 = $this->getMockGlobalSet(1);
101
        $mockGlobalSet2 = $this->getMockGlobalSet(2);
102
103
        return [
104
            'emptyArray' => [
105
                'GlobalSets' => [],
106
                'expectedResult' => [],
107
            ],
108
            'single set' => [
109
                'GlobalSets' => [
110
                    'set1' => $mockGlobalSet1,
111
                ],
112
                'expectedResult' => [
113
                    'setHandle1' => $this->getMockGlobalSetDefinition($mockGlobalSet1),
0 ignored issues
show
Documentation introduced by
$mockGlobalSet1 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\elements\GlobalSet>.

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...
114
                ],
115
            ],
116
            'multiple sets' => [
117
                'GlobalSets' => [
118
                    'set1' => $mockGlobalSet1,
119
                    'set2' => $mockGlobalSet2,
120
                ],
121
                'expectedResult' => [
122
                    'setHandle1' => $this->getMockGlobalSetDefinition($mockGlobalSet1),
0 ignored issues
show
Documentation introduced by
$mockGlobalSet1 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\elements\GlobalSet>.

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...
123
                    'setHandle2' => $this->getMockGlobalSetDefinition($mockGlobalSet2),
0 ignored issues
show
Documentation introduced by
$mockGlobalSet2 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\elements\GlobalSet>.

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...
124
                ],
125
            ],
126
        ];
127
    }
128
129
    /**
130
     * @return array
131
     */
132
    public function provideValidGlobalSetDefinitions()
133
    {
134
        $mockGlobalSet1 = $this->getMockGlobalSet(1);
135
        $mockGlobalSet2 = $this->getMockGlobalSet(2);
136
137
        return [
138
            'emptyArray' => [
139
                'setDefinitions' => [],
140
                'existingSets' => [
141
                    $mockGlobalSet1,
142
                ],
143
                'saveCount' => 0,
144
                'deleteCount' => 1,
145
            ],
146
            'single set' => [
147
                'setDefinitions' => [
148
                    'setHandle1' => $this->getMockGlobalSetDefinition($mockGlobalSet1),
0 ignored issues
show
Documentation introduced by
$mockGlobalSet1 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\elements\GlobalSet>.

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...
149
                    'setHandle2' => $this->getMockGlobalSetDefinition($mockGlobalSet2),
0 ignored issues
show
Documentation introduced by
$mockGlobalSet2 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\elements\GlobalSet>.

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...
150
                ],
151
                'existingSets' => [
152
                    $mockGlobalSet1,
153
                ],
154
                'saveCount' => 1,
155
                'deleteCount' => 0,
156
            ],
157
        ];
158
    }
159
160
    //==============================================================================================================
161
    //================================================  HELPERS  ===================================================
162
    //==============================================================================================================
163
164
    /**
165
     * @param GlobalSet $mockGlobalSet
166
     *
167
     * @return array
168
     */
169
    private function getMockGlobalSetDefinition(GlobalSet $mockGlobalSet)
170
    {
171
        return [
172
            'class' => get_class($mockGlobalSet),
173
            'attributes' => [
174
                'name' => $mockGlobalSet->name,
175
                'handle' => $mockGlobalSet->handle,
176
                'enabled' => true,
177
                'archived' => false,
178
                'enabledForSite' => true,
179
                'title' => null,
180
                'slug' => null,
181
                'uri' => null,
182
                'hasDescendants' => null,
183
                'ref' => null,
184
                'status' => null,
185
                'totalDescendants' => null,
186
                'url' => null,
187
                'text' => null,
188
            ],
189
            'fieldLayout' => [
190
                'fields' => [],
191
            ],
192
            'site' => 'default',
193
        ];
194
    }
195
196
    /**
197
     * @param int $setId
198
     *
199
     * @return Mock|GlobalSet
200
     */
201
    private function getMockGlobalSet(int $setId)
202
    {
203
        $mockSet = $this->getMockBuilder(GlobalSet::class)
204
                                    ->setMethods(array_diff(
205
                                        get_class_methods(GlobalSet::class),
206
                                        ['setAttributes', 'safeAttributes', 'getAttributes']
207
                                    ))
208
                                    ->disableOriginalConstructor()
209
                                    ->getMock();
210
211
        $mockSet->expects($this->any())
212
          ->method('attributes')
213
          ->willReturn([
214
              'id',
215
              'fieldLayoutId',
216
              'siteId',
217
              'structureId',
218
              'tempId',
219
              'uid',
220
              'contentId',
221
              'name',
222
              'handle',
223
              'enabled',
224
              'archived',
225
              'enabledForSite',
226
              'title',
227
              'slug',
228
              'uri',
229
              'hasDescendants',
230
              'ref',
231
              'status',
232
              'structureId',
233
              'totalDescendants',
234
              'url',
235
              'text',
236
          ]);
237
238
        $mockSet->id = $setId;
0 ignored issues
show
Bug introduced by
Accessing id on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
239
        $mockSet->fieldLayoutId = $setId;
0 ignored issues
show
Bug introduced by
Accessing fieldLayoutId on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
240
        $mockSet->handle = 'setHandle'.$setId;
0 ignored issues
show
Bug introduced by
Accessing handle on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
241
        $mockSet->name = 'setName'.$setId;
0 ignored issues
show
Bug introduced by
Accessing name on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
242
243
        $mockSet->expects($this->any())
244
                ->method('getSite')
245
                ->willReturn($this->getMockSite());
246
247
        $mockFieldLayout = $this->getMockBuilder(FieldLayout::class)->getMock();
248
249
        $mockSet->expects($this->any())
250
                  ->method('getFieldLayout')
251
                  ->willReturn($mockFieldLayout);
252
253
        return $mockSet;
254
    }
255
256
    /**
257
     * Get a mock site.
258
     *
259
     * @return Mock|Site
260
     */
261
    private function getMockSite()
262
    {
263
        $mockSite = new Site([
264
            'id' => 99,
265
            'handle' => 'default',
266
        ]);
267
268
        return $mockSite;
269
    }
270
271
    /**
272
     * Expect a list of global sets.
273
     *
274
     * @param GlobalSet[] $GlobalSets
0 ignored issues
show
Documentation introduced by
There is no parameter named $GlobalSets. Did you maybe mean $globalSets?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
275
     */
276
    private function expectList(array $globalSets)
277
    {
278
        Craft::$app->globals
279
                   ->expects($this->exactly(1))
280
                   ->method('getAllSets')
281
                   ->willReturn($globalSets);
282
    }
283
284
    /**
285
     * Expect a number of set saves.
286
     *
287
     * @param int $saveCount
288
     */
289
    private function expectSaves(int $saveCount)
290
    {
291
        Craft::$app->globals
292
                   ->expects($this->exactly($saveCount))
293
                   ->method('saveSet')
294
                   ->willReturn(true);
295
    }
296
297
    /**
298
     * Expect a number of set deletes.
299
     *
300
     * @param int $deleteCount
301
     */
302
    private function expectDeletes(int $deleteCount)
303
    {
304
        Craft::$app->elements
305
                    ->expects($this->exactly($deleteCount))
306
                    ->method('deleteElementById');
307
    }
308
}
309