1515use Symfony \Bridge \PhpUnit \ClassExistsMock ;
1616use Symfony \Bridge \Twig \Extension \SecurityExtension ;
1717use Symfony \Component \Security \Acl \Voter \FieldVote ;
18+ use Symfony \Component \Security \Core \Authorization \AccessDecision ;
1819use Symfony \Component \Security \Core \Authorization \AuthorizationCheckerInterface ;
1920use Symfony \Component \Security \Core \Authorization \UserAuthorizationCheckerInterface ;
2021use Symfony \Component \Security \Core \User \UserInterface ;
2122
2223class SecurityExtensionTest extends TestCase
2324{
25+ public static function setUpBeforeClass (): void
26+ {
27+ ClassExistsMock::register (SecurityExtension::class);
28+ }
29+
30+ protected function tearDown (): void
31+ {
32+ ClassExistsMock::withMockedClasses ([FieldVote::class => true ]);
33+ }
34+
2435 /**
2536 * @dataProvider provideObjectFieldAclCases
2637 */
@@ -39,17 +50,16 @@ public function testIsGrantedCreatesFieldVoteObjectWhenFieldNotNull($object, $fi
3950
4051 public function testIsGrantedThrowsWhenFieldNotNullAndFieldVoteClassDoesNotExist ()
4152 {
42- if (!class_exists (UserAuthorizationCheckerInterface::class)) {
53+ if (!interface_exists (UserAuthorizationCheckerInterface::class)) {
4354 $ this ->markTestSkipped ('This test requires symfony/security-core 7.3 or superior. ' );
4455 }
4556
4657 $ securityChecker = $ this ->createMock (AuthorizationCheckerInterface::class);
4758
48- ClassExistsMock::register (SecurityExtension::class);
4959 ClassExistsMock::withMockedClasses ([FieldVote::class => false ]);
5060
5161 $ this ->expectException (\LogicException::class);
52- $ this ->expectExceptionMessageMatches ('Passing a $field to the "is_granted()" function requires symfony/acl. ' );
62+ $ this ->expectExceptionMessage ('Passing a $field to the "is_granted()" function requires symfony/acl. ' );
5363
5464 $ securityExtension = new SecurityExtension ($ securityChecker );
5565 $ securityExtension ->isGranted ('ROLE ' , 'object ' , 'bar ' );
@@ -60,49 +70,74 @@ public function testIsGrantedThrowsWhenFieldNotNullAndFieldVoteClassDoesNotExist
6070 */
6171 public function testIsGrantedForUserCreatesFieldVoteObjectWhenFieldNotNull ($ object , $ field , $ expectedSubject )
6272 {
63- if (!class_exists (UserAuthorizationCheckerInterface::class)) {
73+ if (!interface_exists (UserAuthorizationCheckerInterface::class)) {
6474 $ this ->markTestSkipped ('This test requires symfony/security-core 7.3 or superior. ' );
6575 }
6676
6777 $ user = $ this ->createMock (UserInterface::class);
68- $ userSecurityChecker = $ this ->createMock (UserAuthorizationCheckerInterface::class);
69- $ userSecurityChecker
70- ->expects ($ this ->once ())
71- ->method ('isGrantedForUser ' )
72- ->with ($ user , 'ROLE ' , $ expectedSubject )
73- ->willReturn (true );
78+ $ securityChecker = $ this ->createMockAuthorizationChecker ();
7479
75- $ securityExtension = new SecurityExtension (null , null , $ userSecurityChecker );
80+ $ securityExtension = new SecurityExtension ($ securityChecker );
7681 $ this ->assertTrue ($ securityExtension ->isGrantedForUser ($ user , 'ROLE ' , $ object , $ field ));
82+ $ this ->assertSame ($ user , $ securityChecker ->user );
83+ $ this ->assertSame ('ROLE ' , $ securityChecker ->attribute );
84+
85+ if (null === $ field ) {
86+ $ this ->assertSame ($ object , $ securityChecker ->subject );
87+ } else {
88+ $ this ->assertEquals ($ expectedSubject , $ securityChecker ->subject );
89+ }
90+ }
91+
92+ public static function provideObjectFieldAclCases ()
93+ {
94+ return [
95+ [null , null , null ],
96+ ['object ' , null , 'object ' ],
97+ ['object ' , false , new FieldVote ('object ' , false )],
98+ ['object ' , 0 , new FieldVote ('object ' , 0 )],
99+ ['object ' , '' , new FieldVote ('object ' , '' )],
100+ ['object ' , 'field ' , new FieldVote ('object ' , 'field ' )],
101+ ];
77102 }
78103
79104 public function testIsGrantedForUserThrowsWhenFieldNotNullAndFieldVoteClassDoesNotExist ()
80105 {
81- if (!class_exists (UserAuthorizationCheckerInterface::class)) {
106+ if (!interface_exists (UserAuthorizationCheckerInterface::class)) {
82107 $ this ->markTestSkipped ('This test requires symfony/security-core 7.3 or superior. ' );
83108 }
84109
85- $ securityChecker = $ this ->createMock (UserAuthorizationCheckerInterface::class );
110+ $ securityChecker = $ this ->createMockAuthorizationChecker ( );
86111
87- ClassExistsMock::register (SecurityExtension::class);
88112 ClassExistsMock::withMockedClasses ([FieldVote::class => false ]);
89113
90114 $ this ->expectException (\LogicException::class);
91- $ this ->expectExceptionMessageMatches ('Passing a $field to the "is_granted_for_user()" function requires symfony/acl. ' );
115+ $ this ->expectExceptionMessage ('Passing a $field to the "is_granted_for_user()" function requires symfony/acl. ' );
92116
93- $ securityExtension = new SecurityExtension (null , null , $ securityChecker );
94- $ securityExtension ->isGrantedForUser ($ this ->createMock (UserInterface::class), 'object ' , 'bar ' );
117+ $ securityExtension = new SecurityExtension ($ securityChecker );
118+ $ securityExtension ->isGrantedForUser ($ this ->createMock (UserInterface::class), 'ROLE ' , ' object ' , 'bar ' );
95119 }
96120
97- public static function provideObjectFieldAclCases ()
121+ private function createMockAuthorizationChecker (): AuthorizationCheckerInterface & UserAuthorizationCheckerInterface
98122 {
99- return [
100- [null , null , null ],
101- ['object ' , null , 'object ' ],
102- ['object ' , false , new FieldVote ('object ' , false )],
103- ['object ' , 0 , new FieldVote ('object ' , 0 )],
104- ['object ' , '' , new FieldVote ('object ' , '' )],
105- ['object ' , 'field ' , new FieldVote ('object ' , 'field ' )],
106- ];
123+ return new class implements AuthorizationCheckerInterface, UserAuthorizationCheckerInterface {
124+ public UserInterface $ user ;
125+ public mixed $ attribute ;
126+ public mixed $ subject ;
127+
128+ public function isGranted (mixed $ attribute , mixed $ subject = null , ?AccessDecision $ accessDecision = null ): bool
129+ {
130+ throw new \BadMethodCallException ('This method should not be called. ' );
131+ }
132+
133+ public function isGrantedForUser (UserInterface $ user , mixed $ attribute , mixed $ subject = null , ?AccessDecision $ accessDecision = null ): bool
134+ {
135+ $ this ->user = $ user ;
136+ $ this ->attribute = $ attribute ;
137+ $ this ->subject = $ subject ;
138+
139+ return true ;
140+ }
141+ };
107142 }
108143}
0 commit comments