Clean up MessageTest and documentation for Message classes

This commit is contained in:
PJ Dietz 2018-06-22 13:43:44 -04:00
parent b82ebf6d95
commit 72d5df244d
3 changed files with 109 additions and 98 deletions

View File

@ -15,20 +15,19 @@ abstract class Message implements MessageInterface
/** @var StreamInterface */ /** @var StreamInterface */
protected $body; protected $body;
/** @var string */ /** @var string */
protected $protocolVersion = "1.1"; protected $protocolVersion = '1.1';
/** /**
* Create a new Message, optionally with headers and a body. * Create a new Message, optionally with headers and a body.
* *
* If provided, $headers MUST by an associative array with header field * $headers is an optional associative array with header field names as
* names as (string) keys and lists of header field values (string[]) * (string) keys and lists of header field values (string[]) as values.
* as values.
* *
* If no StreamInterface is provided for $body, the instance will create * If no StreamInterface is provided for $body, the instance will create
* a NullStream instance for the message body. * a NullStream instance for the message body.
* *
* @param array $headers Associative array of headers fields with header * @param array $headers Associative array with header field names as
* field names as keys and list arrays of field values as values * (string) keys and lists of header field values (string[]) as values.
* @param StreamInterface $body A stream representation of the message * @param StreamInterface $body A stream representation of the message
* entity body * entity body
*/ */
@ -61,8 +60,6 @@ abstract class Message implements MessageInterface
/** /**
* Retrieves the HTTP protocol version as a string. * Retrieves the HTTP protocol version as a string.
* *
* The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
*
* @return string HTTP protocol version. * @return string HTTP protocol version.
*/ */
public function getProtocolVersion() public function getProtocolVersion()
@ -73,9 +70,6 @@ abstract class Message implements MessageInterface
/** /**
* Create a new instance with the specified HTTP protocol version. * Create a new instance with the specified HTTP protocol version.
* *
* The version string MUST contain only the HTTP version number (e.g.,
* "1.1", "1.0").
*
* @param string $version HTTP protocol version * @param string $version HTTP protocol version
* @return static * @return static
*/ */
@ -94,7 +88,7 @@ abstract class Message implements MessageInterface
* *
* // Represent the headers as a string * // Represent the headers as a string
* foreach ($message->getHeaders() as $name => $values) { * foreach ($message->getHeaders() as $name => $values) {
* echo $name . ": " . implode(", ", $values); * echo $name . ': ' . implode(', ', $values);
* } * }
* *
* // Emit headers iteratively: * // Emit headers iteratively:
@ -177,9 +171,9 @@ abstract class Message implements MessageInterface
public function getHeaderLine($name) public function getHeaderLine($name)
{ {
if (isset($this->headers[$name])) { if (isset($this->headers[$name])) {
return join(", ", $this->headers[$name]); return join(', ', $this->headers[$name]);
} else { } else {
return ""; return '';
} }
} }
@ -278,7 +272,7 @@ abstract class Message implements MessageInterface
}; };
if (!is_string($name)) { if (!is_string($name)) {
throw new \InvalidArgumentException("Header name must be a string"); throw new \InvalidArgumentException('Header name must be a string');
} }
if ($is_allowed($value)) { if ($is_allowed($value)) {
@ -286,7 +280,7 @@ abstract class Message implements MessageInterface
} elseif (is_array($value) && count($value) === count(array_filter($value, $is_allowed))) { } elseif (is_array($value) && count($value) === count(array_filter($value, $is_allowed))) {
return $value; return $value;
} else { } else {
throw new \InvalidArgumentException("Header values must be a string or string[]"); throw new \InvalidArgumentException('Header values must be a string or string[]');
} }
} }
} }

View File

