Skip to content

Commit 5b04afd

Browse files
authored
Release/4.0.1 (#36)
1 parent eb7ecf3 commit 5b04afd

File tree

9 files changed

+169
-80
lines changed

9 files changed

+169
-80
lines changed

composer.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@
5151
"ext-mbstring": "*"
5252
},
5353
"require-dev": {
54-
"slim/psr7": "^1.7",
55-
"slim/slim": "^4.14",
54+
"slim/psr7": "^1",
55+
"slim/slim": "^4",
5656
"phpmd/phpmd": "^2.15",
5757
"phpstan/phpstan": "^1",
5858
"phpunit/phpunit": "^11",
5959
"infection/infection": "^0",
60-
"squizlabs/php_codesniffer": "^3.11"
60+
"squizlabs/php_codesniffer": "^3.11",
61+
"laminas/laminas-httphandlerrunner": "^2"
6162
},
6263
"suggest": {
6364
"ext-mbstring": "Provides multibyte-specific string functions that help us deal with multibyte encodings in PHP."

src/CacheControl.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ public static function fromResponseDirectives(ResponseCacheDirectives ...$direct
2424

2525
public function toArray(): array
2626
{
27-
return ['Cache-Control' => implode(', ', $this->directives)];
27+
return ['Cache-Control' => [implode(', ', $this->directives)]];
2828
}
2929
}

src/ContentType.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ public static function applicationFormUrlencoded(?Charset $charset = null): Cont
4848

4949
public function toArray(): array
5050
{
51-
return [
52-
'Content-Type' => $this->charset
53-
? sprintf('%s; %s', $this->mimeType->value, $this->charset->toString())
54-
: $this->mimeType->value
55-
];
51+
$value = $this->charset
52+
? sprintf('%s; %s', $this->mimeType->value, $this->charset->toString())
53+
: $this->mimeType->value;
54+
55+
return ['Content-Type' => [$value]];
5656
}
5757
}

src/Internal/Response/ResponseHeaders.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,14 @@ public static function fromOrDefault(Headers ...$headers): ResponseHeaders
2525

2626
public static function fromNameAndValue(string $name, mixed $value): ResponseHeaders
2727
{
28-
return new ResponseHeaders(headers: [$name => $value]);
28+
return new ResponseHeaders(headers: [$name => [$value]]);
2929
}
3030

3131
public function getByName(string $name): array
3232
{
3333
$headers = array_change_key_case($this->headers);
34-
$value = $headers[strtolower($name)] ?? [];
3534

36-
return is_array($value) ? $value : [$value];
35+
return $headers[strtolower($name)] ?? [];
3736
}
3837

3938
public function hasHeader(string $name): bool
@@ -53,7 +52,6 @@ public function removeByName(string $name): ResponseHeaders
5352
return new ResponseHeaders(headers: $headers);
5453
}
5554

