2424use CodeIgniter \Test \Mock \MockSecurity ;
2525use Config \Security as SecurityConfig ;
2626use PHPUnit \Framework \Attributes \BackupGlobals ;
27+ use PHPUnit \Framework \Attributes \DataProvider ;
2728use PHPUnit \Framework \Attributes \Group ;
2829
2930/**
@@ -42,13 +43,23 @@ protected function setUp(): void
4243 $ this ->resetServices ();
4344 }
4445
45- private function createMockSecurity (? SecurityConfig $ config = null ): MockSecurity
46+ private static function createMockSecurity (SecurityConfig $ config = new SecurityConfig () ): MockSecurity
4647 {
47- $ config ??= new SecurityConfig ();
48-
4948 return new MockSecurity ($ config );
5049 }
5150
51+ private static function createIncomingRequest (): IncomingRequest
52+ {
53+ $ config = new MockAppConfig ();
54+
55+ return new IncomingRequest (
56+ $ config ,
57+ new SiteURI ($ config ),
58+ null ,
59+ new UserAgent (),
60+ );
61+ }
62+
5263 public function testBasicConfigIsSaved (): void
5364 {
5465 $ security = $ this ->createMockSecurity ();
@@ -108,18 +119,6 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void
108119 $ security ->verify ($ request );
109120 }
110121
111- private function createIncomingRequest (): IncomingRequest
112- {
113- $ config = new MockAppConfig ();
114-
115- return new IncomingRequest (
116- $ config ,
117- new SiteURI ($ config ),
118- null ,
119- new UserAgent (),
120- );
121- }
122-
123122 public function testCSRFVerifyPostReturnsSelfOnMatch (): void
124123 {
125124 $ _SERVER ['REQUEST_METHOD ' ] = 'POST ' ;
@@ -315,4 +314,73 @@ public function testGetters(): void
315314 $ this ->assertIsString ($ security ->getCookieName ());
316315 $ this ->assertIsBool ($ security ->shouldRedirect ());
317316 }
317+
318+ public function testGetPostedTokenReturnsTokenFromPost (): void
319+ {
320+ $ _POST ['csrf_test_name ' ] = '8b9218a55906f9dcc1dc263dce7f005a ' ;
321+ $ request = $ this ->createIncomingRequest ();
322+ $ method = $ this ->getPrivateMethodInvoker ($ this ->createMockSecurity (), 'getPostedToken ' );
323+
324+ $ this ->assertSame ('8b9218a55906f9dcc1dc263dce7f005a ' , $ method ($ request ));
325+ }
326+
327+ public function testGetPostedTokenReturnsTokenFromHeader (): void
328+ {
329+ $ _POST = [];
330+ $ request = $ this ->createIncomingRequest ()->setHeader ('X-CSRF-TOKEN ' , '8b9218a55906f9dcc1dc263dce7f005a ' );
331+ $ method = $ this ->getPrivateMethodInvoker ($ this ->createMockSecurity (), 'getPostedToken ' );
332+
333+ $ this ->assertSame ('8b9218a55906f9dcc1dc263dce7f005a ' , $ method ($ request ));
334+ }
335+
336+ public function testGetPostedTokenReturnsTokenFromJsonBody (): void
337+ {
338+ $ _POST = [];
339+ $ jsonBody = json_encode (['csrf_test_name ' => '8b9218a55906f9dcc1dc263dce7f005a ' ]);
340+ $ request = $ this ->createIncomingRequest ()->setBody ($ jsonBody );
341+ $ method = $ this ->getPrivateMethodInvoker ($ this ->createMockSecurity (), 'getPostedToken ' );
342+
343+ $ this ->assertSame ('8b9218a55906f9dcc1dc263dce7f005a ' , $ method ($ request ));
344+ }
345+
346+ public function testGetPostedTokenReturnsTokenFromFormBody (): void
347+ {
348+ $ _POST = [];
349+ $ formBody = 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a ' ;
350+ $ request = $ this ->createIncomingRequest ()->setBody ($ formBody );
351+ $ method = $ this ->getPrivateMethodInvoker ($ this ->createMockSecurity (), 'getPostedToken ' );
352+
353+ $ this ->assertSame ('8b9218a55906f9dcc1dc263dce7f005a ' , $ method ($ request ));
354+ }
355+
356+ #[DataProvider('provideGetPostedTokenReturnsNullForInvalidInputs ' )]
357+ public function testGetPostedTokenReturnsNullForInvalidInputs (string $ case , IncomingRequest $ request ): void
358+ {
359+ $ method = $ this ->getPrivateMethodInvoker ($ this ->createMockSecurity (), 'getPostedToken ' );
360+
361+ $ this ->assertNull (
362+ $ method ($ request ),
363+ sprintf ('Failed asserting that %s returns null on invalid input. ' , $ case ),
364+ );
365+ }
366+
367+ /**
368+ * @return iterable<string, array{string, IncomingRequest}>
369+ */
370+ public static function provideGetPostedTokenReturnsNullForInvalidInputs (): iterable
371+ {
372+ $ testCases = [
373+ 'empty_post ' => self ::createIncomingRequest (),
374+ 'invalid_post_data ' => self ::createIncomingRequest ()->setGlobal ('post ' , ['csrf_test_name ' => ['invalid ' => 'data ' ]]),
375+ 'empty_header ' => self ::createIncomingRequest ()->setHeader ('X-CSRF-TOKEN ' , '' ),
376+ 'invalid_json_data ' => self ::createIncomingRequest ()->setBody (json_encode (['csrf_test_name ' => ['invalid ' => 'data ' ]])),
377+ 'invalid_json ' => self ::createIncomingRequest ()->setBody ('{invalid json} ' ),
378+ 'missing_token_in_body ' => self ::createIncomingRequest ()->setBody ('other=value&another=test ' ),
379+ 'invalid_form_data ' => self ::createIncomingRequest ()->setBody ('csrf_test_name[]=invalid ' ),
380+ ];
381+
382+ foreach ($ testCases as $ case => $ request ) {
383+ yield $ case => [$ case , $ request ];
384+ }
385+ }
318386}
0 commit comments