Completed
Push — master ( ba78f6...0a7dac )
by Łukasz
35:28 queued 20:34
created

PermissionTest::getLimitationServiceMock()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12

Duplication

Lines 12
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 12
loc 12
rs 9.8666
c 0
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\API\Repository\Values\User\Limitation;
11
use eZ\Publish\API\Repository\Values\ValueObject;
12
use eZ\Publish\Core\Repository\Permission\PermissionResolver;
13
use eZ\Publish\Core\Repository\Values\User\UserReference;
14
use eZ\Publish\Core\Repository\Repository as CoreRepository;
15
use eZ\Publish\Core\Base\Exceptions\NotFound\LimitationNotFoundException;
16
use eZ\Publish\Core\Repository\Helper\RoleDomainMapper;
17
use eZ\Publish\Core\Repository\Tests\Service\Mock\Base as BaseServiceMockTest;
18
use eZ\Publish\SPI\Limitation\Type;
19
use eZ\Publish\SPI\Persistence\User\RoleAssignment;
20
use eZ\Publish\SPI\Persistence\User\Role;
21
use eZ\Publish\SPI\Persistence\User\Policy;
22
23
/**
24
 * Mock test case for PermissionResolver.
25
 *
26
 * @todo Move to "Tests/Permission/"
27
 */
