Completed
Push — EZP-26057-permission-api ( b4c475...de9e2b )
by
unknown
23:03
created

PermissionTest::testCanUserSimple()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 11

Duplication

Lines 18
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 11
nc 1
nop 2
dl 18
loc 18
rs 9.4285
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\Core\Repository\Tests\Service\Mock;
8
9
use eZ\Publish\API\Repository\Repository;
10
use eZ\Publish\Core\Repository\PermissionService;
11
use eZ\Publish\Core\Repository\Values\User\UserReference;
12
use eZ\Publish\Core\Base\Exceptions\NotFound\LimitationNotFoundException;
13
use eZ\Publish\Core\Repository\Tests\Service\Mock\Base as BaseServiceMockTest;
14
use eZ\Publish\SPI\Persistence\User\RoleAssignment;
15
use eZ\Publish\SPI\Persistence\User\Role;
16
use eZ\Publish\SPI\Persistence\User\Policy;
17
18
/**
19
 * Mock test case for PermissionService.
20
 */
21
class PermissionTest extends BaseServiceMockTest
22
{
23
    public function providerForTestHasAccessReturnsTrue()
24
    {
25
        return array(
26
            array(
27
                array(
28
                    25 => $this->createRole(
29
                        array(
30
                            array('dummy-module', 'dummy-function', 'dummy-limitation'),
31
                            array('dummy-module2', 'dummy-function2', 'dummy-limitation2'),
32
                        ),
33
                        25
34
                    ),
35
                    26 => $this->createRole(
36
                        array(
37
                            array('*', 'dummy-function', 'dummy-limitation'),
38
                        ),
39
                        26
40
                    ),
41
                ),
42
                array(
43
                    new RoleAssignment(
44
                        array(
45
                            'roleId' => 25,
46
                        )
47
                    ),
48
                    new RoleAssignment(
49
                        array(
50
                            'roleId' => 26,
51
                        )
52
                    ),
53
                ),
54
            ),
55
            array(
56
                array(
57
                    27 => $this->createRole(
58
                        array(
59
                            array('test-module', '*', 'dummy-limitation'),
60
                        ),
61
                        27
62
                    ),
63
                ),
64
                array(
65
                    new RoleAssignment(
66
                        array(
67
                            'roleId' => 27,
68
                        )
69
                    ),
70
                ),
71
            ),
72
            array(
73
                array(
74
                    28 => $this->createRole(
75
                        array(
76
                            array('test-module', 'test-function', '*'),
77
                        ),
78
                        28
79
                    ),
80
                ),
81
                array(
82
                    new RoleAssignment(
83
                        array(
84
                            'roleId' => 28,
85
                        )
86
                    ),
87
                ),
88
            ),
89
        );
90
    }
91
92
    /**
93
     * Test for the hasAccess() method.
94
     *
95
     * @dataProvider providerForTestHasAccessReturnsTrue
96
     */
97 View Code Duplication
    public function testHasAccessReturnsTrue(array $roles, array $roleAssignments)
98
    {
99
        /** @var $userHandlerMock \PHPUnit_Framework_MockObject_MockObject */
100
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
101
        $userReferenceMock = $this->getUserReferenceMock();
102
        $mockedService = $this->getPermissionServiceMock(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

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...
103
104
        $userReferenceMock
105
            ->expects($this->once())
106
            ->method('getUserId')
107
            ->will($this->returnValue(10));
108
109
        $userHandlerMock
110
            ->expects($this->once())
111
            ->method('loadRoleAssignmentsByGroupId')
112
            ->with($this->equalTo(10), $this->equalTo(true))
113
            ->will($this->returnValue($roleAssignments));
114
115
        foreach ($roleAssignments as $at => $roleAssignment) {
116
            $userHandlerMock
117
                ->expects($this->at($at + 1))
118
                ->method('loadRole')
119
                ->with($roleAssignment->roleId)
120
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
121
        }
122
123
        $result = $mockedService->hasAccess('test-module', 'test-function');
124
125
        self::assertEquals(true, $result);
126
    }
127
128
    public function providerForTestHasAccessReturnsFalse()
129
    {
130
        return array(
131
            array(array(), array()),
132
            array(
133
                array(
134
                    29 => $this->createRole(
135
                        array(
136
                            array('dummy-module', 'dummy-function', 'dummy-limitation'),
137
                        ),
138
                        29
139
                    ),
140
                ),
141
                array(
142
                    new RoleAssignment(
143
                        array(
144
                            'roleId' => 29,
145
                        )
146
                    ),
147
                ),
148
            ),
149
            array(
150
                array(
151
                    30 => $this->createRole(
152
                        array(
153
                            array('test-module', 'dummy-function', 'dummy-limitation'),
154
                        ),
155
                        30
156
                    ),
157
                ),
158
                array(
159
                    new RoleAssignment(
160
                        array(
161
                            'roleId' => 30,
162
                        )
163
                    ),
164
                ),
165
            ),
166
        );
167
    }
168
169
    /**
170
     * Test for the hasAccess() method.
171
     *
172
     * @dataProvider providerForTestHasAccessReturnsFalse
173
     */
174 View Code Duplication
    public function testHasAccessReturnsFalse(array $roles, array $roleAssignments)
175
    {
176
        /** @var $userHandlerMock \PHPUnit_Framework_MockObject_MockObject */
177
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
178
        $userReferenceMock = $this->getUserReferenceMock();
179
        $service = $this->getPermissionServiceMock(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

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...
180
181
        $userReferenceMock
182
            ->expects($this->once())
183
            ->method('getUserId')
184
            ->will($this->returnValue(10));
185
186
        $userHandlerMock
187
            ->expects($this->once())
188
            ->method('loadRoleAssignmentsByGroupId')
189
            ->with($this->equalTo(10), $this->equalTo(true))
190
            ->will($this->returnValue($roleAssignments));
191
192
        foreach ($roleAssignments as $at => $roleAssignment) {
193
            $userHandlerMock
194
                ->expects($this->at($at + 1))
195
                ->method('loadRole')
196
                ->with($roleAssignment->roleId)
197
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
198
        }
199
200
        $result = $service->hasAccess('test-module', 'test-function');
201
202
        self::assertEquals(false, $result);
203
    }
204
205
    /**
206
     * Test for the sudo() & hasAccess() method.
207
     */
208
    public function testHasAccessReturnsFalseButSudoSoTrue()
209
    {
210
        /** @var $userHandlerMock \PHPUnit_Framework_MockObject_MockObject */
211
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
212
        $service = $this->getPermissionServiceMock(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

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...
213
        $this->getRepositoryMock()
214
            ->expects($this->any())
215
            ->method('getPermissionService')
216
            ->will($this->returnValue($service));
217
218
        $userHandlerMock
219
            ->expects($this->never())
220
            ->method($this->anything());
221
222
        $result = $service->sudo(
223
            function (Repository $repo) {
224
                return $repo->hasAccess('test-module', 'test-function');
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::hasAccess() has been deprecated with message: since 6.5, to be removed. Use PermissionService::hasAccess() instead.

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
225
            }
226
        );
227
228
        self::assertEquals(true, $result);
229
    }
230
231
    /**
232
     * @return array
233
     */
234 View Code Duplication
    public function providerForTestHasAccessReturnsPermissionSets()
235
    {
236
        return array(
237
            array(
238
                array(
239
                    31 => $this->createRole(
240
                        array(
241
                            array('test-module', 'test-function', 'test-limitation'),
242
                        ),
243
                        31
244
                    ),
245
                ),
246
                array(
247
                    new RoleAssignment(
248
                        array(
249
                            'roleId' => 31,
250
                        )
251
                    ),
252
                ),
253
            ),
254
            array(
255
                array(
256
                    31 => $this->createRole(
257
                        array(
258
                            array('test-module', 'test-function', 'test-limitation'),
259
                        ),
260
                        31
261
                    ),
262
                    32 => $this->createRole(
263
                        array(
264
                            array('test-module', 'test-function', 'test-limitation2'),
265
                        ),
266
                        32
267
                    ),
268
                ),
269
                array(
270
                    new RoleAssignment(
271
                        array(
272
                            'roleId' => 31,
273
                        )
274
                    ),
275
                    new RoleAssignment(
276
                        array(
277
                            'roleId' => 32,
278
                        )
279
                    ),
280
                ),
281
            ),
282
        );
283
    }
284
285
    /**
286
     * Test for the hasAccess() method.
287
     *
288
     * @dataProvider providerForTestHasAccessReturnsPermissionSets
289
     */
290
    public function testHasAccessReturnsPermissionSets(array $roles, array $roleAssignments)
291
    {
292
        /** @var $userHandlerMock \PHPUnit_Framework_MockObject_MockObject */
293
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
294
        $roleDomainMapper = $this->getRoleDomainMapperMock(['buildDomainPolicyObject']);
295
        $permissionServiceMock = $this->getPermissionServiceMock(['getCurrentUserReference']);
296
297
        $permissionServiceMock
298
            ->expects($this->once())
299
            ->method('getCurrentUserReference')
300
            ->will($this->returnValue(new UserReference(14)));
301
302
        $userHandlerMock
303
            ->expects($this->once())
304
            ->method('loadRoleAssignmentsByGroupId')
305
            ->with($this->isType('integer'), $this->equalTo(true))
306
            ->will($this->returnValue($roleAssignments));
307
308
        foreach ($roleAssignments as $at => $roleAssignment) {
309
            $userHandlerMock
310
                ->expects($this->at($at + 1))
311
                ->method('loadRole')
312
                ->with($roleAssignment->roleId)
313
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
314
        }
315
316
        $permissionSets = array();
317
        $count = 0;
318
        /* @var $roleAssignments \eZ\Publish\SPI\Persistence\User\RoleAssignment[] */
319
        foreach ($roleAssignments as $i => $roleAssignment) {
320
            $permissionSet = array('limitation' => null);
321
            foreach ($roles[$roleAssignment->roleId]->policies as $k => $policy) {
322
                $policyName = 'policy-' . $i . '-' . $k;
323
                $return = $this->returnValue($policyName);
324
                $permissionSet['policies'][] = $policyName;
325
326
                $roleDomainMapper
327
                    ->expects($this->at($count++))
328
                    ->method('buildDomainPolicyObject')
329
                    ->with($policy)
330
                    ->will($return);
331
            }
332
333
            if (!empty($permissionSet['policies'])) {
334
                $permissionSets[] = $permissionSet;
335
            }
336
        }
337
338
        /* @var $repositoryMock \eZ\Publish\Core\Repository\Repository */
339
        self::assertEquals(
340
            $permissionSets,
341
            $permissionServiceMock->hasAccess('test-module', 'test-function')
342
        );
343
    }
344
345
    /**
346
     * @return array
347
     */
348 View Code Duplication
    public function providerForTestHasAccessReturnsException()
349
    {
350
        return array(
351
            array(
352
                array(
353
                    31 => $this->createRole(
354
                        array(
355
                            array('test-module', 'test-function', 'notfound'),
356
                        ),
357
                        31
358
                    ),
359
                ),
360
                array(
361
                    new RoleAssignment(
362
                        array(
363
                            'roleId' => 31,
364
                        )
365
                    ),
366
                ),
367
            ),
368
            array(
369
                array(
370
                    31 => $this->createRole(
371
                        array(
372
                            array('test-module', 'test-function', 'test-limitation'),
373
                        ),
374
                        31
375
                    ),
376
                    32 => $this->createRole(
377
                        array(
378
                            array('test-module', 'test-function', 'notfound'),
379
                        ),
380
                        32
381
                    ),
382
                ),
383
                array(
384
                    new RoleAssignment(
385
                        array(
386
                            'roleId' => 31,
387
                        )
388
                    ),
389
                    new RoleAssignment(
390
                        array(
391
                            'roleId' => 32,
392
                        )
393
                    ),
394
                ),
395
            ),
396
        );
397
    }
398
399
    /**
400
     * Test for the hasAccess() method.
401
     *
402
     * @dataProvider providerForTestHasAccessReturnsException
403
     * @expectedException \eZ\Publish\Core\Base\Exceptions\NotFound\LimitationNotFoundException
404
     */
405
    public function testHasAccessReturnsException(array $roles, array $roleAssignments)
406
    {
407
        /** @var $userHandlerMock \PHPUnit_Framework_MockObject_MockObject */
408
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
409
        $roleDomainMapper = $this->getRoleDomainMapperMock();
410
        $permissionServiceMock = $this->getPermissionServiceMock(['getCurrentUserReference']);
411
412
        $permissionServiceMock
413
            ->expects($this->once())
414
            ->method('getCurrentUserReference')
415
            ->will($this->returnValue(new UserReference(14)));
416
417
        $userHandlerMock
418
            ->expects($this->once())
419
            ->method('loadRoleAssignmentsByGroupId')
420
            ->with($this->isType('integer'), $this->equalTo(true))
421
            ->will($this->returnValue($roleAssignments));
422
423
        foreach ($roleAssignments as $at => $roleAssignment) {
424
            $userHandlerMock
425
                ->expects($this->at($at + 1))
426
                ->method('loadRole')
427
                ->with($roleAssignment->roleId)
428
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
429
        }
430
431
        $count = 0;
432
        /* @var $roleAssignments \eZ\Publish\SPI\Persistence\User\RoleAssignment[] */
433
        foreach ($roleAssignments as $i => $roleAssignment) {
434
            $permissionSet = array('limitation' => null);
435
            foreach ($roles[$roleAssignment->roleId]->policies as $k => $policy) {
436
                $policyName = 'policy-' . $i . '-' . $k;
437
                if ($policy->limitations === 'notfound') {
438
                    $return = $this->throwException(new LimitationNotFoundException('notfound'));
439
                } else {
440
                    $return = $this->returnValue($policyName);
441
                    $permissionSet['policies'][] = $policyName;
442
                }
443
444
                $roleDomainMapper
445
                    ->expects($this->at($count++))
446
                    ->method('buildDomainPolicyObject')
447
                    ->with($policy)
448
                    ->will($return);
449
450
                if ($policy->limitations === 'notfound') {
451
                    break 2;// no more execution after exception
452
                }
453
            }
454
        }
455
456
        $permissionServiceMock->hasAccess('test-module', 'test-function');
457
    }
458
459 View Code Duplication
    public function providerForTestHasAccessReturnsPermissionSetsWithRoleLimitation()
460
    {
461
        return array(
462
            array(
463
                array(
464
                    32 => $this->createRole(
465
                        array(
466
                            array('test-module', 'test-function', 'test-limitation'),
467
                        ),
468
                        32
469
                    ),
470
                ),
471
                array(
472
                    new RoleAssignment(
473
                        array(
474
                            'roleId' => 32,
475
                            'limitationIdentifier' => 'test-role-limitation',
476
                            'values' => array('test-role-limitation-value'),
477
                        )
478
                    ),
479
                ),
480
            ),
481
            array(
482
                array(
483
                    33 => $this->createRole(array(array('*', '*', '*')), 33),
484
                ),
485
                array(
486
                    new RoleAssignment(
487
                        array(
488
                            'roleId' => 33,
489
                            'limitationIdentifier' => 'test-role-limitation',
490
                            'values' => array('test-role-limitation-value'),
491
                        )
492
                    ),
493
                ),
494
            ),
495
        );
496
    }
497
498
    /**
499
     * Test for the hasAccess() method.
500
     *
501
     * @dataProvider providerForTestHasAccessReturnsPermissionSetsWithRoleLimitation
502
     */
503
    public function testHasAccessReturnsPermissionSetsWithRoleLimitation(array $roles, array $roleAssignments)
504
    {
505
        /** @var $userHandlerMock \PHPUnit_Framework_MockObject_MockObject */
506
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
507
        $limitationTypeMock = $this->getMock('eZ\\Publish\\SPI\\Limitation\\Type');
508
        $limitationService = $this->getLimitationServiceMock();
509
        $roleDomainMapper = $this->getRoleDomainMapperMock();
510
        $permissionServiceMock = $this->getPermissionServiceMock(['getCurrentUserReference']);
511
512
        $permissionServiceMock
513
            ->expects($this->once())
514
            ->method('getCurrentUserReference')
515
            ->will($this->returnValue(new UserReference(14)));
516
517
        $userHandlerMock
518
            ->expects($this->once())
519
            ->method('loadRoleAssignmentsByGroupId')
520
            ->with($this->isType('integer'), $this->equalTo(true))
521
            ->will($this->returnValue($roleAssignments));
522
523
        foreach ($roleAssignments as $at => $roleAssignment) {
524
            $userHandlerMock
525
                ->expects($this->at($at + 1))
526
                ->method('loadRole')
527
                ->with($roleAssignment->roleId)
528
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
529
        }
530
531
        $permissionSets = array();
532
        /** @var $roleAssignments \eZ\Publish\SPI\Persistence\User\RoleAssignment[] */
533
        foreach ($roleAssignments as $i => $roleAssignment) {
534
            $permissionSet = array();
535
            foreach ($roles[$roleAssignment->roleId]->policies as $k => $policy) {
536
                $policyName = "policy-{$i}-{$k}";
537
                $permissionSet['policies'][] = $policyName;
538
                $roleDomainMapper
539
                    ->expects($this->at($k))
540
                    ->method('buildDomainPolicyObject')
541
                    ->with($policy)
542
                    ->will($this->returnValue($policyName));
543
            }
544
545
            $permissionSet['limitation'] = "limitation-{$i}";
546
            $limitationTypeMock
547
                ->expects($this->at($i))
548
                ->method('buildValue')
549
                ->with($roleAssignment->values)
550
                ->will($this->returnValue($permissionSet['limitation']));
551
            $limitationService
552
                ->expects($this->any())
553
                ->method('getLimitationType')
554
                ->with($roleAssignment->limitationIdentifier)
555
                ->will($this->returnValue($limitationTypeMock));
556
557
            $permissionSets[] = $permissionSet;
558
        }
559
560
        self::assertEquals(
561
            $permissionSets,
562
            $permissionServiceMock->hasAccess('test-module', 'test-function')
563
        );
564
    }
565
566
    /**
567
     * Returns Role stub.
568
     *
569
     * @param array $policiesData
570
     * @param mixed $roleId
571
     *
572
     * @return \eZ\Publish\SPI\Persistence\User\Role
573
     */
574
    private function createRole(array $policiesData, $roleId = null)
575
    {
576
        $policies = array();
577
        foreach ($policiesData as $policyData) {
578
            $policies[] = new Policy(
579
                array(
580
                    'module' => $policyData[0],
581
                    'function' => $policyData[1],
582
                    'limitations' => $policyData[2],
583
                )
584
            );
585
        }
586
587
        return new Role(
588
            array(
589
                'id' => $roleId,
590
                'policies' => $policies,
591
            )
592
        );
593
    }
594
595
    public function providerForTestCanUserSimple()
596
    {
597
        return array(
598
            array(true, true),
599
            array(false, false),
600
            array(array(), false),
601
        );
602
    }
603
604
    /**
605
     * Test for the canUser() method.
606
     *
607
     * Tests execution paths with permission sets equaling to boolean value or empty array.
608
     *
609
     * @dataProvider providerForTestCanUserSimple
610
     */
611 View Code Duplication
    public function testCanUserSimple($permissionSets, $result)
612
    {
613
        $permissionServiceMock = $this->getPermissionServiceMock(['hasAccess']);
614
615
        $permissionServiceMock
616
            ->expects($this->once())
617
            ->method('hasAccess')
618
            ->with($this->equalTo('test-module'), $this->equalTo('test-function'))
619
            ->will($this->returnValue($permissionSets));
620
621
        /** @var $valueObject \eZ\Publish\API\Repository\Values\ValueObject */
622
        $valueObject = $this->getMockForAbstractClass('eZ\\Publish\\API\\Repository\\Values\\ValueObject');
623
624
        self::assertEquals(
625
            $result,
626
            $permissionServiceMock->canUser('test-module', 'test-function', $valueObject, $valueObject)
627
        );
628
    }
629
630
    /**
631
     * Test for the canUser() method.
632
     *
633
     * Tests execution path with permission set defining no limitations.
634
     */
635
    public function testCanUserWithoutLimitations()
636
    {
637
        $permissionServiceMock = $this->getPermissionServiceMock(
638
            [
639
                'hasAccess',
640
                'getCurrentUserReference',
641
            ]
642
        );
643
644
        $policyMock = $this->getMock(
645
            'eZ\\Publish\\SPI\\Persistence\\User\\Policy',
646
            array('getLimitations'),
647
            array(),
648
            '',
649
            false
650
        );
651
        $policyMock
652
            ->expects($this->once())
653
            ->method('getLimitations')
654
            ->will($this->returnValue('*'));
655
        $permissionSets = array(
656
            array(
657
                'limitation' => null,
658
                'policies' => array($policyMock),
659
            ),
660
        );
661
        $permissionServiceMock
662
            ->expects($this->once())
663
            ->method('hasAccess')
664
            ->with($this->equalTo('test-module'), $this->equalTo('test-function'))
665
            ->will($this->returnValue($permissionSets));
666
667
        $permissionServiceMock
668
            ->expects($this->once())
669
            ->method('getCurrentUserReference')
670
            ->will($this->returnValue(new UserReference(14)));
671
672
        /** @var $valueObject \eZ\Publish\API\Repository\Values\ValueObject */
673
        $valueObject = $this->getMockForAbstractClass(
674
            'eZ\\Publish\\API\\Repository\\Values\\ValueObject'
675
        );
676
677
        self::assertTrue(
678
            $permissionServiceMock->canUser(
679
                'test-module',
680
                'test-function',
681
                $valueObject,
682
                $valueObject
683
            )
684
        );
685
    }
686
687
    /**
688
     * @return array
689
     */
690
    private function getPermissionSetsMock()
691
    {
692
        $roleLimitationMock = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\User\\Limitation');
693
        $roleLimitationMock
694
            ->expects($this->any())
695
            ->method('getIdentifier')
696
            ->will($this->returnValue('test-role-limitation-identifier'));
697
698
        $policyLimitationMock = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\User\\Limitation');
699
        $policyLimitationMock
700
            ->expects($this->any())
701
            ->method('getIdentifier')
702
            ->will($this->returnValue('test-policy-limitation-identifier'));
703
704
        $policyMock = $this->getMock(
705
            'eZ\\Publish\\SPI\\Persistence\\User\\Policy',
706
            array('getLimitations'),
707
            array(),
708
            '',
709
            false
710
        );
711
        $policyMock
712
            ->expects($this->any())
713
            ->method('getLimitations')
714
            ->will($this->returnValue(array($policyLimitationMock, $policyLimitationMock)));
715
716
        $permissionSet = array(
717
            'limitation' => clone $roleLimitationMock,
718
            'policies' => array($policyMock, $policyMock),
719
        );
720
        $permissionSets = array($permissionSet, $permissionSet);
721
722
        return $permissionSets;
723
    }
724
725
    /**
726
     * Provides evaluation results for two permission sets, each with a role limitation and two policies,
727
     * with two limitations per policy.
728
     *
729
     * @return array
730
     */
731
    public function providerForTestCanUserComplex()
732
    {
733
        return array(
734
            array(
735
                array(true, true),
736
                array(
737
                    array(
738
                        array(true, true),
739
                        array(true, true),
740
                    ),
741
                    array(
742
                        array(true, true),
743
                        array(true, true),
744
                    ),
745
                ),
746
                true,
747
            ),
748
            array(
749
                array(false, false),
750
                array(
751
                    array(
752
                        array(true, true),
753
                        array(true, true),
754
                    ),
755
                    array(
756
                        array(true, true),
757
                        array(true, true),
758
                    ),
759
                ),
760
                false,
761
            ),
762
            array(
763
                array(false, true),
764
                array(
765
                    array(
766
                        array(true, true),
767
                        array(true, true),
768
                    ),
769
                    array(
770
                        array(true, true),
771
                        array(true, true),
772
                    ),
773
                ),
774
                true,
775
            ),
776
            array(
777
                array(false, true),
778
                array(
779
                    array(
780
                        array(true, true),
781
                        array(true, true),
782
                    ),
783
                    array(
784
                        array(true, false),
785
                        array(true, true),
786
                    ),
787
                ),
788
                true,
789
            ),
790
            array(
791
                array(true, false),
792
                array(
793
                    array(
794
                        array(true, false),
795
                        array(false, true),
796
                    ),
797
                    array(
798
                        array(true, true),
799
                        array(true, true),
800
                    ),
801
                ),
802
                false,
803
            ),
804
        );
805
    }
806
807
    /**
808
     * Test for the canUser() method.
809
     *
810
     * Tests execution paths with permission sets containing limitations.
811
     *
812
     * @dataProvider providerForTestCanUserComplex
813
     */
814
    public function testCanUserComplex(array $roleLimitationEvaluations, array $policyLimitationEvaluations, $userCan)
815
    {
816
        /** @var $valueObject \eZ\Publish\API\Repository\Values\ValueObject */
817
        $valueObject = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\ValueObject');
818
        $limitationServiceMock = $this->getLimitationServiceMock();
819
        $permissionServiceMock = $this->getPermissionServiceMock(
820
            [
821
                'hasAccess',
822
                'getCurrentUserReference',
823
            ]
824
        );
825
826
        $permissionSets = $this->getPermissionSetsMock();
827
        $permissionServiceMock
828
            ->expects($this->once())
829
            ->method('hasAccess')
830
            ->with($this->equalTo('test-module'), $this->equalTo('test-function'))
831
            ->will($this->returnValue($permissionSets));
832
833
        $userRef = new UserReference(14);
834
        $permissionServiceMock
835
            ->expects($this->once())
836
            ->method('getCurrentUserReference')
837
            ->will($this->returnValue(new UserReference(14)));
838
839
        $invocation = 0;
840
        for ($i = 0; $i < count($permissionSets); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
841
            $limitation = $this->getMock('eZ\\Publish\\SPI\\Limitation\\Type');
842
            $limitation
843
                ->expects($this->once())
844
                ->method('evaluate')
845
                ->with($permissionSets[$i]['limitation'], $userRef, $valueObject, array($valueObject))
846
                ->will($this->returnValue($roleLimitationEvaluations[$i]));
847
            $limitationServiceMock
848
                ->expects($this->at($invocation++))
849
                ->method('getLimitationType')
850
                ->with('test-role-limitation-identifier')
851
                ->will($this->returnValue($limitation));
852
853
            if (!$roleLimitationEvaluations[$i]) {
854
                continue;
855
            }
856
857
            for ($j = 0; $j < count($permissionSets[$i]['policies']); ++$j) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
858
                /** @var $policy \eZ\Publish\API\Repository\Values\User\Policy */
859
                $policy = $permissionSets[$i]['policies'][$j];
860
                $limitations = $policy->getLimitations();
861
                for ($k = 0; $k < count($limitations); ++$k) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
862
                    $limitationsPass = true;
863
                    $limitation = $this->getMock('eZ\\Publish\\SPI\\Limitation\\Type');
864
                    $limitation
865
                        ->expects($this->once())
866
                        ->method('evaluate')
867
                        ->with($limitations[$k], $userRef, $valueObject, array($valueObject))
868
                        ->will($this->returnValue($policyLimitationEvaluations[$i][$j][$k]));
869
                    $limitationServiceMock
870
                        ->expects($this->at($invocation++))
871
                        ->method('getLimitationType')
872
                        ->with('test-policy-limitation-identifier')
873
                        ->will($this->returnValue($limitation));
874
875
                    if (!$policyLimitationEvaluations[$i][$j][$k]) {
876
                        $limitationsPass = false;
877
                        break;
878
                    }
879
                }
880
881
                /** @var $limitationsPass */
882
                if ($limitationsPass) {
0 ignored issues
show
Bug introduced by
The variable $limitationsPass does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
883
                    break 2;
884
                }
885
            }
886
        }
887
888
        self::assertEquals(
889
            $userCan,
890
            $permissionServiceMock->canUser(
891
                'test-module',
892
                'test-function',
893
                $valueObject,
894
                $valueObject
895
            )
896
        );
897
    }
898
899
    /**
900
     * Test for the canUser() method.
901
     *
902
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
903
     */
904
    public function testCanUserThrowsInvalidArgumentException()
905
    {
906
        $permissionServiceMock = $this->getPermissionServiceMock(['hasAccess']);
907
908
        $permissionServiceMock
909
            ->expects($this->once())
910
            ->method('hasAccess')
911
            ->with($this->equalTo('test-module'), $this->equalTo('test-function'))
912
            ->will($this->returnValue(array()));
913
914
        /** @var $valueObject \eZ\Publish\API\Repository\Values\ValueObject */
915
        $valueObject = $this->getMockForAbstractClass('eZ\\Publish\\API\\Repository\\Values\\ValueObject');
916
917
        $permissionServiceMock->canUser(
918
            'test-module',
919
            'test-function',
920
            $valueObject,
921
            'This is not a target'
922
        );
923
    }
924
925
    /**
926
     * Test for the setCurrentUserReference() and getCurrentUserReference() methods.
927
     */
928
    public function testSetAndGetCurrentUserReference()
929
    {
930
        $permissionServiceMock = $this->getPermissionServiceMock(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

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...
931
        $userReferenceMock = $this->getUserReferenceMock();
932
933
        $permissionServiceMock->setCurrentUserReference($userReferenceMock);
934
935
        self::assertSame(
936
            $userReferenceMock,
937
            $permissionServiceMock->getCurrentUserReference()
938
        );
939
    }
940
941
    /**
942
     * Test for the getCurrentUserReference() method.
943
     */
944
    public function testGetCurrentUserReferenceReturnsAnonymousUser()
945
    {
946
        $permissionServiceMock = $this->getPermissionServiceMock(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

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...
947
        $userReferenceMock = $this->getUserReferenceMock();
948
949
        $userReferenceMock
950
            ->expects($this->once())
951
            ->method('getUserId')
952
            ->will($this->returnValue('Anonymous User ID'));
953
954
        self::assertSame(
955
            $userReferenceMock,
956
            $permissionServiceMock->getCurrentUserReference()
957
        );
958
    }
959
960
    protected $permissionServiceMock;
961
962
    /**
963
     * @return \eZ\Publish\API\Repository\PermissionService|\PHPUnit_Framework_MockObject_MockObject
964
     */
965
    protected function getPermissionServiceMock($methods = [])
966
    {
967
        if ($this->permissionServiceMock === null) {
968
            $this->permissionServiceMock = $this
969
                ->getMockBuilder('eZ\\Publish\\Core\\Repository\\PermissionService')
970
                ->setMethods($methods)
971
                ->setConstructorArgs(
972
                    [
973
                        $this->getRepositoryMock(),
974
                        $this->getRoleDomainMapperMock(),
975
                        $this->getLimitationServiceMock(),
976
                        $this->getPersistenceMock()->userHandler(),
977
                        $this->getUserReferenceMock(),
978
                    ]
979
                )
980
                ->getMock();
981
        }
982
983
        return $this->permissionServiceMock;
984
    }
985
986
    protected $userReferenceMock;
987
988
    protected function getUserReferenceMock()
989
    {
990
        if ($this->userReferenceMock === null) {
991
            $this->userReferenceMock = $this
992
                ->getMockBuilder('eZ\Publish\API\Repository\Values\User\UserReference')
993
                ->getMock();
994
        }
995
996
        return $this->userReferenceMock;
997
    }
998
999
    protected $repositoryMock;
1000
1001
    /**
1002
     * @return \eZ\Publish\API\Repository\Repository|\PHPUnit_Framework_MockObject_MockObject
1003
     */
1004
    protected function getRepositoryMock($methods = [])
0 ignored issues
show
Unused Code introduced by
The parameter $methods 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...
1005
    {
1006
        if ($this->repositoryMock === null) {
1007
            $this->repositoryMock = $this
1008
                ->getMockBuilder('eZ\\Publish\\Core\\Repository\\Repository')
1009
                ->setMethods(['getPermissionService'])
1010
                ->disableOriginalConstructor()
1011
                ->getMock();
1012
        }
1013
1014
        return $this->repositoryMock;
1015
    }
1016
1017
    protected $roleDomainMapperMock;
1018
1019
    /**
1020
     * @return \eZ\Publish\Core\Repository\Helper\RoleDomainMapper|\PHPUnit_Framework_MockObject_MockObject
1021
     */
1022
    protected function getRoleDomainMapperMock($methods = [])
1023
    {
1024
        if ($this->roleDomainMapperMock === null) {
1025
            $this->roleDomainMapperMock = $this
1026
                ->getMockBuilder('eZ\\Publish\\Core\\Repository\\Helper\\RoleDomainMapper')
1027
                ->setMethods($methods)
1028
                ->disableOriginalConstructor()
1029
                ->getMock();
1030
        }
1031
1032
        return $this->roleDomainMapperMock;
1033
    }
1034
1035
    protected $limitationServiceMock;
1036
1037
    /**
1038
     * @return \eZ\Publish\Core\Repository\Helper\LimitationService|\PHPUnit_Framework_MockObject_MockObject
1039
     */
1040 View Code Duplication
    protected function getLimitationServiceMock($methods = [])
1041
    {
1042
        if ($this->limitationServiceMock === null) {
1043
            $this->limitationServiceMock = $this
1044
                ->getMockBuilder('eZ\\Publish\\Core\\Repository\\Helper\\LimitationService')
1045
                ->setMethods($methods)
1046
                ->disableOriginalConstructor()
1047
                ->getMock();
1048
        }
1049
1050
        return $this->limitationServiceMock;
1051
    }
1052
}
1053