Completed
Push — master ( 6c5a34...58d4d9 )
by André
52:17 queued 34:30
created

TrashServiceTest   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 876
Duplicated Lines 10.84 %

Coupling/Cohesion

Components 1
Dependencies 22

Importance

Changes 0
Metric Value
dl 95
loc 876
rs 8.924
c 0
b 0
f 0
wmc 40
lcom 1
cbo 22

28 Methods

Rating   Name   Duplication   Size   Complexity  
A testTrash() 0 11 1
A testTrashSetsExpectedTrashItemProperties() 0 27 1
A testTrashRemovesLocationFromMainStorage() 0 17 1
A testTrashRemovesChildLocationsFromMainStorage() 0 29 3
A testTrashDecrementsChildCountOnParentLocation() 20 20 1
A testTrashUpdatesMainLocation() 0 24 1
A testTrashReturnsNull() 17 17 1
A testLoadTrashItem() 0 33 1
A testLoadTrashItemThrowsNotFoundException() 0 13 1
A testRecover() 0 37 2
A testRecoverThrowsNotFoundExceptionForNonExistingTrashItem() 0 13 1
A testNotFoundAliasAfterRemoveIt() 0 18 1
A testAliasesForRemovedItems() 0 36 1
A testRecoverDoesNotRestoreChildLocations() 0 43 4
A testRecoverWithLocationCreateStructParameter() 0 43 2
A testRecoverIncrementsChildCountOnOriginalParent() 0 33 2
A testRecoverWithLocationCreateStructParameterIncrementsChildCountOnNewParent() 0 39 2
A testRecoverToNonExistingLocation() 17 17 1
A testFindTrashItems() 0 29 1
A testFindTrashItemsLimitedAccess() 0 34 1
A testEmptyTrash() 25 25 1
A testDeleteTrashItem() 0 45 1
A testDeleteThrowsNotFoundExceptionForNonExistingTrashItem() 0 11 1
A createRemoteIdList() 0 23 3
A createNewContentInPlaceTrashedOne() 16 16 1
A assertAliasExists() 0 8 1
A assertAliasNotExists() 0 9 2
A getTrashItemDouble() 0 8 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like TrashServiceTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TrashServiceTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * File containing the TrashServiceTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\API\Repository\Tests;
10
11
use eZ\Publish\API\Repository\Repository;
12
use eZ\Publish\API\Repository\URLAliasService;
13
use eZ\Publish\API\Repository\Values\Content\Content;
14
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
15
use eZ\Publish\API\Repository\Values\Content\Location as APILocation;
16
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
17
use eZ\Publish\API\Repository\Values\Content\Query;
18
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
19
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
20
use eZ\Publish\API\Repository\Values\Content\Trash\SearchResult;
21
use eZ\Publish\API\Repository\Values\Content\TrashItem as APITrashItem;
22
use eZ\Publish\Core\Repository\Values\Content\TrashItem;
23
use eZ\Publish\Core\Repository\Values\Content\Location;
24
25
/**
26
 * Test case for operations in the TrashService using in memory storage.
27
 *
28
 * @see eZ\Publish\API\Repository\TrashService
29
 * @group integration
30
 * @group trash
31
 */