@ -2,32 +2,45 @@
namespace WellRESTed\Test\Unit\Message; namespace WellRESTed\Test\Unit\Message;
use WellRESTed\Message\Message;
use WellRESTed\Message\Response;
use WellRESTed\Message\Stream;
use WellRESTed\Test\TestCase; use WellRESTed\Test\TestCase;
class MessageTest extends TestCase class MessageTest extends TestCase
{ {
/** @var Message */
private $message;
public function setUp()
{
$this->message = new Response();
}
public function testSetsHeadersOnConstruction() public function testSetsHeadersOnConstruction()
{ {
$headers = ["X-foo" => ["bar", "baz"]]; $headers = ['X-foo' => ['bar', 'baz']];
$body = null; $message = new Response(200, $headers);
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message', [$headers, $body]); $this->assertEquals(['bar', 'baz'], $message->getHeader('X-foo'));
$this->assertEquals(["bar", "baz"], $message->getHeader("X-foo"));
} }
public function testSetsBodyOnConstruction() public function testSetsBodyOnConstruction()
{ {
$headers = null; $body = new Stream('Hello, world');
$body = $this->prophesize('\Psr\Http\Message\StreamInterface'); $message = new Response(200, [], $body);
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message', [$headers, $body->reveal()]); $this->assertSame($body, $message->getBody());
$this->assertSame($body->reveal(), $message->getBody());
} }
public function testCloneMakesDeepCopyOfHeaders() public function testCloneMakesDeepCopyOfHeaders()
{ {
$message1 = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message1 = (new Response())
$message1 = $message1->withHeader("Content-type", "text/plain"); ->withHeader('Content-type', 'text/plain');
$message2 = $message1->withHeader("Content-type", "application/json"); $message2 = $message1
$this->assertNotEquals($message1->getHeader("Content-type"), $message2->getHeader("Content-type")); ->withHeader('Content-type', 'application/json');
$this->assertNotEquals(
$message1->getHeader('Content-type'),
$message2->getHeader('Content-type'));
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -35,22 +48,22 @@ class MessageTest extends TestCase
public function testGetProtocolVersionReturnsProtocolVersion1Point1ByDefault() public function testGetProtocolVersionReturnsProtocolVersion1Point1ByDefault()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = new Response();
$this->assertEquals("1.1", $message->getProtocolVersion()); $this->assertEquals('1.1', $message->getProtocolVersion());
} }
public function testGetProtocolVersionReturnsProtocolVersion() public function testGetProtocolVersionReturnsProtocolVersion()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withProtocolVersion("1.0"); ->withProtocolVersion('1.0');
$this->assertEquals("1.0", $message->getProtocolVersion()); $this->assertEquals('1.0', $message->getProtocolVersion());
} }
public function testGetProtocolVersionReplacesProtocolVersion() public function testGetProtocolVersionReplacesProtocolVersion()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withProtocolVersion("1.0"); ->withProtocolVersion('1.0');
$this->assertEquals("1.0", $message->getProtocolVersion()); $this->assertEquals('1.0', $message->getProtocolVersion());
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -59,17 +72,17 @@ class MessageTest extends TestCase
/** @dataProvider validHeaderValueProvider */ /** @dataProvider validHeaderValueProvider */
public function testWithHeaderReplacesHeader($expected, $value) public function testWithHeaderReplacesHeader($expected, $value)
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withHeader("X-foo", "Original value"); ->withHeader('X-foo', 'Original value')
$message = $message->withHeader("X-foo", $value); ->withHeader('X-foo', $value);
$this->assertEquals($expected, $message->getHeader("X-foo")); $this->assertEquals($expected, $message->getHeader('X-foo'));
} }
public function validHeaderValueProvider() public function validHeaderValueProvider()
{ {
return [ return [
[["0"], 0], [['0'], 0],
[["molly","bear"],["molly","bear"]] [['molly','bear'],['molly','bear']]
]; ];
} }
@ -79,114 +92,118 @@ class MessageTest extends TestCase
*/ */
public function testWithHeaderThrowsExceptionWithInvalidArgument($name, $value) public function testWithHeaderThrowsExceptionWithInvalidArgument($name, $value)
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message->withHeader($name, $value); ->withHeader($name, $value);
} }
public function invalidHeaderProvider() public function invalidHeaderProvider()
{ {
return [ return [
[0, 1024], [0, 1024],
["Content-length", false], ['Content-length', false],
["Content-length", [false]] ['Content-length', [false]]
]; ];
} }
public function testWithAddedHeaderSetsHeader() public function testWithAddedHeaderSetsHeader()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withAddedHeader("Content-type", "application/json"); ->withAddedHeader('Content-type', 'application/json');
$this->assertEquals(["application/json"], $message->getHeader("Content-type")); $this->assertEquals(['application/json'], $message->getHeader('Content-type'));
} }
public function testWithAddedHeaderAppendsValue() public function testWithAddedHeaderAppendsValue()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withAddedHeader("Set-Cookie", ["cat=Molly"]); ->withAddedHeader('Set-Cookie', ['cat=Molly'])
$message = $message->withAddedHeader("Set-Cookie", ["dog=Bear"]); ->withAddedHeader('Set-Cookie', ['dog=Bear']);
$cookies = $message->getHeader("Set-Cookie"); $cookies = $message->getHeader('Set-Cookie');
$this->assertTrue(in_array("cat=Molly", $cookies) && in_array("dog=Bear", $cookies)); $this->assertTrue(
in_array('cat=Molly', $cookies) &&
in_array('dog=Bear', $cookies));
} }
public function testWithoutHeaderRemovesHeader() public function testWithoutHeaderRemovesHeader()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withHeader("Content-type", "application/json"); ->withHeader('Content-type', 'application/json')
$message = $message->withoutHeader("Content-type"); ->withoutHeader('Content-type');
$this->assertFalse($message->hasHeader("Content-type")); $this->assertFalse($message->hasHeader('Content-type'));
} }
public function testGetHeaderReturnsEmptyArrayForUnsetHeader() public function testGetHeaderReturnsEmptyArrayForUnsetHeader()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = new Response();
$this->assertEquals([], $message->getHeader("X-name")); $this->assertEquals([], $message->getHeader('X-name'));
} }
public function testGetHeaderReturnsSingleHeader() public function testGetHeaderReturnsSingleHeader()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withAddedHeader("Content-type", "application/json"); ->withAddedHeader('Content-type', 'application/json');
$this->assertEquals(["application/json"], $message->getHeader("Content-type")); $this->assertEquals(['application/json'], $message->getHeader('Content-type'));
} }
public function testGetHeaderReturnsMultipleValuesForHeader() public function testGetHeaderReturnsMultipleValuesForHeader()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withAddedHeader("X-name", "cat=Molly"); ->withAddedHeader('X-name', 'cat=Molly')
$message = $message->withAddedHeader("X-name", "dog=Bear"); ->withAddedHeader('X-name', 'dog=Bear');
$this->assertEquals(["cat=Molly", "dog=Bear"], $message->getHeader("X-name")); $this->assertEquals(['cat=Molly', 'dog=Bear'], $message->getHeader('X-name'));
} }
public function testGetHeaderLineReturnsEmptyStringForUnsetHeader() public function testGetHeaderLineReturnsEmptyStringForUnsetHeader()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = new Response();
$this->assertSame("", $message->getHeaderLine("X-not-set")); $this->assertSame('', $message->getHeaderLine('X-not-set'));
} }
public function testGetHeaderLineReturnsMultipleHeadersJoinedByCommas() public function testGetHeaderLineReturnsMultipleHeadersJoinedByCommas()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withAddedHeader("X-name", "cat=Molly"); ->withAddedHeader('X-name', 'cat=Molly')
$message = $message->withAddedHeader("X-name", "dog=Bear"); ->withAddedHeader('X-name', 'dog=Bear');
$this->assertEquals("cat=Molly, dog=Bear", $message->getHeaderLine("X-name")); $this->assertEquals('cat=Molly, dog=Bear', $message->getHeaderLine('X-name'));
} }
public function testHasHeaderReturnsTrueWhenHeaderIsSet() public function testHasHeaderReturnsTrueWhenHeaderIsSet()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withHeader("Content-type", "application/json"); ->withHeader('Content-type', 'application/json');
$this->assertTrue($message->hasHeader("Content-type")); $this->assertTrue($message->hasHeader('Content-type'));
} }
public function testHasHeaderReturnsFalseWhenHeaderIsNotSet() public function testHasHeaderReturnsFalseWhenHeaderIsNotSet()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = new Response();
$this->assertFalse($message->hasHeader("Content-type")); $this->assertFalse($message->hasHeader('Content-type'));
} }
public function testGetHeadersReturnOriginalHeaderNamesAsKeys() public function testGetHeadersReturnOriginalHeaderNamesAsKeys()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withHeader("Set-Cookie", "cat=Molly"); ->withHeader('Set-Cookie', 'cat=Molly')
$message = $message->withAddedHeader("Set-Cookie", "dog=Bear"); ->withAddedHeader('Set-Cookie', 'dog=Bear')
$message = $message->withHeader("Content-type", "application/json"); ->withHeader('Content-type', 'application/json');
$headers = []; $headers = [];
foreach ($message->getHeaders() as $key => $values) { foreach ($message->getHeaders() as $key => $values) {
$headers[] = $key; $headers[] = $key;
} }
$expected = ["Content-type", "Set-Cookie"]; $expected = ['Content-type', 'Set-Cookie'];
$countUnmatched = count(array_diff($expected, $headers)) + count(array_diff($headers, $expected)); $countUnmatched
= count(array_diff($expected, $headers))
+ count(array_diff($headers, $expected));
$this->assertEquals(0, $countUnmatched); $this->assertEquals(0, $countUnmatched);
} }
public function testGetHeadersReturnOriginalHeaderNamesAndValues() public function testGetHeadersReturnOriginalHeaderNamesAndValues()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withHeader("Set-Cookie", "cat=Molly"); ->withHeader('Set-Cookie', 'cat=Molly')
$message = $message->withAddedHeader("Set-Cookie", "dog=Bear"); ->withAddedHeader('Set-Cookie', 'dog=Bear')
$message = $message->withHeader("Content-type", "application/json"); ->withHeader('Content-type', 'application/json');
$headers = []; $headers = [];
@ -201,8 +218,8 @@ class MessageTest extends TestCase
} }
$expected = [ $expected = [
"Set-Cookie" => ["cat=Molly", "dog=Bear"], 'Set-Cookie' => ['cat=Molly', 'dog=Bear'],
"Content-type" => ["application/json"] 'Content-type' => ['application/json']
]; ];
$this->assertEquals($expected, $headers); $this->assertEquals($expected, $headers);
@ -213,17 +230,16 @@ class MessageTest extends TestCase
public function testGetBodyReturnsEmptyStreamByDefault() public function testGetBodyReturnsEmptyStreamByDefault()
{ {
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = new Response();
$this->assertEquals("", (string) $message->getBody()); $this->assertEquals('', (string) $message->getBody());
} }
public function testGetBodyReturnsAttachedStream() public function testGetBodyReturnsAttachedStream()
{ {
$stream = $this->prophesize('\Psr\Http\Message\StreamInterface'); $stream = new Stream('Hello, world!');
$stream = $stream->reveal();
$message = $this->getMockForAbstractClass('\WellRESTed\Message\Message'); $message = (new Response())
$message = $message->withBody($stream); ->withBody($stream);
$this->assertSame($stream, $message->getBody()); $this->assertSame($stream, $message->getBody());
} }
} }

View File

@ -2,6 +2,7 @@
namespace WellRESTed\Test\Unit\Message; namespace WellRESTed\Test\Unit\Message;
use Psr\Http\Message\StreamInterface;
use WellRESTed\Message\UploadedFile; use WellRESTed\Message\UploadedFile;
use WellRESTed\Message\UploadedFileState; use WellRESTed\Message\UploadedFileState;
use WellRESTed\Test\TestCase; use WellRESTed\Test\TestCase;
@ -39,7 +40,7 @@ class UploadedFileTest extends TestCase
public function testGetStreamReturnsStreamInterface() public function testGetStreamReturnsStreamInterface()
{ {
$file = new UploadedFile("", "", 0, "", 0); $file = new UploadedFile("", "", 0, "", 0);
$this->assertInstanceOf('\Psr\Http\Message\StreamInterface', $file->getStream()); $this->assertInstanceOf(StreamInterface::class, $file->getStream());
} }
public function testGetStreamReturnsStreamWrappingUploadedFile() public function testGetStreamReturnsStreamWrappingUploadedFile()