getMockBuilder(Controller::class)->disableOriginalConstructor();
if ($methods) {
$builder->setMethods($methods);
}
return $builder->getMockForAbstractClass();
}
/**
* Test running controller
*/
public function testInvoke()
{
$test = $this;
$controller = $this->getController();
$request = $this->createMock(ServerRequestInterface::class);
$response = $this->createMock(ResponseInterface::class);
$finalResponse = $this->createMock(ResponseInterface::class);
$controller->expects($this->once())->method('run')
->willReturnCallback(Closure::bind(function() use ($test, $request, $response, $finalResponse) {
$test->assertSame($request, $this->getRequest());
$test->assertSame($response, $this->getResponse());
return $finalResponse;
}, $controller, Controller::class));
$result = $controller($request, $response);
$this->assertEquals($finalResponse, $result);
}
/**
* Test response status functions if response object is not set
*/
public function testResponseStatusEmptyResponse()
{
$controller = $this->getController();
$data = $this->getStatusCodesMap(null);
foreach ($data as $func => $value) {
$this->assertEquals($value, $controller->$func(), "Method '$func' returns incorrect value");
}
}
/**
* Test functions that check response status code
*
* @dataProvider responseStatusProvider
* @param int status code
*/
public function testResponseStatus($code)
{
$controller = $this->getController();
list($request, $response) = $this->getRequests();
$response->method('getStatusCode')->will($this->returnValue($code));
$controller($request, $response);
$data = $this->getStatusCodesMap($code);
foreach ($data as $func => $value) {
$this->assertEquals($value, $controller->$func(), "Method '$func' returns incorrect value");
}
$this->assertEquals($data['isClientError'] || $data['isServerError'], $controller->isError()
, "Method 'isError' returns incorrect value");
}
/**
* Provide data for testing status methods
*
* @return array
*/
public function responseStatusProvider()
{
return [
[null], [199],
[200], [201], [299],
[300], [304], [399],
[400], [403], [499],
[500], [503]
];
}
/**
* Test functions that check request method
*
* @dataProvider requestMethodProvider
* @param string $method
*/
public function testRequestMethod($method)
{
$controller = $this->getController();
list($request, $response) = $this->getRequests();
$request->method('getMethod')->will($this->returnValue($method));
$controller($request, $response);
$data = $this->getMethodsMap($method);
foreach ($data as $func => $value) {
$this->assertEquals($value, $controller->$func(), "Method '$func' returns incorrect value");
}
}
/**
* Provide data for testing functions that determine request method
*
* @return array
*/
public function requestMethodProvider()
{
return [
['GET'], ['POST'], ['PUT'], ['DELETE'], ['HEAD']
];
}
/**
* Test encodeData method, positive tests
*
* @dataProvider encodeDataPositiveProvider
* @param mixed $data
* @param string $format
* @param string $callback Callback name for testing jsonp request
*/
public function testEncodeDataPositive($data, $format, $callback = null)
{
$this->markTestSkipped();
$controller = $this->getController(['getRequest']);
list($request) = $this->getRequests();
if ($callback) {
$request->method('getQueryParams')->will($this->returnValue(['callback' => $callback]));
}
$controller->method('getRequest')->will($this->returnValue($request));
$result = $controller->encodeData($data, $format);
$expect = null;
if ($format === 'json') {
$expect = json_encode($data);
if ($callback) $expect = "$callback($expect)";
} else {
$expect = $data->asXML();
}
$this->assertNotEmpty($result, "Result should not be empty");
$this->assertEquals($expect, $result, "Data was not encoded correctly");
}
/**
* Provide data for testing encodeData method
*
* @return array
*/
public function encodeDataPositiveProvider()
{
$xml = simplexml_load_string(
"
Test tag
Test
"
);
return [
['test_string', 'json'],
[['testKey' => 'testValue'], 'json'],
[['testKey' => 'testValue'], 'json', 'test_callback'],
['', 'json'],
['', 'json', 'test_callback'],
[$xml, 'xml']
];
}
/**
* Test encodeData method, negative tests
*
* @dataProvider encodeDataNegativeProvider
* @param mixed $data
* @param string $format
*/
public function testEncodeDataNegative($data, $format)
{
$this->markTestSkipped();
$controller = $this->getController(['getRequest']);
list($request) = $this->getRequests();
$controller->method('getRequest')->will($this->returnValue($request));
$this->expectException(\InvalidArgumentException::class);
$result = $controller->encodeData($data, $format);
}
/**
* Provide data for testing encodeData method
*
* @return array
*/
public function encodeDataNegativeProvider()
{
return [
['test_string', 'html'],
['test_string', 'jpg']
];
}
/**
* Test output
*
* @dataProvider outputProvider
* @param mixed $data
* @param string $format
* @param string $contentType
* @param string $callback Callback name for testing jsonp request
*/
public function testOutput($data, $format, $contentType, $callback = '')
{
$controller = $this->getController(['getRequest', 'getResponse']);
list($request, $response) = $this->getRequests();
if (is_scalar($data)) {
$content = $data;
} elseif ($format === 'json') {
$content = json_encode($data);
if ($callback) $content = "$callback($content)";
} elseif ($format === 'xml') {
$content = $data->asXML();
}
$this->expectOutput($response, $content, $contentType);
if ($callback) {
$request->method('getQueryParams')->will($this->returnValue(['callback' => $callback]));
}
$controller->method('getRequest')->will($this->returnValue($request));
$controller->method('getResponse')->will($this->returnValue($response));
$result = $controller->output($data, $format);
$this->assertEquals($result, $response, "Output should return response instance");
}
/**
* Provide data for testing output
*
* @return array
*/
public function outputProvider()
{
$xml = simplexml_load_string(
"
Test tag
Test
"
);
return [
['test_string', 'text', 'text/plain'],
['javascript:test_call();', 'js', 'application/javascript'],
['test {}', 'css', 'text/css'],
['test_string', 'json', 'application/json'],
[['testKey' => 'testValue'], 'json', 'application/json'],
[['testKey' => 'testValue'], 'json', 'application/json', 'test_callback'],
['', 'json', 'application/json'],
['', 'json', 'application/json', 'test_callback'],
[$xml, 'xml', 'application/xml']
];
}
/**
* Test functions that deal with error messages
*
* @dataProvider errorMessagesProvider
* @param string $function
* @param int $code
* @param boolean $default Is code default for this function
*/
public function testErrorMessages($function, $code, $default)
{
$message = 'Test message';
$controller = $this->getController(['getResponse']);
list(, $response) = $this->getRequests();
$this->expectErrorMessage($response, $message, $code);
$controller->method('getResponse')->will($this->returnValue($response));
$result = $default ?
$controller->{$function}($message) :
$controller->{$function}($message, $code);
$this->assertEquals($result, $response, "Response object should be returned");
}
/**
* Provide data for testing error messages functions
*
* @return array
*/
public function errorMessagesProvider()
{
return [
['error', 400, true],
['error', 403, false],
['tooManyRequests', 429, true],
['tooManyRequests', 400, false],
['conflict', 409, true],
['conflict', 403, false],
['notFound', 404, true],
['notFound', 400, false],
['forbidden', 403, true],
['forbidden', 409, false],
['badRequest', 400, true],
['badRequest', 403, false]
];
}
/**
* Test setting flash
*
* @dataProvider flashProvider
* @param object $data
*/
public function testFlash($data)
{
$controller = $this->getMockBuilder(Controller::class)->disableOriginalConstructor()->getMockForAbstractClass();
$flash = $controller->flash();
$this->assertInstanceOf(Flash::class, $flash, "Flash is not set");
$this->assertEmpty($flash->get(), "Flash data should be empty");
$flash = $controller->flash($data->type, $data->message);
$this->assertInstanceOf(Flash::class, $flash, "Flash is not set");
$this->assertEquals($data, $flash->get(), "Flash data is incorrect");
$flash = $controller->flash();
$this->assertInstanceOf(Flash::class, $flash, "Flash is not set");
$this->assertEquals($data, $flash->get(), "Flash data is incorrect");
$flash->clear();
}
/**
* Test setting flash
*
* @return array
*/
public function flashProvider()
{
return [
[(object)['type' => 'test_type', 'message' => 'Test message']]
];
}
/**
* Test respondWith function
*
* @dataProvider respondWithProvider
* @param int|string $code
* @param string $format
* @param int $setCode Actual code that will be set in response
* @param string $contentType
*/
public function testRespondWith($code, $format, $setCode, $contentType)
{
$controller = $this->getController(['getResponse']);
list(, $response) = $this->getRequests();
$this->expectResponseWith($response, $setCode, $contentType);
$controller->method('getResponse')->will($this->returnValue($response));
$result = $controller->respondWith($code, $format);
$this->assertEquals($result, $response, "Response object should be returned");
}
/**
* Test function respondWith
*
* @return array
*/
public function respondWithProvider()
{
return [
[200, 'json', 200, 'application/json'],
[200, 'application/json', 200, 'application/json'],
[204, null, 204, null],
['204 Created', null, 204, null],
['json', null, null, 'application/json']
];
}
/**
* Test functions that are simple wrappers around respondWith function
*
* @dataProvider respondWithWrappersProvider
* @param string $function
* @param int $code
*/
public function testResponseWithWrappers($function, $code)
{
$controller = $this->getController(['getResponse']);
list(, $response) = $this->getRequests();
$this->expectResponseWith($response, $code);
$controller->method('getResponse')->will($this->returnValue($response));
$result = $controller->{$function}();
$this->assertEquals($result, $response, "Response object should be returned");
}
/**
* Provide data for testing respondWith wrappers
*
* @return array
*/
public function respondWithWrappersProvider()
{
return [
['ok', 200],
['noContent', 204]
];
}
/**
* Test 'created' function
*
* @dataProvider createdProvider
* @param string $location
*/
public function testCreated($location)
{
$controller = $this->getController(['getResponse']);
list(, $response) = $this->getRequests();
$response->expects($this->once())->method('withStatus')->with($this->equalTo(201))->will($this->returnSelf());
if ($location) {
$response->expects($this->once())->method('withHeader')->with($this->equalTo('Location'), $this->equalTo($location))->will($this->returnSelf());
}
$controller->method('getResponse')->will($this->returnValue($response));
$result = $controller->created($location);
$this->assertEquals($result, $response, "Response object should be returned");
}
/**
* Provide data for testing 'created' function
*
* @return array
*/
public function createdProvider()
{
return [
[''], ['/some-path/test']
];
}
/**
* Test 'redirect' function
*
* @dataProvider redirectProvider
* @param string $url
* @param int $code
* @param boolean $default
*/
public function testRedirect($url, $code, $default)
{
$controller = $this->getController(['getResponse']);
list(, $response) = $this->getRequests();
$this->expectRedirect($response, $url, $code);
$controller->method('getResponse')->will($this->returnValue($response));
$result = $default ?
$controller->redirect($url) :
$controller->redirect($url, $code);
$this->assertEquals($result, $response, "Response object should be returned");
}
/**
* Provide data for testing 'redirect' function
*
* @return array
*/
public function redirectProvider()
{
return [
['/test-url', 303, true],
['/test-url', 301, false]
];
}
/**
* Test 'requireLogin' function
*
* @dataProvider requireLoginProvider
* @param string $function
*/
public function testRequireLogin($function)
{
$controller = $this->getController(['getResponse']);
list(, $response) = $this->getRequests();
$this->expectRedirect($response, '/401', 303);
$controller->method('getResponse')->will($this->returnValue($response));
$result = $controller->{$function}();
$this->assertEquals($result, $response, "Response object should be returned");
}
/**
* Provide data for testing 'requireLogon' function
*
* @return array
*/
public function requireLoginProvider()
{
return [
['requireLogin'], ['requireAuth']
];
}
/**
* Test 'getLocalReferer' funtion
*
* @dataProvider localRefererProvider
* @param string $referer
* @param string $host
* @param boolean $local
*/
public function testLocalReferer($referer, $host, $local)
{
$controller = $this->getController(['getRequest']);
list($request) = $this->getRequests();
$this->expectLocalReferer($request, $referer, $host);
$controller->method('getRequest')->will($this->returnValue($request));
$result = $controller->getLocalReferer();
$local ?
$this->assertEquals($referer, $result, "Local referer should be returned") :
$this->assertEquals('', $result, "Local referer should not be returned");
}
/**
* Test 'back' function
*
* @dataProvider localRefererProvider
* @param string $referer
* @param string $host
* @param boolean $local
*/
public function testBack($referer, $host, $local)
{
$controller = $this->getController(['getRequest', 'getResponse']);
list($request, $response) = $this->getRequests();
$this->expectLocalReferer($request, $referer, $host);
$this->expectRedirect($response, $local ? $referer : '/', 303);
$controller->method('getRequest')->will($this->returnValue($request));
$controller->method('getResponse')->will($this->returnValue($response));
$result = $controller->back();
$this->assertEquals($result, $response, "Response object should be returned");
}
/**
* Provide data fot testing 'getLocalReferer' function
*
* @return array
*/
public function localRefererProvider()
{
return [
['http://not-local-host.com/path', 'local-host.com', false],
['http://local-host.com/path', 'local-host.com', true]
];
}
/**
* Expect for 'getLocalReferer' function to work correctly
*
* @param ServerRequestInterface $request
* @param string $referer
* @param string $host
*/
public function expectLocalReferer($request, $referer, $host)
{
$request->expects($this->exactly(2))->method('getHeaderLine')->withConsecutive(
[$this->equalTo('HTTP_REFERER')],
[$this->equalTo('HTTP_HOST')]
)->will($this->returnCallback(function($header) use ($referer, $host) {
return $header === 'HTTP_REFERER' ? $referer : $host;
}));
}
/**
* Expect for redirect
*
* @param ResponseInterface $response
* @param string $url
* @param int $code
*/
public function expectRedirect($response, $url, $code)
{
$stream = $this->createMock(StreamInterface::class);
$stream->expects($this->once())->method('write')->with($this->equalTo('You are being redirected to ' . $url . ''));
$response->expects($this->once())->method('getBody')->will($this->returnValue($stream));
$response->expects($this->once())->method('withStatus')->with($this->equalTo($code))->will($this->returnSelf());
$response->expects($this->exactly(2))->method('withHeader')->withConsecutive(
[$this->equalTo('Content-Type'), $this->equalTo('text/html')],
[$this->equalTo('Location'), $this->equalTo($url)]
)->will($this->returnSelf());
}
/**
* Expect correct work of respondWith function
*
* @param ResponseInterface $response
* @param int $code
* @param string $contentType
*/
public function expectResponseWith($response, $code, $contentType = null)
{
$code ?
$response->expects($this->once())->method('withStatus')->with($this->equalTo($code))->will($this->returnSelf()) :
$response->expects($this->never())->method('withStatus')->with($this->equalTo($code));
$contentType ?
$response->expects($this->once())->method('withHeader')->with($this->equalTo('Content-Type'), $this->equalTo($contentType))->will($this->returnSelf()) :
$response->expects($this->never())->method('withHeader')->with($this->equalTo('Content-Type'), $this->equalTo($contentType));
}
/**
* Expect for correct work of error message functions
*
* @param ResponseInterface $response
* @param string $message
* @param int $code
*/
public function expectErrorMessage($response, $message, $code)
{
$stream = $this->createMock(StreamInterface::class);
$stream->expects($this->once())->method('write')->with($this->equalTo($message));
$response->expects($this->once())->method('withStatus')->with($this->equalTo($code))->will($this->returnSelf());
$response->expects($this->once())->method('getBody')->will($this->returnValue($stream));
}
/**
* Expects that output will be set to content
*
* @param ResponseInterface $response
* @param string $content
* @param string $contentType
*/
public function expectOutput($response, $content, $contentType)
{
$stream = $this->createMock(StreamInterface::class);
$stream->expects($this->once())->method('write')->with($this->equalTo($content));
$response->expects($this->once())->method('withHeader')->with($this->equalTo('Content-Type'), $this->equalTo($contentType))->will($this->returnSelf());
$response->expects($this->once())->method('getBody')->will($this->returnValue($stream));
}
/**
* Get request and response instances
*
* @return array
*/
public function getRequests()
{
return [
$this->createMock(ServerRequestInterface::class),
$this->createMock(ResponseInterface::class)
];
}
/**
* Get map of status codes to states
*
* @param int $code
* @return []
*/
public function getStatusCodesMap($code)
{
return [
'isSuccessful' => !$code || ($code >= 200 && $code < 300),
'isRedirection' => $code >= 300 && $code < 400,
'isClientError' => $code >= 400 && $code < 500,
'isServerError' => $code >= 500
];
}
/**
* Get map of request methods
*
* @param string $method
* @return array
*/
public function getMethodsMap($method)
{
return [
'isGetRequest' => $method === 'GET',
'isPostRequest' => $method === 'POST',
'isPutRequest' => $method === 'PUT',
'isDeleteRequest' => $method === 'DELETE',
'isHeadRequest' => $method === 'HEAD'
];
}
}