32
class TrashServiceTest extends BaseTrashServiceTest
33
{
34
    /**
35
     * Test for the trash() method.
36
     *
37
     * @see \eZ\Publish\API\Repository\TrashService::trash()
38
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationByRemoteId
39
     */
40
    public function testTrash()
41
    {
42
        /* BEGIN: Use Case */
43
        $trashItem = $this->createTrashItem();
44
        /* END: Use Case */
45
46
        $this->assertInstanceOf(
47
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\TrashItem',
48
            $trashItem
49
        );
50
    }
51
52
    /**
53
     * Test for the trash() method.
54
     *
55
     * @see \eZ\Publish\API\Repository\TrashService::trash()
56
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
57
     */
58
    public function testTrashSetsExpectedTrashItemProperties()
59
    {
60
        $repository = $this->getRepository();
61
62
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
63
64
        // Load the location that will be trashed
65
        $location = $repository->getLocationService()
66
            ->loadLocationByRemoteId($mediaRemoteId);
67
68
        $expected = array(
69
            'id' => $location->id,
70
            'depth' => $location->depth,
71
            'hidden' => $location->hidden,
72
            'invisible' => $location->invisible,
73
            'parentLocationId' => $location->parentLocationId,
74
            'pathString' => $location->pathString,
75
            'priority' => $location->priority,
76
            'remoteId' => $location->remoteId,
77
            'sortField' => $location->sortField,
78
            'sortOrder' => $location->sortOrder,
79
        );
80
81
        $trashItem = $this->createTrashItem();
82
83
        $this->assertPropertiesCorrect($expected, $trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 81 can be null; however, eZ\Publish\API\Repositor...sertPropertiesCorrect() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
84
    }
85
86
    /**
87
     * Test for the trash() method.
88
     *
89
     * @see \eZ\Publish\API\Repository\TrashService::trash()
90
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
91
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
92
     */
93
    public function testTrashRemovesLocationFromMainStorage()
94
    {
95
        $repository = $this->getRepository();
96
97
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
98
99
        /* BEGIN: Use Case */
100
        $this->createTrashItem();
101
102
        // Load the location service
103
        $locationService = $repository->getLocationService();
104
105
        // This call will fail with a "NotFoundException", because the media
106
        // location was marked as trashed in the main storage
107
        $locationService->loadLocationByRemoteId($mediaRemoteId);
108
        /* END: Use Case */
109
    }
110
111
    /**
112
     * Test for the trash() method.
113
     *
114
     * @see \eZ\Publish\API\Repository\TrashService::trash()
115
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
116
     */
117
    public function testTrashRemovesChildLocationsFromMainStorage()
118
    {
119
        $repository = $this->getRepository();
120
121
        /* BEGIN: Use Case */
122
        $remoteIds = $this->createRemoteIdList();
123
124
        $this->createTrashItem();
125
126
        // All invocations to loadLocationByRemoteId() to one of the above
127
        // collected remoteIds will return in an "NotFoundException"
128
        /* END: Use Case */
129
130
        $locationService = $repository->getLocationService();
131
        foreach ($remoteIds as $remoteId) {
132
            try {
133
                $locationService->loadLocationByRemoteId($remoteId);
134
                $this->fail("Location '{$remoteId}' should exist.'");
135
            } catch (NotFoundException $e) {
136
                // echo $e->getFile(), ' +', $e->getLine(), PHP_EOL;
137
            }
138
        }
139
140
        $this->assertGreaterThan(
141
            0,
142
            count($remoteIds),
143
            "There should be at least one 'Community' child location."
144
        );
145
    }
146
147
    /**
148
     * Test for the trash() method.
149
     *
150
     * @see \eZ\Publish\API\Repository\TrashService::trash()
151
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
152
     */
153 View Code Duplication
    public function testTrashDecrementsChildCountOnParentLocation()
154
    {
155
        $repository = $this->getRepository();
156
        $locationService = $repository->getLocationService();
157
158
        $baseLocationId = $this->generateId('location', 1);
159
160
        $location = $locationService->loadLocation($baseLocationId);
161
162
        $childCount = $locationService->getLocationChildCount($location);
163
164
        $this->createTrashItem();
165
166
        $this->refreshSearch($repository);
167
168
        $this->assertEquals(
169
            $childCount - 1,
170
            $locationService->getLocationChildCount($location)
171
        );
172
    }
173
174
    /**
175
     * Test sending a location to trash updates Content mainLocation.
176
     *
177
     * @covers \eZ\Publish\API\Repository\TrashService::trash
178
     */
179
    public function testTrashUpdatesMainLocation()
180
    {
181
        $repository = $this->getRepository();
182
        $contentService = $repository->getContentService();
183
        $locationService = $repository->getLocationService();
184
        $trashService = $repository->getTrashService();
185
186
        $contentInfo = $contentService->loadContentInfo(42);
187
188
        // Create additional location that will become new main location
189
        $location = $locationService->createLocation(
190
            $contentInfo,
191
            new LocationCreateStruct(['parentLocationId' => 2])
192
        );
193
194
        $trashService->trash(
195
            $locationService->loadLocation($contentInfo->mainLocationId)
196
        );
197
198
        self::assertEquals(
199
            $location->id,
200
            $contentService->loadContentInfo(42)->mainLocationId
201
        );
202
    }
203
204
    /**
205
     * Test sending a location to trash.
206
     *
207
     * @covers \eZ\Publish\API\Repository\TrashService::trash
208
     */
209 View Code Duplication
    public function testTrashReturnsNull()
210
    {
211
        $repository = $this->getRepository();
212
        $contentService = $repository->getContentService();
213
        $locationService = $repository->getLocationService();
214
        $trashService = $repository->getTrashService();
215
216
        // Create additional location to trash
217
        $location = $locationService->createLocation(
218
            $contentService->loadContentInfo(42),
219
            new LocationCreateStruct(['parentLocationId' => 2])
220
        );
221
222
        $trashItem = $trashService->trash($location);
223
224
        self::assertNull($trashItem);
225
    }
226
227
    /**
228
     * Test for the loadTrashItem() method.
229
     *
230
     * @covers \eZ\Publish\API\Repository\TrashService::loadTrashItem
231
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
232
     */
233
    public function testLoadTrashItem()
234
    {
235
        $repository = $this->getRepository();
236
        $trashService = $repository->getTrashService();
237
238
        /* BEGIN: Use Case */
239
        $trashItem = $this->createTrashItem();
240
241
        // Reload the trash item
242
        $trashItemReloaded = $trashService->loadTrashItem($trashItem->id);
243
        /* END: Use Case */
244
245
        $this->assertInstanceOf(
246
            APITrashItem::class,
247
            $trashItemReloaded
248
        );
249
250
        $this->assertEquals(
251
            $trashItem->pathString,
252
            $trashItemReloaded->pathString
253
        );
254
255
        $this->assertEquals(
256
            $trashItem,
257
            $trashItemReloaded
258
        );
259
260
        $this->assertInstanceOf(
261
            Content::class,
262
            $content = $trashItemReloaded->getContent()
263
        );
264
        $this->assertEquals($trashItem->contentId, $content->contentInfo->id);
265
    }
266
267
    /**
268
     * Test for the loadTrashItem() method.
269
     *
270
     * @see \eZ\Publish\API\Repository\TrashService::loadTrashItem()
271
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
272
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testLoadTrashItem
273
     */
274
    public function testLoadTrashItemThrowsNotFoundException()
275
    {
276
        $repository = $this->getRepository();
277
278
        $nonExistingTrashId = $this->generateId('trash', 2342);
279
        /* BEGIN: Use Case */
280
        $trashService = $repository->getTrashService();
281
282
        // This call will fail with a "NotFoundException", because no trash item
283
        // with the ID 1342 should exist in an eZ Publish demo installation
284
        $trashService->loadTrashItem($nonExistingTrashId);
285
        /* END: Use Case */
286
    }
287
288
    /**
289
     * Test for the recover() method.
290
     *
291
     * @covers \eZ\Publish\API\Repository\TrashService::recover
292
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
293
     */
294
    public function testRecover()
295
    {
296
        $repository = $this->getRepository();
297
        $trashService = $repository->getTrashService();
298
        $locationService = $repository->getLocationService();
299
300
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
301
302
        /* BEGIN: Use Case */
303
        $trashItem = $this->createTrashItem();
304
305
        // Recover the trashed item
306
        $location = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 303 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
307
308
        // Load the recovered location
309
        $locationReloaded = $locationService->loadLocationByRemoteId(
310
            $mediaRemoteId
311
        );
312
        /* END: Use Case */
313
314
        $this->assertInstanceOf(
315
            APILocation::class,
316
            $location
317
        );
318
319
        $this->assertEquals(
320
            $location,
321
            $locationReloaded
322
        );
323
324
        try {
325
            $trashService->loadTrashItem($trashItem->id);
326
            $this->fail('Trash item was not removed after being recovered.');
327
        } catch (NotFoundException $e) {
328
            // All well
329
        }
330
    }
331
332
    /**
333
     * Test recovering a non existing trash item results in a NotFoundException.
334
     *
335
     * @covers \eZ\Publish\API\Repository\TrashService::recover
336
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
337
     */
338
    public function testRecoverThrowsNotFoundExceptionForNonExistingTrashItem()
339
    {
340
        $repository = $this->getRepository();
341
        $trashService = $repository->getTrashService();
342
343
        $trashService->recover(
344
            $this->getTrashItemDouble(
345
                12364,
346
                12345,
347
                12363
348
            )
349
        );
350
    }
351
352
    /**
353
     * Test for the trash() method.
354
     *
355
     * @see \eZ\Publish\API\Repository\TrashService::recover()
356
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
357
     *
358
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
359
     */
360
    public function testNotFoundAliasAfterRemoveIt()
361
    {
362
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
363
364
        $repository = $this->getRepository();
365
        $trashService = $repository->getTrashService();
366
        $urlAliasService = $repository->getURLAliasService();
367
        $locationService = $repository->getLocationService();
368
369
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
370
        $urlAliasService->lookup('/Media');
371
        $urlAliasService->lookup('/Media');
372
373
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
374
        $trashService->trash($mediaLocation);
375
376
        $urlAliasService->lookup('/Media');
377
    }
378
379
    /**
380
     * Test for the recover() method.
381
     *
382
     * @see \eZ\Publish\API\Repository\TrashService::recover()
383
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
384
     */
385
    public function testAliasesForRemovedItems()
386
    {
387
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
388
389
        $repository = $this->getRepository();
390
        $trashService = $repository->getTrashService();
391
        $urlAliasService = $repository->getURLAliasService();
392
        $locationService = $repository->getLocationService();
393
394
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
395
        $urlAliasService->lookup('/Media');
396
        $trashedLocationAlias = $urlAliasService->lookup('/Media');
397
398
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
399
        $trashItem = $trashService->trash($mediaLocation);
400
        $this->assertAliasNotExists($urlAliasService, '/Media');
401
402
        $this->createNewContentInPlaceTrashedOne($repository, $mediaLocation->parentLocationId);
403
404
        $createdLocationAlias = $urlAliasService->lookup('/Media');
405
406
        $this->assertNotEquals(
407
            $trashedLocationAlias->destination,
408
            $createdLocationAlias->destination,
409
            'Destination for /media url should changed'
410
        );
411
412
        $recoveredLocation = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($mediaLocation) on line 399 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
413
        $recoveredLocationAlias = $urlAliasService->lookup('/Media2');
414
        $recoveredLocationAliasReverse = $urlAliasService->reverseLookup($recoveredLocation);
415
416
        $this->assertEquals($recoveredLocationAlias->destination, $recoveredLocationAliasReverse->destination);
417
418
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $trashedLocationAlias->destination);
419
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $createdLocationAlias->destination);
420
    }
