Refactor Transmitter

This commit is contained in:
PJ Dietz 2020-08-13 07:26:19 -04:00
parent 8649090774
commit 4796e1d5c5
3 changed files with 57 additions and 55 deletions

View File

@ -53,25 +53,26 @@ class Transmitter implements TransmitterInterface
$this->chunkSize = $chunkSize; $this->chunkSize = $chunkSize;
} }
protected function prepareResponse( private function prepareResponse(
ServerRequestInterface $request, ServerRequestInterface $request,
ResponseInterface $response ResponseInterface $response
): ResponseInterface { ): 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 Content-length header
// - Response does not have a Transfer-encoding: chunked header // - Response does not have a Transfer-encoding: chunked header
// - Response body stream is readable and reports a non-null size // - Response body stream is readable and reports a non-null size
// //
if (!$response->hasHeader('Content-length') $contentLengthMissing = !$response->hasHeader('Content-length');
&& !(strtolower($response->getHeaderLine('Transfer-encoding')) === 'chunked') $notChunked = strtolower($response->getHeaderLine('Transfer-encoding'))
) { !== 'chunked';
$size = $response->getBody()->getSize(); $size = $response->getBody()->getSize();
if ($size !== null) {
$response = $response->withHeader('Content-length', (string) $size); if ($contentLengthMissing && $notChunked && $size !== null) {
} $response = $response->withHeader('Content-length', (string) $size);
} }
return $response; return $response;
} }

View File

@ -1,28 +0,0 @@
<?php
namespace WellRESTed\Transmission;
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);
}

View File

@ -1,6 +1,6 @@
<?php <?php
namespace WellRESTed\Test\Unit\Transmission; namespace WellRESTed\Transmission;
use Prophecy\Argument; use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\PhpUnit\ProphecyTrait;
@ -9,10 +9,6 @@ use RuntimeException;
use WellRESTed\Message\Response; use WellRESTed\Message\Response;
use WellRESTed\Message\ServerRequest; use WellRESTed\Message\ServerRequest;
use WellRESTed\Test\TestCase; use WellRESTed\Test\TestCase;
use WellRESTed\Transmission\HeaderStack;
use WellRESTed\Transmission\Transmitter;
require_once __DIR__ . '/../../../src/HeaderStack.php';
class TransmitterTest extends TestCase class TransmitterTest extends TestCase
{ {
@ -40,14 +36,14 @@ class TransmitterTest extends TestCase
->withBody($stream); ->withBody($stream);
} }
public function testSendStatusCodeWithReasonPhrase() public function testSendStatusCodeWithReasonPhrase(): void
{ {
$transmitter = new Transmitter(); $transmitter = new Transmitter();
$transmitter->transmit($this->request, $this->response); $transmitter->transmit($this->request, $this->response);
$this->assertContains('HTTP/1.1 200 OK', HeaderStack::getHeaders()); $this->assertContains('HTTP/1.1 200 OK', HeaderStack::getHeaders());
} }
public function testSendStatusCodeWithoutReasonPhrase() public function testSendStatusCodeWithoutReasonPhrase(): void
{ {
$this->response = $this->response->withStatus(999); $this->response = $this->response->withStatus(999);
@ -56,8 +52,11 @@ class TransmitterTest extends TestCase
$this->assertContains('HTTP/1.1 999', HeaderStack::getHeaders()); $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 $this->response = $this->response
->withHeader('Content-length', ['2048']) ->withHeader('Content-length', ['2048'])
@ -68,7 +67,7 @@ class TransmitterTest extends TestCase
$this->assertContains($header, HeaderStack::getHeaders()); $this->assertContains($header, HeaderStack::getHeaders());
} }
public function headerProvider() public function headerProvider(): array
{ {
return [ return [
['Content-length: 2048'], ['Content-length: 2048'],
@ -77,7 +76,7 @@ class TransmitterTest extends TestCase
]; ];
} }
public function testOutputsBody() public function testOutputsBody(): void
{ {
$content = 'Hello, world!'; $content = 'Hello, world!';
@ -95,7 +94,7 @@ class TransmitterTest extends TestCase
$this->assertEquals($content, $captured); $this->assertEquals($content, $captured);
} }
public function testOutputsBodyInChunks() public function testOutputsBodyInChunks(): void
{ {
$content = 'Hello, world!'; $content = 'Hello, world!';
$chunkSize = 3; $chunkSize = 3;
@ -128,7 +127,7 @@ class TransmitterTest extends TestCase
$this->assertEquals($content, $captured); $this->assertEquals($content, $captured);
} }
public function testOutputsUnseekableStreamInChunks() public function testOutputsUnseekableStreamInChunks(): void
{ {
$content = 'Hello, world!'; $content = 'Hello, world!';
$chunkSize = 3; $chunkSize = 3;
@ -164,7 +163,7 @@ class TransmitterTest extends TestCase
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Preparation // Preparation
public function testAddContentLengthHeader() public function testAddContentLengthHeader(): void
{ {
$bodySize = 1024; $bodySize = 1024;
$this->body->isReadable()->willReturn(true); $this->body->isReadable()->willReturn(true);
@ -178,7 +177,7 @@ class TransmitterTest extends TestCase
$this->assertContains("Content-length: $bodySize", HeaderStack::getHeaders()); $this->assertContains("Content-length: $bodySize", HeaderStack::getHeaders());
} }
public function testDoesNotReplaceContentLengthHeaderWhenContentLengthIsAlreadySet() public function testDoesNotReplaceContentLengthHeaderWhenContentLengthIsAlreadySet(): void
{ {
$streamSize = 1024; $streamSize = 1024;
$headerSize = 2048; $headerSize = 2048;
@ -196,7 +195,7 @@ class TransmitterTest extends TestCase
$this->assertContains("Content-length: $headerSize", HeaderStack::getHeaders()); $this->assertContains("Content-length: $headerSize", HeaderStack::getHeaders());
} }
public function testDoesNotAddContentLengthHeaderWhenTransferEncodingIsChunked() public function testDoesNotAddContentLengthHeaderWhenTransferEncodingIsChunked(): void
{ {
$bodySize = 1024; $bodySize = 1024;
@ -213,7 +212,7 @@ class TransmitterTest extends TestCase
$this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:'); $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:');
} }
public function testDoesNotAddContentLengthHeaderWhenBodySizeIsNull() public function testDoesNotAddContentLengthHeaderWhenBodySizeIsNull(): void
{ {
$this->body->isReadable()->willReturn(true); $this->body->isReadable()->willReturn(true);
$this->body->__toString()->willReturn(''); $this->body->__toString()->willReturn('');
@ -226,7 +225,7 @@ class TransmitterTest extends TestCase
$this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:'); $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:');
} }
private function assertArrayDoesNotContainValueWithPrefix($arr, $prefix) private function assertArrayDoesNotContainValueWithPrefix(array $arr, string $prefix): void
{ {
$normalPrefix = strtolower($prefix); $normalPrefix = strtolower($prefix);
foreach ($arr as $item) { foreach ($arr as $item) {
@ -238,3 +237,33 @@ class TransmitterTest extends TestCase
$this->assertTrue(true); $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);
}