28
class PermissionTest extends BaseServiceMockTest
29
{
30
    public function providerForTestHasAccessReturnsTrue()
31
    {
32
        return [
33
            [
34
                [
35
                    25 => $this->createRole(
36
                        [
37
                            ['dummy-module', 'dummy-function', 'dummy-limitation'],
38
                            ['dummy-module2', 'dummy-function2', 'dummy-limitation2'],
39
                        ],
40
                        25
41
                    ),
42
                    26 => $this->createRole(
43
                        [
44
                            ['*', 'dummy-function', 'dummy-limitation'],
45
                        ],
46
                        26
47
                    ),
48
                ],
49
                [
50
                    new RoleAssignment(
51
                        [
52
                            'roleId' => 25,
53
                        ]
54
                    ),
55
                    new RoleAssignment(
56
                        [
57
                            'roleId' => 26,
58
                        ]
59
                    ),
60
                ],
61
            ],
62
            [
63
                [
64
                    27 => $this->createRole(
65
                        [
66
                            ['dummy-module', '*', 'dummy-limitation'],
67
                        ],
68
                        27
69
                    ),
70
                ],
71
                [
72
                    new RoleAssignment(
73
                        [
74
                            'roleId' => 27,
75
                        ]
76
                    ),
77
                ],
78
            ],
79
            [
80
                [
81
                    28 => $this->createRole(
82
                        [
83
                            ['dummy-module', 'dummy-function', '*'],
84
                        ],
85
                        28
86
                    ),
87
                ],
88
                [
89
                    new RoleAssignment(
90
                        [
91
                            'roleId' => 28,
92
                        ]
93
                    ),
94
                ],
95
            ],
96
        ];
97
    }
98
99
    /**
100
     * Test for the hasAccess() method.
101
     *
102
     * @dataProvider providerForTestHasAccessReturnsTrue
103
     */
104 View Code Duplication
    public function testHasAccessReturnsTrue(array $roles, array $roleAssignments)
105
    {
106
        /** @var $userHandlerMock \PHPUnit\Framework\MockObject\MockObject */
107
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
108
        $userReferenceMock = $this->getUserReferenceMock();
109
        $mockedService = $this->getPermissionResolverMock(null);
110
111
        $userReferenceMock
112
            ->expects($this->once())
113
            ->method('getUserId')
114
            ->will($this->returnValue(10));
115
116
        $userHandlerMock
117
            ->expects($this->once())
118
            ->method('loadRoleAssignmentsByGroupId')
119
            ->with($this->equalTo(10), $this->equalTo(true))
120
            ->will($this->returnValue($roleAssignments));
121
122
        foreach ($roleAssignments as $at => $roleAssignment) {
123
            $userHandlerMock
124
                ->expects($this->at($at + 1))
125
                ->method('loadRole')
126
                ->with($roleAssignment->roleId)
127
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
128
        }
129
130
        $result = $mockedService->hasAccess('dummy-module', 'dummy-function');
131
132
        self::assertEquals(true, $result);
133
    }
134
135
    public function providerForTestHasAccessReturnsFalse()
136
    {
137
        return [
138
            [[], []],
139
            [
140
                [
141
                    29 => $this->createRole(
142
                        [
143
                            ['dummy-module', 'dummy-function', 'dummy-limitation'],
144
                        ],
145
                        29
146
                    ),
147
                ],
148
                [
149
                    new RoleAssignment(
150
                        [
151
                            'roleId' => 29,
152
                        ]
153
                    ),
154
                ],
155
            ],
156
            [
157
                [
158
                    30 => $this->createRole(
159
                        [
160
                            ['dummy-module', '*', 'dummy-limitation'],
161
                        ],
162
                        30
163
                    ),
164
                ],
165
                [
166
                    new RoleAssignment(
167
                        [
168
                            'roleId' => 30,
169
                        ]
170
                    ),
171
                ],
172
            ],
173
        ];
174
    }
175
176
    /**
177
     * Test for the hasAccess() method.
178
     *
179
     * @dataProvider providerForTestHasAccessReturnsFalse
180
     */
181 View Code Duplication
    public function testHasAccessReturnsFalse(array $roles, array $roleAssignments)
182
    {
183
        /** @var $userHandlerMock \PHPUnit\Framework\MockObject\MockObject */
184
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
185
        $userReferenceMock = $this->getUserReferenceMock();
186
        $service = $this->getPermissionResolverMock(null);
187
188
        $userReferenceMock
189
            ->expects($this->once())
190
            ->method('getUserId')
191
            ->will($this->returnValue(10));
192
193
        $userHandlerMock
194
            ->expects($this->once())
195
            ->method('loadRoleAssignmentsByGroupId')
196
            ->with($this->equalTo(10), $this->equalTo(true))
197
            ->will($this->returnValue($roleAssignments));
198
199
        foreach ($roleAssignments as $at => $roleAssignment) {
200
            $userHandlerMock
201
                ->expects($this->at($at + 1))
202
                ->method('loadRole')
203
                ->with($roleAssignment->roleId)
204
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
205
        }
206
207
        $result = $service->hasAccess('dummy-module2', 'dummy-function2');
208
209
        self::assertEquals(false, $result);
210
    }
211
212
    /**
213
     * Test for the sudo() & hasAccess() method.
214
     */
215
    public function testHasAccessReturnsFalseButSudoSoTrue()
216
    {
217
        /** @var $userHandlerMock \PHPUnit\Framework\MockObject\MockObject */
218
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
219
        $service = $this->getPermissionResolverMock(null);
220
        $repositoryMock = $this->getRepositoryMock();
221
        $repositoryMock
222
            ->expects($this->any())
223
            ->method('getPermissionResolver')
224
            ->will($this->returnValue($service));
225
226
        $userHandlerMock
227
            ->expects($this->never())
228
            ->method($this->anything());
229
230
        $result = $service->sudo(
231
            function (Repository $repo) {
232
                return $repo->getPermissionResolver()->hasAccess('dummy-module', 'dummy-function');
233
            },
234
            $repositoryMock
235
        );
236
237
        self::assertEquals(true, $result);
238
    }
239
240
    /**
241
     * @return array
242
     */
243 View Code Duplication
    public function providerForTestHasAccessReturnsPermissionSets()
244
    {
245
        return [
246
            [
247
                [
248
                    31 => $this->createRole(
249
                        [
250
                            ['dummy-module', 'dummy-function', 'test-limitation'],
251
                        ],
252
                        31
253
                    ),
254
                ],
255
                [
256
                    new RoleAssignment(
257
                        [
258
                            'roleId' => 31,
259
                        ]
260
                    ),
261
                ],
262
            ],
263
            [
264
                [
265
                    31 => $this->createRole(
266
                        [
267
                            ['dummy-module', 'dummy-function', 'test-limitation'],
268
                        ],
269
                        31
270
                    ),
271
                    32 => $this->createRole(
272
                        [
273
                            ['dummy-module', 'dummy-function', 'test-limitation2'],
274
                        ],
275
                        32
276
                    ),
277
                ],
278
                [
279
                    new RoleAssignment(
280
                        [
281
                            'roleId' => 31,
282
                        ]
283
                    ),
284
                    new RoleAssignment(
285
                        [
286
                            'roleId' => 32,
287
                        ]
288
                    ),
289
                ],
290
            ],
291
        ];
292
    }
293
294
    /**
295
     * Test for the hasAccess() method.
296
     *
297
     * @dataProvider providerForTestHasAccessReturnsPermissionSets
298
     */
299
    public function testHasAccessReturnsPermissionSets(array $roles, array $roleAssignments)
300
    {
301
        /** @var $userHandlerMock \PHPUnit\Framework\MockObject\MockObject */
302
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
303
        $roleDomainMapper = $this->getRoleDomainMapperMock(['buildDomainPolicyObject']);
304
        $permissionResolverMock = $this->getPermissionResolverMock(['getCurrentUserReference']);
305
306
        $permissionResolverMock
307
            ->expects($this->once())
308
            ->method('getCurrentUserReference')
309
            ->will($this->returnValue(new UserReference(14)));
310
311
        $userHandlerMock
312
            ->expects($this->once())
313
            ->method('loadRoleAssignmentsByGroupId')
314
            ->with($this->isType('integer'), $this->equalTo(true))
315
            ->will($this->returnValue($roleAssignments));
316
317
        foreach ($roleAssignments as $at => $roleAssignment) {
318
            $userHandlerMock
319
                ->expects($this->at($at + 1))
320
                ->method('loadRole')
321
                ->with($roleAssignment->roleId)
322
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
323
        }
324
325
        $permissionSets = [];
326
        $count = 0;
327
        /* @var $roleAssignments \eZ\Publish\SPI\Persistence\User\RoleAssignment[] */
328
        foreach ($roleAssignments as $i => $roleAssignment) {
329
            $permissionSet = ['limitation' => null];
330
            foreach ($roles[$roleAssignment->roleId]->policies as $k => $policy) {
331
                $policyName = 'policy-' . $i . '-' . $k;
332
                $return = $this->returnValue($policyName);
333
                $permissionSet['policies'][] = $policyName;
334
335
                $roleDomainMapper
336
                    ->expects($this->at($count++))
337
                    ->method('buildDomainPolicyObject')
338
                    ->with($policy)
339
                    ->will($return);
340
            }
341
342
            if (!empty($permissionSet['policies'])) {
343
                $permissionSets[] = $permissionSet;
344
            }
345
        }
346
347
        /* @var $repositoryMock \eZ\Publish\Core\Repository\Repository */
348
        self::assertEquals(
349
            $permissionSets,
350
            $permissionResolverMock->hasAccess('dummy-module', 'dummy-function')
351
        );
352
    }
353
354
    /**
355
     * @return array
356
     */
357 View Code Duplication
    public function providerForTestHasAccessReturnsLimitationNotFoundException()
358
    {
359
        return [
360
            [
361
                [
362
                    31 => $this->createRole(
363
                        [
364
                            ['dummy-module', 'dummy-function', 'notfound'],
365
                        ],
366
                        31
367
                    ),
368
                ],
369
                [
370
                    new RoleAssignment(
371
                        [
372
                            'roleId' => 31,
373
                        ]
374
                    ),
375
                ],
376
            ],
377
            [
378
                [
379
                    31 => $this->createRole(
380
                        [
381
                            ['dummy-module', 'dummy-function', 'test-limitation'],
382
                        ],
383
                        31
384
                    ),
385
                    32 => $this->createRole(
386
                        [
387
                            ['dummy-module', 'dummy-function', 'notfound'],
388
                        ],
389
                        32
390
                    ),
391
                ],
392
                [
393
                    new RoleAssignment(
394
                        [
395
                            'roleId' => 31,
396
                        ]
397
                    ),
398
                    new RoleAssignment(
399
                        [
400
                            'roleId' => 32,
401
                        ]
402
                    ),
403
                ],
404
            ],
405
        ];
406
    }
407
408
    /**
409
     * Test for the hasAccess() method.
410
     *
411
     * @dataProvider providerForTestHasAccessReturnsLimitationNotFoundException
412
     */
413
    public function testHasAccessReturnsLimitationNotFoundException(array $roles, array $roleAssignments)
414
    {
415
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\NotFound\LimitationNotFoundException::class);
416
417
        /** @var $userHandlerMock \PHPUnit\Framework\MockObject\MockObject */
418
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
419
        $roleDomainMapper = $this->getRoleDomainMapperMock();
420
        $permissionResolverMock = $this->getPermissionResolverMock(['getCurrentUserReference']);
421
422
        $permissionResolverMock
423
            ->expects($this->once())
424
            ->method('getCurrentUserReference')
425
            ->will($this->returnValue(new UserReference(14)));
426
427
        $userHandlerMock
428
            ->expects($this->once())
429
            ->method('loadRoleAssignmentsByGroupId')
430
            ->with($this->isType('integer'), $this->equalTo(true))
431
            ->will($this->returnValue($roleAssignments));
432
433
        foreach ($roleAssignments as $at => $roleAssignment) {
434
            $userHandlerMock
435
                ->expects($this->at($at + 1))
436
                ->method('loadRole')
437
                ->with($roleAssignment->roleId)
438
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
439
        }
440
441
        $count = 0;
442
        /* @var $roleAssignments \eZ\Publish\SPI\Persistence\User\RoleAssignment[] */
443
        foreach ($roleAssignments as $i => $roleAssignment) {
444
            $permissionSet = ['limitation' => null];
445
            foreach ($roles[$roleAssignment->roleId]->policies as $k => $policy) {
446
                $policyName = 'policy-' . $i . '-' . $k;
447
                if ($policy->limitations === 'notfound') {
448
                    $return = $this->throwException(new LimitationNotFoundException('notfound'));
449
                } else {
450
                    $return = $this->returnValue($policyName);
451
                    $permissionSet['policies'][] = $policyName;
452
                }
453
454
                $roleDomainMapper
455
                    ->expects($this->at($count++))
456
                    ->method('buildDomainPolicyObject')
457
                    ->with($policy)
458
                    ->will($return);
459
460
                if ($policy->limitations === 'notfound') {
461
                    break 2; // no more execution after exception
462
                }
463
            }
464
        }
465
466
        $permissionResolverMock->hasAccess('dummy-module', 'dummy-function');
467
    }