421
422
    /**
423
     * Test for the recover() method.
424
     *
425
     * @see \eZ\Publish\API\Repository\TrashService::recover()
426
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
427
     */
428
    public function testRecoverDoesNotRestoreChildLocations()
429
    {
430
        $repository = $this->getRepository();
431
        $trashService = $repository->getTrashService();
432
        $locationService = $repository->getLocationService();
433
434
        $remoteIds = $this->createRemoteIdList();
435
436
        // Unset remote ID of actually restored location
437
        unset($remoteIds[array_search('3f6d92f8044aed134f32153517850f5a', $remoteIds)]);
438
439
        $trashItem = $this->createTrashItem();
440
441
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 439 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
442
443
        $this->assertGreaterThan(
444
            0,
445
            count($remoteIds),
446
            "There should be at least one 'Community' child location."
447
        );
448
449
        // None of the child locations will be available again
450
        foreach ($remoteIds as $remoteId) {
451
            try {
452
                $locationService->loadLocationByRemoteId($remoteId);
453
                $this->fail(
454
                    sprintf(
455
                        'Location with remote ID "%s" unexpectedly restored.',
456
                        $remoteId
457
                    )
458
                );
459
            } catch (NotFoundException $e) {
460
                // All well
461
            }
462
        }
463
464
        try {
465
            $trashService->loadTrashItem($trashItem->id);
466
            $this->fail('Trash item was not removed after being recovered.');
467
        } catch (NotFoundException $e) {
468
            // All well
469
        }
470
    }
