Completed
Pull Request — master (#114)
by Bart
04:26
created

CategoryGroupTest   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 214
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 7
dl 0
loc 214
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A _before() 0 4 1
A testGetRecordDefinition() 0 6 1
A testSetRecordAttributes() 0 18 1
A testSaveRecord() 0 11 1
A testDeleteRecord() 0 8 1
A provideCategoryGroups() 0 17 1
B getMockCategoryGroupDefinition() 0 24 1
B getMockCategoryGroup() 0 27 1
A getMockSiteSettings() 0 12 1
A getMockSite() 0 4 1
1
<?php
2
3
namespace NerdsAndCompany\Schematic\Converters\Models;
4
5
use Craft;
6
use craft\models\CategoryGroup as CategoryGroupModel;
7
use craft\models\CategoryGroup_SiteSettings;
8
use craft\models\FieldLayout;
9
use craft\models\Site;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, NerdsAndCompany\Schematic\Converters\Models\Site.

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
12
/**
13
 * Class CategoryGroupTest.
14
 *
15
 * @author    Nerds & Company
16
 * @copyright Copyright (c) 2015-2017, Nerds & Company
17
 * @license   MIT
18
 *
19
 * @see      http://www.nerds.company
20
 */
21
class CategoryGroupTest extends Unit
22
{
23
    /**
24
     * @var CategoryGroups
25
     */
26
    private $converter;
27
28
    /**
29
     * Set the converter.
30
     *
31
     * @SuppressWarnings(PHPMD.CamelCaseMethodName)
32
     */
33
    protected function _before()
34
    {
35
        $this->converter = new CategoryGroup();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \NerdsAndCompany\Sch...\Models\CategoryGroup() of type object<NerdsAndCompany\S...s\Models\CategoryGroup> is incompatible with the declared type object<NerdsAndCompany\S...\Models\CategoryGroups> of property $converter.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
36
    }
37
38
    //==============================================================================================================
39
    //=================================================  TESTS  ====================================================
40
    //==============================================================================================================
41
42
    /**
43
     * @dataProvider provideCategoryGroups
44
     *
45
     * @param CategoryGroupModel $group
46
     * @param array              $definition
47
     */
48
    public function testGetRecordDefinition(CategoryGroupModel $group, array $definition)
49
    {
50
        $result = $this->converter->getRecordDefinition($group);
51
52
        $this->assertSame($definition, $result);
53
    }
54
55
    /**
56
     * @dataProvider provideCategoryGroups
57
     *
58
     * @param CategoryGroupModel $group
59
     * @param array              $definition
60
     * @param Site|null          $site
61
     */
62
    public function testSetRecordAttributes(CategoryGroupModel $group, array $definition, $site)
63
    {
64
        $newGroup = $this->getMockBuilder(CategoryGroupModel::class)
65
                         ->setMethods(['setSiteSettings'])
66
                         ->getMock();
67
68
        $newGroup->expects($this->exactly(1))
69
                 ->method('setSiteSettings');
70
71
        Craft::$app->sites->expects($this->any())
72
                           ->method('getSiteByHandle')
73
                           ->willReturn($site);
74
75
        $this->converter->setRecordAttributes($newGroup, $definition, []);
76
77
        $this->assertSame($group->name, $newGroup->name);
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...
78
        $this->assertSame($group->handle, $newGroup->handle);
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...
79
    }
80
81
    /**
82
     * @dataProvider provideCategoryGroups
83
     *
84
     * @param CategoryGroupModel $group
85
     * @param array              $definition
86
     */
87
    public function testSaveRecord(CategoryGroupModel $group, array $definition)
88
    {
89
        Craft::$app->categories->expects($this->exactly(1))
90
                               ->method('saveGroup')
91
                               ->with($group)
92
                               ->willReturn(true);
93
94
        $result = $this->converter->saveRecord($group, $definition);
95
96
        $this->assertTrue($result);
97
    }
98
99
    /**
100
     * @dataProvider provideCategoryGroups
101
     *
102
     * @param CategoryGroupModel $group
103
     */
104
    public function testDeleteRecord(CategoryGroupModel $group)
105
    {
106
        Craft::$app->categories->expects($this->exactly(1))
107
                               ->method('deleteGroupById')
108
                               ->with($group->id);
109
110
        $this->converter->deleteRecord($group);
111
    }
112
113
    //==============================================================================================================
114
    //==============================================  PROVIDERS  ===================================================
115
    //==============================================================================================================
116
117
    /**
118
     * @return array
119
     */
120
    public function provideCategoryGroups()
121
    {
122
        $mockCategoryGroup = $this->getMockCategoryGroup(1);
123
124
        return [
125
            'category group with site' => [
126
                'group' => $mockCategoryGroup,
127
                'definition' => $this->getMockCategoryGroupDefinition($mockCategoryGroup),
0 ignored issues
show
Documentation introduced by
$mockCategoryGroup is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\models\CategoryGroup>.

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...
128
                'site' => $this->getMockSite(),
129
            ],
130
            'category group without site' => [
131
                'group' => $mockCategoryGroup,
132
                'definition' => $this->getMockCategoryGroupDefinition($mockCategoryGroup),
0 ignored issues
show
Documentation introduced by
$mockCategoryGroup is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\models\CategoryGroup>.

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...
133
                'site' => null,
134
            ],
135
        ];
136
    }
137
138
    //==============================================================================================================
139
    //================================================  HELPERS  ===================================================
140
    //==============================================================================================================
141
142
    /**
143
     * @param CategoryGroupModel $mockCategoryGroup
144
     *
145
     * @return array
146
     */
147
    private function getMockCategoryGroupDefinition(CategoryGroupModel $mockCategoryGroup)
148
    {
149
        return [
150
            'class' => get_class($mockCategoryGroup),
151
            'attributes' => [
152
                'name' => $mockCategoryGroup->name,
153
                'handle' => $mockCategoryGroup->handle,
154
                'maxLevels' => 3,
155
            ],
156
            'fieldLayout' => [
157
                'fields' => [],
158
            ],
159
            'siteSettings' => [
160
                '' => [
161
                    'class' => get_class($mockCategoryGroup->getSiteSettings()[0]),
162
                    'attributes' => [
163
                        'hasUrls' => null,
164
                        'uriFormat' => null,
165
                        'template' => null,
166
                    ],
167
                ],
168
            ],
169
        ];
170
    }
171
172
    /**
173
     * @param int $groupId
174
     *
175
     * @return Mock|CategoryGroupModel
176
     */
177
    private function getMockCategoryGroup(int $groupId)
178
    {
179
        $mockGroup = $this->getMockBuilder(CategoryGroupModel::class)
180
                                    ->setMethods(['getFieldLayout', 'getSiteSettings'])
181
                                    ->getMock();
182
        $mockGroup->setAttributes([
183
            'id' => $groupId,
184
            'fieldLayoutId' => $groupId,
185
            'handle' => 'groupHandle'.$groupId,
186
            'name' => 'groupName'.$groupId,
187
            'maxLevels' => 3,
188
        ]);
189
190
        $mockFieldLayout = $this->getMockBuilder(FieldLayout::class)->getMock();
191
192
        $mockGroup->expects($this->any())
193
                  ->method('getFieldLayout')
194
                  ->willReturn($mockFieldLayout);
195
196
        $mockSiteSettings = $this->getMockSiteSettings();
197
198
        $mockGroup->expects($this->any())
199
                  ->method('getSiteSettings')
200
                  ->willReturn([$mockSiteSettings]);
201
202
        return $mockGroup;
203
    }
204
205
    /**
206
     * Get mock siteSettings.
207
     *
208
     * @param string $class
0 ignored issues
show
Bug introduced by
There is no parameter named $class. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

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

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

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

Loading history...
209
     *
210
     * @return Mock|CategoryGroup_SiteSettings
211
     */
212
    private function getMockSiteSettings()
213
    {
214
        $mockSiteSettings = $this->getMockBuilder(CategoryGroup_SiteSettings::class)
215
                                 ->setMethods(['getSite'])
216
                                 ->getMock();
217
218
        $mockSiteSettings->expects($this->any())
219
          ->method('getSite')
220
          ->willReturn($this->getMockSite());
221
222
        return $mockSiteSettings;
223
    }
224
225
    /**
226
     * Get a mock site.
227
     *
228
     * @return Mock|Site
229
     */
230
    private function getMockSite()
231
    {
232
        return $this->getMockBuilder(Site::class)->getMock();
233
    }
234
}
235