468
469
    /**
470
     * @return array
471
     */
472 View Code Duplication
    public function providerForTestHasAccessReturnsInvalidArgumentValueException()
473
    {
474
        return [
475
            [
476
                [
477
                    31 => $this->createRole(
478
                        [
479
                            ['test-module', 'test-function', '*'],
480
                        ],
481
                        31
482
                    ),
483
                ],
484
                [
485
                    new RoleAssignment(
486
                        [
487
                            'roleId' => 31,
488
                        ]
489
                    ),
490
                ],
491
            ],
492
            [
493
                [
494
                    31 => $this->createRole(
495
                        [
496
                            ['other-module', 'test-function', '*'],
497
                        ],
498
                        31
499
                    ),
500
                    32 => $this->createRole(
501
                        [
502
                            ['test-module', 'other-function', '*'],
503
                        ],
504
                        32
505
                    ),
506
                ],
507
                [
508
                    new RoleAssignment(
509
                        [
510
                            'roleId' => 31,
511
                        ]
512
                    ),
513
                    new RoleAssignment(
514
                        [
515
                            'roleId' => 32,
516
                        ]
517
                    ),
518
                ],
519
            ],
520
        ];
521
    }
522
523
    /**
524
     * Test for the hasAccess() method.
525
     *
526
     * @dataProvider providerForTestHasAccessReturnsInvalidArgumentValueException
527
     */
