From 791acd81f14e5578b485bd6f3635663f1188d350 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 10 Aug 2025 10:54:52 -0400 Subject: [PATCH 1/7] refactor(tests): Move cookie-related tests from `ServerRequestAdapterTest` to new `CookiesPsr7Test` class for better organization and clarity. --- tests/adapter/CookiesPsr7Test.php | 531 +++++++++++++++++++++ tests/adapter/ServerRequestAdapterTest.php | 516 +------------------- 2 files changed, 533 insertions(+), 514 deletions(-) create mode 100644 tests/adapter/CookiesPsr7Test.php diff --git a/tests/adapter/CookiesPsr7Test.php b/tests/adapter/CookiesPsr7Test.php new file mode 100644 index 00000000..950ce101 --- /dev/null +++ b/tests/adapter/CookiesPsr7Test.php @@ -0,0 +1,531 @@ +withCookieParams(['reset_cookie' => 'test_value']); + + $request = new Request(); + + $request->enableCookieValidation = false; + $request->cookieValidationKey = 'test-validation-key-32-characters'; + + $request->setPsr7Request($psr7Request); + + $cookies1 = $request->getCookies(); + $request->reset(); + + $newPsr7Request = FactoryHelper::createRequest('GET', '/test'); + + $newPsr7Request = $newPsr7Request->withCookieParams(['new_cookie' => 'new_value']); + + $request->setPsr7Request($newPsr7Request); + + $cookies2 = $request->getCookies(); + + self::assertNotSame( + $cookies1, + $cookies2, + "After 'reset' method, 'getCookies()' should return a new CookieCollection instance.", + ); + self::assertTrue( + $cookies2->has('new_cookie'), + "New CookieCollection should contain 'new_cookie' after 'reset' method.", + ); + self::assertSame( + 'new_value', + $cookies2->getValue('new_cookie'), + "New cookie 'new_cookie' should have the expected value after 'reset' method.", + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnCookieCollectionWhenCookiesPresent(): void + { + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams( + [ + 'session_id' => 'abc123', + 'theme' => 'dark', + 'empty_cookie' => '', + ], + ); + + $request = new Request(); + + $request->enableCookieValidation = false; + $request->cookieValidationKey = 'test-validation-key-32-characters'; + + $request->setPsr7Request($psr7Request); + + $cookies = $request->getCookies(); + + self::assertCount( + 2, + $cookies, + "CookieCollection should contain '2' cookies when empty cookies are filtered out.", + ); + self::assertTrue( + $cookies->has('session_id'), + "CookieCollection should contain 'session_id' cookie.", + ); + self::assertSame( + 'abc123', + $cookies->getValue('session_id'), + "Cookie 'session_id' should have the expected value from the PSR-7 request.", + ); + self::assertTrue( + $cookies->has('theme'), + "CookieCollection should contain 'theme' cookie.", + ); + self::assertSame( + 'dark', + $cookies->getValue('theme'), + "Cookie 'theme' should have the expected value from the PSR-7 request.", + ); + self::assertFalse( + $cookies->has('empty_cookie'), + 'CookieCollection should not contain empty cookies.', + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnCookieCollectionWhenNoCookiesPresent(): void + { + $request = new Request(); + + $request->enableCookieValidation = false; + $request->cookieValidationKey = 'test-validation-key-32-characters'; + + $request->setPsr7Request( + FactoryHelper::createRequest('GET', '/test'), + ); + + self::assertCount( + 0, + $request->getCookies(), + 'CookieCollection should be empty when no cookies are present in the PSR-7 request.', + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnCookieCollectionWithValidationDisabled(): void + { + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams( + [ + 'user_id' => '42', + 'preferences' => 'compact', + ], + ); + + $request = new Request(); + + $request->enableCookieValidation = false; + $request->cookieValidationKey = 'test-validation-key-32-characters'; + + $request->setPsr7Request($psr7Request); + + $cookies = $request->getCookies(); + + self::assertCount( + 2, + $cookies, + 'CookieCollection should contain all non-empty cookies when validation is disabled.', + ); + self::assertTrue( + $cookies->has('user_id'), + "CookieCollection should contain 'user_id' cookie when validation is disabled.", + ); + self::assertSame( + '42', + $cookies->getValue('user_id'), + "Cookie 'user_id' should have the expected value when validation is disabled.", + ); + self::assertTrue( + $cookies->has('preferences'), + "CookieCollection should contain 'preferences' cookie when validation is disabled.", + ); + self::assertSame( + 'compact', + $cookies->getValue('preferences'), + "Cookie 'preferences' should have the expected value when validation is disabled.", + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnCookieWithCorrectNamePropertyWhenAdapterIsSet(): void + { + $cookieName = 'session_id'; + $cookieValue = 'abc123'; + + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams([$cookieName => $cookieValue]); + + $request = new Request(); + + $request->enableCookieValidation = false; + $request->cookieValidationKey = 'test-validation-key-32-characters'; + + $request->setPsr7Request($psr7Request); + + $cookies = $request->getCookies(); + + $cookie = $cookies[$cookieName] ?? null; + + if ($cookie === null) { + foreach ($cookies as $cookieObj) { + if ($cookieObj->value === $cookieValue) { + $cookie = $cookieObj; + break; + } + } + } + + self::assertNotNull( + $cookie, + 'Cookie should be found in the collection.', + ); + self::assertInstanceOf( + Cookie::class, + $cookie, + 'Should be a Cookie instance.', + ); + self::assertSame( + $cookieName, + $cookie->name, + "Cookie 'name' property should match the original cookie 'name' from PSR-7 request.", + ); + self::assertSame( + $cookieValue, + $cookie->value, + "Cookie 'value' property should match the original cookie 'value' from PSR-7 request.", + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnEmptyCookieCollectionWhenValidationEnabledWithInvalidCookies(): void + { + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams( + [ + 'invalid_cookie' => 'invalid_data', + 'empty_cookie' => '', + ], + ); + + $request = new Request(); + + $request->enableCookieValidation = true; + $request->cookieValidationKey = 'test-validation-key-32-characters'; + + $request->setPsr7Request($psr7Request); + + self::assertCount( + 0, + $request->getCookies(), + 'CookieCollection should be empty when validation is enabled but cookies are invalid.', + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMultipleValidCookies(): void + { + $validationKey = 'test-validation-key-32-characters'; + + $cookies = [ + 'session_id' => 'session_value_123', + 'user_pref' => 'preference_value_456', + 'theme' => 'dark_theme_789', + 'language' => 'en_US_012', + ]; + + $signedCookies = []; + + foreach ($cookies as $name => $value) { + $data = [$name, $value]; + $signedCookies[$name] = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); + } + + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams($signedCookies); + + $request = new Request(); + + $request->enableCookieValidation = true; + $request->cookieValidationKey = $validationKey; + + $request->setPsr7Request($psr7Request); + + $cookieCollection = $request->getCookies(); + + self::assertCount( + 4, + $cookieCollection, + "Should return all '4' validated cookies, not just one.", + ); + + foreach ($cookies as $expectedName => $expectedValue) { + self::assertTrue( + $cookieCollection->has($expectedName), + "Cookie collection should contain '{$expectedName}'", + ); + self::assertSame( + $expectedValue, + $cookieCollection->getValue($expectedName), + "Cookie '{$expectedName}' should have the correct decrypted value", + ); + } + + $cookieNames = []; + + foreach ($cookieCollection as $cookie) { + $cookieNames[] = $cookie->name; + } + + self::assertCount( + 4, + $cookieNames, + "Should have exactly '4' cookie names", + ); + + foreach (array_keys($cookies) as $expectedName) { + self::assertContains( + $expectedName, + $cookieNames, + "Cookie name '{$expectedName}' should be present in the collection", + ); + } + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnNewCookieCollectionInstanceOnEachCall(): void + { + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams(['cached_cookie' => 'test_value']); + + $request = new Request(); + + $request->enableCookieValidation = false; + $request->cookieValidationKey = 'test-validation-key-32-characters'; + + $request->setPsr7Request($psr7Request); + + $cookies1 = $request->getCookies(); + $cookies2 = $request->getCookies(); + + self::assertNotSame( + $cookies1, + $cookies2, + "Each call to 'getCookies()' should return a new CookieCollection instance, not a cached one.", + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies(): void + { + $validationKey = 'test-validation-key-32-characters'; + + // create a valid signed cookie using Yii security component + $cookieName = 'valid_session'; + $cookieValue = 'abc123session'; + $data = [$cookieName, $cookieValue]; + + $signedCookieValue = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams( + [ + $cookieName => $signedCookieValue, + 'invalid_cookie' => 'invalid_data', + ], + ); + + $request = new Request(); + + $request->enableCookieValidation = true; + $request->cookieValidationKey = $validationKey; + + $request->setPsr7Request($psr7Request); + + $cookies = $request->getCookies(); + + self::assertCount( + 1, + $cookies, + 'CookieCollection should contain only the valid signed cookie when validation is enabled.', + ); + self::assertTrue( + $cookies->has($cookieName), + "CookieCollection should contain the valid signed cookie '{$cookieName}'.", + ); + self::assertSame( + $cookieValue, + $cookies->getValue($cookieName), + "Valid signed cookie '{$cookieName}' should have the expected decrypted value.", + ); + self::assertFalse( + $cookies->has('invalid_cookie'), + 'CookieCollection should not contain invalid cookies when validation is enabled.', + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnValidatedCookieWithCorrectNamePropertyWhenValidationEnabled(): void + { + $validationKey = 'test-validation-key-32-characters'; + $cookieName = 'validated_session'; + $cookieValue = 'secure_session_value'; + $data = [$cookieName, $cookieValue]; + + $signedCookieValue = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); + + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams([$cookieName => $signedCookieValue]); + + $request = new Request(); + + $request->enableCookieValidation = true; + $request->cookieValidationKey = $validationKey; + + $request->setPsr7Request($psr7Request); + + $cookies = $request->getCookies(); + + $cookie = null; + + foreach ($cookies as $cookieObj) { + if ($cookieObj->value === $cookieValue) { + $cookie = $cookieObj; + break; + } + } + + self::assertNotNull( + $cookie, + 'Validated cookie should be found in the collection.', + ); + self::assertInstanceOf( + Cookie::class, + $cookie, + 'Should be a Cookie instance.', + ); + self::assertSame( + $cookieName, + $cookie->name, + "Validated cookie 'name' property should match the original cookie 'name' from PSR-7 request", + ); + self::assertSame( + $cookieValue, + $cookie->value, + "Validated cookie 'value' property should match the decrypted cookie 'value'", + ); + self::assertNull( + $cookie->expire, + "Validated cookie 'expire' property should be 'null' as set in the constructor", + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testThrowInvalidCallExceptionWhenReturnReadOnlyCookieCollectionWhenAdapterIsSet(): void + { + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams( + [ + 'another_cookie' => 'another_value', + 'test_cookie' => 'test_value', + ], + ); + + $request = new Request(); + + $request->enableCookieValidation = false; + $request->cookieValidationKey = 'test-validation-key-32-characters'; + + $request->setPsr7Request($psr7Request); + + $cookies = $request->getCookies(); + + $this->expectException(InvalidCallException::class); + $this->expectExceptionMessage('The cookie collection is read only.'); + + $cookies->add( + new Cookie( + [ + 'name' => 'new_cookie', + 'value' => 'new_value', + ], + ), + ); + } + + public function testThrowInvalidConfigExceptionWhenValidationEnabledButNoValidationKey(): void + { + $psr7Request = FactoryHelper::createRequest('GET', '/test'); + + $psr7Request = $psr7Request->withCookieParams(['session_id' => 'abc123']); + + $request = new Request(); + + $request->enableCookieValidation = true; + $request->cookieValidationKey = ''; + + $this->expectException(InvalidConfigException::class); + $this->expectExceptionMessage(Message::COOKIE_VALIDATION_KEY_REQUIRED->getMessage()); + + $request->setPsr7Request($psr7Request); + + $request->getCookies(); + } +} diff --git a/tests/adapter/ServerRequestAdapterTest.php b/tests/adapter/ServerRequestAdapterTest.php index 96d63d7e..e6b1c994 100644 --- a/tests/adapter/ServerRequestAdapterTest.php +++ b/tests/adapter/ServerRequestAdapterTest.php @@ -6,11 +6,8 @@ use PHPUnit\Framework\Attributes\{DataProviderExternal, Group}; use Psr\Http\Message\ServerRequestInterface; -use Yii; -use yii\base\{InvalidCallException, InvalidConfigException}; -use yii\helpers\Json; -use yii\web\{Cookie, UploadedFile}; -use yii2\extensions\psrbridge\exception\Message; +use yii\base\{InvalidConfigException}; +use yii\web\{UploadedFile}; use yii2\extensions\psrbridge\http\Request; use yii2\extensions\psrbridge\tests\provider\RequestProvider; use yii2\extensions\psrbridge\tests\support\FactoryHelper; @@ -24,49 +21,6 @@ #[Group('http')] final class ServerRequestAdapterTest extends TestCase { - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testResetCookieCollectionAfterReset(): void - { - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams(['reset_cookie' => 'test_value']); - - $request = new Request(); - - $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; - - $request->setPsr7Request($psr7Request); - - $cookies1 = $request->getCookies(); - $request->reset(); - - $newPsr7Request = FactoryHelper::createRequest('GET', '/test'); - - $newPsr7Request = $newPsr7Request->withCookieParams(['new_cookie' => 'new_value']); - - $request->setPsr7Request($newPsr7Request); - - $cookies2 = $request->getCookies(); - - self::assertNotSame( - $cookies1, - $cookies2, - "After 'reset' method, 'getCookies()' should return a new CookieCollection instance.", - ); - self::assertTrue( - $cookies2->has('new_cookie'), - "New CookieCollection should contain 'new_cookie' after 'reset' method.", - ); - self::assertSame( - 'new_value', - $cookies2->getValue('new_cookie'), - "New cookie 'new_cookie' should have the expected value after 'reset' method.", - ); - } - /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ @@ -167,209 +121,6 @@ public function testReturnBodyParamsWithMethodParamRemoved(): void ); } - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnCookieCollectionWhenCookiesPresent(): void - { - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams( - [ - 'session_id' => 'abc123', - 'theme' => 'dark', - 'empty_cookie' => '', - ], - ); - - $request = new Request(); - - $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; - - $request->setPsr7Request($psr7Request); - - $cookies = $request->getCookies(); - - self::assertCount( - 2, - $cookies, - "CookieCollection should contain '2' cookies when empty cookies are filtered out.", - ); - self::assertTrue( - $cookies->has('session_id'), - "CookieCollection should contain 'session_id' cookie.", - ); - self::assertSame( - 'abc123', - $cookies->getValue('session_id'), - "Cookie 'session_id' should have the expected value from the PSR-7 request.", - ); - self::assertTrue( - $cookies->has('theme'), - "CookieCollection should contain 'theme' cookie.", - ); - self::assertSame( - 'dark', - $cookies->getValue('theme'), - "Cookie 'theme' should have the expected value from the PSR-7 request.", - ); - self::assertFalse( - $cookies->has('empty_cookie'), - 'CookieCollection should not contain empty cookies.', - ); - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnCookieCollectionWhenNoCookiesPresent(): void - { - $request = new Request(); - - $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; - - $request->setPsr7Request( - FactoryHelper::createRequest('GET', '/test'), - ); - - self::assertCount( - 0, - $request->getCookies(), - 'CookieCollection should be empty when no cookies are present in the PSR-7 request.', - ); - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnCookieCollectionWithValidationDisabled(): void - { - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams( - [ - 'user_id' => '42', - 'preferences' => 'compact', - ], - ); - - $request = new Request(); - - $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; - - $request->setPsr7Request($psr7Request); - - $cookies = $request->getCookies(); - - self::assertCount( - 2, - $cookies, - 'CookieCollection should contain all non-empty cookies when validation is disabled.', - ); - self::assertTrue( - $cookies->has('user_id'), - "CookieCollection should contain 'user_id' cookie when validation is disabled.", - ); - self::assertSame( - '42', - $cookies->getValue('user_id'), - "Cookie 'user_id' should have the expected value when validation is disabled.", - ); - self::assertTrue( - $cookies->has('preferences'), - "CookieCollection should contain 'preferences' cookie when validation is disabled.", - ); - self::assertSame( - 'compact', - $cookies->getValue('preferences'), - "Cookie 'preferences' should have the expected value when validation is disabled.", - ); - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnCookieWithCorrectNamePropertyWhenAdapterIsSet(): void - { - $cookieName = 'session_id'; - $cookieValue = 'abc123'; - - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams([$cookieName => $cookieValue]); - - $request = new Request(); - - $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; - - $request->setPsr7Request($psr7Request); - - $cookies = $request->getCookies(); - - $cookie = $cookies[$cookieName] ?? null; - - if ($cookie === null) { - foreach ($cookies as $cookieObj) { - if ($cookieObj->value === $cookieValue) { - $cookie = $cookieObj; - break; - } - } - } - - self::assertNotNull( - $cookie, - 'Cookie should be found in the collection.', - ); - self::assertInstanceOf( - Cookie::class, - $cookie, - 'Should be a Cookie instance.', - ); - self::assertSame( - $cookieName, - $cookie->name, - "Cookie 'name' property should match the original cookie 'name' from PSR-7 request.", - ); - self::assertSame( - $cookieValue, - $cookie->value, - "Cookie 'value' property should match the original cookie 'value' from PSR-7 request.", - ); - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnEmptyCookieCollectionWhenValidationEnabledWithInvalidCookies(): void - { - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams( - [ - 'invalid_cookie' => 'invalid_data', - 'empty_cookie' => '', - ], - ); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = 'test-validation-key-32-characters'; - - $request->setPsr7Request($psr7Request); - - self::assertCount( - 0, - $request->getCookies(), - 'CookieCollection should be empty when validation is enabled but cookies are invalid.', - ); - } - public function testReturnEmptyQueryParamsWhenAdapterIsSet(): void { $request = new Request(); @@ -641,105 +392,6 @@ public function testReturnMultipleUploadedFilesWithDifferentStructures(): void ); } - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMultipleValidCookies(): void - { - $validationKey = 'test-validation-key-32-characters'; - - $cookies = [ - 'session_id' => 'session_value_123', - 'user_pref' => 'preference_value_456', - 'theme' => 'dark_theme_789', - 'language' => 'en_US_012', - ]; - - $signedCookies = []; - - foreach ($cookies as $name => $value) { - $data = [$name, $value]; - $signedCookies[$name] = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); - } - - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams($signedCookies); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = $validationKey; - - $request->setPsr7Request($psr7Request); - - $cookieCollection = $request->getCookies(); - - self::assertCount( - 4, - $cookieCollection, - "Should return all '4' validated cookies, not just one.", - ); - - foreach ($cookies as $expectedName => $expectedValue) { - self::assertTrue( - $cookieCollection->has($expectedName), - "Cookie collection should contain '{$expectedName}'", - ); - self::assertSame( - $expectedValue, - $cookieCollection->getValue($expectedName), - "Cookie '{$expectedName}' should have the correct decrypted value", - ); - } - - $cookieNames = []; - - foreach ($cookieCollection as $cookie) { - $cookieNames[] = $cookie->name; - } - - self::assertCount( - 4, - $cookieNames, - "Should have exactly '4' cookie names", - ); - - foreach (array_keys($cookies) as $expectedName) { - self::assertContains( - $expectedName, - $cookieNames, - "Cookie name '{$expectedName}' should be present in the collection", - ); - } - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnNewCookieCollectionInstanceOnEachCall(): void - { - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams(['cached_cookie' => 'test_value']); - - $request = new Request(); - - $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; - - $request->setPsr7Request($psr7Request); - - $cookies1 = $request->getCookies(); - $cookies2 = $request->getCookies(); - - self::assertNotSame( - $cookies1, - $cookies2, - "Each call to 'getCookies()' should return a new CookieCollection instance, not a cached one.", - ); - } - /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ @@ -1306,168 +958,4 @@ public function testReturnUrlFromAdapterWhenAdapterIsSet(string $url, string $ex "URL should match the expected value for: {$url}.", ); } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies(): void - { - $validationKey = 'test-validation-key-32-characters'; - - // create a valid signed cookie using Yii security component - $cookieName = 'valid_session'; - $cookieValue = 'abc123session'; - $data = [$cookieName, $cookieValue]; - - $signedCookieValue = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams( - [ - $cookieName => $signedCookieValue, - 'invalid_cookie' => 'invalid_data', - ], - ); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = $validationKey; - - $request->setPsr7Request($psr7Request); - - $cookies = $request->getCookies(); - - self::assertCount( - 1, - $cookies, - 'CookieCollection should contain only the valid signed cookie when validation is enabled.', - ); - self::assertTrue( - $cookies->has($cookieName), - "CookieCollection should contain the valid signed cookie '{$cookieName}'.", - ); - self::assertSame( - $cookieValue, - $cookies->getValue($cookieName), - "Valid signed cookie '{$cookieName}' should have the expected decrypted value.", - ); - self::assertFalse( - $cookies->has('invalid_cookie'), - 'CookieCollection should not contain invalid cookies when validation is enabled.', - ); - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnValidatedCookieWithCorrectNamePropertyWhenValidationEnabled(): void - { - $validationKey = 'test-validation-key-32-characters'; - $cookieName = 'validated_session'; - $cookieValue = 'secure_session_value'; - $data = [$cookieName, $cookieValue]; - - $signedCookieValue = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); - - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams([$cookieName => $signedCookieValue]); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = $validationKey; - - $request->setPsr7Request($psr7Request); - - $cookies = $request->getCookies(); - - $cookie = null; - - foreach ($cookies as $cookieObj) { - if ($cookieObj->value === $cookieValue) { - $cookie = $cookieObj; - break; - } - } - - self::assertNotNull( - $cookie, - 'Validated cookie should be found in the collection.', - ); - self::assertInstanceOf( - Cookie::class, - $cookie, - 'Should be a Cookie instance.', - ); - self::assertSame( - $cookieName, - $cookie->name, - "Validated cookie 'name' property should match the original cookie 'name' from PSR-7 request", - ); - self::assertSame( - $cookieValue, - $cookie->value, - "Validated cookie 'value' property should match the decrypted cookie 'value'", - ); - self::assertNull( - $cookie->expire, - "Validated cookie 'expire' property should be 'null' as set in the constructor", - ); - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testThrowInvalidCallExceptionWhenReturnReadOnlyCookieCollectionWhenAdapterIsSet(): void - { - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams( - [ - 'another_cookie' => 'another_value', - 'test_cookie' => 'test_value', - ], - ); - - $request = new Request(); - - $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; - - $request->setPsr7Request($psr7Request); - - $cookies = $request->getCookies(); - - $this->expectException(InvalidCallException::class); - $this->expectExceptionMessage('The cookie collection is read only.'); - - $cookies->add( - new Cookie( - [ - 'name' => 'new_cookie', - 'value' => 'new_value', - ], - ), - ); - } - - public function testThrowInvalidConfigExceptionWhenValidationEnabledButNoValidationKey(): void - { - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams(['session_id' => 'abc123']); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = ''; - - $this->expectException(InvalidConfigException::class); - $this->expectExceptionMessage(Message::COOKIE_VALIDATION_KEY_REQUIRED->getMessage()); - - $request->setPsr7Request($psr7Request); - $request->getCookies(); - } } From c72ed9aa24ade2aa1da4d441dc3ce417f08273b9 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 10 Aug 2025 11:25:12 -0400 Subject: [PATCH 2/7] refactor(tests): Replace Yii security component calls with local Security instance in `CookiesPsr7Test` for improved clarity and consistency. --- src/adapter/ServerRequestAdapter.php | 6 ++++-- tests/adapter/CookiesPsr7Test.php | 14 +++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/adapter/ServerRequestAdapter.php b/src/adapter/ServerRequestAdapter.php index 000a6d04..b20cfa7b 100644 --- a/src/adapter/ServerRequestAdapter.php +++ b/src/adapter/ServerRequestAdapter.php @@ -6,7 +6,7 @@ use Psr\Http\Message\ServerRequestInterface; use Yii; -use yii\base\InvalidConfigException; +use yii\base\{InvalidConfigException, Security}; use yii\helpers\Json; use yii\web\{Cookie, HeaderCollection}; use yii2\extensions\psrbridge\exception\Message; @@ -416,9 +416,11 @@ private function getValidatedCookies(string $validationKey): array $cookies = []; $cookieParams = $this->psrRequest->getCookieParams(); + $security = Yii::$app->security ?? new Security(); + foreach ($cookieParams as $name => $value) { if (is_string($value) && $value !== '') { - $data = Yii::$app->getSecurity()->validateData($value, $validationKey); + $data = $security->validateData($value, $validationKey); if (is_string($data)) { $data = Json::decode($data); diff --git a/tests/adapter/CookiesPsr7Test.php b/tests/adapter/CookiesPsr7Test.php index 950ce101..02d95cd1 100644 --- a/tests/adapter/CookiesPsr7Test.php +++ b/tests/adapter/CookiesPsr7Test.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\Attributes\Group; use Yii; use yii\base\{InvalidCallException, InvalidConfigException}; +use yii\base\Security; use yii\helpers\Json; use yii\web\Cookie; use yii2\extensions\psrbridge\exception\Message; @@ -270,6 +271,8 @@ public function testReturnEmptyCookieCollectionWhenValidationEnabledWithInvalidC */ public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMultipleValidCookies(): void { + $security = new Security(); + $validationKey = 'test-validation-key-32-characters'; $cookies = [ @@ -283,7 +286,7 @@ public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMulti foreach ($cookies as $name => $value) { $data = [$name, $value]; - $signedCookies[$name] = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); + $signedCookies[$name] = $security->hashData(Json::encode($data), $validationKey); } $psr7Request = FactoryHelper::createRequest('GET', '/test'); @@ -369,6 +372,8 @@ public function testReturnNewCookieCollectionInstanceOnEachCall(): void */ public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies(): void { + $security = new Security(); + $validationKey = 'test-validation-key-32-characters'; // create a valid signed cookie using Yii security component @@ -376,7 +381,8 @@ public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies( $cookieValue = 'abc123session'; $data = [$cookieName, $cookieValue]; - $signedCookieValue = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); + $signedCookieValue = $security->hashData(Json::encode($data), $validationKey); + $psr7Request = FactoryHelper::createRequest('GET', '/test'); $psr7Request = $psr7Request->withCookieParams( @@ -420,12 +426,14 @@ public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies( */ public function testReturnValidatedCookieWithCorrectNamePropertyWhenValidationEnabled(): void { + $security = new Security(); + $validationKey = 'test-validation-key-32-characters'; $cookieName = 'validated_session'; $cookieValue = 'secure_session_value'; $data = [$cookieName, $cookieValue]; - $signedCookieValue = Yii::$app->getSecurity()->hashData(Json::encode($data), $validationKey); + $signedCookieValue = $security->hashData(Json::encode($data), $validationKey); $psr7Request = FactoryHelper::createRequest('GET', '/test'); From 2fe607b95be4bc1eb72bc5fb2e823cadb42f89ba Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 10 Aug 2025 11:40:39 -0400 Subject: [PATCH 3/7] refactor(tests): Replace hardcoded cookie validation key with constant in `CookiesPsr7Test` for consistency and maintainability. --- tests/adapter/CookiesPsr7Test.php | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/tests/adapter/CookiesPsr7Test.php b/tests/adapter/CookiesPsr7Test.php index 02d95cd1..ad86af4f 100644 --- a/tests/adapter/CookiesPsr7Test.php +++ b/tests/adapter/CookiesPsr7Test.php @@ -32,7 +32,7 @@ public function testResetCookieCollectionAfterReset(): void $request = new Request(); $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); @@ -81,7 +81,7 @@ public function testReturnCookieCollectionWhenCookiesPresent(): void $request = new Request(); $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); @@ -124,7 +124,7 @@ public function testReturnCookieCollectionWhenNoCookiesPresent(): void $request = new Request(); $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request( FactoryHelper::createRequest('GET', '/test'), @@ -154,7 +154,7 @@ public function testReturnCookieCollectionWithValidationDisabled(): void $request = new Request(); $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); @@ -200,7 +200,7 @@ public function testReturnCookieWithCorrectNamePropertyWhenAdapterIsSet(): void $request = new Request(); $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); @@ -255,7 +255,7 @@ public function testReturnEmptyCookieCollectionWhenValidationEnabledWithInvalidC $request = new Request(); $request->enableCookieValidation = true; - $request->cookieValidationKey = 'test-validation-key-32-characters'; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); @@ -273,8 +273,6 @@ public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMulti { $security = new Security(); - $validationKey = 'test-validation-key-32-characters'; - $cookies = [ 'session_id' => 'session_value_123', 'user_pref' => 'preference_value_456', @@ -286,7 +284,7 @@ public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMulti foreach ($cookies as $name => $value) { $data = [$name, $value]; - $signedCookies[$name] = $security->hashData(Json::encode($data), $validationKey); + $signedCookies[$name] = $security->hashData(Json::encode($data), self::COOKIE_VALIDATION_KEY); } $psr7Request = FactoryHelper::createRequest('GET', '/test'); @@ -296,7 +294,7 @@ public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMulti $request = new Request(); $request->enableCookieValidation = true; - $request->cookieValidationKey = $validationKey; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); @@ -353,7 +351,7 @@ public function testReturnNewCookieCollectionInstanceOnEachCall(): void $request = new Request(); $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); @@ -374,7 +372,7 @@ public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies( { $security = new Security(); - $validationKey = 'test-validation-key-32-characters'; + $validationKey = self::COOKIE_VALIDATION_KEY; // create a valid signed cookie using Yii security component $cookieName = 'valid_session'; @@ -428,12 +426,11 @@ public function testReturnValidatedCookieWithCorrectNamePropertyWhenValidationEn { $security = new Security(); - $validationKey = 'test-validation-key-32-characters'; $cookieName = 'validated_session'; $cookieValue = 'secure_session_value'; $data = [$cookieName, $cookieValue]; - $signedCookieValue = $security->hashData(Json::encode($data), $validationKey); + $signedCookieValue = $security->hashData(Json::encode($data), self::COOKIE_VALIDATION_KEY); $psr7Request = FactoryHelper::createRequest('GET', '/test'); @@ -442,7 +439,7 @@ public function testReturnValidatedCookieWithCorrectNamePropertyWhenValidationEn $request = new Request(); $request->enableCookieValidation = true; - $request->cookieValidationKey = $validationKey; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); @@ -499,7 +496,7 @@ public function testThrowInvalidCallExceptionWhenReturnReadOnlyCookieCollectionW $request = new Request(); $request->enableCookieValidation = false; - $request->cookieValidationKey = 'test-validation-key-32-characters'; + $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; $request->setPsr7Request($psr7Request); From 10d7c05ab93fe2c6899356aad712c7d31d29cceb Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 10 Aug 2025 14:01:29 -0400 Subject: [PATCH 4/7] refactor(tests): Update cookie validation logic in `ServerRequestAdapter` and add comprehensive tests in `StatelessApplicationTest` for improved validation handling. --- src/adapter/ServerRequestAdapter.php | 4 +- tests/adapter/CookiesPsr7Test.php | 218 ----------------------- tests/http/StatelessApplicationTest.php | 225 ++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 221 deletions(-) diff --git a/src/adapter/ServerRequestAdapter.php b/src/adapter/ServerRequestAdapter.php index b20cfa7b..43f20213 100644 --- a/src/adapter/ServerRequestAdapter.php +++ b/src/adapter/ServerRequestAdapter.php @@ -416,11 +416,9 @@ private function getValidatedCookies(string $validationKey): array $cookies = []; $cookieParams = $this->psrRequest->getCookieParams(); - $security = Yii::$app->security ?? new Security(); - foreach ($cookieParams as $name => $value) { if (is_string($value) && $value !== '') { - $data = $security->validateData($value, $validationKey); + $data = Yii::$app->getSecurity()->validateData($value, $validationKey); if (is_string($data)) { $data = Json::decode($data); diff --git a/tests/adapter/CookiesPsr7Test.php b/tests/adapter/CookiesPsr7Test.php index ad86af4f..5deeba72 100644 --- a/tests/adapter/CookiesPsr7Test.php +++ b/tests/adapter/CookiesPsr7Test.php @@ -5,10 +5,7 @@ namespace yii2\extensions\psrbridge\tests\adapter; use PHPUnit\Framework\Attributes\Group; -use Yii; use yii\base\{InvalidCallException, InvalidConfigException}; -use yii\base\Security; -use yii\helpers\Json; use yii\web\Cookie; use yii2\extensions\psrbridge\exception\Message; use yii2\extensions\psrbridge\http\Request; @@ -238,107 +235,6 @@ public function testReturnCookieWithCorrectNamePropertyWhenAdapterIsSet(): void ); } - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnEmptyCookieCollectionWhenValidationEnabledWithInvalidCookies(): void - { - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams( - [ - 'invalid_cookie' => 'invalid_data', - 'empty_cookie' => '', - ], - ); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; - - $request->setPsr7Request($psr7Request); - - self::assertCount( - 0, - $request->getCookies(), - 'CookieCollection should be empty when validation is enabled but cookies are invalid.', - ); - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMultipleValidCookies(): void - { - $security = new Security(); - - $cookies = [ - 'session_id' => 'session_value_123', - 'user_pref' => 'preference_value_456', - 'theme' => 'dark_theme_789', - 'language' => 'en_US_012', - ]; - - $signedCookies = []; - - foreach ($cookies as $name => $value) { - $data = [$name, $value]; - $signedCookies[$name] = $security->hashData(Json::encode($data), self::COOKIE_VALIDATION_KEY); - } - - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams($signedCookies); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; - - $request->setPsr7Request($psr7Request); - - $cookieCollection = $request->getCookies(); - - self::assertCount( - 4, - $cookieCollection, - "Should return all '4' validated cookies, not just one.", - ); - - foreach ($cookies as $expectedName => $expectedValue) { - self::assertTrue( - $cookieCollection->has($expectedName), - "Cookie collection should contain '{$expectedName}'", - ); - self::assertSame( - $expectedValue, - $cookieCollection->getValue($expectedName), - "Cookie '{$expectedName}' should have the correct decrypted value", - ); - } - - $cookieNames = []; - - foreach ($cookieCollection as $cookie) { - $cookieNames[] = $cookie->name; - } - - self::assertCount( - 4, - $cookieNames, - "Should have exactly '4' cookie names", - ); - - foreach (array_keys($cookies) as $expectedName) { - self::assertContains( - $expectedName, - $cookieNames, - "Cookie name '{$expectedName}' should be present in the collection", - ); - } - } - /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ @@ -365,120 +261,6 @@ public function testReturnNewCookieCollectionInstanceOnEachCall(): void ); } - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies(): void - { - $security = new Security(); - - $validationKey = self::COOKIE_VALIDATION_KEY; - - // create a valid signed cookie using Yii security component - $cookieName = 'valid_session'; - $cookieValue = 'abc123session'; - $data = [$cookieName, $cookieValue]; - - $signedCookieValue = $security->hashData(Json::encode($data), $validationKey); - - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams( - [ - $cookieName => $signedCookieValue, - 'invalid_cookie' => 'invalid_data', - ], - ); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = $validationKey; - - $request->setPsr7Request($psr7Request); - - $cookies = $request->getCookies(); - - self::assertCount( - 1, - $cookies, - 'CookieCollection should contain only the valid signed cookie when validation is enabled.', - ); - self::assertTrue( - $cookies->has($cookieName), - "CookieCollection should contain the valid signed cookie '{$cookieName}'.", - ); - self::assertSame( - $cookieValue, - $cookies->getValue($cookieName), - "Valid signed cookie '{$cookieName}' should have the expected decrypted value.", - ); - self::assertFalse( - $cookies->has('invalid_cookie'), - 'CookieCollection should not contain invalid cookies when validation is enabled.', - ); - } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testReturnValidatedCookieWithCorrectNamePropertyWhenValidationEnabled(): void - { - $security = new Security(); - - $cookieName = 'validated_session'; - $cookieValue = 'secure_session_value'; - $data = [$cookieName, $cookieValue]; - - $signedCookieValue = $security->hashData(Json::encode($data), self::COOKIE_VALIDATION_KEY); - - $psr7Request = FactoryHelper::createRequest('GET', '/test'); - - $psr7Request = $psr7Request->withCookieParams([$cookieName => $signedCookieValue]); - - $request = new Request(); - - $request->enableCookieValidation = true; - $request->cookieValidationKey = self::COOKIE_VALIDATION_KEY; - - $request->setPsr7Request($psr7Request); - - $cookies = $request->getCookies(); - - $cookie = null; - - foreach ($cookies as $cookieObj) { - if ($cookieObj->value === $cookieValue) { - $cookie = $cookieObj; - break; - } - } - - self::assertNotNull( - $cookie, - 'Validated cookie should be found in the collection.', - ); - self::assertInstanceOf( - Cookie::class, - $cookie, - 'Should be a Cookie instance.', - ); - self::assertSame( - $cookieName, - $cookie->name, - "Validated cookie 'name' property should match the original cookie 'name' from PSR-7 request", - ); - self::assertSame( - $cookieValue, - $cookie->value, - "Validated cookie 'value' property should match the decrypted cookie 'value'", - ); - self::assertNull( - $cookie->expire, - "Validated cookie 'expire' property should be 'null' as set in the constructor", - ); - } - /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ diff --git a/tests/http/StatelessApplicationTest.php b/tests/http/StatelessApplicationTest.php index a37bdf0d..d40cbde8 100644 --- a/tests/http/StatelessApplicationTest.php +++ b/tests/http/StatelessApplicationTest.php @@ -16,6 +16,7 @@ use yii\i18n\{Formatter, I18N}; use yii\log\Dispatcher; use yii\web\{AssetManager, NotFoundHttpException, Session, UrlManager, User, View}; +use yii\web\Cookie; use yii2\extensions\psrbridge\exception\Message; use yii2\extensions\psrbridge\http\{ErrorHandler, Request, Response}; use yii2\extensions\psrbridge\tests\provider\StatelessApplicationProvider; @@ -994,6 +995,39 @@ public function testReturnCoreComponentsConfigurationAfterHandle(): void ); } + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnEmptyCookieCollectionWhenValidationEnabledWithInvalidCookies(): void + { + $app = $this->statelessApplication( + [ + 'components' => [ + 'request' => [ + 'cookieValidationKey' => self::COOKIE_VALIDATION_KEY, + 'enableCookieValidation' => true, + ], + ], + ], + ); + + $response = $app->handle( + FactoryHelper::createRequest('GET', 'site/getcookies') + ->withCookieParams( + [ + 'invalid_cookie' => 'invalid_data', + 'empty_cookie' => '', + ], + ), + ); + + self::assertSame( + '[]', + $response->getBody()->getContents(), + 'CookieCollection should be empty when validation is enabled but cookies are invalid.', + ); + } + /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ @@ -1312,6 +1346,106 @@ public function testReturnJsonResponseWithRouteParameterForSiteUpdateRoute(): vo ); } + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMultipleValidCookies(): void + { + $security = new Security(); + + $cookies = [ + 'session_id' => 'session_value_123', + 'user_pref' => 'preference_value_456', + 'theme' => 'dark_theme_789', + 'language' => 'en_US_012', + ]; + + $signedCookies = []; + + foreach ($cookies as $name => $value) { + $data = [$name, $value]; + $signedCookies[$name] = $security->hashData(Json::encode($data), self::COOKIE_VALIDATION_KEY); + } + + $app = $this->statelessApplication( + [ + 'components' => [ + 'request' => [ + 'cookieValidationKey' => self::COOKIE_VALIDATION_KEY, + 'enableCookieValidation' => true, + ], + ], + ], + ); + + $response = $app->handle( + FactoryHelper::createRequest('GET', 'site/getcookies') + ->withCookieParams($signedCookies), + ); + + /** + * @phpstan-var array< + * string, + * array{ + * name: string, + * value: string, + * domain: string, + * expire: ?int, + * path: string, + * secure: bool, + * httpOnly: bool, + * sameSite: string + * } + * > + */ + $expectedCookies = Json::decode($response->getBody()->getContents()); + + self::assertCount( + 4, + $expectedCookies, + "Should return all '4' validated cookies, not just '1'.", + ); + + foreach ($cookies as $name => $value) { + self::assertSame( + $name, + $expectedCookies[$name]['name'] ?? null, + "Cookie name for '{$name}' should match the original cookie name in 'StatelessApplication'.", + ); + self::assertSame( + $value, + $expectedCookies[$name]['value'], + "Cookie value for '{$name}' should match the original cookie value in 'StatelessApplication'.", + ); + self::assertEmpty( + $expectedCookies[$name]['domain'], + "Cookie 'domain' for '{$name}' should be an empty string in 'StatelessApplication'.", + ); + self::assertNull( + $expectedCookies[$name]['expire'], + "Cookie 'expire' for '{$name}' should be 'null' in 'StatelessApplication'.", + ); + self::assertSame( + '/', + $expectedCookies[$name]['path'], + "Cookie 'path' for '{$name}' should be '/' in 'StatelessApplication'.", + ); + self::assertFalse( + $expectedCookies[$name]['secure'], + "Cookie 'secure' flag for '{$name}' should be 'false' in 'StatelessApplication'.", + ); + self::assertTrue( + $expectedCookies[$name]['httpOnly'], + "Cookie 'httpOnly' flag for '{$name}' should be 'true' in 'StatelessApplication'.", + ); + self::assertSame( + 'Lax', + $expectedCookies[$name]['sameSite'], + "Cookie 'sameSite' for '{$name}' should be 'Lax' in 'StatelessApplication'.", + ); + } + } + /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ @@ -1528,6 +1662,97 @@ public function testReturnsStatusCode201ForSiteStatusCodeRoute(): void ); } + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies(): void + { + $security = new Security(); + + $signedCookieValue = $security->hashData( + Json::encode(['valid_session', 'abc123session']), + self::COOKIE_VALIDATION_KEY, + ); + + $app = $this->statelessApplication( + [ + 'components' => [ + 'request' => [ + 'cookieValidationKey' => self::COOKIE_VALIDATION_KEY, + 'enableCookieValidation' => true, + ], + ], + ], + ); + + $response = $app->handle( + FactoryHelper::createRequest('GET', 'site/getcookies') + ->withCookieParams( + [ + 'invalid_cookie' => 'invalid_data', + 'valid_session' => $signedCookieValue, + ], + ), + ); + + self::assertSame( + 200, + $response->getStatusCode(), + "Response 'status code' should be '200' for 'site/getcookies' route in 'StatelessApplication'.", + ); + self::assertSame( + <<getBody()->getContents(), + "Response 'body' should match expected JSON string for cookie 'validated_session' on 'site/getcookies' " . + "route in 'StatelessApplication'.", + ); + } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testReturnValidatedCookieWithCorrectNamePropertyWhenValidationEnabled(): void + { + $security = new Security(); + + $signedCookieValue = $security->hashData( + Json::encode(['validated_session', 'secure_session_value']), + self::COOKIE_VALIDATION_KEY, + ); + + $app = $this->statelessApplication( + [ + 'components' => [ + 'request' => [ + 'cookieValidationKey' => self::COOKIE_VALIDATION_KEY, + 'enableCookieValidation' => true, + ], + ], + ], + ); + + $response = $app->handle( + FactoryHelper::createRequest('GET', 'site/getcookies') + ->withCookieParams(['validated_session' => $signedCookieValue]), + ); + + self::assertSame( + 200, + $response->getStatusCode(), + "Response 'status code' should be '200' for 'site/getcookies' route in 'StatelessApplication'.", + ); + self::assertSame( + <<getBody()->getContents(), + "Response 'body' should match expected JSON string for cookie 'validated_session' on 'site/getcookies' " . + "route in 'StatelessApplication'.", + ); + } + /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ From 29856fd32ab1e634c78e3dd4964f5f02a20bcdff Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 10 Aug 2025 14:05:51 -0400 Subject: [PATCH 5/7] refactor(adapter): Remove unused Security component import in `ServerRequestAdapter` for cleaner code. --- src/adapter/ServerRequestAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adapter/ServerRequestAdapter.php b/src/adapter/ServerRequestAdapter.php index 43f20213..000a6d04 100644 --- a/src/adapter/ServerRequestAdapter.php +++ b/src/adapter/ServerRequestAdapter.php @@ -6,7 +6,7 @@ use Psr\Http\Message\ServerRequestInterface; use Yii; -use yii\base\{InvalidConfigException, Security}; +use yii\base\InvalidConfigException; use yii\helpers\Json; use yii\web\{Cookie, HeaderCollection}; use yii2\extensions\psrbridge\exception\Message; From 9940df0b0c1455f61422d30af663334e6eae31d9 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 10 Aug 2025 14:08:40 -0400 Subject: [PATCH 6/7] refactor(tests): Reorganize use statements in `ServerRequestAdapterTest` and remove unused import in `StatelessApplicationTest` for improved clarity. --- tests/adapter/ServerRequestAdapterTest.php | 4 ++-- tests/http/StatelessApplicationTest.php | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/adapter/ServerRequestAdapterTest.php b/tests/adapter/ServerRequestAdapterTest.php index e6b1c994..e497f928 100644 --- a/tests/adapter/ServerRequestAdapterTest.php +++ b/tests/adapter/ServerRequestAdapterTest.php @@ -6,8 +6,8 @@ use PHPUnit\Framework\Attributes\{DataProviderExternal, Group}; use Psr\Http\Message\ServerRequestInterface; -use yii\base\{InvalidConfigException}; -use yii\web\{UploadedFile}; +use yii\base\InvalidConfigException; +use yii\web\UploadedFile; use yii2\extensions\psrbridge\http\Request; use yii2\extensions\psrbridge\tests\provider\RequestProvider; use yii2\extensions\psrbridge\tests\support\FactoryHelper; diff --git a/tests/http/StatelessApplicationTest.php b/tests/http/StatelessApplicationTest.php index d40cbde8..3cb212be 100644 --- a/tests/http/StatelessApplicationTest.php +++ b/tests/http/StatelessApplicationTest.php @@ -16,7 +16,6 @@ use yii\i18n\{Formatter, I18N}; use yii\log\Dispatcher; use yii\web\{AssetManager, NotFoundHttpException, Session, UrlManager, User, View}; -use yii\web\Cookie; use yii2\extensions\psrbridge\exception\Message; use yii2\extensions\psrbridge\http\{ErrorHandler, Request, Response}; use yii2\extensions\psrbridge\tests\provider\StatelessApplicationProvider; From e2df6a4f6f769a5888f8273b32a900788dce84aa Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 10 Aug 2025 14:20:18 -0400 Subject: [PATCH 7/7] refactor(tests): Correct variable name from `$expectedUpdloadedFiles` to `$expectedUploadedFiles` in `ServerRequestAdapterTest` for consistency and clarity. --- tests/adapter/ServerRequestAdapterTest.php | 24 ++++++++++----------- tests/http/StatelessApplicationTest.php | 25 ++++++++++++++++++++-- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/tests/adapter/ServerRequestAdapterTest.php b/tests/adapter/ServerRequestAdapterTest.php index e497f928..566604e8 100644 --- a/tests/adapter/ServerRequestAdapterTest.php +++ b/tests/adapter/ServerRequestAdapterTest.php @@ -711,7 +711,7 @@ public function testReturnUploadedFilesRecursivelyConvertsNestedArrays(): void $deepNestedUploadedFiles = $request->getUploadedFiles(); - $expectedUpdloadedFiles = [ + $expectedUploadedFiles = [ 'file1' => [ 'name' => 'test1.txt', 'type' => 'text/plain', @@ -741,27 +741,27 @@ public function testReturnUploadedFilesRecursivelyConvertsNestedArrays(): void "Uploaded file '{$name}' should be an instance of '" . UploadedFile::class . "'.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['name'] ?? null, + $expectedUploadedFiles[$name]['name'] ?? null, $uploadedFile->name, "Uploaded file '{$name}' should have the expected client filename.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['type'] ?? null, + $expectedUploadedFiles[$name]['type'] ?? null, $uploadedFile->type, "Uploaded file '{$name}' should have the expected client media type.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['tempName'] ?? null, + $expectedUploadedFiles[$name]['tempName'] ?? null, $uploadedFile->tempName, "Uploaded file '{$name}' should have the expected temporary name.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['error'] ?? null, + $expectedUploadedFiles[$name]['error'] ?? null, $uploadedFile->error, "Uploaded file '{$name}' should have the expected error code.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['size'] ?? null, + $expectedUploadedFiles[$name]['size'] ?? null, $uploadedFile->size, "Uploaded file '{$name}' should have the expected size.", ); @@ -819,7 +819,7 @@ public function testReturnUploadedFilesWhenAdapterIsSet(): void 'file1', 'file2', ]; - $expectedUpdloadedFiles = [ + $expectedUploadedFiles = [ 'file1' => [ 'name' => 'test1.txt', 'type' => 'text/plain', @@ -850,27 +850,27 @@ public function testReturnUploadedFilesWhenAdapterIsSet(): void "Uploaded file '{$name}' should be an instance of '" . UploadedFile::class . "'.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['name'] ?? null, + $expectedUploadedFiles[$name]['name'] ?? null, $uploadedFile->name, "Uploaded file '{$name}' should have the expected client filename.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['type'] ?? null, + $expectedUploadedFiles[$name]['type'] ?? null, $uploadedFile->type, "Uploaded file '{$name}' should have the expected client media type.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['tempName'] ?? null, + $expectedUploadedFiles[$name]['tempName'] ?? null, $uploadedFile->tempName, "Uploaded file '{$name}' should have the expected temporary name.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['error'] ?? null, + $expectedUploadedFiles[$name]['error'] ?? null, $uploadedFile->error, "Uploaded file '{$name}' should have the expected error code.", ); self::assertSame( - $expectedUpdloadedFiles[$name]['size'] ?? null, + $expectedUploadedFiles[$name]['size'] ?? null, $uploadedFile->size, "Uploaded file '{$name}' should have the expected size.", ); diff --git a/tests/http/StatelessApplicationTest.php b/tests/http/StatelessApplicationTest.php index 3cb212be..25262fbc 100644 --- a/tests/http/StatelessApplicationTest.php +++ b/tests/http/StatelessApplicationTest.php @@ -1020,6 +1020,16 @@ public function testReturnEmptyCookieCollectionWhenValidationEnabledWithInvalidC ), ); + self::assertSame( + 200, + $response->getStatusCode(), + "Response 'status code' should be '200' for 'site/getcookies' with validation enabled.", + ); + self::assertSame( + 'application/json; charset=UTF-8', + $response->getHeaders()['content-type'][0] ?? '', + "Response 'content-type' should be 'application/json; charset=UTF-8' for 'site/getcookies'.", + ); self::assertSame( '[]', $response->getBody()->getContents(), @@ -1382,6 +1392,17 @@ public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMulti ->withCookieParams($signedCookies), ); + self::assertSame( + 200, + $response->getStatusCode(), + "Response 'status code' should be '200' for 'site/getcookies' route in 'StatelessApplication'.", + ); + self::assertSame( + 'application/json; charset=UTF-8', + $response->getHeaders()['content-type'][0] ?? '', + "Response 'content-type' should be 'application/json; charset=UTF-8' for 'site/getcookies'.", + ); + /** * @phpstan-var array< * string, @@ -1395,7 +1416,7 @@ public function testReturnMultipleValidatedCookiesWhenValidationEnabledWithMulti * httpOnly: bool, * sameSite: string * } - * > + * > $expectedCookies */ $expectedCookies = Json::decode($response->getBody()->getContents()); @@ -1704,7 +1725,7 @@ public function testReturnValidatedCookiesWhenValidationEnabledWithValidCookies( {"valid_session":{"name":"valid_session","value":"abc123session","domain":"","expire":null,"path":"/","secure":false,"httpOnly":true,"sameSite":"Lax"}} JSON, $response->getBody()->getContents(), - "Response 'body' should match expected JSON string for cookie 'validated_session' on 'site/getcookies' " . + "Response 'body' should match expected JSON string for cookie 'valid_session' on 'site/getcookies' " . "route in 'StatelessApplication'.", ); }