Completed
Pull Request — master (#114)
by Bart
03:44
created

SectionTest::getMockSiteSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 1
eloc 8
nc 1
nop 0
1
<?php
2
3
namespace NerdsAndCompany\Schematic\Converters\Models;
4
5
use Craft;
6
use craft\models\Section as SectionModel;
7
use craft\models\Section_SiteSettings;
8
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...
9
use Codeception\Test\Unit;
10
11
/**
12
 * Class SectionTest.
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 SectionTest extends Unit
21
{
22
    /**
23
     * @var Sections
24
     */
25
    private $converter;
26
27
    /**
28
     * Set the converter.
29
     *
30
     * @SuppressWarnings(PHPMD.CamelCaseMethodName)
31
     */
32
    protected function _before()
33
    {
34
        $this->converter = new Section();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \NerdsAndCompany\Sch...erters\Models\Section() of type object<NerdsAndCompany\S...verters\Models\Section> is incompatible with the declared type object<NerdsAndCompany\S...erters\Models\Sections> 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...
35
    }
36
37
    //==============================================================================================================
38
    //=================================================  TESTS  ====================================================
39
    //==============================================================================================================
40
41
    /**
42
     * @dataProvider provideSections
43
     *
44
     * @param SectionModel $section
45
     * @param array        $definition
46
     */
47
    public function testGetRecordDefinition(SectionModel $section, array $definition)
48
    {
49
        Craft::$app->controller->module->modelMapper->expects($this->exactly(1))
50
                           ->method('export')
51
                           ->with($section->getEntryTypes())
52
                           ->willReturn($definition['entryTypes']);
53
54
        $result = $this->converter->getRecordDefinition($section);
55
56
        $this->assertSame($definition, $result);
57
    }
58
59
    /**
60
     * @dataProvider provideSections
61
     *
62
     * @param SectionModel $section
63
     * @param array        $definition
64
     * @param bool         $valid
65
     */
66
    public function testSaveRecord(SectionModel $section, array $definition, bool $valid)
67
    {
68
        Craft::$app->sections->expects($this->exactly(1))
69
                             ->method('saveSection')
70
                             ->with($section)
71
                             ->willReturn($valid);
72
73
        Craft::$app->controller->module->modelMapper->expects($this->exactly($valid ? 1 : 0))
74
                                     ->method('import')
75
                                     ->with($definition['entryTypes'], $section->getEntryTypes(), ['sectionId' => $section->id])
76
                                     ->willReturn($section->getEntryTypes());
77
78
        $result = $this->converter->saveRecord($section, $definition);
79
80
        $this->assertSame($valid, $result);
81
    }
82
83
    /**
84
     * @dataProvider provideSections
85
     *
86
     * @param SectionModel $section
87
     */
88
    public function testDeleteRecord(SectionModel $section)
89
    {
90
        Craft::$app->sections->expects($this->exactly(1))
91
                             ->method('deleteSection')
92
                             ->with($section);
93
94
        $this->converter->deleteRecord($section);
95
    }
96
97
    //==============================================================================================================
98
    //==============================================  PROVIDERS  ===================================================
99
    //==============================================================================================================
100
101
    /**
102
     * @return array
103
     */
104
    public function provideSections()
105
    {
106
        $mockSection1 = $this->getMockSection(1);
107
        $mockSection2 = $this->getMockSection(2);
108
109
        return [
110
            'valid section' => [
111
                'section' => $mockSection1,
112
                'definition' => $this->getMockSectionDefinition($mockSection1),
0 ignored issues
show
Documentation introduced by
$mockSection1 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\models\Section>.

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...
113
                'validSave' => true,
114
            ],
115
            'invalid section' => [
116
                'section' => $mockSection2,
117
                'definition' => $this->getMockSectionDefinition($mockSection2),
0 ignored issues
show
Documentation introduced by
$mockSection2 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<craft\models\Section>.

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
                'validSave' => false,
119
            ],
120
        ];
121
    }
122
123
    //==============================================================================================================
124
    //================================================  HELPERS  ===================================================
125
    //==============================================================================================================
126
127
    /**
128
     * @param SectionModel $mockSection
129
     *
130
     * @return array
131
     */
132
    private function getMockSectionDefinition(SectionModel $mockSection)
133
    {
134
        $siteSettingsDef = [];
135
        foreach ($mockSection->getSiteSettings() as $siteSetting) {
136
            $siteSettingsDef[$siteSetting->site->handle] = [
137
                'class' => get_class($siteSetting),
138
                'attributes' => [
139
                    'enabledByDefault' => true,
140
                    'hasUrls' => null,
141
                    'uriFormat' => null,
142
                    'template' => null,
143
                ],
144
            ];
145
        }
146
147
        return [
148
            'class' => get_class($mockSection),
149
            'attributes' => [
150
                'name' => 'sectionName'.$mockSection->id,
151
                'handle' => 'sectionHandle'.$mockSection->id,
152
                'type' => null,
153
                'maxLevels' => null,
154
                'enableVersioning' => true,
155
                'propagateEntries' => true,
156
            ],
157
            'siteSettings' => $siteSettingsDef,
158
            'entryTypes' => [
159
                'entryTypeDefinition1',
160
                'entryTypeDefinition2',
161
            ],
162
        ];
163
    }
164
165
    /**
166
     * @param int $sectionId
167
     *
168
     * @return Mock|SectionModel
169
     */
170
    private function getMockSection(int $sectionId)
171
    {
172
        $mockSection = $this->getMockBuilder(SectionModel::class)
173
                           ->setMethods(['getGroup', 'getEntryTypes', 'getSiteSettings'])
174
                           ->disableOriginalConstructor()
175
                           ->getMock();
176
177
        $mockSection->id = $sectionId;
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...
178
        $mockSection->handle = 'sectionHandle'.$sectionId;
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...
179
        $mockSection->name = 'sectionName'.$sectionId;
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...
180
181
        $mockSection->expects($this->any())
182
                   ->method('getEntryTypes')
183
                   ->willReturn([
184
                       $this->getMockEntryType(1),
185
                       $this->getMockEntryType(2),
186
                   ]);
187
188
        $mockSection->expects($this->any())
189
                    ->method('getSiteSettings')
190
                    ->willReturn([$this->getMockSiteSettings()]);
191
192
        return $mockSection;
193
    }
194
195
    /**
196
     * Get a mock entry block type.
197
     *
198
     * @param int $blockId
199
     *
200
     * @return Mock|EntryType
201
     */
202
    private function getMockEntryType($blockId)
203
    {
204
        $mockBlockType = $this->getMockBuilder(EntryType::class)
205
                              ->disableOriginalConstructor()
206
                              ->getmock();
207
208
        $mockBlockType->id = $blockId;
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...
209
        $mockBlockType->handle = 'blockHandle'.$blockId;
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...
210
211
        return $mockBlockType;
212
    }
213
214
    /**
215
     * Get mock siteSettings.
216
     *
217
     * @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...
218
     *
219
     * @return Mock|Section_SiteSettings
220
     */
221
    private function getMockSiteSettings()
222
    {
223
        $mockSiteSettings = $this->getMockBuilder(Section_SiteSettings::class)
224
                                 ->setMethods(['getSite'])
225
                                 ->getMock();
226
227
        $mockSiteSettings->expects($this->any())
228
          ->method('getSite')
229
          ->willReturn($this->getMockSite());
230
231
        return $mockSiteSettings;
232
    }
233
234
    /**
235
     * Get a mock site.
236
     *
237
     * @return Mock|Site
238
     */
239
    private function getMockSite()
240
    {
241
        $mockSite = $this->getMockBuilder(Site::class)->getMock();
242
        $mockSite->handle = 'default';
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...
243
244
        return $mockSite;
245
    }
246
}
247