471
472
    /**
473
     * Test for the recover() method.
474
     *
475
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
476
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
477
     *
478
     * @todo Fix naming
479
     */
480
    public function testRecoverWithLocationCreateStructParameter()
481
    {
482
        $repository = $this->getRepository();
483
        $trashService = $repository->getTrashService();
484
        $locationService = $repository->getLocationService();
485
486
        $homeLocationId = $this->generateId('location', 2);
487
        /* BEGIN: Use Case */
488
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
489
        // demo installation
490
491
        $trashItem = $this->createTrashItem();
492
493
        // Get the new parent location
494
        $newParentLocation = $locationService->loadLocation($homeLocationId);
495
496
        // Recover location with new location
497
        $location = $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 491 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
498
        /* END: Use Case */
499
500
        $this->assertPropertiesCorrect(
501
            array(
502
                'remoteId' => $trashItem->remoteId,
503
                'parentLocationId' => $homeLocationId,
504
                // Not the full sub tree is restored
505
                'depth' => $newParentLocation->depth + 1,
506
                'hidden' => false,
507
                'invisible' => $trashItem->invisible,
508
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $location->id) . '/',
509
                'priority' => 0,
510
                'sortField' => APILocation::SORT_FIELD_NAME,
511
                'sortOrder' => APILocation::SORT_ORDER_ASC,
512
            ),
513
            $location
514
        );
