Passed
Pull Request — master (#133)
by
unknown
02:21
created

testObjectsToUpdateOnSiteTreeRearrange()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 35
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
cc 1
eloc 22
c 3
b 0
f 1
nc 1
nop 0
dl 0
loc 35
rs 9.568
1
<?php
2
3
namespace SilverStripe\StaticPublishQueue\Test;
4
5
use SilverStripe\CMS\Model\SiteTree;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\ORM\ArrayList;
10
use SilverStripe\StaticPublishQueue\Extension\Engine\SiteTreePublishingEngine;
11
use SilverStripe\StaticPublishQueue\Extension\Publishable\PublishableSiteTree;
12
use SilverStripe\StaticPublishQueue\Test\PublishableSiteTreeTest\Model\PublishablePage;
13
use Symbiote\QueuedJobs\Services\QueuedJobHandler;
14
use Symbiote\QueuedJobs\Services\QueuedJobService;
15
use Symbiote\QueuedJobs\Tests\QueuedJobsTest\QueuedJobsTest_Handler;
0 ignored issues
show
Bug introduced by
The type Symbiote\QueuedJobs\Test...\QueuedJobsTest_Handler was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
17
class PublishableSiteTreeTest extends SapphireTest
18
{
19
    protected $usesDatabase = true;
20
21
    protected static $required_extensions = [
22
        SiteTree::class => [
23
            PublishableSiteTree::class,
24
        ],
25
    ];
26
27
    protected static $extra_dataobjects = [
28
        PublishablePage::class,
29
    ];
30
31
    protected function setUp()
32
    {
33
        parent::setUp();
34
35
        Config::modify()->set(QueuedJobService::class, 'use_shutdown_function', false);
36
        Injector::inst()->registerService(new QueuedJobsTest_Handler(), QueuedJobHandler::class);
37
        Injector::inst()->registerService(new QueuedJobsTestService(), QueuedJobService::class);
38
    }
39
40
    public function testObjectsToUpdateOnURLSegmentChange()
41
    {
42
        $this->setExpectedFlushChangesOutput([
43
            [[], ['stub/']],
44
            [['stub/'], []],
45
            [[], ['stub-a-lub-a-dub-dub/']],
46
        ]);
47
48
        $page = new PublishablePage;
49
        $page->URLSegment = 'stub';
50
51
        // publish the page
52
        $page->write();
53
        $page->publishRecursive();
0 ignored issues
show
Bug introduced by
The method publishRecursive() does not exist on SilverStripe\StaticPubli...t\Model\PublishablePage. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

53
        $page->/** @scrutinizer ignore-call */ 
54
               publishRecursive();
Loading history...
54
55
        // change the URL and go again
56
        $page->URLSegment = 'stub-a-lub-a-dub-dub';
57
        $page->write();
58
        $page->publishRecursive();
59
    }
60
61
    public function testObjectsToUpdateOnURLSegmentChangeWithParents()
62
    {
63
        $this->setExpectedFlushChangesOutput([
64
            [[], ['parent/']],
65
            [[], ['parent/stub/', 'parent/']],
66
            [['parent/stub/'], ['parent/']],
67
            [[], ['parent/stub-a-lub-a-dub-dub/', 'parent/']]
68
        ]);
69
70
        $parent = new PublishablePage;
71
        $parent->URLSegment = 'parent';
72
        $parent->write();
73
        $parent->publishRecursive();
74
75
        $page = new PublishablePage;
76
        $page->URLSegment = 'stub';
77
        $page->ParentID = $parent->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property ParentID does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
78
79
        // publish the page
80
        $page->write();
81
        $page->publishRecursive();
82
83
        // change the URL and go again
84
        $page->URLSegment = 'stub-a-lub-a-dub-dub';
85
        $page->write();
86
        $page->publishRecursive();
87
    }
88
89
    public function testObjectsToUpdateOnSiteTreeRearrange()
90
    {
91
        $this->setExpectedFlushChangesOutput([
92
            [[], ['parent/']],
93
            [[], ['parent/stub/', 'parent/']],
94
            [['parent/stub/'], ['parent/']],
95
            [[], ['stub/']],
96
            [['stub/'], []],
97
            [[], ['parent/stub/', 'parent/']],
98
        ]);
99
100
        $parent = new PublishablePage;
101
102
        $parent->URLSegment = 'parent';
103
        $parent->write();
104
        $parent->publishRecursive();
105
106
        $page = new PublishablePage;
107
108
        $page->URLSegment = 'stub';
109
        $page->ParentID = $parent->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property ParentID does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
110
111
        // publish the page
112
        $page->write();
113
        $page->publishRecursive();
114
115
        // move to root
116
        $page->ParentID = 0;
117
        $page->write();
118
        $page->publishRecursive();
119
120
        // move back
121
        $page->ParentID = $parent->ID;
122
        $page->write();
123
        $page->publishRecursive();
124
    }
125
126
    public function testObjectsToUpdateOnPublish()
127
    {
128
        $parent = new PublishablePage;
129
130
        $stub = $this->getMockBuilder(PublishablePage::class)
131
            ->setMethods(
132
                [
133
                    'getParentID',
134
                    'Parent',
135
                ]
136
            )->getMock();
137
138
        $stub->expects($this->once())
139
            ->method('getParentID')
140
            ->will($this->returnValue('2'));
141
142
        $stub->expects($this->once())
143
            ->method('Parent')
144
            ->will($this->returnValue($parent));
145
146
        $objects = $stub->objectsToUpdate(['action' => 'publish']);
147
        $this->assertContains($stub, $objects);
148
        $this->assertContains($parent, $objects);
149
        $this->assertCount(2, $objects);
150
    }
151
152
    public function testObjectsToUpdateOnUnpublish()
153
    {
154
        $parent = new PublishablePage;
155
156
        $stub = $this->getMockBuilder(PublishablePage::class)
157
            ->setMethods(
158
                [
159
                    'getParentID',
160
                    'Parent',
161
                ]
162
            )->getMock();
163
164
        $stub->expects($this->once())
165
            ->method('getParentID')
166
            ->will($this->returnValue('2'));
167
168
        $stub->expects($this->once())
169
            ->method('Parent')
170
            ->will($this->returnValue($parent));
171
172
        $updates = $stub->objectsToUpdate(['action' => 'unpublish']);
173
        $deletions = $stub->objectsToDelete(['action' => 'unpublish']);
174
        $this->assertContains($stub, $deletions);
175
        $this->assertNotContains($parent, $deletions);
176
        $this->assertContains($parent, $updates);
177
        $this->assertNotContains($stub, $updates);
178
        $this->assertCount(1, $deletions);
179
        $this->assertCount(1, $updates);
180
    }
181
182
    public function testObjectsToDeleteOnPublish()
183
    {
184
        $stub = new PublishablePage;
185
        $objects = $stub->objectsToDelete(['action' => 'publish']);
0 ignored issues
show
Bug introduced by
The method objectsToDelete() does not exist on SilverStripe\StaticPubli...t\Model\PublishablePage. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

185
        /** @scrutinizer ignore-call */ 
186
        $objects = $stub->objectsToDelete(['action' => 'publish']);
Loading history...
186
        $this->assertEmpty($objects);
187
    }
188
189
    public function testObjectsToDeleteOnUnpublish()
190
    {
191
        $stub = new PublishablePage;
192
        $stub->Title = 'stub';
193
        $objects = $stub->objectsToDelete(['action' => 'unpublish']);
194
        $this->assertContains($stub, $objects);
195
        $this->assertCount(1, $objects);
196
    }
197
198
    public function testObjectsToUpdateOnPublishIfVirtualExists()
199
    {
200
        $redir = new PublishablePage;
201
202
        $stub = $this->getMockBuilder(PublishablePage::class)
203
            ->setMethods(['getMyVirtualPages'])
204
            ->getMock();
205
206
        $stub->expects($this->once())
207
            ->method('getMyVirtualPages')
208
            ->will(
209
                $this->returnValue(
210
                    new ArrayList([$redir])
211
                )
212
            );
213
214
        $objects = $stub->objectsToUpdate(['action' => 'publish']);
215
        $this->assertContains($stub, $objects);
216
        $this->assertContains($redir, $objects);
217
        $this->assertCount(2, $objects);
218
    }
219
220
    public function testObjectsToDeleteOnUnpublishIfVirtualExists()
221
    {
222
        $redir = new PublishablePage;
223
224
        $stub = $this->getMockBuilder(PublishablePage::class)
225
            ->setMethods(['getMyVirtualPages'])
226
            ->getMock();
227
228
        $stub->Title = 'stub';
0 ignored issues
show
Bug introduced by
Accessing Title on the interface PHPUnit_Framework_MockObject_MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
229
230
        $stub->expects($this->once())
231
            ->method('getMyVirtualPages')
232
            ->will(
233
                $this->returnValue(
234
                    new ArrayList([$redir])
235
                )
236
            );
237
238
        $objects = $stub->objectsToDelete(['action' => 'unpublish']);
239
        $this->assertContains($stub, $objects);
240
        $this->assertContains($redir, $objects);
241
        $this->assertCount(2, $objects);
242
    }
243
244
    /**
245
     * Takes in a map of urls we expect to be deleted and updated on each successive flushChanges call
246
     * [
247
     *   [['deleted'], ['updated']], // first time its called
248
     *   [['deleted'], ['updated']], // second time its called
249
     * ]
250
     * @param $map
251
     */
252
    protected function setExpectedFlushChangesOutput($map)
253
    {
254
        // build a mock of the extension overriding flushChanges to prevent writing to the queue
255
        $mockExtension = $this->getMockBuilder(SiteTreePublishingEngine::class)
256
            ->setMethods(['flushChanges'])
257
            ->getMock();
258
259
        // IF YOU'RE OF A NERVOUS DISPOSITION, LOOK AWAY NOW
260
        // stub the flushChanges method and make sure that each call is able to assert the correct items are in the
261
        $mockExtension
262
            ->expects($this->exactly(count($map)))
263
            ->method('flushChanges')
264
            ->willReturnOnConsecutiveCalls(...$this->transformMapToCallback($map, $mockExtension));
265
266
        // register our extension instance so it's applied to all SiteTree objects
267
        Injector::inst()->registerService($mockExtension, SiteTreePublishingEngine::class);
268
    }
269
270
    /**
271
     * Transforms the array [['deleted'], ['updated']] into callbacks with assertions
272
     * @param $map
273
     * @param $mockExtension
274
     * @return array
275
     */
276
    protected function transformMapToCallback($map, $mockExtension)
277
    {
278
        $getURL = function ($value) {
279
            return $value->RelativeLink();
280
        };
281
282
        $callbacks = [];
283
        $count = 0;
284
        foreach ($map as $urls) {
285
            ++$count;
286
            list($toDelete, $toUpdate) = $urls;
287
            $callbacks[] = new \PHPUnit_Framework_MockObject_Stub_ReturnCallback(
288
                function () use ($toDelete, $toUpdate, $mockExtension, $getURL, $count) {
289
                    $this->assertSame(
290
                        $toDelete,
291
                        array_map($getURL, $mockExtension->getToDelete()),
292
                        'Failed on delete, iteration ' . $count
293
                    );
294
                    $mockExtension->setToDelete([]);
295
                    $this->assertSame(
296
                        $toUpdate,
297
                        array_map($getURL, $mockExtension->getToUpdate()),
298
                        'Failed on update, iteration ' . $count
299
                    );
300
                    $mockExtension->setToUpdate([]);
301
                }
302
            );
303
        }
304
        return $callbacks;
305
    }
306
}
307