528
    public function testHasAccessReturnsInvalidArgumentValueException(array $roles, array $roleAssignments)
529
    {
530
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue::class);
531
532
        $permissionResolverMock = $this->getPermissionResolverMock(['getCurrentUserReference']);
533
534
        /** @var $role \eZ\Publish\SPI\Persistence\User\Role */
535
        foreach ($roles as $role) {
536
            /** @var $policy \eZ\Publish\SPI\Persistence\User\Policy */
537
            foreach ($role->policies as $policy) {
538
                $permissionResolverMock->hasAccess($policy->module, $policy->function);
539
            }
540
        }
541
    }
542
543
    public function providerForTestHasAccessReturnsPermissionSetsWithRoleLimitation()
544
    {
545
        return [
546
            [
547
                [
548
                    32 => $this->createRole(
549
                        [
550
                            [
551
                                'dummy-module', 'dummy-function', [
552
                                'Subtree' => [
553
                                    '/1/2/',
554
                                ],
555
                            ],
556
                            ],
557
                        ],
558
                        32
559
                    ),
560
                ],
561
                [
562
                    new RoleAssignment(
563
                        [
564
                            'roleId' => 32,
565
                            'limitationIdentifier' => 'Subtree',
566
                            'values' => ['/1/2/'],
567
                        ]
568
                    ),
569
                ],
570
            ],
571
            [
572
                [
573
                    33 => $this->createRole([['*', '*', '*']], 33),
574
                ],
575
                [
576
                    new RoleAssignment(
577
                        [
578
                            'roleId' => 33,
579
                            'limitationIdentifier' => 'Subtree',
580
                            'values' => ['/1/2/'],
581
                        ]
582
                    ),
583
                ],
584
            ],
585
        ];
586
    }
