From 9311b90bb469e2c49b314dcc9b89ed88b7425b37 Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Sat, 15 Oct 2022 17:41:04 -0500 Subject: [PATCH 1/8] Require PHP 7.4 --- .github/workflows/ci.yml | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a238b8..44989f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: operating-system: [ ubuntu-latest ] - php-versions: [ '7.2','7.3', '7.4', '8.0', '8.1' ] + php-versions: [ '7.4', '8.0', '8.1' ] runs-on: ${{ matrix.operating-system }} diff --git a/composer.json b/composer.json index 0b78ce5..f9851d7 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "library", "require": { "psr/http-message": "^1.0", - "php": ">=7.2" + "php": ">=7.4" }, "require-dev": { "phpunit/phpunit": "^6.5 || ^9.3", From 64bd766e4dd6d5016e66895ebfddd12bf2e08dde Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Sat, 15 Oct 2022 18:17:09 -0500 Subject: [PATCH 2/8] Adds rough CookieBuilder --- LICENSE.md | 1 + src/CookieBuilder.php | 212 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 src/CookieBuilder.php diff --git a/LICENSE.md b/LICENSE.md index 90a5463..bd7f42b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -3,6 +3,7 @@ The MIT License Copyright (c) 2021 Jesse G. Donat Copyright (c) 2017 Woody Gilk +Copyright (c) 2017 Hans Ott hansott@hotmail.be Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/CookieBuilder.php b/src/CookieBuilder.php new file mode 100644 index 0000000..e257b11 --- /dev/null +++ b/src/CookieBuilder.php @@ -0,0 +1,212 @@ +name = $name; + $this->value = $value; + $this->expiration = $expiration; + $this->path = $path; + $this->domain = $domain; + $this->secure = $secure; + $this->httpOnly = $httpOnly; + $this->sameSite = $sameSite; + } + + /** + * Apply the Cookie to a callable matching the signature of PHP 7.4+ + * `setcookie(string $name, string $value = "", array $options = []) : bool` + */ + public function apply( callable $callee = "\\setcookie" ) : bool { + return $callee( + $this->name, + $this->value, + [ + 'expires' => $this->expiration + time(), + 'path' => $this->path, + 'domain' => $this->domain, + 'secure' => $this->secure, + 'httponly' => $this->httpOnly, + 'samesite' => $this->sameSite, + ], + ); + } + + public function responseWithHeaderAdded( ResponseInterface $response ) : ResponseInterface { + return $response->withAddedHeader('Set-Cookie', $this->toHeaderValue()); + } + + public function responseWithHeader( ResponseInterface $response ) : ResponseInterface { + return $response->withHeader('Set-Cookie', $this->toHeaderValue()); + } + + public function withName( string $name ) : self { + $clone = clone $this; + $clone->name = $name; + + return $clone; + } + + public function withValue( string $value ) : self { + $that = clone $this; + $that->value = $value; + + return $that; + } + + /** + * Expire the cookie NOW and invoke it. + */ + public function withExpireNow() : self { + $that = clone $this; + $that->expiration = -604800; + $that->value = ''; + + return $that; + } + + public function withExpiration( int $expiration ) : self { + $that = clone $this; + $that->expiration = $expiration; + + return $that; + } + + public function withPath( string $path ) : self { + $that = clone $this; + $that->path = $path; + + return $that; + } + + public function withDomain( string $domain ) : self { + $that = clone $this; + $that->domain = $domain; + + return $that; + } + + public function withSecure( bool $secure ) : self { + $that = clone $this; + $that->secure = $secure; + + return $that; + } + + public function withHttpOnly( bool $httpOnly ) : self { + $that = clone $this; + $that->httpOnly = $httpOnly; + + return $that; + } + + public function withSameSite( string $sameSite ) : self { + $that = clone $this; + $that->sameSite = $sameSite; + + return $that; + } + + public function getName() : string { + return $this->name; + } + + public function getExpiration() : int { + return $this->expiration; + } + + public function getPath() : string { + return $this->path; + } + + public function getDomain() : string { + return $this->domain; + } + + public function isSecure() : bool { + return $this->secure; + } + + public function isHttpOnly() : bool { + return $this->httpOnly; + } + + public function getSameSite() : string { + return $this->sameSite; + } + + public function getValue() : string { + return $this->value; + } + + public function toHeaderValue() : string { + $headerValue = sprintf('%s=%s', $this->name, urlencode($this->value)); + + if( $this->expiration !== 0 ) { + $headerValue .= sprintf( + '; expires=%s', + gmdate(DATE_RFC1123, time() + $this->expiration) + ); + } + + if( $this->path ) { + $headerValue .= sprintf('; path=%s', $this->path); + } + + if( $this->domain ) { + $headerValue .= sprintf('; domain=%s', $this->domain); + } + + if( $this->secure ) { + $headerValue .= '; secure'; + } + + if( $this->httpOnly ) { + $headerValue .= '; httponly'; + } + + if( $this->sameSite ) { + $headerValue .= sprintf('; samesite=%s', $this->sameSite); + } + + return $headerValue; + } + +} From 3179eddec98b199c7608c633008f797228c7190e Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Sun, 16 Oct 2022 15:12:47 -0500 Subject: [PATCH 3/8] Adds a massive ammount of docs --- src/CookieBuilder.php | 79 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/src/CookieBuilder.php b/src/CookieBuilder.php index e257b11..ff208ec 100644 --- a/src/CookieBuilder.php +++ b/src/CookieBuilder.php @@ -27,8 +27,10 @@ class CookieBuilder { * @param string $path The path on which this cookie is available * @param string $domain The domain to which the cookie is sent * @param bool $secure Indicates that the cookie should only be transmitted over a secure HTTPS connection - * @param bool $httpOnly When true the cookie will be made accessible only through the HTTP protocol, e.g. Not JavaScript - * @param string $sameSite Set the SameSite value - expects "None", "Lax" or "Strict". If the samesite element is empty, no SameSite cookie attribute is set + * @param bool $httpOnly When true the cookie will be made accessible only through the HTTP protocol, e.g. Not + * JavaScript + * @param string $sameSite Set the SameSite value - expects "None", "Lax" or "Strict". If the samesite element is + * empty, no SameSite cookie attribute is set */ public function __construct( string $name, @@ -69,21 +71,35 @@ public function apply( callable $callee = "\\setcookie" ) : bool { ); } + /** + * Given a \Psr\Http\Message\ResponseInterface returns a new instance of ResponseInterface with an added + * `Set-Cookie` header representing this Cookie. + */ public function responseWithHeaderAdded( ResponseInterface $response ) : ResponseInterface { return $response->withAddedHeader('Set-Cookie', $this->toHeaderValue()); } + /** + * Given a \Psr\Http\Message\ResponseInterface returns a new instance of ResponseInterface replacing any + * `Set-Cookie` headers with one representing this Cookie. + */ public function responseWithHeader( ResponseInterface $response ) : ResponseInterface { return $response->withHeader('Set-Cookie', $this->toHeaderValue()); } + /** + * Return an instance with the specified name. + */ public function withName( string $name ) : self { - $clone = clone $this; + $clone = clone $this; $clone->name = $name; return $clone; } + /** + * Return an instance with the specified value. + */ public function withValue( string $value ) : self { $that = clone $this; $that->value = $value; @@ -92,7 +108,7 @@ public function withValue( string $value ) : self { } /** - * Expire the cookie NOW and invoke it. + * Return an instance with an expiration in the past and a cleared value. */ public function withExpireNow() : self { $that = clone $this; @@ -102,6 +118,11 @@ public function withExpireNow() : self { return $that; } + /** + * Return an instance with the specified duration. + * + * @param int $expiration The number of seconds for which this cookie will be valid. `time() + $expiration` + */ public function withExpiration( int $expiration ) : self { $that = clone $this; $that->expiration = $expiration; @@ -109,6 +130,9 @@ public function withExpiration( int $expiration ) : self { return $that; } + /** + * Return an instance with the specified path. + */ public function withPath( string $path ) : self { $that = clone $this; $that->path = $path; @@ -116,6 +140,9 @@ public function withPath( string $path ) : self { return $that; } + /** + * Return an instance with the specified domain. + */ public function withDomain( string $domain ) : self { $that = clone $this; $that->domain = $domain; @@ -123,6 +150,9 @@ public function withDomain( string $domain ) : self { return $that; } + /** + * Return an instance with the specified secure flag. + */ public function withSecure( bool $secure ) : self { $that = clone $this; $that->secure = $secure; @@ -130,6 +160,9 @@ public function withSecure( bool $secure ) : self { return $that; } + /** + * Return an instance with the specified httpOnly flag. + */ public function withHttpOnly( bool $httpOnly ) : self { $that = clone $this; $that->httpOnly = $httpOnly; @@ -137,6 +170,9 @@ public function withHttpOnly( bool $httpOnly ) : self { return $that; } + /** + * Return an instance with the specified SameSite value. + */ public function withSameSite( string $sameSite ) : self { $that = clone $this; $that->sameSite = $sameSite; @@ -144,38 +180,65 @@ public function withSameSite( string $sameSite ) : self { return $that; } + /** + * Get the cookie name. + */ public function getName() : string { return $this->name; } + /** + * Get the cookie value. + */ + public function getValue() : string { + return $this->value; + } + + /** + * Get the cookie expiration. + */ public function getExpiration() : int { return $this->expiration; } + /** + * Get the cookie path. + */ public function getPath() : string { return $this->path; } + /** + * Get the cookie domain. + */ public function getDomain() : string { return $this->domain; } + /** + * Get the cookie secure flag. + */ public function isSecure() : bool { return $this->secure; } + /** + * Get the cookie httpOnly flag. + */ public function isHttpOnly() : bool { return $this->httpOnly; } + /** + * Get the cookie SameSite value. + */ public function getSameSite() : string { return $this->sameSite; } - public function getValue() : string { - return $this->value; - } - + /** + * Get the cookie as a header value. + */ public function toHeaderValue() : string { $headerValue = sprintf('%s=%s', $this->name, urlencode($this->value)); From 136afa84ad2907480fbf2139ecf6462511755d1e Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Sun, 16 Oct 2022 15:28:53 -0500 Subject: [PATCH 4/8] Pull CookieEncoder out of CookieBuilder, move into Cookie namespace. --- src/{ => Cookie}/CookieBuilder.php | 75 +++------------------------ src/Cookie/CookieEncoder.php | 47 +++++++++++++++++ src/Cookie/CookieEncoderInterface.php | 12 +++++ src/Cookie/CookieInterface.php | 47 +++++++++++++++++ 4 files changed, 114 insertions(+), 67 deletions(-) rename src/{ => Cookie}/CookieBuilder.php (78%) create mode 100644 src/Cookie/CookieEncoder.php create mode 100644 src/Cookie/CookieEncoderInterface.php create mode 100644 src/Cookie/CookieInterface.php diff --git a/src/CookieBuilder.php b/src/Cookie/CookieBuilder.php similarity index 78% rename from src/CookieBuilder.php rename to src/Cookie/CookieBuilder.php index ff208ec..7914f4d 100644 --- a/src/CookieBuilder.php +++ b/src/Cookie/CookieBuilder.php @@ -1,16 +1,13 @@ secure = $secure; $this->httpOnly = $httpOnly; $this->sameSite = $sameSite; + + $this->encoder = new CookieEncoder; } /** @@ -76,7 +77,7 @@ public function apply( callable $callee = "\\setcookie" ) : bool { * `Set-Cookie` header representing this Cookie. */ public function responseWithHeaderAdded( ResponseInterface $response ) : ResponseInterface { - return $response->withAddedHeader('Set-Cookie', $this->toHeaderValue()); + return $response->withAddedHeader('Set-Cookie', ($this->encoder)($this)); } /** @@ -84,7 +85,7 @@ public function responseWithHeaderAdded( ResponseInterface $response ) : Respons * `Set-Cookie` headers with one representing this Cookie. */ public function responseWithHeader( ResponseInterface $response ) : ResponseInterface { - return $response->withHeader('Set-Cookie', $this->toHeaderValue()); + return $response->withHeader('Set-Cookie', ($this->encoder)($this)); } /** @@ -180,96 +181,36 @@ public function withSameSite( string $sameSite ) : self { return $that; } - /** - * Get the cookie name. - */ public function getName() : string { return $this->name; } - /** - * Get the cookie value. - */ public function getValue() : string { return $this->value; } - /** - * Get the cookie expiration. - */ public function getExpiration() : int { return $this->expiration; } - /** - * Get the cookie path. - */ public function getPath() : string { return $this->path; } - /** - * Get the cookie domain. - */ public function getDomain() : string { return $this->domain; } - /** - * Get the cookie secure flag. - */ public function isSecure() : bool { return $this->secure; } - /** - * Get the cookie httpOnly flag. - */ public function isHttpOnly() : bool { return $this->httpOnly; } - /** - * Get the cookie SameSite value. - */ public function getSameSite() : string { return $this->sameSite; } - /** - * Get the cookie as a header value. - */ - public function toHeaderValue() : string { - $headerValue = sprintf('%s=%s', $this->name, urlencode($this->value)); - - if( $this->expiration !== 0 ) { - $headerValue .= sprintf( - '; expires=%s', - gmdate(DATE_RFC1123, time() + $this->expiration) - ); - } - - if( $this->path ) { - $headerValue .= sprintf('; path=%s', $this->path); - } - - if( $this->domain ) { - $headerValue .= sprintf('; domain=%s', $this->domain); - } - - if( $this->secure ) { - $headerValue .= '; secure'; - } - - if( $this->httpOnly ) { - $headerValue .= '; httponly'; - } - - if( $this->sameSite ) { - $headerValue .= sprintf('; samesite=%s', $this->sameSite); - } - - return $headerValue; - } - } diff --git a/src/Cookie/CookieEncoder.php b/src/Cookie/CookieEncoder.php new file mode 100644 index 0000000..2f4898b --- /dev/null +++ b/src/Cookie/CookieEncoder.php @@ -0,0 +1,47 @@ +getName(), urlencode($cookie->getValue())); + + if( $cookie->getExpiration() !== 0 ) { + $headerValue .= sprintf( + '; expires=%s', + gmdate(DATE_RFC1123, time() + $cookie->getExpiration()) + ); + } + + if( $cookie->getPath() ) { + $headerValue .= sprintf('; path=%s', $cookie->getPath()); + } + + if( $cookie->getDomain() ) { + $headerValue .= sprintf('; domain=%s', $cookie->getDomain()); + } + + if( $cookie->isSecure() ) { + $headerValue .= '; secure'; + } + + if( $cookie->isHttpOnly() ) { + $headerValue .= '; httponly'; + } + + if( $cookie->getSameSite() ) { + $headerValue .= sprintf('; samesite=%s', $cookie->getSameSite()); + } + + return $headerValue; + } + +} diff --git a/src/Cookie/CookieEncoderInterface.php b/src/Cookie/CookieEncoderInterface.php new file mode 100644 index 0000000..6e1e920 --- /dev/null +++ b/src/Cookie/CookieEncoderInterface.php @@ -0,0 +1,12 @@ + Date: Sun, 16 Oct 2022 15:30:41 -0500 Subject: [PATCH 5/8] Fixes `apply` callable default value, improves documentation --- src/Cookie/CookieBuilder.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Cookie/CookieBuilder.php b/src/Cookie/CookieBuilder.php index 7914f4d..ca300aa 100644 --- a/src/Cookie/CookieBuilder.php +++ b/src/Cookie/CookieBuilder.php @@ -54,10 +54,17 @@ public function __construct( } /** - * Apply the Cookie to a callable matching the signature of PHP 7.4+ + * Apply the Cookie to `setcookie` a callable matching the signature of PHP 7.4+ * `setcookie(string $name, string $value = "", array $options = []) : bool` + * + * @param callable|null $callee The `setcookie` compatible callback to be used. + * If set to null, the default setcookie() */ - public function apply( callable $callee = "\\setcookie" ) : bool { + public function apply( ?callable $callee = null ) : bool { + if( $callee === null ) { + $callee = '\\setcookie'; + } + return $callee( $this->name, $this->value, From 2cf80fde85aa61790f3b30dc15b3bf555ec07ffa Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Sun, 16 Oct 2022 15:36:14 -0500 Subject: [PATCH 6/8] Exclude Interface from docs --- .mddoc.xml.dist | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.mddoc.xml.dist b/.mddoc.xml.dist index f1bb507..b88401c 100644 --- a/.mddoc.xml.dist +++ b/.mddoc.xml.dist @@ -18,9 +18,10 @@
- \ No newline at end of file + From 08b8980d1766f9b5cc3e90338353b6c2d051741f Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Sun, 16 Oct 2022 15:47:09 -0500 Subject: [PATCH 7/8] Makes cookie encoding purely the buisness of CookieEncoder --- src/Cookie/CookieBuilder.php | 50 +------------------------- src/Cookie/CookieEncoder.php | 52 +++++++++++++++++++++++++-- src/Cookie/CookieEncoderInterface.php | 12 ------- 3 files changed, 51 insertions(+), 63 deletions(-) delete mode 100644 src/Cookie/CookieEncoderInterface.php diff --git a/src/Cookie/CookieBuilder.php b/src/Cookie/CookieBuilder.php index ca300aa..b0bf556 100644 --- a/src/Cookie/CookieBuilder.php +++ b/src/Cookie/CookieBuilder.php @@ -2,8 +2,6 @@ namespace Corpus\HttpMessageUtils\Cookie; -use Psr\Http\Message\ResponseInterface; - /** * Utility to build an HTTP Cookie header */ @@ -18,8 +16,6 @@ class CookieBuilder implements CookieInterface { private bool $httpOnly; private string $sameSite; - private CookieEncoder $encoder; - /** * @param string $name The name of the cookie * @param int $expiration The number of seconds for which this cookie will be valid. `time() + $expiration` @@ -39,7 +35,7 @@ public function __construct( string $domain = '', bool $secure = false, bool $httpOnly = false, - string $sameSite = "None" + string $sameSite = '' ) { $this->name = $name; $this->value = $value; @@ -49,50 +45,6 @@ public function __construct( $this->secure = $secure; $this->httpOnly = $httpOnly; $this->sameSite = $sameSite; - - $this->encoder = new CookieEncoder; - } - - /** - * Apply the Cookie to `setcookie` a callable matching the signature of PHP 7.4+ - * `setcookie(string $name, string $value = "", array $options = []) : bool` - * - * @param callable|null $callee The `setcookie` compatible callback to be used. - * If set to null, the default setcookie() - */ - public function apply( ?callable $callee = null ) : bool { - if( $callee === null ) { - $callee = '\\setcookie'; - } - - return $callee( - $this->name, - $this->value, - [ - 'expires' => $this->expiration + time(), - 'path' => $this->path, - 'domain' => $this->domain, - 'secure' => $this->secure, - 'httponly' => $this->httpOnly, - 'samesite' => $this->sameSite, - ], - ); - } - - /** - * Given a \Psr\Http\Message\ResponseInterface returns a new instance of ResponseInterface with an added - * `Set-Cookie` header representing this Cookie. - */ - public function responseWithHeaderAdded( ResponseInterface $response ) : ResponseInterface { - return $response->withAddedHeader('Set-Cookie', ($this->encoder)($this)); - } - - /** - * Given a \Psr\Http\Message\ResponseInterface returns a new instance of ResponseInterface replacing any - * `Set-Cookie` headers with one representing this Cookie. - */ - public function responseWithHeader( ResponseInterface $response ) : ResponseInterface { - return $response->withHeader('Set-Cookie', ($this->encoder)($this)); } /** diff --git a/src/Cookie/CookieEncoder.php b/src/Cookie/CookieEncoder.php index 2f4898b..c07f36a 100644 --- a/src/Cookie/CookieEncoder.php +++ b/src/Cookie/CookieEncoder.php @@ -2,16 +2,22 @@ namespace Corpus\HttpMessageUtils\Cookie; +use Psr\Http\Message\ResponseInterface; + /** * Utility to encode a Cookie into a `Set-Cookie` header * * Based on `hansott/psr7-cookies` * MIT License Copyright (c) 2017 Hans Ott hansott@hotmail.be + * * @see https://github.com/hansott/psr7-cookies/blob/ec7bc4b3393677730b1e607c987328655d27dfbf/src/SetCookie.php#L160-L192 */ -class CookieEncoder implements CookieEncoderInterface { +class CookieEncoder { - public function __invoke( CookieInterface $cookie ) : string { + /** + * Encode the given Cookie to a `Set-Cookie` compatible header string + */ + public function encode( CookieInterface $cookie ) : string { $headerValue = sprintf('%s=%s', $cookie->getName(), urlencode($cookie->getValue())); if( $cookie->getExpiration() !== 0 ) { @@ -44,4 +50,46 @@ public function __invoke( CookieInterface $cookie ) : string { return $headerValue; } + /** + * Apply the Cookie to `setcookie` a callable matching the signature of PHP 7.4+ + * `setcookie(string $name, string $value = "", array $options = []) : bool` + * + * @param callable|null $callee The `setcookie` compatible callback to be used. + * If set to null, the default setcookie() + */ + public function apply( CookieInterface $cookie, ?callable $callee = null ) : bool { + if( $callee === null ) { + $callee = '\\setcookie'; + } + + return $callee( + $cookie->getName(), + $cookie->getValue(), + [ + 'expires' => $cookie->getExpiration() + time(), + 'path' => $cookie->getPath(), + 'domain' => $cookie->getDomain(), + 'secure' => $cookie->isSecure(), + 'httponly' => $cookie->isHttpOnly(), + 'samesite' => $cookie->getSameSite(), + ], + ); + } + + /** + * Given a \Psr\Http\Message\ResponseInterface returns a new instance of ResponseInterface with an added + * `Set-Cookie` header representing this Cookie. + */ + public function responseWithHeaderAdded( CookieInterface $cookie, ResponseInterface $response ) : ResponseInterface { + return $response->withAddedHeader('Set-Cookie', $this->encode($cookie)); + } + + /** + * Given a \Psr\Http\Message\ResponseInterface returns a new instance of ResponseInterface replacing any + * `Set-Cookie` headers with one representing this Cookie. + */ + public function responseWithHeader( CookieInterface $cookie, ResponseInterface $response ) : ResponseInterface { + return $response->withHeader('Set-Cookie', $this->encode($cookie)); + } + } diff --git a/src/Cookie/CookieEncoderInterface.php b/src/Cookie/CookieEncoderInterface.php deleted file mode 100644 index 6e1e920..0000000 --- a/src/Cookie/CookieEncoderInterface.php +++ /dev/null @@ -1,12 +0,0 @@ - Date: Sun, 16 Oct 2022 15:48:37 -0500 Subject: [PATCH 8/8] Adds rough CookieBuilderTest --- test/Cookie/CookieBuilderTest.php | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 test/Cookie/CookieBuilderTest.php diff --git a/test/Cookie/CookieBuilderTest.php b/test/Cookie/CookieBuilderTest.php new file mode 100644 index 0000000..3459fb9 --- /dev/null +++ b/test/Cookie/CookieBuilderTest.php @@ -0,0 +1,56 @@ +withName('WayDifferentCookie'); + $this->assertSame('WayDifferentCookie', $valueCheck->getName()); + $this->assertSame('ExampleCookie', $cookieBuilder->getName()); + + $valueCheck = $cookieBuilder->withValue('test'); + $this->assertSame('test', $valueCheck->getValue()); + $this->assertSame('', $cookieBuilder->getValue()); + + $valueCheck = $cookieBuilder->withExpiration(123); + $this->assertSame(123, $valueCheck->getExpiration()); + $this->assertSame(0, $cookieBuilder->getExpiration()); + + $valueCheck = $cookieBuilder->withPath('/test'); + $this->assertSame('/test', $valueCheck->getPath()); + $this->assertSame('', $cookieBuilder->getPath()); + + $valueCheck = $cookieBuilder->withDomain('www.example.dev'); + $this->assertSame('www.example.dev', $valueCheck->getDomain()); + $this->assertSame('', $cookieBuilder->getDomain()); + + $valueCheck = $cookieBuilder->withHttpOnly(true); + $this->assertTrue($valueCheck->isHttpOnly()); + $this->assertFalse($cookieBuilder->isHttpOnly()); + + $valueCheck = $cookieBuilder->withSecure(true); + $this->assertTrue($valueCheck->isSecure()); + $this->assertFalse($cookieBuilder->isSecure()); + + $valueCheck = $cookieBuilder->withSameSite('Lax'); + $this->assertSame('Lax', $valueCheck->getSameSite()); + $this->assertSame('', $cookieBuilder->getSameSite()); + } + + public function test_withExpireNow() : void { + $cookieBuilder = (new CookieBuilder('ExampleCookie')) + ->withValue('bye bye birdie') + ->withExpiration(123); + + $cookieBuilder = $cookieBuilder->withExpireNow(); + $this->assertSame('', $cookieBuilder->getValue()); + $this->assertLessThan(0, $cookieBuilder->getExpiration()); + } + +}