56-
5755
public function toArray(): array
5856
{
5957
return $this->headers;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TinyBlocks\Http\Drivers\Laminas;
6+
7+
use DateTimeInterface;
8+
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
9+
use PHPUnit\Framework\MockObject\Exception;
10+
use PHPUnit\Framework\TestCase;
11+
use Psr\Http\Message\ServerRequestInterface;
12+
use TinyBlocks\Http\CacheControl;
13+
use TinyBlocks\Http\Charset;
14+
use TinyBlocks\Http\Code;
15+
use TinyBlocks\Http\ContentType;
16+
use TinyBlocks\Http\Drivers\Endpoint;
17+
use TinyBlocks\Http\Drivers\Middleware;
18+
use TinyBlocks\Http\Response;
19+
use TinyBlocks\Http\ResponseCacheDirectives;
20+
21+
final class LaminasTest extends TestCase
22+
{
23+
private SapiEmitter $emitter;
24+
25+
private Middleware $middleware;
26+
27+
protected function setUp(): void
28+
{
29+
$this->emitter = new SapiEmitter();
30+
$this->middleware = new Middleware();
31+
}
32+
33+
/**
34+
* @throws Exception
35+
*/
36+
public function testSuccessfulRequestProcessingWithLaminas(): void
37+
{
38+
/** @Given a valid request */
39+
$request = $this->createMock(ServerRequestInterface::class);
40+
41+
/** @And the Content-Type for the response is set to application/json with UTF-8 charset */
42+
$contentType = ContentType::applicationJson(charset: Charset::UTF_8);
43+
44+
/** @And a Cache-Control header is set with no-cache directive */
45+
$cacheControl = CacheControl::fromResponseDirectives(noCache: ResponseCacheDirectives::noCache());
46+
47+
/** @And an HTTP response is created with a 200 OK status and a body containing the creation timestamp */
48+
$response = Response::ok(['createdAt' => date(DateTimeInterface::ATOM)], $contentType, $cacheControl);
49+
50+
/** @When the request is processed by the handler */
51+
$actual = $this->middleware->process(request: $request, handler: new Endpoint(response: $response));
52+
53+
/** @Then the response status should indicate success */
54+
self::assertSame(Code::OK->value, $actual->getStatusCode());
55+
56+
/** @And the response body should match the expected body */
57+
self::assertSame($response->getBody()->getContents(), $actual->getBody()->getContents());
58+
59+
/** @And the response headers should match the expected headers */
60+
self::assertSame($response->getHeaders(), $actual->getHeaders());
61+
}
62+
63+
public function testResponseEmissionWithLaminas(): void
64+
{
65+
/** @Given the Content-Type for the response is set to application/json with UTF-8 charset */
66+
$contentType = ContentType::applicationJson(charset: Charset::UTF_8);
67+
68+
/** @And a Cache-Control header is set with no-cache directive */
69+
$cacheControl = CacheControl::fromResponseDirectives(noCache: ResponseCacheDirectives::noCache());
70+
71+
/** @And an HTTP response is created with a 200 OK status and a body containing the creation timestamp */
72+
$response = Response::ok(
73+
['createdAt' => date(DateTimeInterface::ATOM)],
74+
$contentType,
75+
$cacheControl
76+
)->withHeader(name: 'X-Request-ID', value: '123456');
77+
78+
/** @When the response is emitted */
79+
ob_start();
80+
$this->emitter->emit($response);
81+
$actual = ob_get_clean();
82+
83+
/** @Then the emitted response content should match the response body */
84+
self::assertSame($response->getBody()->__toString(), $actual);
85+
}
86+
}

tests/Drivers/Slim/RequestFactory.php

Lines changed: 0 additions & 41 deletions
This file was deleted.

tests/Drivers/Slim/SlimTest.php

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
namespace TinyBlocks\Http\Drivers\Slim;
66

77
use DateTimeInterface;
8+
use PHPUnit\Framework\MockObject\Exception;
89
use PHPUnit\Framework\TestCase;
10+
use Psr\Http\Message\ServerRequestInterface;
11+
use Slim\ResponseEmitter;
912
use TinyBlocks\Http\CacheControl;
1013
use TinyBlocks\Http\Charset;
1114
use TinyBlocks\Http\Code;
@@ -17,20 +20,23 @@
1720

1821
final class SlimTest extends TestCase
1922
{
23+
private ResponseEmitter $emitter;
24+
2025
private Middleware $middleware;
2126

2227
protected function setUp(): void
2328
{
29+
$this->emitter = new ResponseEmitter();
2430
$this->middleware = new Middleware();
2531
}
2632

27-
public function testSuccessfulResponse(): void
33+
/**
34+
* @throws Exception
35+
*/
36+
public function testSuccessfulRequestProcessingWithSlim(): void
2837
{
29-
/** @Given valid data */
30-
$payload = ['id' => PHP_INT_MAX, 'name' => 'Drakkor Emberclaw'];
31-
32-
/** @And this data is used to create a request */
33-
$request = RequestFactory::postFrom(payload: $payload);
38+
/** @Given a valid request */
39+
$request = $this->createMock(ServerRequestInterface::class);
3440

3541
/** @And the Content-Type for the response is set to application/json with UTF-8 charset */
3642
$contentType = ContentType::applicationJson(charset: Charset::UTF_8);
@@ -53,4 +59,28 @@ public function testSuccessfulResponse(): void
5359
/** @And the response headers should match the expected headers */
5460
self::assertSame($response->getHeaders(), $actual->getHeaders());
5561
}
62+
63+
public function testResponseEmissionWithSlim(): void
64+
{
65+
/** @Given the Content-Type for the response is set to application/json with UTF-8 charset */
66+
$contentType = ContentType::applicationJson(charset: Charset::UTF_8);
67+
68+
/** @And a Cache-Control header is set with no-cache directive */
69+
$cacheControl = CacheControl::fromResponseDirectives(noCache: ResponseCacheDirectives::noCache());
70+
71+
/** @And an HTTP response is created with a 200 OK status and a body containing the creation timestamp */
72+
$response = Response::ok(
73+
['createdAt' => date(DateTimeInterface::ATOM)],
74+
$contentType,
75+
$cacheControl
76+
)->withHeader(name: 'X-Request-ID', value: '123456');
77+
78+
/** @When the response is emitted */
79+
ob_start();
80+
$this->emitter->emit($response);
81+
$actual = ob_get_clean();
82+
83+
/** @Then the emitted response content should match the response body */
84+
self::assertSame($response->getBody()->__toString(), $actual);
85+
}
5686
}

tests/Response/HeadersTest.php

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public function testResponseWithCustomHeaders(): void
1818
$response = Response::noContent();
1919

2020
/** @And by default, the response contains the 'Content-Type' header set to 'application/json; charset=utf-8' */
21-
self::assertSame(['Content-Type' => 'application/json; charset=utf-8'], $response->getHeaders());
21+
self::assertSame(['Content-Type' => ['application/json; charset=utf-8']], $response->getHeaders());
2222

2323
/** @When we add custom headers to the response */
2424
$actual = $response
@@ -27,7 +27,7 @@ public function testResponseWithCustomHeaders(): void
2727

2828
/** @Then the response should contain the correct headers */
2929
self::assertSame(
30-
['Content-Type' => 'application/json; charset=utf-8', 'X-ID' => 100, 'X-NAME' => 'Xpto'],
30+
['Content-Type' => ['application/json; charset=utf-8'], 'X-ID' => [100], 'X-NAME' => ['Xpto']],
3131
$actual->getHeaders()
3232
);
3333

@@ -37,15 +37,18 @@ public function testResponseWithCustomHeaders(): void
3737
/** @Then the response should contain the updated 'X-ID' header value */
3838
self::assertSame('200', $actual->withAddedHeader(name: 'X-ID', value: 200)->getHeaderLine(name: 'X-ID'));
3939
self::assertSame(
40-
['Content-Type' => 'application/json; charset=utf-8', 'X-ID' => 200, 'X-NAME' => 'Xpto'],
40+
['Content-Type' => ['application/json; charset=utf-8'], 'X-ID' => [200], 'X-NAME' => ['Xpto']],
4141
$actual->getHeaders()
4242
);
4343

4444
/** @And when we remove the 'X-NAME' header */
4545
$actual = $actual->withoutHeader(name: 'X-NAME');
4646

4747
/** @Then the response should contain only the 'X-ID' header and the default 'Content-Type' header */
48-
self::assertSame(['Content-Type' => 'application/json; charset=utf-8', 'X-ID' => 200], $actual->getHeaders());
48+
self::assertSame(
49+
['Content-Type' => ['application/json; charset=utf-8'], 'X-ID' => [200]],
50+
$actual->getHeaders()
51+
);
4952
}
5053