587
588
    /**
589
     * Test for the hasAccess() method.
590
     *
591
     * @dataProvider providerForTestHasAccessReturnsPermissionSetsWithRoleLimitation
592
     */
593
    public function testHasAccessReturnsPermissionSetsWithRoleLimitation(array $roles, array $roleAssignments)
594
    {
595
        /** @var $userHandlerMock \PHPUnit\Framework\MockObject\MockObject */
596
        $userHandlerMock = $this->getPersistenceMock()->userHandler();
597
        $limitationTypeMock = $this->createMock(Type::class);
598
        $limitationService = $this->getLimitationServiceMock();
599
        $roleDomainMapper = $this->getRoleDomainMapperMock();
600
        $permissionResolverMock = $this->getPermissionResolverMock(['getCurrentUserReference']);
601
602
        $permissionResolverMock
603
            ->expects($this->once())
604
            ->method('getCurrentUserReference')
605
            ->will($this->returnValue(new UserReference(14)));
606
607
        $userHandlerMock
608
            ->expects($this->once())
609
            ->method('loadRoleAssignmentsByGroupId')
610
            ->with($this->isType('integer'), $this->equalTo(true))
611
            ->will($this->returnValue($roleAssignments));
612
613
        foreach ($roleAssignments as $at => $roleAssignment) {
614
            $userHandlerMock
615
                ->expects($this->at($at + 1))
616
                ->method('loadRole')
617
                ->with($roleAssignment->roleId)
618
                ->will($this->returnValue($roles[$roleAssignment->roleId]));
619
        }
620
621
        $permissionSets = [];
622
        /** @var $roleAssignments \eZ\Publish\SPI\Persistence\User\RoleAssignment[] */
623
        foreach ($roleAssignments as $i => $roleAssignment) {
624
            $permissionSet = [];
625
            foreach ($roles[$roleAssignment->roleId]->policies as $k => $policy) {
626
                $policyName = "policy-{$i}-{$k}";
627
                $permissionSet['policies'][] = $policyName;
628
                $roleDomainMapper
629
                    ->expects($this->at($k))
630
                    ->method('buildDomainPolicyObject')
631
                    ->with($policy)
632
                    ->will($this->returnValue($policyName));
633
            }
634
635
            $permissionSet['limitation'] = "limitation-{$i}";
636
            $limitationTypeMock
637
                ->expects($this->at($i))
638
                ->method('buildValue')
639
                ->with($roleAssignment->values)
640
                ->will($this->returnValue($permissionSet['limitation']));
641
            $limitationService
642
                ->expects($this->any())
643
                ->method('getLimitationType')
644
                ->with($roleAssignment->limitationIdentifier)
645
                ->will($this->returnValue($limitationTypeMock));
646
647
            $permissionSets[] = $permissionSet;
648
        }
649
650
        self::assertEquals(
651
            $permissionSets,
652
            $permissionResolverMock->hasAccess('dummy-module', 'dummy-function')
653
        );
654
    }
655
656
    /**
657
     * Returns Role stub.
658
     *
659
     * @param array $policiesData
660
     * @param mixed $roleId
661
     *
662
     * @return \eZ\Publish\SPI\Persistence\User\Role
663
     */
664
    private function createRole(array $policiesData, $roleId = null)
665
    {
666
        $policies = [];
667
        foreach ($policiesData as $policyData) {
668
            $policies[] = new Policy(
669
                [
670
                    'module' => $policyData[0],
671
                    'function' => $policyData[1],
672
                    'limitations' => $policyData[2],
673
                ]
674
            );
675
        }
676
677
        return new Role(
678
            [
679
                'id' => $roleId,
680
                'policies' => $policies,
681
            ]
682
        );
683
    }
684
685 View Code Duplication
    public function providerForTestCanUserSimple()
686
    {
687
        return [
688
            [true, true],
689
            [false, false],
690
            [[], false],
691
        ];
692
    }