515
516
        try {
517
            $trashService->loadTrashItem($trashItem->id);
518
            $this->fail('Trash item was not removed after being recovered.');
519
        } catch (NotFoundException $e) {
520
            // All well
521
        }
522
    }
523
524
    /**
525
     * Test for the recover() method.
526
     *
527
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem)
528
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
529
     */
530
    public function testRecoverIncrementsChildCountOnOriginalParent()
531
    {
532
        $repository = $this->getRepository();
533
        $trashService = $repository->getTrashService();
534
        $locationService = $repository->getLocationService();
535
536
        $location = $locationService->loadLocation($this->generateId('location', 1));
537
538
        $trashItem = $this->createTrashItem();
539
540
        $this->refreshSearch($repository);
541
542
        /* BEGIN: Use Case */
543
        $childCount = $locationService->getLocationChildCount($location);
544
545
        // Recover location with new location
546
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 538 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
547
        /* END: Use Case */
548
549
        $this->refreshSearch($repository);
550
551
        $this->assertEquals(
552
            $childCount + 1,
553
            $locationService->getLocationChildCount($location)
554
        );
555
556
        try {
557
            $trashService->loadTrashItem($trashItem->id);
558
            $this->fail('Trash item was not removed after being recovered.');
559
        } catch (NotFoundException $e) {
560
            // All well
561
        }
562
    }
