From 4796e1d5c5d5a19f42e74a4edd5548c532662ccf Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 13 Aug 2020 07:26:19 -0400 Subject: [PATCH] Refactor Transmitter --- src/Transmission/Transmitter.php | 19 +++--- test/src/HeaderStack.php | 28 -------- .../unit/Transmission/TransmitterTest.php | 65 ++++++++++++++----- 3 files changed, 57 insertions(+), 55 deletions(-) delete mode 100644 test/src/HeaderStack.php diff --git a/src/Transmission/Transmitter.php b/src/Transmission/Transmitter.php index 768c458..451131b 100644 --- a/src/Transmission/Transmitter.php +++ b/src/Transmission/Transmitter.php @@ -53,25 +53,26 @@ class Transmitter implements TransmitterInterface $this->chunkSize = $chunkSize; } - protected function prepareResponse( + private function prepareResponse( ServerRequestInterface $request, ResponseInterface $response ): ResponseInterface { - // Add a Content-length header to the response when all of these are true: + // Add Content-length header to the response when all of these are true: // // - Response does not have a Content-length header // - Response does not have a Transfer-encoding: chunked header // - Response body stream is readable and reports a non-null size // - if (!$response->hasHeader('Content-length') - && !(strtolower($response->getHeaderLine('Transfer-encoding')) === 'chunked') - ) { - $size = $response->getBody()->getSize(); - if ($size !== null) { - $response = $response->withHeader('Content-length', (string) $size); - } + $contentLengthMissing = !$response->hasHeader('Content-length'); + $notChunked = strtolower($response->getHeaderLine('Transfer-encoding')) + !== 'chunked'; + $size = $response->getBody()->getSize(); + + if ($contentLengthMissing && $notChunked && $size !== null) { + $response = $response->withHeader('Content-length', (string) $size); } + return $response; } diff --git a/test/src/HeaderStack.php b/test/src/HeaderStack.php deleted file mode 100644 index 23e309f..0000000 --- a/test/src/HeaderStack.php +++ /dev/null @@ -1,28 +0,0 @@ -withBody($stream); } - public function testSendStatusCodeWithReasonPhrase() + public function testSendStatusCodeWithReasonPhrase(): void { $transmitter = new Transmitter(); $transmitter->transmit($this->request, $this->response); $this->assertContains('HTTP/1.1 200 OK', HeaderStack::getHeaders()); } - public function testSendStatusCodeWithoutReasonPhrase() + public function testSendStatusCodeWithoutReasonPhrase(): void { $this->response = $this->response->withStatus(999); @@ -56,8 +52,11 @@ class TransmitterTest extends TestCase $this->assertContains('HTTP/1.1 999', HeaderStack::getHeaders()); } - /** @dataProvider headerProvider */ - public function testSendsHeaders($header) + /** + * @dataProvider headerProvider + * @param string $header + */ + public function testSendsHeaders(string $header): void { $this->response = $this->response ->withHeader('Content-length', ['2048']) @@ -68,7 +67,7 @@ class TransmitterTest extends TestCase $this->assertContains($header, HeaderStack::getHeaders()); } - public function headerProvider() + public function headerProvider(): array { return [ ['Content-length: 2048'], @@ -77,7 +76,7 @@ class TransmitterTest extends TestCase ]; } - public function testOutputsBody() + public function testOutputsBody(): void { $content = 'Hello, world!'; @@ -95,7 +94,7 @@ class TransmitterTest extends TestCase $this->assertEquals($content, $captured); } - public function testOutputsBodyInChunks() + public function testOutputsBodyInChunks(): void { $content = 'Hello, world!'; $chunkSize = 3; @@ -128,7 +127,7 @@ class TransmitterTest extends TestCase $this->assertEquals($content, $captured); } - public function testOutputsUnseekableStreamInChunks() + public function testOutputsUnseekableStreamInChunks(): void { $content = 'Hello, world!'; $chunkSize = 3; @@ -164,7 +163,7 @@ class TransmitterTest extends TestCase // ------------------------------------------------------------------------ // Preparation - public function testAddContentLengthHeader() + public function testAddContentLengthHeader(): void { $bodySize = 1024; $this->body->isReadable()->willReturn(true); @@ -178,7 +177,7 @@ class TransmitterTest extends TestCase $this->assertContains("Content-length: $bodySize", HeaderStack::getHeaders()); } - public function testDoesNotReplaceContentLengthHeaderWhenContentLengthIsAlreadySet() + public function testDoesNotReplaceContentLengthHeaderWhenContentLengthIsAlreadySet(): void { $streamSize = 1024; $headerSize = 2048; @@ -196,7 +195,7 @@ class TransmitterTest extends TestCase $this->assertContains("Content-length: $headerSize", HeaderStack::getHeaders()); } - public function testDoesNotAddContentLengthHeaderWhenTransferEncodingIsChunked() + public function testDoesNotAddContentLengthHeaderWhenTransferEncodingIsChunked(): void { $bodySize = 1024; @@ -213,7 +212,7 @@ class TransmitterTest extends TestCase $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:'); } - public function testDoesNotAddContentLengthHeaderWhenBodySizeIsNull() + public function testDoesNotAddContentLengthHeaderWhenBodySizeIsNull(): void { $this->body->isReadable()->willReturn(true); $this->body->__toString()->willReturn(''); @@ -226,7 +225,7 @@ class TransmitterTest extends TestCase $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:'); } - private function assertArrayDoesNotContainValueWithPrefix($arr, $prefix) + private function assertArrayDoesNotContainValueWithPrefix(array $arr, string $prefix): void { $normalPrefix = strtolower($prefix); foreach ($arr as $item) { @@ -238,3 +237,33 @@ class TransmitterTest extends TestCase $this->assertTrue(true); } } + +// ----------------------------------------------------------------------------- + +// Declare header function in this namespace so the class under test will use +// this instead of the internal global functions during testing. + +class HeaderStack +{ + private static $headers; + + public static function reset() + { + self::$headers = []; + } + + public static function push($header) + { + self::$headers[] = $header; + } + + public static function getHeaders() + { + return self::$headers; + } +} + +function header($string, $dummy = true) +{ + HeaderStack::push($string); +}