wellrested/test/tests/unit/Message/ServerRequestTest.php

687 lines
22 KiB
PHP

<?php
namespace WellRESTed\Test\Unit\Message;
use InvalidArgumentException;
use WellRESTed\Message\NullStream;
use WellRESTed\Message\ServerRequest;
use WellRESTed\Message\UploadedFile;
use WellRESTed\Message\Uri;
use WellRESTed\Test\TestCase;
class ServerRequestTest extends TestCase
{
// ------------------------------------------------------------------------
// Construction and Marshalling
/** @backupGlobals enabled */
public function testGetServerRequestReadsFromRequest()
{
$_SERVER = [
'HTTP_HOST' => 'localhost',
'HTTP_ACCEPT' => 'application/json',
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded',
'QUERY_STRING' => 'guinea_pig=Claude&hamster=Fizzgig'
];
$_COOKIE = [
'cat' => 'Molly'
];
$_FILES = [];
$_POST = [
'dog' => 'Bear'
];
$attributes = ['guinea_pig' => 'Claude'];
$request = ServerRequest::getServerRequest($attributes);
$this->assertNotNull($request);
return $request;
}
// ------------------------------------------------------------------------
// Marshalling Request Information
/**
* @backupGlobals enabled
* @dataProvider protocolVersionProvider
*/
public function testGetServerRequestReadsProtocolVersion($expectedProtocol, $serverProtocol)
{
$_SERVER = [
'HTTP_HOST' => 'localhost',
'SERVER_PROTOCOL' => $serverProtocol,
'REQUEST_METHOD' => 'GET'
];
$request = ServerRequest::getServerRequest();
$this->assertEquals($expectedProtocol, $request->getProtocolVersion());
}
public function protocolVersionProvider()
{
return [
['1.1', 'HTTP/1.1'],
['1.0', 'HTTP/1.0'],
['1.1', null],
['1.1', 'INVALID']
];
}
/**
* @backupGlobals enabled
* @dataProvider methodProvider
*/
public function testGetServerRequestReadsMethod($expectedMethod, $serverMethod)
{
$_SERVER = [
'HTTP_HOST' => 'localhost',
'REQUEST_METHOD' => $serverMethod
];
$request = ServerRequest::getServerRequest();
$this->assertEquals($expectedMethod, $request->getMethod());
}
public function methodProvider()
{
return [
['GET', 'GET'],
['POST', 'POST'],
['DELETE', 'DELETE'],
['PUT', 'PUT'],
['OPTIONS', 'OPTIONS'],
['GET', null]
];
}
/**
* @backupGlobals enabled
* @dataProvider requestTargetProvider
*/
public function testGetServerRequestReadsRequestTargetFromRequest($expectedRequestTarget, $serverRequestUri)
{
$_SERVER = [
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => $serverRequestUri
];
$request = ServerRequest::getServerRequest();
$this->assertEquals($expectedRequestTarget, $request->getRequestTarget());
}
public function requestTargetProvider()
{
return [
['/', '/'],
['/hello', '/hello'],
['/my/path.txt', '/my/path.txt'],
['/', null]
];
}
/** @depends testGetServerRequestReadsFromRequest */
public function testGetServerRequestReadsHeaders($request)
{
/** @var ServerRequest $request */
$this->assertEquals(['application/json'], $request->getHeader('Accept'));
}
/**
* @backupGlobals enabled
*/
public function testGetServerRequestReadsContentHeaders()
{
$_SERVER = [
'CONTENT_LENGTH' => '1024',
'CONTENT_TYPE' => 'application/json'
];
$request = ServerRequest::getServerRequest();
$this->assertEquals('1024', $request->getHeaderLine('Content-length'));
$this->assertEquals('application/json', $request->getHeaderLine('Content-type'));
}
/**
* @backupGlobals enabled
*/
public function testGetServerRequestDoesNotReadEmptyContentHeaders()
{
$_SERVER = [
'CONTENT_LENGTH' => '',
'CONTENT_TYPE' => ' '
];
$request = ServerRequest::getServerRequest();
$this->assertFalse($request->hasHeader('Content-length'));
$this->assertFalse($request->hasHeader('Content-type'));
}
public function testGetServerRequestReadsBody()
{
$body = new NullStream();
$request = $this->getMockBuilder('WellRESTed\Message\ServerRequest')
->setMethods(['getStreamForBody'])
->getMock();
$request->expects($this->any())
->method('getStreamForBody')
->will($this->returnValue($body));
$called = false;
$callReadFromServerRequest = function () use (&$called) {
$called = true;
$this->readFromServerRequest();
};
$callReadFromServerRequest = $callReadFromServerRequest->bindTo($request, $request);
$callReadFromServerRequest();
$this->assertSame($body, $request->getBody());
}
/**
* @backupGlobals enabled
* @dataProvider uriProvider
*/
public function testGetServerRequestReadsUri($expected, $server)
{
$_SERVER = $server;
$request = ServerRequest::getServerRequest();
$this->assertEquals($expected, $request->getUri());
}
public function uriProvider()
{
return [
[
new Uri('http://localhost/path'),
[
'HTTPS' => 'off',
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/path',
'QUERY_STRING' => ''
]
],
[
new Uri('https://foo.com/path/to/stuff?cat=molly'),
[
'HTTPS' => '1',
'HTTP_HOST' => 'foo.com',
'REQUEST_URI' => '/path/to/stuff?cat=molly',
'QUERY_STRING' => 'cat=molly'
]
],
[
new Uri('http://foo.com:8080/path/to/stuff?cat=molly'),
[
'HTTP' => '1',
'HTTP_HOST' => 'foo.com:8080',
'REQUEST_URI' => '/path/to/stuff?cat=molly',
'QUERY_STRING' => 'cat=molly'
]
]
];
}
// ------------------------------------------------------------------------
// Marshalling ServerRequest Information
/** @depends testGetServerRequestReadsFromRequest */
public function testGetServerRequestReadsServerParams($request)
{
/** @var ServerRequest $request */
$this->assertEquals('localhost', $request->getServerParams()['HTTP_HOST']);
}
/** @depends testGetServerRequestReadsFromRequest */
public function testGetServerRequestReadsCookieParams($request)
{
/** @var ServerRequest $request */
$this->assertEquals('Molly', $request->getCookieParams()['cat']);
}
/** @depends testGetServerRequestReadsFromRequest */
public function testGetServerRequestReadsQueryParams($request)
{
/** @var ServerRequest $request */
$this->assertEquals('Claude', $request->getQueryParams()['guinea_pig']);
}
/**
* @backupGlobals enabled
* @dataProvider uploadedFileProvider
*/
public function testGetServerRequestReadsUploadedFiles($file, $path)
{
$_SERVER = [
'HTTP_HOST' => 'localhost',
'HTTP_ACCEPT' => 'application/json',
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded'
];
$_FILES = [
'single' => [
'name' => 'single.txt',
'type' => 'text/plain',
'tmp_name' => '/tmp/php9hNlHe',
'error' => UPLOAD_ERR_OK,
'size' => 524
],
'nested' => [
'level2' => [
'name' => 'nested.json',
'type' => 'application/json',
'tmp_name' => '/tmp/phpadhjk',
'error' => UPLOAD_ERR_OK,
'size' => 1024
]
],
'nestedList' => [
'level2' => [
'name' => [
0 => 'nestedList0.jpg',
1 => 'nestedList1.jpg',
2 => ''
],
'type' => [
0 => 'image/jpeg',
1 => 'image/jpeg',
2 => ''
],
'tmp_name' => [
0 => '/tmp/phpjpg0',
1 => '/tmp/phpjpg1',
2 => ''
],
'error' => [
0 => UPLOAD_ERR_OK,
1 => UPLOAD_ERR_OK,
2 => UPLOAD_ERR_NO_FILE
],
'size' => [
0 => 256,
1 => 4096,
2 => 0
]
]
],
'nestedDictionary' => [
'level2' => [
'name' => [
'file0' => 'nestedDictionary0.jpg',
'file1' => 'nestedDictionary1.jpg'
],
'type' => [
'file0' => 'image/png',
'file1' => 'image/png'
],
'tmp_name' => [
'file0' => '/tmp/phppng0',
'file1' => '/tmp/phppng1'
],
'error' => [
'file0' => UPLOAD_ERR_OK,
'file1' => UPLOAD_ERR_OK
],
'size' => [
'file0' => 256,
'file1' => 4096
]
]
]
];
$request = ServerRequest::getServerRequest();
$current = $request->getUploadedFiles();
foreach ($path as $item) {
$current = $current[$item];
}
$this->assertEquals($file, $current);
}
public function uploadedFileProvider()
{
return [
[new UploadedFile('single.txt', 'text/plain', 524, '/tmp/php9hNlHe', UPLOAD_ERR_OK), ['single']],
[new UploadedFile('nested.json', 'application/json', 1024, '/tmp/phpadhjk', UPLOAD_ERR_OK), ['nested', 'level2']],
[new UploadedFile('nestedList0.jpg', 'image/jpeg', 256, '/tmp/phpjpg0', UPLOAD_ERR_OK), ['nestedList', 'level2', 0]],
[new UploadedFile('nestedList1.jpg', 'image/jpeg', 4096, '/tmp/phpjpg1', UPLOAD_ERR_OK), ['nestedList', 'level2', 1]],
[new UploadedFile('', '', 0, '', UPLOAD_ERR_NO_FILE), ['nestedList', 'level2', 2]],
[new UploadedFile('nestedDictionary0.jpg', 'image/png', 256, '/tmp/phppng0', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file0']],
[new UploadedFile('nestedDictionary1.jpg', 'image/png', 4096, '/tmp/phppngg1', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file1']]
];
}
/**
* @backupGlobals enabled
* @dataProvider formContentTypeProvider
*/
public function testGetServerRequestParsesFormBody($contentType)
{
$_SERVER = [
'HTTP_HOST' => 'localhost',
'HTTP_CONTENT_TYPE' => $contentType,
];
$_COOKIE = [];
$_FILES = [];
$_POST = [
'dog' => 'Bear'
];
$request = ServerRequest::getServerRequest();
$this->assertEquals('Bear', $request->getParsedBody()['dog']);
}
public function formContentTypeProvider()
{
return [
['application/x-www-form-urlencoded'],
['multipart/form-data']
];
}
/** @depends testGetServerRequestReadsFromRequest */
public function testGetServerRequestProvidesAttributesIfPassed($request)
{
/** @var ServerRequest $request */
$this->assertEquals('Claude', $request->getAttribute('guinea_pig'));
}
// ------------------------------------------------------------------------
// Server Params
public function testGetServerParamsReturnsEmptyArrayByDefault()
{
$request = new ServerRequest();
$this->assertEquals([], $request->getServerParams());
}
// ------------------------------------------------------------------------
// Cookies
public function testGetCookieParamsReturnsEmptyArrayByDefault()
{
$request = new ServerRequest();
$this->assertEquals([], $request->getCookieParams());
}
/** @depends testGetServerRequestReadsFromRequest */
public function testWithCookieParamsCreatesNewInstance($request1)
{
/** @var ServerRequest $request1 */
$request2 = $request1->withCookieParams([
'cat' => 'Oscar'
]);
$this->assertNotEquals($request1->getCookieParams()['cat'], $request2->getCookieParams()['cat']);
}
// ------------------------------------------------------------------------
// Query
public function testGetQueryParamsReturnsEmptyArrayByDefault()
{
$request = new ServerRequest();
$this->assertEquals([], $request->getQueryParams());
}
/** @depends testGetServerRequestReadsFromRequest */
public function testWithQueryParamsCreatesNewInstance($request1)
{
/** @var ServerRequest $request1 */
$request2 = $request1->withQueryParams([
'guinea_pig' => 'Clyde'
]);
$this->assertNotEquals($request1->getQueryParams()['guinea_pig'], $request2->getQueryParams()['guinea_pig']);
}
// ------------------------------------------------------------------------
// Uploaded Files
public function testGetUploadedFilesReturnsEmptyArrayByDefault()
{
$request = new ServerRequest();
$this->assertEquals([], $request->getUploadedFiles());
}
/** @backupGlobals enabled */
public function testGetUploadedFilesReturnsEmptyArrayWhenNoFilesAreUploaded()
{
$_SERVER = [
'HTTP_HOST' => 'localhost',
'HTTP_ACCEPT' => 'application/json',
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded'
];
$_FILES = [];
$request = ServerRequest::getServerRequest();
$this->assertSame([], $request->getUploadedFiles());
}
public function testWithUploadedFilesCreatesNewInstance()
{
$uploadedFiles = [
'file' => new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0)
];
$request = new ServerRequest();
$request1 = $request->withUploadedFiles([]);
$request2 = $request1->withUploadedFiles($uploadedFiles);
$this->assertNotSame($request2, $request1);
}
/** @dataProvider validUploadedFilesProvider */
public function testWithUploadedFilesStoresPassedUploadedFiles($uploadedFiles)
{
$request = new ServerRequest();
$request = $request->withUploadedFiles($uploadedFiles);
$this->assertSame($uploadedFiles, $request->getUploadedFiles());
}
public function validUploadedFilesProvider()
{
return [
[[]],
[['files' => new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0)]],
[['nested' => [
'level2' => new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0)
]]],
[['nestedList' => [
'level2' => [
new UploadedFile('file1.html', 'text/html', 524, '/tmp/php9hNlHe', 0),
new UploadedFile('file2.html', 'text/html', 524, '/tmp/php9hNshj', 0)
]
]]],
[['nestedDictionary' => [
'level2' => [
'file1' => new UploadedFile('file1.html', 'text/html', 524, '/tmp/php9hNlHe', 0),
'file2' => new UploadedFile('file2.html', 'text/html', 524, '/tmp/php9hNshj', 0)
]
]]]
];
}
/**
* @dataProvider invalidUploadedFilesProvider
*/
public function testWithUploadedFilesThrowsExceptionWithInvalidTree($uploadedFiles)
{
$this->expectException(InvalidArgumentException::class);
$request = new ServerRequest();
$request->withUploadedFiles($uploadedFiles);
}
public function invalidUploadedFilesProvider()
{
return [
// All keys must be strings
[[new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0)]],
[
[new UploadedFile('index1.html', 'text/html', 524, '/tmp/php9hNlHe', 0)],
[new UploadedFile('index2.html', 'text/html', 524, '/tmp/php9hNlHe', 0)]
],
[
'single' => [
'name' => 'single.txt',
'type' => 'text/plain',
'tmp_name' => '/tmp/php9hNlHe',
'error' => UPLOAD_ERR_OK,
'size' => 524
],
'nested' => [
'level2' => [
'name' => 'nested.json',
'type' => 'application/json',
'tmp_name' => '/tmp/phpadhjk',
'error' => UPLOAD_ERR_OK,
'size' => 1024
]
]
],
[
'nestedList' => [
'level2' => [
'name' => [
0 => 'nestedList0.jpg',
1 => 'nestedList1.jpg',
2 => ''
],
'type' => [
0 => 'image/jpeg',
1 => 'image/jpeg',
2 => ''
],
'tmp_name' => [
0 => '/tmp/phpjpg0',
1 => '/tmp/phpjpg1',
2 => ''
],
'error' => [
0 => UPLOAD_ERR_OK,
1 => UPLOAD_ERR_OK,
2 => UPLOAD_ERR_NO_FILE
],
'size' => [
0 => 256,
1 => 4096,
2 => 0
]
]
]
]
];
}
// ------------------------------------------------------------------------
// Parsed Body
public function testGetParsedBodyReturnsNullByDefault()
{
$request = new ServerRequest();
$this->assertNull($request->getParsedBody());
}
/** @depends testGetServerRequestReadsFromRequest */
public function testWithParsedBodyCreatesNewInstance($request1)
{
/** @var ServerRequest $request1 */
$body1 = $request1->getParsedBody();
$request2 = $request1->withParsedBody([
'guinea_pig' => 'Clyde'
]);
$body2 = $request2->getParsedBody();
$this->assertNotSame($body1, $body2);
}
/**
* @dataProvider invalidParsedBodyProvider
*/
public function testWithParsedBodyThrowsExceptionWithInvalidType($body)
{
$this->expectException(InvalidArgumentException::class);
$request = new ServerRequest();
$request->withParsedBody($body);
}
public function invalidParsedBodyProvider()
{
return [
[false],
[1]
];
}
public function testCloneMakesDeepCopiesOfParsedBody()
{
$body = (object) [
'cat' => 'Dog'
];
$request1 = new ServerRequest();
$request1 = $request1->withParsedBody($body);
$request2 = $request1->withHeader('X-extra', 'hello world');
$this->assertTrue(
$request1->getParsedBody() == $request2->getParsedBody()
&& $request1->getParsedBody() !== $request2->getParsedBody()
);
}
// ------------------------------------------------------------------------
// Attributes
public function testGetAttributesReturnsEmptyArrayByDefault()
{
$request = new ServerRequest();
$this->assertEquals([], $request->getAttributes());
}
public function testGetAttributesReturnsAllAttributes()
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
$request = $request->withAttribute('dog', 'Bear');
$expected = [
'cat' => 'Molly',
'dog' => 'Bear'
];
$this->assertEquals($expected, $request->getAttributes());
}
public function testGetAttributeReturnsDefaultIfNotSet()
{
$request = new ServerRequest();
$this->assertEquals('Oscar', $request->getAttribute('cat', 'Oscar'));
}
public function testWithAttributeCreatesNewInstance()
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
$this->assertEquals('Molly', $request->getAttribute('cat'));
}
public function testWithAttributePreserversOtherAttributes()
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
$request = $request->withAttribute('dog', 'Bear');
$expected = [
'cat' => 'Molly',
'dog' => 'Bear'
];
$this->assertEquals($expected, $request->getAttributes());
}
public function testWithoutAttributeCreatesNewInstance()
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
$this->assertNotEquals($request, $request->withoutAttribute('cat'));
}
public function testWithoutAttributeRemovesAttribute()
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
$request = $request->withoutAttribute('cat');
$this->assertEquals('Oscar', $request->getAttribute('cat', 'Oscar'));
}
public function testWithoutAttributePreservesOtherAttributes()
{
$request = new ServerRequest();
$request = $request->withAttribute('cat', 'Molly');
$request = $request->withAttribute('dog', 'Bear');
$request = $request->withoutAttribute('cat');
$this->assertEquals('Bear', $request->getAttribute('dog'));
}
}