563
564
    /**
565
     * Test for the recover() method.
566
     *
567
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
568
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecoverWithLocationCreateStructParameter
569
     */
570
    public function testRecoverWithLocationCreateStructParameterIncrementsChildCountOnNewParent()
571
    {
572
        $repository = $this->getRepository();
573
        $trashService = $repository->getTrashService();
574
        $locationService = $repository->getLocationService();
575
576
        $homeLocationId = $this->generateId('location', 2);
577
578
        $location = $locationService->loadLocation($homeLocationId);
579
580
        $childCount = $locationService->getLocationChildCount($location);
581
582
        /* BEGIN: Use Case */
583
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
584
        // demo installation
585
586
        $trashItem = $this->createTrashItem();
587
588
        // Get the new parent location
589
        $newParentLocation = $locationService->loadLocation($homeLocationId);
590
591
        // Recover location with new location
592
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 586 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
593
        /* END: Use Case */
594
595
        $this->refreshSearch($repository);
596
597
        $this->assertEquals(
598
            $childCount + 1,
599
            $locationService->getLocationChildCount($location)
600
        );
601
602
        try {
603
            $trashService->loadTrashItem($trashItem->id);
604
            $this->fail('Trash item was not removed after being recovered.');
605
        } catch (NotFoundException $e) {
606
            // All well
607
        }
608
    }
609
610
    /**
611
     * Test recovering a location from trash to non existing location.
612
     *
613
     * @covers \eZ\Publish\API\Repository\TrashService::recover
614
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
615
     */
616 View Code Duplication
    public function testRecoverToNonExistingLocation()
617
    {
618
        $repository = $this->getRepository();
619
        $trashService = $repository->getTrashService();
620
        $locationService = $repository->getLocationService();
621
622
        $location = $locationService->loadLocation(44);
623
        $trashItem = $trashService->trash($location);
624
625
        $newParentLocation = new Location(
626
            array(
627
                'id' => 123456,
628
                'parentLocationId' => 123455,
629
            )
630
        );
631
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($location) on line 623 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
632
    }
633
634
    /**
635
     * Test for the findTrashItems() method.
636
     *
637
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
638
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
639
     */
640
    public function testFindTrashItems()
641
    {
642
        $repository = $this->getRepository();
643
        $trashService = $repository->getTrashService();
644
645
        /* BEGIN: Use Case */
646
        $this->createTrashItem();
647
648
        // Create a search query for all trashed items
649
        $query = new Query();
650
        $query->filter = new Criterion\LogicalAnd(
651
            array(
652
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
653
            )
654
        );
655
656
        // Load all trashed locations
657
        $searchResult = $trashService->findTrashItems($query);
658
        /* END: Use Case */
659
660
        $this->assertInstanceOf(
661
            SearchResult::class,
662
            $searchResult
663
        );
664
665
        // 4 trashed locations from the sub tree
666
        $this->assertEquals(4, $searchResult->count);
0 ignored issues
show
Deprecated Code introduced by
The property eZ\Publish\API\Repositor...sh\SearchResult::$count has been deprecated with message: Property is here purely for BC with 5.x/6.x.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
667
        $this->assertEquals(4, $searchResult->totalCount);
668
    }
669
670
    /**
671
     * Test for the findTrashItems() method.
672
     *
673
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
674
     * @depends \eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
675
     */
676
    public function testFindTrashItemsLimitedAccess()