693
694
    /**
695
     * Test for the canUser() method.
696
     *
697
     * Tests execution paths with permission sets equaling to boolean value or empty array.
698
     *
699
     * @dataProvider providerForTestCanUserSimple
700
     */
701 View Code Duplication
    public function testCanUserSimple($permissionSets, $result)
702
    {
703
        $permissionResolverMock = $this->getPermissionResolverMock(['hasAccess']);
704
705
        $permissionResolverMock
706
            ->expects($this->once())
707
            ->method('hasAccess')
708
            ->with($this->equalTo('test-module'), $this->equalTo('test-function'))
709
            ->will($this->returnValue($permissionSets));
710
711
        /** @var $valueObject \eZ\Publish\API\Repository\Values\ValueObject */
712
        $valueObject = $this->getMockForAbstractClass(ValueObject::class);
713
714
        self::assertEquals(
715
            $result,
716
            $permissionResolverMock->canUser('test-module', 'test-function', $valueObject, [$valueObject])
717
        );
718
    }
719
720
    /**
721
     * Test for the canUser() method.
722
     *
723
     * Tests execution path with permission set defining no limitations.
724
     */
725
    public function testCanUserWithoutLimitations()
726
    {
727
        $permissionResolverMock = $this->getPermissionResolverMock(
728
            [
729
                'hasAccess',
730
                'getCurrentUserReference',
731
            ]
732
        );
733
734
        $policyMock = $this->getMockBuilder(Policy::class)
735
            ->setMethods(['getLimitations'])
736
            ->setConstructorArgs([])
737
            ->disableOriginalConstructor()
738
            ->getMock();
739
740
        $policyMock
741
            ->expects($this->once())
742
            ->method('getLimitations')
743
            ->will($this->returnValue('*'));
744
        $permissionSets = [
745
            [
746
                'limitation' => null,
747
                'policies' => [$policyMock],
748
            ],
749
        ];
750
        $permissionResolverMock
751
            ->expects($this->once())
752
            ->method('hasAccess')
753
            ->with($this->equalTo('test-module'), $this->equalTo('test-function'))
754
            ->will($this->returnValue($permissionSets));
755
756
        $permissionResolverMock
757
            ->expects($this->once())
758
            ->method('getCurrentUserReference')
759
            ->will($this->returnValue(new UserReference(14)));
760
761
        /** @var $valueObject \eZ\Publish\API\Repository\Values\ValueObject */
762
        $valueObject = $this->getMockForAbstractClass(ValueObject::class);
763
764
        self::assertTrue(
765
            $permissionResolverMock->canUser(
766
                'test-module',
767
                'test-function',
768
                $valueObject,
769
                [$valueObject]
770
            )
771
        );
772
    }
773
774
    /**
775
     * @return array
776
     */
777
    private function getPermissionSetsMock()
778
    {
779
        $roleLimitationMock = $this->createMock(Limitation::class);
780
        $roleLimitationMock
781
            ->expects($this->any())
782
            ->method('getIdentifier')
783
            ->will($this->returnValue('test-role-limitation-identifier'));
784
785
        $policyLimitationMock = $this->createMock(Limitation::class);
786
        $policyLimitationMock
787
            ->expects($this->any())
788
            ->method('getIdentifier')
789
            ->will($this->returnValue('test-policy-limitation-identifier'));
790
791
        $policyMock = $this->getMockBuilder(Policy::class)
792
            ->setMethods(['getLimitations'])
793
            ->setConstructorArgs([])
794
            ->getMock();
795
796
        $policyMock
797
            ->expects($this->any())
798
            ->method('getLimitations')
799
            ->will($this->returnValue([$policyLimitationMock, $policyLimitationMock]));
800
801
        $permissionSet = [
802
            'limitation' => clone $roleLimitationMock,
803
            'policies' => [$policyMock, $policyMock],
804
        ];
805
        $permissionSets = [$permissionSet, $permissionSet];
806
807
        return $permissionSets;
808
    }
809
810
    /**
811
     * Provides evaluation results for two permission sets, each with a role limitation and two policies,
812
     * with two limitations per policy.
813
     *
814
     * @return array
815
     */
816
    public function providerForTestCanUserComplex()
