From 66e9fe1d53b9e992ebc043019e41dc96ba576e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=B6ller?= Date: Tue, 7 Feb 2023 19:16:06 +0100 Subject: [PATCH] Fix: Split and clean up tests --- .../SecurityDataCollectorTest.php | 206 +++++++++++------- 1 file changed, 124 insertions(+), 82 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php index 231f8c133702f..b092b8a18d0e6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php @@ -33,6 +33,7 @@ use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Http\FirewallMapInterface; use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator; +use Symfony\Component\VarDumper\Caster\ClassStub; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SecurityDataCollectorTest extends TestCase @@ -223,22 +224,36 @@ public function testGetListeners() $this->assertSame(1, $listenerCalled); } - public static function providerCollectDecisionLog(): \Generator + public function testCollectCollectsDecisionLogWhenStrategyIsAffirmative() { $voter1 = new DummyVoter(); $voter2 = new DummyVoter(); - $eventDispatcher = new class() implements EventDispatcherInterface { + $decoratedVoter1 = new TraceableVoter($voter1, new class() implements EventDispatcherInterface { public function dispatch(object $event, string $eventName = null): object { return new \stdClass(); } - }; - $decoratedVoter1 = new TraceableVoter($voter1, $eventDispatcher); + }); + + $strategy = MainConfiguration::STRATEGY_AFFIRMATIVE; + + $accessDecisionManager = $this->createMock(TraceableAccessDecisionManager::class); + + $accessDecisionManager + ->method('getStrategy') + ->willReturn($strategy); - yield [ - MainConfiguration::STRATEGY_AFFIRMATIVE, - [[ + $accessDecisionManager + ->method('getVoters') + ->willReturn([ + $decoratedVoter1, + $decoratedVoter1, + ]); + + $accessDecisionManager + ->method('getDecisionLog') + ->willReturn([[ 'attributes' => ['view'], 'object' => new \stdClass(), 'result' => true, @@ -246,23 +261,74 @@ public function dispatch(object $event, string $eventName = null): object ['voter' => $voter1, 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_ABSTAIN], ['voter' => $voter2, 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_ABSTAIN], ], - ]], - [$decoratedVoter1, $decoratedVoter1], - [\get_class($voter1), \get_class($voter2)], - [[ - 'attributes' => ['view'], - 'object' => new \stdClass(), - 'result' => true, - 'voter_details' => [ - ['class' => \get_class($voter1), 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_ABSTAIN], - ['class' => \get_class($voter2), 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_ABSTAIN], - ], - ]], + ]]); + + $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null, true); + + $dataCollector->collect(new Request(), new Response()); + + $actualDecisionLog = $dataCollector->getAccessDecisionLog(); + + $expectedDecisionLog = [[ + 'attributes' => ['view'], + 'object' => new \stdClass(), + 'result' => true, + 'voter_details' => [ + ['class' => \get_class($voter1), 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_ABSTAIN], + ['class' => \get_class($voter2), 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_ABSTAIN], + ], + ]]; + + $this->assertEquals($actualDecisionLog, $expectedDecisionLog, 'Wrong value returned by getAccessDecisionLog'); + + $actualVoterClasses = array_map(static function (ClassStub $classStub): string { + return (string) $classStub; + }, $dataCollector->getVoters()); + + $expectedVoterClasses = [ + \get_class($voter1), + \get_class($voter2), ]; - yield [ - MainConfiguration::STRATEGY_UNANIMOUS, - [ + $this->assertSame( + $actualVoterClasses, + $expectedVoterClasses, + 'Wrong value returned by getVoters' + ); + + $this->assertSame($dataCollector->getVoterStrategy(), $strategy, 'Wrong value returned by getVoterStrategy'); + } + + public function testCollectCollectsDecisionLogWhenStrategyIsUnanimous() + { + $voter1 = new DummyVoter(); + $voter2 = new DummyVoter(); + + $decoratedVoter1 = new TraceableVoter($voter1, new class() implements EventDispatcherInterface { + public function dispatch(object $event, string $eventName = null): object + { + return new \stdClass(); + } + }); + + $strategy = MainConfiguration::STRATEGY_UNANIMOUS; + + $accessDecisionManager = $this->createMock(TraceableAccessDecisionManager::class); + + $accessDecisionManager + ->method('getStrategy') + ->willReturn($strategy); + + $accessDecisionManager + ->method('getVoters') + ->willReturn([ + $decoratedVoter1, + $decoratedVoter1, + ]); + + $accessDecisionManager + ->method('getDecisionLog') + ->willReturn([ [ 'attributes' => ['view', 'edit'], 'object' => new \stdClass(), @@ -283,78 +349,54 @@ public function dispatch(object $event, string $eventName = null): object ['voter' => $voter2, 'attributes' => ['update'], 'vote' => VoterInterface::ACCESS_GRANTED], ], ], - ], - [$decoratedVoter1, $decoratedVoter1], - [\get_class($voter1), \get_class($voter2)], + ]); + + $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null, true); + + $dataCollector->collect(new Request(), new Response()); + + $actualDecisionLog = $dataCollector->getAccessDecisionLog(); + + $expectedDecisionLog = [ [ - [ - 'attributes' => ['view', 'edit'], - 'object' => new \stdClass(), - 'result' => false, - 'voter_details' => [ - ['class' => \get_class($voter1), 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_DENIED], - ['class' => \get_class($voter1), 'attributes' => ['edit'], 'vote' => VoterInterface::ACCESS_DENIED], - ['class' => \get_class($voter2), 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_GRANTED], - ['class' => \get_class($voter2), 'attributes' => ['edit'], 'vote' => VoterInterface::ACCESS_GRANTED], - ], + 'attributes' => ['view', 'edit'], + 'object' => new \stdClass(), + 'result' => false, + 'voter_details' => [ + ['class' => \get_class($voter1), 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_DENIED], + ['class' => \get_class($voter1), 'attributes' => ['edit'], 'vote' => VoterInterface::ACCESS_DENIED], + ['class' => \get_class($voter2), 'attributes' => ['view'], 'vote' => VoterInterface::ACCESS_GRANTED], + ['class' => \get_class($voter2), 'attributes' => ['edit'], 'vote' => VoterInterface::ACCESS_GRANTED], ], - [ - 'attributes' => ['update'], - 'object' => new \stdClass(), - 'result' => true, - 'voter_details' => [ - ['class' => \get_class($voter1), 'attributes' => ['update'], 'vote' => VoterInterface::ACCESS_GRANTED], - ['class' => \get_class($voter2), 'attributes' => ['update'], 'vote' => VoterInterface::ACCESS_GRANTED], - ], + ], + [ + 'attributes' => ['update'], + 'object' => new \stdClass(), + 'result' => true, + 'voter_details' => [ + ['class' => \get_class($voter1), 'attributes' => ['update'], 'vote' => VoterInterface::ACCESS_GRANTED], + ['class' => \get_class($voter2), 'attributes' => ['update'], 'vote' => VoterInterface::ACCESS_GRANTED], ], ], ]; - } - /** - * Test the returned data when AccessDecisionManager is a TraceableAccessDecisionManager. - * - * @param string $strategy strategy returned by the AccessDecisionManager - * @param array $voters voters returned by AccessDecisionManager - * @param array $decisionLog log of the votes and final decisions from AccessDecisionManager - * @param array $expectedVoterClasses expected voter classes returned by the collector - * @param array $expectedDecisionLog expected decision log returned by the collector - * - * @dataProvider providerCollectDecisionLog - */ - public function testCollectDecisionLog(string $strategy, array $decisionLog, array $voters, array $expectedVoterClasses, array $expectedDecisionLog) - { - $accessDecisionManager = $this - ->getMockBuilder(TraceableAccessDecisionManager::class) - ->disableOriginalConstructor() - ->setMethods(['getStrategy', 'getVoters', 'getDecisionLog']) - ->getMock(); + $this->assertEquals($actualDecisionLog, $expectedDecisionLog, 'Wrong value returned by getAccessDecisionLog'); - $accessDecisionManager - ->expects($this->any()) - ->method('getStrategy') - ->willReturn($strategy); + $actualVoterClasses = array_map(static function (ClassStub $classStub): string { + return (string) $classStub; + }, $dataCollector->getVoters()); - $accessDecisionManager - ->expects($this->any()) - ->method('getVoters') - ->willReturn($voters); - - $accessDecisionManager - ->expects($this->any()) - ->method('getDecisionLog') - ->willReturn($decisionLog); - - $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null, true); - $dataCollector->collect(new Request(), new Response()); - - $this->assertEquals($dataCollector->getAccessDecisionLog(), $expectedDecisionLog, 'Wrong value returned by getAccessDecisionLog'); + $expectedVoterClasses = [ + \get_class($voter1), + \get_class($voter2), + ]; $this->assertSame( - array_map(function ($classStub) { return (string) $classStub; }, $dataCollector->getVoters()), + $actualVoterClasses, $expectedVoterClasses, 'Wrong value returned by getVoters' ); + $this->assertSame($dataCollector->getVoterStrategy(), $strategy, 'Wrong value returned by getVoterStrategy'); } @@ -390,7 +432,7 @@ private function getRoleHierarchy() } } -class DummyVoter implements VoterInterface +final class DummyVoter implements VoterInterface { public function vote(TokenInterface $token, $subject, array $attributes) {