5154
public function testResponseWithDuplicatedHeader(): void
@@ -62,7 +65,19 @@ public function testResponseWithDuplicatedHeader(): void
6265
self::assertSame('application/json; charset=ISO-8859-1', $actual->getHeaderLine(name: 'Content-Type'));
6366

6467
/** @And the headers should only contain the last 'Content-Type' value */
65-
self::assertSame(['Content-Type' => 'application/json; charset=ISO-8859-1'], $actual->getHeaders());
68+
self::assertSame(['Content-Type' => ['application/json; charset=ISO-8859-1']], $actual->getHeaders());
69+
}
70+
71+
public function testResponseHeadersWithNoCustomHeader(): void
72+
{
73+
/** @Given an HTTP response with no custom headers */
74+
$response = Response::noContent();
75+
76+
/** @When we retrieve the header that doesn't exist */
77+
$actual = $response->getHeader(name: 'Non-Existent-Header');
78+
79+
/** @Then the header should return an empty array */
80+
self::assertSame([], $actual);
6681
}
6782

6883
public function testResponseWithCacheControl(): void
@@ -108,7 +123,7 @@ public function testResponseWithContentTypePDF(): void
108123

109124
self::assertSame($expected, $actual->getHeaderLine(name: 'Content-Type'));
110125
self::assertSame([$expected], $actual->getHeader(name: 'Content-Type'));
111-
self::assertSame(['Content-Type' => $expected], $actual->getHeaders());
126+
self::assertSame(['Content-Type' => [$expected]], $actual->getHeaders());
112127
}
113128