677
    {
678
        $repository = $this->getRepository();
679
        $trashService = $repository->getTrashService();
680
681
        /* BEGIN: Use Case */
682
        $this->createTrashItem();
683
684
        // Create a search query for all trashed items
685
        $query = new Query();
686
        $query->filter = new Criterion\LogicalAnd(
687
            array(
688
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
689
            )
690
        );
691
692
        // Create a user in the Editor user group.
693
        $user = $this->createUserVersion1();
694
695
        // Set the Editor user as current user, these users have no access to Trash by default.
696
        $repository->getPermissionResolver()->setCurrentUserReference($user);
697
698
        // Load all trashed locations
699
        $searchResult = $trashService->findTrashItems($query);
700
        /* END: Use Case */
701
702
        $this->assertInstanceOf(
703
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\SearchResult',
704
            $searchResult
705
        );
706
707
        // 0 trashed locations found, though 4 exist
708
        $this->assertEquals(0, $searchResult->count);
0 ignored issues
show
Deprecated Code introduced by
The property eZ\Publish\API\Repositor...sh\SearchResult::$count has been deprecated with message: Property is here purely for BC with 5.x/6.x.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
709
    }
710
711
    /**
712
     * Test for the emptyTrash() method.
713
     *
714
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
715
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
716
     */
717 View Code Duplication
    public function testEmptyTrash()
718
    {
719
        $repository = $this->getRepository();
720
        $trashService = $repository->getTrashService();
721
722
        /* BEGIN: Use Case */
723
        $this->createTrashItem();
724
725
        // Empty the trash
726
        $trashService->emptyTrash();
727
728
        // Create a search query for all trashed items
729
        $query = new Query();
730
        $query->filter = new Criterion\LogicalAnd(
731
            array(
732
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
733
            )
734
        );
735
736
        // Load all trashed locations, search result should be empty
737
        $searchResult = $trashService->findTrashItems($query);
738
        /* END: Use Case */
739
740
        $this->assertEquals(0, $searchResult->count);
0 ignored issues
show
Deprecated Code introduced by
The property eZ\Publish\API\Repositor...sh\SearchResult::$count has been deprecated with message: Property is here purely for BC with 5.x/6.x.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
741
    }
742
743
    /**
744
     * Test for the deleteTrashItem() method.
745
     *
746
     * @see \eZ\Publish\API\Repository\TrashService::deleteTrashItem()
747
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
748
     */
749
    public function testDeleteTrashItem()