817
    {
818
        return [
819
            [
820
                [true, true],
821
                [
822
                    [
823
                        [true, true],
824
                        [true, true],
825
                    ],
826
                    [
827
                        [true, true],
828
                        [true, true],
829
                    ],
830
                ],
831
                true,
832
            ],
833
            [
834
                [false, false],
835
                [
836
                    [
837
                        [true, true],
838
                        [true, true],
839
                    ],
840
                    [
841
                        [true, true],
842
                        [true, true],
843
                    ],
844
                ],
845
                false,
846
            ],
847
            [
848
                [false, true],
849
                [
850
                    [
851
                        [true, true],
852
                        [true, true],
853
                    ],
854
                    [
855
                        [true, true],
856
                        [true, true],
857
                    ],
858
                ],
859
                true,
860
            ],
861
            [
862
                [false, true],
863
                [
864
                    [
865
                        [true, true],
866
                        [true, true],
867
                    ],
868
                    [
869
                        [true, false],
870
                        [true, true],
871
                    ],
872
                ],
873
                true,
874
            ],
875
            [
876
                [true, false],
877
                [
878
                    [
879
                        [true, false],
880
                        [false, true],
881
                    ],
882
                    [
883
                        [true, true],
884
                        [true, true],
885
                    ],
886
                ],
887
                false,
888
            ],
889
        ];
890
    }
891
892
    /**
893
     * Test for the canUser() method.
894
     *
895
     * Tests execution paths with permission sets containing limitations.
896
     *
897
     * @dataProvider providerForTestCanUserComplex
898
     */
899
    public function testCanUserComplex(array $roleLimitationEvaluations, array $policyLimitationEvaluations, $userCan)
900
    {
901
        /** @var $valueObject \eZ\Publish\API\Repository\Values\ValueObject */
902
        $valueObject = $this->createMock(ValueObject::class);
903
        $limitationServiceMock = $this->getLimitationServiceMock();
904
        $permissionResolverMock = $this->getPermissionResolverMock(
905
            [
906
                'hasAccess',
907
                'getCurrentUserReference',
908
            ]
909
        );
910
911
        $permissionSets = $this->getPermissionSetsMock();
912
        $permissionResolverMock
913
            ->expects($this->once())
914
            ->method('hasAccess')
915
            ->with($this->equalTo('test-module'), $this->equalTo('test-function'))
916
            ->will($this->returnValue($permissionSets));
917
918
        $userRef = new UserReference(14);
919
        $permissionResolverMock
920
            ->expects($this->once())
921
            ->method('getCurrentUserReference')
922
            ->will($this->returnValue(new UserReference(14)));
923
924
        $invocation = 0;
925
        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...
926
            $limitation = $this->createMock(Type::class);
927
            $limitation
928
                ->expects($this->once())
929
                ->method('evaluate')
930
                ->with($permissionSets[$i]['limitation'], $userRef, $valueObject, [$valueObject])
931
                ->will($this->returnValue($roleLimitationEvaluations[$i]));
932
            $limitationServiceMock
933
                ->expects($this->at($invocation++))
934
                ->method('getLimitationType')
935
                ->with('test-role-limitation-identifier')
936
                ->will($this->returnValue($limitation));
937
938
            if (!$roleLimitationEvaluations[$i]) {
939
                continue;
940
            }
941
942
            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...
943
                /** @var $policy \eZ\Publish\API\Repository\Values\User\Policy */
944
                $policy = $permissionSets[$i]['policies'][$j];
945
                $limitations = $policy->getLimitations();
946
                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...
947
                    $limitationsPass = true;
948
                    $limitation = $this->createMock(Type::class);
949
                    $limitation
950
                        ->expects($this->once())
951
                        ->method('evaluate')
952
                        ->with($limitations[$k], $userRef, $valueObject, [$valueObject])
953
                        ->will($this->returnValue($policyLimitationEvaluations[$i][$j][$k]));
954
                    $limitationServiceMock
955
                        ->expects($this->at($invocation++))
956
                        ->method('getLimitationType')
957
                        ->with('test-policy-limitation-identifier')
958
                        ->will($this->returnValue($limitation));
959
960
                    if (!$policyLimitationEvaluations[$i][$j][$k]) {
961
                        $limitationsPass = false;
962
                        break;
963
                    }
964
                }
965
966
                /** @var $limitationsPass */
967
                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...
968
                    break 2;
969
                }
970
            }
971
        }
972
973
        self::assertEquals(
974
            $userCan,
975
            $permissionResolverMock->canUser(
976
                'test-module',
977
                'test-function',
978
                $valueObject,
979
                [$valueObject]
980
            )
981
        );
982
    }