114129
public function testResponseWithContentTypeHTML(): void
@@ -127,7 +142,7 @@ public function testResponseWithContentTypeHTML(): void
127142

128143
self::assertSame($expected, $actual->getHeaderLine(name: 'Content-Type'));
129144
self::assertSame([$expected], $actual->getHeader(name: 'Content-Type'));
130-
self::assertSame(['Content-Type' => $expected], $actual->getHeaders());
145+
self::assertSame(['Content-Type' => [$expected]], $actual->getHeaders());
131146
}
132147

133148
public function testResponseWithContentTypeJSON(): void
@@ -146,7 +161,7 @@ public function testResponseWithContentTypeJSON(): void
146161

147162
self::assertSame($expected, $actual->getHeaderLine(name: 'Content-Type'));
148163
self::assertSame([$expected], $actual->getHeader(name: 'Content-Type'));
149-
self::assertSame(['Content-Type' => $expected], $actual->getHeaders());
164+
self::assertSame(['Content-Type' => [$expected]], $actual->getHeaders());
150165
}
151166

152167
public function testResponseWithContentTypePlainText(): void
@@ -165,7 +180,7 @@ public function testResponseWithContentTypePlainText(): void
165180

166181
self::assertSame($expected, $actual->getHeaderLine(name: 'Content-Type'));
167182
self::assertSame([$expected], $actual->getHeader(name: 'Content-Type'));
168-
self::assertSame(['Content-Type' => $expected], $actual->getHeaders());
183+
self::assertSame(['Content-Type' => [$expected]], $actual->getHeaders());
169184
}
170185

171186
public function testResponseWithContentTypeOctetStream(): void
@@ -184,7 +199,7 @@ public function testResponseWithContentTypeOctetStream(): void
184199

185200
self::assertSame($expected, $actual->getHeaderLine(name: 'Content-Type'));
186201
self::assertSame([$expected], $actual->getHeader(name: 'Content-Type'));
187-
self::assertSame(['Content-Type' => $expected], $actual->getHeaders());
202+
self::assertSame(['Content-Type' => [$expected]], $actual->getHeaders());
188203
}
189204

190205
public function testResponseWithContentTypeFormUrlencoded(): void
@@ -203,6 +218,6 @@ public function testResponseWithContentTypeFormUrlencoded(): void
203218

204219
self::assertSame($expected, $actual->getHeaderLine(name: 'Content-Type'));
205220
self::assertSame([$expected], $actual->getHeader(name: 'Content-Type'));
206-
self::assertSame(['Content-Type' => $expected], $actual->getHeaders());
221+
self::assertSame(['Content-Type' => [$expected]], $actual->getHeaders());
207222
}
208223
}

0 commit comments

Comments
 (0)