750
    {
751
        $repository = $this->getRepository();
752
        $trashService = $repository->getTrashService();
753
        $locationService = $repository->getLocationService();
754
755
        $demoDesignLocationId = $this->generateId('location', 56);
756
        /* BEGIN: Use Case */
757
        // $demoDesignLocationId is the ID of the "Demo Design" location in an eZ
758
        // Publish demo installation
759
760
        $trashItem = $this->createTrashItem();
761
762
        // Trash one more location
763
        $trashService->trash(
764
            $locationService->loadLocation($demoDesignLocationId)
765
        );
766
767
        // Empty the trash
768
        $trashService->deleteTrashItem($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 760 can be null; however, eZ\Publish\API\Repositor...vice::deleteTrashItem() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
769
770
        // Create a search query for all trashed items
771
        $query = new Query();
772
        $query->filter = new Criterion\LogicalAnd(
773
            array(
774
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
775
            )
776
        );
777
778
        // Load all trashed locations, should only contain the Demo Design location
779
        $searchResult = $trashService->findTrashItems($query);
780
        /* END: Use Case */
781
782
        $foundIds = array_map(
783
            function ($trashItem) {
784
                return $trashItem->id;
785
            },
786
            $searchResult->items
787
        );
788
789
        $this->assertEquals(4, $searchResult->count);
0 ignored issues
show
Deprecated Code introduced by
The property eZ\Publish\API\Repositor...sh\SearchResult::$count has been deprecated with message: Property is here purely for BC with 5.x/6.x.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
790
        $this->assertTrue(
791
            in_array($demoDesignLocationId, $foundIds)
792
        );
793
    }
794
795
    /**
796
     * Test deleting a non existing trash item.
797
     *
798
     * @covers \eZ\Publish\API\Repository\TrashService::deleteTrashItem
799
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
800
     */
801
    public function testDeleteThrowsNotFoundExceptionForNonExistingTrashItem()
802
    {
803
        $repository = $this->getRepository();
804
        $trashService = $repository->getTrashService();
805
806
        $trashService->deleteTrashItem($this->getTrashItemDouble(
807
            12364,
808
            12345,
809
            12363
810
        ));
811
    }
812
813
    /**
814
     * Returns an array with the remoteIds of all child locations of the
815
     * <b>Community</b> location. It is stored in a local variable named
816
     * <b>$remoteIds</b>.
817
     *
818
     * @return string[]
819
     */
820
    private function createRemoteIdList()
821
    {
822
        $repository = $this->getRepository();
823
824
        /* BEGIN: Inline */
825
        // remoteId of the "Community" location in an eZ Publish demo installation
826
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
827
828
        // Load the location service
829
        $locationService = $repository->getLocationService();
830
831
        $remoteIds = array();
832
        $children = $locationService->loadLocationChildren($locationService->loadLocationByRemoteId($mediaRemoteId));
833
        foreach ($children->locations as $child) {
834
            $remoteIds[] = $child->remoteId;
835
            foreach ($locationService->loadLocationChildren($child)->locations as $grandChild) {
836
                $remoteIds[] = $grandChild->remoteId;
837
            }
838
        }
839
        /* END: Inline */
840
841
        return $remoteIds;
842
    }
843
844
    /**
845
     * @param Repository $repository
846
     * @param int $parentLocationId
847
     *
848
     * @return \eZ\Publish\API\Repository\Values\Content\Content
849
     */
850 View Code Duplication
    protected function createNewContentInPlaceTrashedOne(Repository $repository, $parentLocationId)
851
    {
852
        $contentService = $repository->getContentService();
853
        $locationService = $repository->getLocationService();
854
        $contentTypeService = $repository->getContentTypeService();
855
856
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
857
        $newContent = $contentService->newContentCreateStruct($contentType, 'eng-US');
858
        $newContent->setField('name', 'Media');
859
860
        $location = $locationService->newLocationCreateStruct($parentLocationId);
861
862
        $draftContent = $contentService->createContent($newContent, [$location]);
863
864
        return $contentService->publishVersion($draftContent->versionInfo);
865
    }
866
867
    /**
868
     * @param URLAliasService $urlAliasService
869
     * @param string $urlPath Url alias path
870
     *
871
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
872
     */
873
    private function assertAliasExists(URLAliasService $urlAliasService, $urlPath)
874
    {
875
        $urlAlias = $urlAliasService->lookup($urlPath);
876
877
        $this->assertInstanceOf('\eZ\Publish\API\Repository\Values\Content\URLAlias', $urlAlias);
878
879
        return $urlAlias;
880
    }
881
882
    /**
883
     * @param URLAliasService $urlAliasService
884
     * @param string $urlPath Url alias path
885
     */
886
    private function assertAliasNotExists(URLAliasService $urlAliasService, $urlPath)
0 ignored issues
show
Unused Code introduced by
The parameter $urlAliasService is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
887
    {
888
        try {
889
            $this->getRepository()->getURLAliasService()->lookup($urlPath);
890
            $this->fail(sprintf('Alias [%s] should not exists', $urlPath));
891
        } catch (\eZ\Publish\API\Repository\Exceptions\NotFoundException $e) {
892
            $this->assertTrue(true);
893
        }
894
    }
895
896
    /**
897
     * Get Test Double for TrashItem for exception testing and similar.
898
     */
899
    private function getTrashItemDouble(int $trashId, int $contentId = 44, int $parentLocationId = 2): TrashItem
900
    {
901
        return new TrashItem([
902
            'id' => $trashId,
903
            'parentLocationId' => $parentLocationId,
904
            'contentInfo' => new ContentInfo(['id' => $contentId]),
905
        ]);
906
    }
907
}
908