Refactor Message classes

This commit is contained in:
PJ Dietz 2020-08-12 07:42:33 -04:00
parent 2e3475b882
commit 4a3545cd3c
6 changed files with 116 additions and 104 deletions

View File

@ -33,11 +33,18 @@ class Request extends Message implements RequestInterface
/**
* Create a new Request.
*
* @see \WellRESTed\Message\Message
* @param string|UriInterface $uri
* $headers is an optional associative array with header field names as
* (string) keys and lists of header field values (string[]) as values.
*
* If no StreamInterface is provided for $body, the instance will create
* a NullStream instance for the message body.
*
* @param string $method
* @param array $headers
* @param StreamInterface|null $body
* @param string|UriInterface $uri
* @param array $headers Associative array with header field names as
* (string) keys and lists of header field values (string[]) as values.
* @param StreamInterface|null $body A stream representation of the message
* entity body
*/
public function __construct(
string $method = 'GET',

View File

@ -35,6 +35,7 @@ class Response extends Message implements ResponseInterface
* a NullStream instance for the message body.
*
* @see \WellRESTed\Message\Message
*
* @param int $statusCode
* @param array $headers
* @param StreamInterface|null $body
@ -58,7 +59,7 @@ class Response extends Message implements ResponseInterface
* The status code is a 3-digit integer result code of the server's attempt
* to understand and satisfy the request.
*
* @return integer Status code.
* @return int Status code.
*/
public function getStatusCode()
{

View File

@ -1,38 +1,27 @@
<?php
namespace WellRESTed\Test\Unit\Message;
namespace WellRESTed\Message;
use InvalidArgumentException;
use WellRESTed\Message\Message;
use WellRESTed\Message\Response;
use WellRESTed\Message\Stream;
use WellRESTed\Test\TestCase;
class MessageTest extends TestCase
{
/** @var Message */
private $message;
public function setUp(): void
{
$this->message = new Response();
}
public function testSetsHeadersOnConstruction()
public function testSetsHeadersOnConstruction(): void
{
$headers = ['X-foo' => ['bar', 'baz']];
$message = new Response(200, $headers);
$this->assertEquals(['bar', 'baz'], $message->getHeader('X-foo'));
}
public function testSetsBodyOnConstruction()
public function testSetsBodyOnConstruction(): void
{
$body = new Stream('Hello, world');
$message = new Response(200, [], $body);
$this->assertSame($body, $message->getBody());
}
public function testCloneMakesDeepCopyOfHeaders()
public function testCloneMakesDeepCopyOfHeaders(): void
{
$message1 = (new Response())
->withHeader('Content-type', 'text/plain');
@ -48,20 +37,20 @@ class MessageTest extends TestCase
// ------------------------------------------------------------------------
// Protocol Version
public function testGetProtocolVersionReturnsProtocolVersion1Point1ByDefault()
public function testGetProtocolVersionReturnsProtocolVersion1Point1ByDefault(): void
{
$message = new Response();
$this->assertEquals('1.1', $message->getProtocolVersion());
}
public function testGetProtocolVersionReturnsProtocolVersion()
public function testGetProtocolVersionReturnsProtocolVersion(): void
{
$message = (new Response())
->withProtocolVersion('1.0');
$this->assertEquals('1.0', $message->getProtocolVersion());
}
public function testGetProtocolVersionReplacesProtocolVersion()
public function testGetProtocolVersionReplacesProtocolVersion(): void
{
$message = (new Response())
->withProtocolVersion('1.0');
@ -71,8 +60,12 @@ class MessageTest extends TestCase
// ------------------------------------------------------------------------
// Headers
/** @dataProvider validHeaderValueProvider */
public function testWithHeaderReplacesHeader($expected, $value)
/**
* @dataProvider validHeaderValueProvider
* @param array $expected
* @param mixed $value
*/
public function testWithHeaderReplacesHeader(array $expected, $value): void
{
$message = (new Response())
->withHeader('X-foo', 'Original value')
@ -80,7 +73,7 @@ class MessageTest extends TestCase
$this->assertEquals($expected, $message->getHeader('X-foo'));
}
public function validHeaderValueProvider()
public function validHeaderValueProvider(): array
{
return [
[['0'], 0],
@ -90,15 +83,17 @@ class MessageTest extends TestCase
/**
* @dataProvider invalidHeaderProvider
* @param mixed $name
* @param mixed $value
*/
public function testWithHeaderThrowsExceptionWithInvalidArgument($name, $value)
public function testWithHeaderThrowsExceptionWithInvalidArgument($name, $value): void
{
$this->expectException(InvalidArgumentException::class);
$message = (new Response())
(new Response())
->withHeader($name, $value);
}
public function invalidHeaderProvider()
public function invalidHeaderProvider(): array
{
return [
[0, 1024],
@ -107,14 +102,14 @@ class MessageTest extends TestCase
];
}
public function testWithAddedHeaderSetsHeader()
public function testWithAddedHeaderSetsHeader(): void
{
$message = (new Response())
->withAddedHeader('Content-type', 'application/json');
$this->assertEquals(['application/json'], $message->getHeader('Content-type'));
}
public function testWithAddedHeaderAppendsValue()
public function testWithAddedHeaderAppendsValue(): void
{
$message = (new Response())
->withAddedHeader('Set-Cookie', ['cat=Molly'])
@ -126,7 +121,7 @@ class MessageTest extends TestCase
);
}
public function testWithoutHeaderRemovesHeader()
public function testWithoutHeaderRemovesHeader(): void
{
$message = (new Response())
->withHeader('Content-type', 'application/json')
@ -134,20 +129,20 @@ class MessageTest extends TestCase
$this->assertFalse($message->hasHeader('Content-type'));
}
public function testGetHeaderReturnsEmptyArrayForUnsetHeader()
public function testGetHeaderReturnsEmptyArrayForUnsetHeader(): void
{
$message = new Response();
$this->assertEquals([], $message->getHeader('X-name'));
}
public function testGetHeaderReturnsSingleHeader()
public function testGetHeaderReturnsSingleHeader(): void
{
$message = (new Response())
->withAddedHeader('Content-type', 'application/json');
$this->assertEquals(['application/json'], $message->getHeader('Content-type'));
}
public function testGetHeaderReturnsMultipleValuesForHeader()
public function testGetHeaderReturnsMultipleValuesForHeader(): void
{
$message = (new Response())
->withAddedHeader('X-name', 'cat=Molly')
@ -155,13 +150,13 @@ class MessageTest extends TestCase
$this->assertEquals(['cat=Molly', 'dog=Bear'], $message->getHeader('X-name'));
}
public function testGetHeaderLineReturnsEmptyStringForUnsetHeader()
public function testGetHeaderLineReturnsEmptyStringForUnsetHeader(): void
{
$message = new Response();
$this->assertSame('', $message->getHeaderLine('X-not-set'));
}
public function testGetHeaderLineReturnsMultipleHeadersJoinedByCommas()
public function testGetHeaderLineReturnsMultipleHeadersJoinedByCommas(): void
{
$message = (new Response())
->withAddedHeader('X-name', 'cat=Molly')
@ -169,20 +164,20 @@ class MessageTest extends TestCase
$this->assertEquals('cat=Molly, dog=Bear', $message->getHeaderLine('X-name'));
}
public function testHasHeaderReturnsTrueWhenHeaderIsSet()
public function testHasHeaderReturnsTrueWhenHeaderIsSet(): void
{
$message = (new Response())
->withHeader('Content-type', 'application/json');
$this->assertTrue($message->hasHeader('Content-type'));
}
public function testHasHeaderReturnsFalseWhenHeaderIsNotSet()
public function testHasHeaderReturnsFalseWhenHeaderIsNotSet(): void
{
$message = new Response();
$this->assertFalse($message->hasHeader('Content-type'));
}
public function testGetHeadersReturnOriginalHeaderNamesAsKeys()
public function testGetHeadersReturnOriginalHeaderNamesAsKeys(): void
{
$message = (new Response())
->withHeader('Set-Cookie', 'cat=Molly')
@ -201,7 +196,7 @@ class MessageTest extends TestCase
$this->assertEquals(0, $countUnmatched);
}
public function testGetHeadersReturnOriginalHeaderNamesAndValues()
public function testGetHeadersReturnOriginalHeaderNamesAndValues(): void
{
$message = (new Response())
->withHeader('Set-Cookie', 'cat=Molly')
@ -231,13 +226,13 @@ class MessageTest extends TestCase
// ------------------------------------------------------------------------
// Body
public function testGetBodyReturnsEmptyStreamByDefault()
public function testGetBodyReturnsEmptyStreamByDefault(): void
{
$message = new Response();
$this->assertEquals('', (string) $message->getBody());
}
public function testGetBodyReturnsAttachedStream()
public function testGetBodyReturnsAttachedStream(): void
{
$stream = new Stream('Hello, world!');

View File

@ -1,11 +1,8 @@
<?php
namespace WellRESTed\Test\Unit\Message;
namespace WellRESTed\Message;
use InvalidArgumentException;
use WellRESTed\Message\NullStream;
use WellRESTed\Message\Request;
use WellRESTed\Message\Uri;
use WellRESTed\Test\TestCase;
class RequestTest extends TestCase
@ -13,34 +10,34 @@ class RequestTest extends TestCase
// ------------------------------------------------------------------------
// Construction
public function testCreatesInstanceWithNoParameters()
public function testCreatesInstanceWithNoParameters(): void
{
$request = new Request();
$this->assertNotNull($request);
}
public function testCreatesInstanceWithMethod()
public function testCreatesInstanceWithMethod(): void
{
$method = 'POST';
$request = new Request($method);
$this->assertSame($method, $request->getMethod());
}
public function testCreatesInstanceWithUri()
public function testCreatesInstanceWithUri(): void
{
$uri = new Uri();
$request = new Request('GET', $uri);
$this->assertSame($uri, $request->getUri());
}
public function testCreatesInstanceWithStringUri()
public function testCreatesInstanceWithStringUri(): void
{
$uri = 'http://localhost:8080';
$request = new Request('GET', $uri);
$this->assertSame($uri, (string) $request->getUri());
}
public function testSetsHeadersOnConstruction()
public function testSetsHeadersOnConstruction(): void
{
$request = new Request('GET', '/', [
'X-foo' => ['bar', 'baz']
@ -48,7 +45,7 @@ class RequestTest extends TestCase
$this->assertEquals(['bar', 'baz'], $request->getHeader('X-foo'));
}
public function testSetsBodyOnConstruction()
public function testSetsBodyOnConstruction(): void
{
$body = new NullStream();
$request = new Request('GET', '/', [], $body);
@ -58,14 +55,14 @@ class RequestTest extends TestCase
// ------------------------------------------------------------------------
// Request Target
public function testGetRequestTargetPrefersExplicitRequestTarget()
public function testGetRequestTargetPrefersExplicitRequestTarget(): void
{
$request = new Request();
$request = $request->withRequestTarget('*');
$this->assertEquals('*', $request->getRequestTarget());
}
public function testGetRequestTargetUsesOriginFormOfUri()
public function testGetRequestTargetUsesOriginFormOfUri(): void
{
$uri = new Uri('/my/path?cat=Molly&dog=Bear');
$request = new Request();
@ -73,13 +70,13 @@ class RequestTest extends TestCase
$this->assertEquals('/my/path?cat=Molly&dog=Bear', $request->getRequestTarget());
}
public function testGetRequestTargetReturnsSlashByDefault()
public function testGetRequestTargetReturnsSlashByDefault(): void
{
$request = new Request();
$this->assertEquals('/', $request->getRequestTarget());
}
public function testWithRequestTargetCreatesNewInstance()
public function testWithRequestTargetCreatesNewInstance(): void
{
$request = new Request();
$request = $request->withRequestTarget('*');
@ -89,13 +86,13 @@ class RequestTest extends TestCase
// ------------------------------------------------------------------------
// Method
public function testGetMethodReturnsGetByDefault()
public function testGetMethodReturnsGetByDefault(): void
{
$request = new Request();
$this->assertEquals('GET', $request->getMethod());
}
public function testWithMethodCreatesNewInstance()
public function testWithMethodCreatesNewInstance(): void
{
$request = new Request();
$request = $request->withMethod('POST');
@ -104,15 +101,16 @@ class RequestTest extends TestCase
/**
* @dataProvider invalidMethodProvider
* @param mixed $method
*/
public function testWithMethodThrowsExceptionOnInvalidMethod($method)
public function testWithMethodThrowsExceptionOnInvalidMethod($method): void
{
$this->expectException(InvalidArgumentException::class);
$request = new Request();
$request->withMethod($method);
}
public function invalidMethodProvider()
public function invalidMethodProvider(): array
{
return [
[0],
@ -124,14 +122,14 @@ class RequestTest extends TestCase
// ------------------------------------------------------------------------
// Request URI
public function testGetUriReturnsEmptyUriByDefault()
public function testGetUriReturnsEmptyUriByDefault(): void
{
$request = new Request();
$uri = new Uri();
$this->assertEquals($uri, $request->getUri());
}
public function testWithUriCreatesNewInstance()
public function testWithUriCreatesNewInstance(): void
{
$uri = new Uri();
$request = new Request();
@ -139,7 +137,7 @@ class RequestTest extends TestCase
$this->assertSame($uri, $request->getUri());
}
public function testWithUriPreservesOriginalRequest()
public function testWithUriPreservesOriginalRequest(): void
{
$uri1 = new Uri();
$uri2 = new Uri();
@ -154,7 +152,7 @@ class RequestTest extends TestCase
$this->assertNotEquals($request1->getHeader('Accept'), $request2->getHeader('Accept'));
}
public function testWithUriUpdatesHostHeader()
public function testWithUriUpdatesHostHeader(): void
{
$hostname = 'bar.com';
$uri = new uri("http://$hostname");
@ -165,7 +163,7 @@ class RequestTest extends TestCase
$this->assertSame([$hostname], $request->getHeader('Host'));
}
public function testWithUriDoesNotUpdatesHostHeaderWhenUriHasNoHost()
public function testWithUriDoesNotUpdatesHostHeaderWhenUriHasNoHost(): void
{
$hostname = 'foo.com';
$uri = new Uri();
@ -176,7 +174,7 @@ class RequestTest extends TestCase
$this->assertSame([$hostname], $request->getHeader('Host'));
}
public function testPreserveHostUpdatesHostHeaderWhenHeaderIsOriginallyMissing()
public function testPreserveHostUpdatesHostHeaderWhenHeaderIsOriginallyMissing(): void
{
$hostname = 'foo.com';
$uri = new uri("http://$hostname");
@ -186,7 +184,7 @@ class RequestTest extends TestCase
$this->assertSame([$hostname], $request->getHeader('Host'));
}
public function testPreserveHostDoesNotUpdatesWhenBothAreMissingHosts()
public function testPreserveHostDoesNotUpdatesWhenBothAreMissingHosts(): void
{
$uri = new Uri();
@ -195,7 +193,7 @@ class RequestTest extends TestCase
$this->assertSame([], $request->getHeader('Host'));
}
public function testPreserveHostDoesNotUpdateHostHeader()
public function testPreserveHostDoesNotUpdateHostHeader(): void
{
$hostname = 'foo.com';
$uri = new uri('http://bar.com');

View File

@ -1,9 +1,7 @@
<?php
namespace WellRESTed\Test\Unit\Message;
namespace WellRESTed\Message;
use WellRESTed\Message\NullStream;
use WellRESTed\Message\Response;
use WellRESTed\Test\TestCase;
class ResponseTest extends TestCase
@ -11,13 +9,13 @@ class ResponseTest extends TestCase
// ------------------------------------------------------------------------
// Construction
public function testSetsStatusCodeOnConstruction()
public function testSetsStatusCodeOnConstruction(): void
{
$response = new Response(200);
$this->assertSame(200, $response->getStatusCode());
}
public function testSetsHeadersOnConstruction()
public function testSetsHeadersOnConstruction(): void
{
$response = new Response(200, [
'X-foo' => ['bar','baz']
@ -25,7 +23,7 @@ class ResponseTest extends TestCase
$this->assertEquals(['bar','baz'], $response->getHeader('X-foo'));
}
public function testSetsBodyOnConstruction()
public function testSetsBodyOnConstruction(): void
{
$body = new NullStream();
$response = new Response(200, [], $body);
@ -35,22 +33,30 @@ class ResponseTest extends TestCase
// ------------------------------------------------------------------------
// Status and Reason Phrase
public function testCreatesNewInstanceWithStatusCode()
public function testCreatesNewInstanceWithStatusCode(): void
{
$response = new Response();
$copy = $response->withStatus(200);
$this->assertEquals(200, $copy->getStatusCode());
}
/** @dataProvider statusProvider */
public function testCreatesNewInstanceWithReasonPhrase($code, $reasonPhrase, $expected)
{
/**
* @dataProvider statusProvider
* @param int $code
* @param string|null $reasonPhrase
* @param string $expected
*/
public function testCreatesNewInstanceWithReasonPhrase(
int $code,
?string $reasonPhrase,
string $expected
): void {
$response = new Response();
$copy = $response->withStatus($code, $reasonPhrase);
$this->assertEquals($expected, $copy->getReasonPhrase());
}
public function statusProvider()
public function statusProvider(): array
{
return [
[100, null, 'Continue'],
@ -95,7 +101,7 @@ class ResponseTest extends TestCase
];
}
public function testWithStatusCodePreservesOriginalResponse()
public function testWithStatusCodePreservesOriginalResponse(): void
{
$response1 = new Response();
$response1 = $response1->withStatus(200);

View File

@ -10,7 +10,7 @@ class ServerRequestTest extends TestCase
// ------------------------------------------------------------------------
// Server Params
public function testGetServerParamsReturnsEmptyArrayByDefault()
public function testGetServerParamsReturnsEmptyArrayByDefault(): void
{
$request = new ServerRequest();
$this->assertEquals([], $request->getServerParams());
@ -19,13 +19,13 @@ class ServerRequestTest extends TestCase
// ------------------------------------------------------------------------
// Cookies
public function testGetCookieParamsReturnsEmptyArrayByDefault()
public function testGetCookieParamsReturnsEmptyArrayByDefault(): void
{
$request = new ServerRequest();
$this->assertEquals([], $request->getCookieParams());
}
public function testWithCookieParamsCreatesNewInstanceWithCookies()
public function testWithCookieParamsCreatesNewInstanceWithCookies(): void
{
$cookies = [
'cat' => 'Oscar'
@ -41,13 +41,13 @@ class ServerRequestTest extends TestCase
// ------------------------------------------------------------------------
// Query
public function testGetQueryParamsReturnsEmptyArrayByDefault()
public function testGetQueryParamsReturnsEmptyArrayByDefault(): void
{
$request = new ServerRequest();
$this->assertEquals([], $request->getQueryParams());
}
public function testWithQueryParamsCreatesNewInstance()
public function testWithQueryParamsCreatesNewInstance(): void
{
$query = [
'cat' => 'Aggie'
@ -63,13 +63,13 @@ class ServerRequestTest extends TestCase
// ------------------------------------------------------------------------
// Uploaded Files
public function testGetUploadedFilesReturnsEmptyArrayByDefault()
public function testGetUploadedFilesReturnsEmptyArrayByDefault(): void
{
$request = new ServerRequest();
$this->assertEquals([], $request->getUploadedFiles());
}
public function testWithUploadedFilesCreatesNewInstance()
public function testWithUploadedFilesCreatesNewInstance(): void
{
$uploadedFiles = [
'file' => new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0)
@ -80,15 +80,18 @@ class ServerRequestTest extends TestCase
$this->assertNotSame($request2, $request1);
}
/** @dataProvider validUploadedFilesProvider */
public function testWithUploadedFilesStoresPassedUploadedFiles($uploadedFiles)
/**
* @dataProvider validUploadedFilesProvider
* @param array $uploadedFiles
*/
public function testWithUploadedFilesStoresPassedUploadedFiles(array $uploadedFiles): void
{
$request = new ServerRequest();
$request = $request->withUploadedFiles($uploadedFiles);
$this->assertSame($uploadedFiles, $request->getUploadedFiles());
}
public function validUploadedFilesProvider()
public function validUploadedFilesProvider(): array
{
return [
[[]],
@ -113,8 +116,9 @@ class ServerRequestTest extends TestCase
/**
* @dataProvider invalidUploadedFilesProvider
* @param array $uploadedFiles
*/
public function testWithUploadedFilesThrowsExceptionWithInvalidTree($uploadedFiles)
public function testWithUploadedFilesThrowsExceptionWithInvalidTree(array $uploadedFiles): void
{
$this->expectException(InvalidArgumentException::class);
$request = new ServerRequest();
@ -185,13 +189,13 @@ class ServerRequestTest extends TestCase
// ------------------------------------------------------------------------
// Parsed Body
public function testGetParsedBodyReturnsNullByDefault()
public function testGetParsedBodyReturnsNullByDefault(): void
{
$request = new ServerRequest();
$this->assertNull($request->getParsedBody());
}
public function testWithParsedBodyCreatesNewInstance()
public function testWithParsedBodyCreatesNewInstance(): void
{
$body = [
'guinea_pig' => 'Clyde'
@ -206,8 +210,9 @@ class ServerRequestTest extends TestCase
/**
* @dataProvider invalidParsedBodyProvider
* @param mixed $body
*/
public function testWithParsedBodyThrowsExceptionWithInvalidType($body)
public function testWithParsedBodyThrowsExceptionWithInvalidType($body): void
{
$this->expectException(InvalidArgumentException::class);
$request = new ServerRequest();
@ -222,7 +227,7 @@ class ServerRequestTest extends TestCase
];
}
public function testCloneMakesDeepCopiesOfParsedBody()
public function testCloneMakesDeepCopiesOfParsedBody(): void
{
$body = (object) [
'cat' => 'Dog'
@ -241,13 +246,13 @@ class ServerRequestTest extends TestCase
// ------------------------------------------------------------------------
// Attributes
public function testGetAttributesReturnsEmptyArrayByDefault()
public function testGetAttributesReturnsEmptyArrayByDefault(): void
{
$request = new ServerRequest();
$this->assertEquals([], $request->getAttributes());
}
public function testGetAttributesReturnsAllAttributes()
public function testGetAttributesReturnsAllAttributes(): void
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
@ -259,20 +264,20 @@ class ServerRequestTest extends TestCase
$this->assertEquals($expected, $request->getAttributes());
}
public function testGetAttributeReturnsDefaultIfNotSet()
public function testGetAttributeReturnsDefaultIfNotSet(): void
{
$request = new ServerRequest();
$this->assertEquals('Oscar', $request->getAttribute('cat', 'Oscar'));
}
public function testWithAttributeCreatesNewInstance()
public function testWithAttributeCreatesNewInstance(): void
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
$this->assertEquals('Molly', $request->getAttribute('cat'));
}
public function testWithAttributePreserversOtherAttributes()
public function testWithAttributePreserversOtherAttributes(): void
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
@ -284,14 +289,14 @@ class ServerRequestTest extends TestCase
$this->assertEquals($expected, $request->getAttributes());
}
public function testWithoutAttributeCreatesNewInstance()
public function testWithoutAttributeCreatesNewInstance(): void
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
$this->assertNotEquals($request, $request->withoutAttribute('cat'));
}
public function testWithoutAttributeRemovesAttribute()
public function testWithoutAttributeRemovesAttribute(): void
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
@ -299,7 +304,7 @@ class ServerRequestTest extends TestCase
$this->assertEquals('Oscar', $request->getAttribute('cat', 'Oscar'));
}
public function testWithoutAttributePreservesOtherAttributes()
public function testWithoutAttributePreservesOtherAttributes(): void
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');