983
984
    /**
985
     * Test for the setCurrentUserReference() and getCurrentUserReference() methods.
986
     */
987
    public function testSetAndGetCurrentUserReference()
988
    {
989
        $permissionResolverMock = $this->getPermissionResolverMock(null);
990
        $userReferenceMock = $this->getUserReferenceMock();
991
992
        $userReferenceMock
993
            ->expects($this->once())
994
            ->method('getUserId')
995
            ->will($this->returnValue(42));
996
997
        $permissionResolverMock->setCurrentUserReference($userReferenceMock);
998
999
        self::assertSame(
1000
            $userReferenceMock,
1001
            $permissionResolverMock->getCurrentUserReference()
1002
        );
1003
    }
1004
1005
    /**
1006
     * Test for the getCurrentUserReference() method.
1007
     */
1008
    public function testGetCurrentUserReferenceReturnsAnonymousUser()
1009
    {
1010
        $permissionResolverMock = $this->getPermissionResolverMock(null);
1011
        $userReferenceMock = $this->getUserReferenceMock();
1012
1013
        self::assertSame(
1014
            $userReferenceMock,
1015
            $permissionResolverMock->getCurrentUserReference()
1016
        );
1017
    }
1018
1019
    protected $permissionResolverMock;
1020
1021
    /**
1022
     * @return \eZ\Publish\API\Repository\PermissionResolver|\PHPUnit\Framework\MockObject\MockObject
1023
     */
1024
    protected function getPermissionResolverMock($methods = [])
1025
    {
1026
        if ($this->permissionResolverMock === null) {
1027
            $this->permissionResolverMock = $this
1028
                ->getMockBuilder(PermissionResolver::class)
1029
                ->setMethods($methods)
1030
                ->setConstructorArgs(
1031
                    [
1032
                        $this->getRoleDomainMapperMock(),
1033
                        $this->getLimitationServiceMock(),
1034
                        $this->getPersistenceMock()->userHandler(),
1035
                        $this->getUserReferenceMock(),
1036
                        [
1037
                            'dummy-module' => [
1038
                                'dummy-function' => [
1039
                                    'dummy-limitation' => true,
1040
                                ],
1041
                                'dummy-function2' => [
1042
                                    'dummy-limitation' => true,
1043
                                ],
1044
                            ],
1045
                            'dummy-module2' => [
1046
                                'dummy-function' => [
1047
                                    'dummy-limitation' => true,
1048
                                ],
1049
                                'dummy-function2' => [
1050
                                    'dummy-limitation' => true,
1051
                                ],
1052
                            ],
1053
                        ],
1054
                    ]
1055
                )
1056
                ->getMock();
1057
        }
1058
1059
        return $this->permissionResolverMock;
1060
    }
1061
1062
    protected $userReferenceMock;
1063
1064
    protected function getUserReferenceMock()
1065
    {
1066
        if ($this->userReferenceMock === null) {
1067
            $this->userReferenceMock = $this->createMock(UserReference::class);
1068
        }
1069
1070
        return $this->userReferenceMock;
1071
    }
1072
1073
    protected $repositoryMock;
1074
1075
    /**
1076
     * @return \eZ\Publish\API\Repository\Repository|\PHPUnit\Framework\MockObject\MockObject
1077
     */
1078
    protected function getRepositoryMock($methods = [])
1079
    {
1080
        if ($this->repositoryMock === null) {
1081
            $this->repositoryMock = $this
1082
                ->getMockBuilder(CoreRepository::class)
1083
                ->setMethods(['getPermissionResolver'])
1084
                ->disableOriginalConstructor()
1085
                ->getMock();
1086
        }
1087
1088
        return $this->repositoryMock;
1089
    }
1090
1091
    protected $roleDomainMapperMock;
1092
1093
    /**
1094
     * @return \eZ\Publish\Core\Repository\Helper\RoleDomainMapper|\PHPUnit\Framework\MockObject\MockObject
1095
     */
1096 View Code Duplication
    protected function getRoleDomainMapperMock($methods = [])
1097
    {
1098
        if ($this->roleDomainMapperMock === null) {
1099
            $this->roleDomainMapperMock = $this
1100
                ->getMockBuilder(RoleDomainMapper::class)
1101
                ->setMethods($methods)
1102
                ->disableOriginalConstructor()
1103
                ->getMock();
1104
        }
1105
1106
        return $this->roleDomainMapperMock;
1107
    }
1108
}
1109