summaryrefslogtreecommitdiffstats
path: root/tests/Router
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Router')
-rw-r--r--tests/Router/Middleware/BasePathTest.php142
-rw-r--r--tests/Router/Middleware/ErrorHandlerTest.php86
-rw-r--r--tests/Router/Middleware/NotFoundTest.php363
-rw-r--r--tests/Router/RouteTest.php42
-rw-r--r--tests/Router/Routes/GlobTest.php323
-rw-r--r--tests/Router/Routes/RouteBindingTest.php263
-rw-r--r--tests/Router/Runner/CallbackTest.php89
-rw-r--r--tests/Router/Runner/ControllerTest.php182
-rw-r--r--tests/Router/Runner/PhpScriptTest.php152
-rw-r--r--tests/Router/Runner/RunnerFactoryTest.php41
-rw-r--r--tests/Router/RunnerFactoryTest.php58
-rw-r--r--tests/Router/RunnerTest.php53
12 files changed, 930 insertions, 864 deletions
diff --git a/tests/Router/Middleware/BasePathTest.php b/tests/Router/Middleware/BasePathTest.php
index eb9a2e8..d615d70 100644
--- a/tests/Router/Middleware/BasePathTest.php
+++ b/tests/Router/Middleware/BasePathTest.php
@@ -1,25 +1,22 @@
<?php
+namespace Jasny\Router\Middleware;
+
use Jasny\Router\Middleware\BasePath;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
-class BasePathTest extends PHPUnit_Framework_TestCase
-{
- /**
- * Test creating middleware with invalid parameter
- *
- * @dataProvider invalidConstructProvider
- */
- public function testInvalidConstruct($basePath)
- {
- $this->expectException(\InvalidArgumentException::class);
-
- $pathHandler = new BasePath($basePath);
- }
+use Jasny\Router\TestHelpers;
+/**
+ * @covers Jasny\Router\Middleware\BasePath
+ */
+class BasePathTest extends \PHPUnit_Framework_TestCase
+{
+ use TestHelpers;
+
/**
* Provide data for testing invalid BasePath creation
*
@@ -39,17 +36,14 @@ class BasePathTest extends PHPUnit_Framework_TestCase
}
/**
- * Test creating BasePath instance
+ * Test creating middleware with invalid parameter
*
- * @dataProvider validConstructProvider
- * @param string $basePath
+ * @dataProvider invalidConstructProvider
+ * @expectedException InvalidArgumentException
*/
- public function testValidConstruct($basePath, $validBasePath)
+ public function testInvalidConstruct($basePath)
{
- $pathHandler = new BasePath($basePath);
-
- $this->assertNotEmpty($pathHandler->getBasePath(), "Empty base path");
- $this->assertEquals($validBasePath, $pathHandler->getBasePath(), "Base path was not set correctly");
+ new BasePath($basePath);
}
/**
@@ -71,41 +65,32 @@ class BasePathTest extends PHPUnit_Framework_TestCase
}
/**
- * Test invoke with invalid 'next' param
+ * Test creating BasePath instance
+ *
+ * @dataProvider validConstructProvider
+ * @param string $basePath
*/
- public function testInvokeInvalidNext()
+ public function testValidConstruct($basePath, $validBasePath)
{
- $middleware = new BasePath('/foo');
- list($request, $response) = $this->getRequests();
-
- $this->expectException(\InvalidArgumentException::class);
+ $pathHandler = new BasePath($basePath);
- $result = $middleware($request, $response, 'not_callable');
+ $this->assertNotEmpty($pathHandler->getBasePath(), "Empty base path");
+ $this->assertEquals($validBasePath, $pathHandler->getBasePath(), "Base path was not set correctly");
}
/**
- * Test case when given request path does not starts with given base path
- *
- * @dataProvider notFoundProvider
- * @param string $basePath
- * @param string $path
+ * Test invoke with invalid 'next' param
+ *
+ * @expectedException InvalidArgumentException
*/
- public function testNotFound($basePath, $path)
+ public function testInvokeInvalidNext()
{
- $middleware = new BasePath($basePath);
- list($request, $response) = $this->getRequests();
-
- $this->expectRequestGetPath($request, $path);
- $this->expectNotFound($response);
-
- $result = $middleware($request, $response, function($response, $request) {
- $response->nextCalled = true;
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
- return $response;
- });
+ $middleware = new BasePath('/foo');
- $this->assertEquals(get_class($response), get_class($result), "Middleware should return response object");
- $this->assertFalse(isset($response->nextCalled), "'next' was called");
+ $middleware($request, $response, 'not_callable');
}
/**
@@ -128,28 +113,27 @@ class BasePathTest extends PHPUnit_Framework_TestCase
}
/**
- * Test correct case, when path contains base path
- *
- * @dataProvider foundProvider
+ * Test case when given request path does not starts with given base path
+ * @dataProvider notFoundProvider
+ *
* @param string $basePath
* @param string $path
- * @param string $noBasePath
*/
- public function testFound($basePath, $path, $noBasePath)
+ public function testNotFound($basePath, $path)
{
- $middleware = new BasePath($basePath);
- list($request, $response) = $this->getRequests();
-
- $this->expectRequestSetBasePath($request, $basePath, $path, $noBasePath);
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
- $result = $middleware($request, $response, function($request, $response) {
- $response->nextCalled = true;
+ $middleware = new BasePath($basePath);
+
+ $this->expectRequestGetPath($request, $path);
+ $finalResponse = $this->expectNotFound($response);
- return $response;
- });
+ $next = $this->createCallbackMock($this->never());
+
+ $result = $middleware($request, $response, $next);
- $this->assertEquals(get_class($response), get_class($result), "Middleware should return response object");
- $this->assertTrue($response->nextCalled, "'next' was not called");
+ $this->assertSame($finalResponse, $result);
}
/**
@@ -172,19 +156,31 @@ class BasePathTest extends PHPUnit_Framework_TestCase
}
/**
- * Get requests for testing
- *
- * @param string $path
- * @return array
+ * Test correct case, when path contains base path
+ * @dataProvider foundProvider
+ *
+ * @param string $basePath
+ * @param string $path
+ * @param string $noBasePath
*/
- public function getRequests($path = null)
+ public function testFound($basePath, $path, $noBasePath)
{
$request = $this->createMock(ServerRequestInterface::class);
$response = $this->createMock(ResponseInterface::class);
+ $finalRespose = $this->createMock(ResponseInterface::class);
+
+ $middleware = new BasePath($basePath);
+
+ $this->expectRequestSetBasePath($request, $basePath, $path, $noBasePath);
- return [$request, $response];
+ $next = $this->createCallbackMock($this->once(), [$request, $response], $finalRespose);
+
+ $result = $middleware($request, $response, $next);
+
+ $this->assertSame($finalRespose, $result);
}
+
/**
* Expect that request will return a path
*
@@ -221,15 +217,19 @@ class BasePathTest extends PHPUnit_Framework_TestCase
* Expect for not found error
*
* @param ResponseInterface $response
+ * @return ResponseInterface
*/
public function expectNotFound(ResponseInterface $response)
{
+ $finalResponse = $this->createMock(ResponseInterface::class);
+
+ $response->expects($this->once())->method('withStatus')->with(404)->willReturn($finalResponse);
+
$stream = $this->createMock(StreamInterface::class);
- $stream->expects($this->once())->method('rewind');
$stream->expects($this->once())->method('write')->with($this->equalTo('Not Found'));
- $response->method('getBody')->will($this->returnValue($stream));
- $response->expects($this->once())->method('withBody')->with($this->equalTo($stream))->will($this->returnSelf());
- $response->expects($this->once())->method('withStatus')->with($this->equalTo(404), $this->equalTo('Not Found'))->will($this->returnSelf());
+ $finalResponse->expects($this->once())->method('getBody')->willReturn($stream);
+
+ return $finalResponse;
}
}
diff --git a/tests/Router/Middleware/ErrorHandlerTest.php b/tests/Router/Middleware/ErrorHandlerTest.php
deleted file mode 100644
index c4b6313..0000000
--- a/tests/Router/Middleware/ErrorHandlerTest.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-
-use Jasny\Router\Middleware\ErrorHandler;
-use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\StreamInterface;
-
-class ErrorHandlerTest extends PHPUnit_Framework_TestCase
-{
- /**
- * Test invoke with invalid 'next' param
- */
- public function testInvokeInvalidNext()
- {
- $middleware = new ErrorHandler();
- list($request, $response) = $this->getRequests();
-
- $this->expectException(\InvalidArgumentException::class);
-
- $result = $middleware($request, $response, 'not_callable');
- }
-
- /**
- * Test that exception in 'next' callback is caught
- */
- public function testInvokeCatchError()
- {
- $middleware = new ErrorHandler();
- list($request, $response) = $this->getRequests();
-
- $this->expectCatchError($response);
-
- $result = $middleware($request, $response, function($request, $response) {
- throw new Exception('Test exception');
- });
-
- $this->assertEquals(get_class($response), get_class($result), "Middleware should return response object");
- }
-
- /**
- * Test case when there is no error
- */
- public function testInvokeNoError()
- {
- $middleware = new ErrorHandler();
- list($request, $response) = $this->getRequests();
-
- $result = $middleware($request, $response, function($request, $response) {
- $response->nextCalled = true;
-
- return $response;
- });
-
- $this->assertEquals(get_class($response), get_class($result), "Middleware should return response object");
- $this->assertTrue($result->nextCalled, "'next' was not called");
- }
-
- /**
- * Get requests for testing
- *
- * @return array
- */
- public function getRequests()
- {
- $request = $this->createMock(ServerRequestInterface::class);
- $response = $this->createMock(ResponseInterface::class);
-
- return [$request, $response];
- }
-
- /**
- * Expect for error
- *
- * @param ResponseInterface $response
- */
- public function expectCatchError($response)
- {
- $stream = $this->createMock(StreamInterface::class);
- $stream->expects($this->once())->method('rewind');
- $stream->expects($this->once())->method('write')->with($this->equalTo('Unexpected error'));
-
- $response->method('getBody')->will($this->returnValue($stream));
- $response->expects($this->once())->method('withBody')->with($this->equalTo($stream))->will($this->returnSelf());
- $response->expects($this->once())->method('withStatus')->with($this->equalTo(500), $this->equalTo('Internal Server Error'))->will($this->returnSelf());
- }
-}
diff --git a/tests/Router/Middleware/NotFoundTest.php b/tests/Router/Middleware/NotFoundTest.php
index 0c40a68..b8cd657 100644
--- a/tests/Router/Middleware/NotFoundTest.php
+++ b/tests/Router/Middleware/NotFoundTest.php
@@ -5,261 +5,222 @@ use Jasny\Router\Middleware\NotFound;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+/**
+ * @covers Jasny\Router\Middleware\NotFound
+ */
class NotFoundTest extends PHPUnit_Framework_TestCase
{
- /**
- * Test creating object with false parameters
- *
- * @dataProvider constructProvider
- * @param string $notFound
- * @param string $notAllowed
- * @param boolean $positive
- */
- public function testConstruct($notFound, $notAllowed, $positive)
- {
- if (!$positive) $this->expectException(\InvalidArgumentException::class);
-
- $middleware = new NotFound($this->getRoutes(), $notFound, $notAllowed);
-
- if ($positive) $this->skipTest();
- }
-
- /**
- * Provide data for testing '__contruct'
- */
- public function constructProvider()
+ public function invalidStatusProvider()
{
return [
- [null, 405, false],
- [true, true, false],
- [99, null, false],
- [600, null, false],
- [404, 99, false],
- [404, 600, false],
- [200, 405, true],
- [404, 200, true]
+ [0],
+ [true],
+ ['foo bar zoo'],
+ [1000],
+ [['abc']]
];
}
/**
- * Test invoke with invalid 'next' param
+ * @dataProvider invalidStatusProvider
+ * @expectedException InvalidArgumentException
+ *
+ * @param string $status
*/
- public function testInvokeInvalidNext()
- {
- $middleware = new NotFound($this->getRoutes(), 404, 405);
- list($request, $response) = $this->getRequests();
-
- $this->expectException(\InvalidArgumentException::class);
-
- $result = $middleware($request, $response, 'not_callable');
- }
-
- /**
- * Test that 'next' callback is invoked when route is found
- *
- * @dataProvider invokeProvider
- * @param callback|int $notFound
- * @param callback|int $notAllowed
- * @param callback $next
- */
- public function testInvokeFound($notFound, $notAllowed, $next)
+ public function testConstructInvalidNotFound($status)
{
- if (!$next) return $this->skipTest();
-
- list($request, $response) = $this->getRequests();
- $routes = $this->getRoutes();
- $middleware = new NotFound($routes, $notFound, $notAllowed);
-
- $this->expectRoute($routes, $request, 'found');
- $this->notExpectSimpleError($response);
-
- $result = $middleware($request, $response, $next);
-
- $this->assertEquals(get_class($response), get_class($result), "Result must be an instance of 'ResponseInterface'");
- $this->assertTrue($result->nextCalled, "'next' was not called");
- $this->assertFalse(isset($result->notAllowedCalled), "'Not allowed' callback was called");
- $this->assertFalse(isset($result->notFoundCalled), "'Not found' callback was called");
+ new NotFound($this->createMock(Routes::class), $status);
}
/**
- * Test __invoke method in case of route is found with another method
- *
- * @dataProvider invokeProvider
- * @param callback|int $notFound
- * @param callback|int $notAllowed
- * @param callback $next
+ * @expectedException InvalidArgumentException
*/
- public function testInvokeNotAllowed($notFound, $notAllowed, $next)
+ public function testConstructNotFoundNotNull()
{
- if (!$notAllowed) return $this->skipTest();
-
- list($request, $response) = $this->getRequests();
- $routes = $this->getRoutes();
- $middleware = new NotFound($routes, $notFound, $notAllowed);
-
- $this->expectRoute($routes, $request, 'notAllowed');
- if (is_numeric($notAllowed)) {
- $this->expectSimpleError($response, $notAllowed);
- }
-
- $result = $middleware($request, $response, $next);
-
- $this->assertEquals(get_class($response), get_class($result), "Result must be an instance of 'ResponseInterface'");
- $this->assertFalse(isset($result->nextCalled), "'next' was called");
-
- if (is_callable($notAllowed)) {
- $this->assertTrue($result->notAllowedCalled, "'Not allowed' callback was not called");
- }
+ new NotFound($this->createMock(Routes::class), null);
}
/**
- * Test __invoke method in case of route not found at all
- *
- * @dataProvider invokeProvider
- * @param callback|int $notFound
- * @param callback|int $notAllowed
- * @param callback $next
+ * @dataProvider invalidStatusProvider
+ * @expectedException InvalidArgumentException
+ *
+ * @param string $status
*/
- public function testInvokeNotFound($notFound, $notAllowed, $next)
+ public function testConstructInvalidMethodNotAllowed($status)
{
- list($request, $response) = $this->getRequests();
- $routes = $this->getRoutes();
- $middleware = new NotFound($routes, $notFound, $notAllowed);
-
- $case = $notAllowed ? 'notFoundTwice' : 'notFoundOnce';
- $this->expectRoute($routes, $request, $case);
-
- if (is_numeric($notFound)) {
- $this->expectSimpleError($response, $notFound);
- }
-
- $result = $middleware($request, $response, $next);
-
- $this->assertEquals(get_class($response), get_class($result), "Result must be an instance of 'ResponseInterface'");
- $this->assertFalse(isset($result->nextCalled), "'next' was called");
-
- if (is_callable($notAllowed)) {
- $this->assertFalse(isset($result->notAllowedCalled), "'Not allowed' callback was called");
- }
- if (is_callable($notFound)) {
- $this->assertTrue($result->notFoundCalled, "'Not found' callback was not called");
- }
+ new NotFound($this->createMock(Routes::class), 404, $status);
}
/**
- * Set expectations on finding route
- *
- * @param Routes $routes
- * @param ServerRequestInterface $request
- * @param string $case
+ * @expectedException InvalidArgumentException
*/
- public function expectRoute($routes, $request, $case)
- {
- if ($case === 'found' || $case === 'notFoundOnce') {
- $found = $case === 'found';
+ public function testInvokeInvalidNext()
+ {
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+
+ $middleware = new NotFound($this->createMock(Routes::class));
- $routes->expects($this->once())->method('hasRoute')
- ->with($this->equalTo($request))->will($this->returnValue($found));
- } elseif ($case === 'notAllowed' || $case === 'notFoundTwice') {
- $routes->expects($this->exactly(2))->method('hasRoute')
- ->withConsecutive(
- [$this->equalTo($request)],
- [$this->equalTo($request), $this->equalTo(false)]
- )->will($this->returnCallback(function($request, $searchMethod = true) use ($case) {
- return $case === 'notFoundTwice' ? false : !$searchMethod;
- }));
- }
+ $middleware($request, $response, 'foo bar zoo');
}
+
/**
* Provide data for testing invoke method
*/
public function invokeProvider()
{
- $callbacks = [];
- foreach (['notFound', 'notAllowed', 'next'] as $type) {
- $var = $type . 'Called';
-
- $callbacks[$type] = function($request, $response) use ($var) {
- $response->$var = true;
- return $response;
- };
- }
-
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+
+ $mockCallback = function() {
+ return $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock();
+ };
+
return [
- [404, 405, $callbacks['next']],
- [404, 405, null],
- [404, null, $callbacks['next']],
- [404, null, null],
- [$callbacks['notFound'], $callbacks['notAllowed'], $callbacks['next']],
- [$callbacks['notFound'], $callbacks['notAllowed'], null],
- [$callbacks['notFound'], null, $callbacks['next']],
- [$callbacks['notFound'], null, null]
+ [$request, $response, 404, 405, $mockCallback()],
+ [$request, $response, 404, null, $mockCallback()],
+ [$request, $response, '200', '402', $mockCallback()],
+ [$request, $response, $mockCallback(), $mockCallback(), $mockCallback()],
+ [$request, $response, $mockCallback(), null, $mockCallback()]
];
}
/**
- * Expect that response is set to simple deny answer
- *
- * @param ResponseInterface $response
- * @param int $statusCode
+ * Test that 'next' callback is invoked when route is found
+ * @dataProvider invokeProvider
+ *
+ * @param ServerRequestInterface|MockObject $request
+ * @param ResponseInterface|MockObject $response
+ * @param callback|MockObject|int $notFound
+ * @param callback|MockObject|int $methodNotAllowed
+ * @param callback|MockObject $next
*/
- public function expectSimpleError(ResponseInterface $response, $statusCode)
+ public function testInvokeFound($request, $response, $notFound, $methodNotAllowed, $next)
{
- $stream = $this->createMock(StreamInterface::class);
- $stream->expects($this->once())->method('rewind');
- $stream->expects($this->once())->method('write')->with($this->equalTo('Not Found'));
+ $finalResponse = $this->createMock(ResponseInterface::class);
+
+ if ($notFound instanceof MockObject) {
+ $notFound->expects($this->never())->method('__invoke');
+ }
+
+ if ($methodNotAllowed instanceof MockObject) {
+ $methodNotAllowed->expects($this->never())->method('__invoke');
+ }
+
+ $next->expects($this->once())->method('__invoke')->with($request, $response)->willReturn($finalResponse);
+
+ $response->expects($this->never())->method('withStatus');
+
+ $routes = $this->createMock(Routes::class);
+ $routes->expects($this->once())->method('hasRoute')->with($request)->willReturn(true);
+
+ $middleware = new NotFound($routes, $notFound, $methodNotAllowed);
+
+ $result = $middleware($request, $response, $next);
- $response->method('getBody')->will($this->returnValue($stream));
- $response->expects($this->once())->method('withBody')->with($this->equalTo($stream))->will($this->returnSelf());
- $response->expects($this->once())->method('withStatus')->with($this->equalTo($statusCode), $this->equalTo('Not Found'))->will($this->returnSelf());
+ $this->assertSame($finalResponse, $result);
}
/**
- * Expect that there would be no simple error response
- *
- * @param ResponseInterface $response
+ * Test __invoke method in case of route is found with another method
+ * @dataProvider invokeProvider
+ *
+ * @param ServerRequestInterface|MockObject $request
+ * @param ResponseInterface|MockObject $response
+ * @param callback|MockObject|int $notFound
+ * @param callback|MockObject|int $methodNotAllowed
+ * @param callback|MockObject $next
*/
- public function notExpectSimpleError(ResponseInterface $response)
+ public function testInvokeNotFound($request, $response, $notFound, $methodNotAllowed, $next)
{
+ $finalResponse = $this->createMock(ResponseInterface::class);
$stream = $this->createMock(StreamInterface::class);
- $stream->expects($this->never())->method('rewind');
- $stream->expects($this->never())->method('write');
-
- $response->expects($this->never())->method('getBody');
- $response->expects($this->never())->method('withBody');
- $response->expects($this->never())->method('withStatus');
- }
+
+ if ($notFound instanceof MockObject) {
+ $notFound->expects($this->once())->method('__invoke')
+ ->with($request, $response)
+ ->willReturn($finalResponse);
+
+ $response->expects($this->never())->method('withStatus');
+ } else {
+ $response->expects($this->once())->method('withStatus')
+ ->with($notFound)
+ ->willReturn($finalResponse);
+
+ $finalResponse->expects($this->once())->method('getBody')->willReturn($stream);
+ $stream->expects($this->once())->method('write')->with('Not found');
+ }
+
+ if ($methodNotAllowed instanceof MockObject) {
+ $methodNotAllowed->expects($this->never())->method('__invoke');
+ }
+
+ $next->expects($this->never())->method('__invoke');
+
+ $routes = $this->createMock(Routes::class);
+
+ $routes->expects($this->exactly(isset($methodNotAllowed) ? 2 : 1))->method('hasRoute')
+ ->withConsecutive([$request], [$request, false])
+ ->willReturn(false);
+
+ $middleware = new NotFound($routes, $notFound, $methodNotAllowed);
- /**
- * Get requests for testing
- *
- * @return array
- */
- public function getRequests()
- {
- $request = $this->createMock(ServerRequestInterface::class);
- $response = $this->createMock(ResponseInterface::class);
+ $result = $middleware($request, $response, $next);
- return [$request, $response];
+ $this->assertSame($finalResponse, $result);
}
/**
- * Get routes array
- *
- * @return Routes
+ * Test __invoke method in case of route is found with another method
+ * @dataProvider invokeProvider
+ *
+ * @param ServerRequestInterface|MockObject $request
+ * @param ResponseInterface|MockObject $response
+ * @param callback|MockObject|int $notFound
+ * @param callback|MockObject|int $methodNotAllowed
+ * @param callback|MockObject $next
*/
- public function getRoutes()
+ public function testInvokeMethodNotAllowed($request, $response, $notFound, $methodNotAllowed, $next)
{
- return $this->getMockBuilder(Routes::class)->disableOriginalConstructor()->getMock();
- }
+ $finalResponse = $this->createMock(ResponseInterface::class);
+ $stream = $this->createMock(StreamInterface::class);
+
+ $expect = $methodNotAllowed ?: $notFound;
+
+ if ($expect !== $notFound && $notFound instanceof MockObject) {
+ $notFound->expects($this->never())->method('__invoke');
+ }
+
+ if ($expect instanceof MockObject) {
+ $expect->expects($this->once())->method('__invoke')
+ ->with($request, $response)
+ ->willReturn($finalResponse);
+
+ $response->expects($this->never())->method('withStatus');
+ } else {
+ $response->expects($this->once())->method('withStatus')
+ ->with($expect)
+ ->willReturn($finalResponse);
+
+ $finalResponse->expects($this->once())->method('getBody')->willReturn($stream);
+ $stream->expects($this->once())->method('write')->with('Not found');
+ }
+
+ $next->expects($this->never())->method('__invoke');
+
+ $routes = $this->createMock(Routes::class);
+
+ $routes->expects($this->exactly(isset($methodNotAllowed) ? 2 : 1))->method('hasRoute')
+ ->withConsecutive([$request], [$request, false])
+ ->will($this->onConsecutiveCalls(false, true));
+
+ $middleware = new NotFound($routes, $notFound, $methodNotAllowed);
- /**
- * Skip the test pass
- */
- public function skipTest()
- {
- return $this->assertTrue(true);
+ $result = $middleware($request, $response, $next);
+
+ $this->assertSame($finalResponse, $result);
}
}
diff --git a/tests/Router/RouteTest.php b/tests/Router/RouteTest.php
new file mode 100644
index 0000000..4a72d27
--- /dev/null
+++ b/tests/Router/RouteTest.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Jasny\Router;
+
+use Jasny\Router\Route;
+
+/**
+ * @covers Jasny\Router\Route
+ */
+class RouteTest extends \PHPUnit_Framework_TestCase
+{
+ public function provider()
+ {
+ return [
+ [['foo' => '$1', 'color' => 'red', 'number' => 42]],
+ [(object)['foo' => '$1', 'color' => 'red', 'number' => 42]]
+ ];
+ }
+
+ /**
+ * @dataProvider provider
+ *
+ * @param array|stdClass $values
+ */
+ public function testConstructionWithObject($values)
+ {
+ $route = new Route($values);
+
+ $this->assertAttributeSame('$1', 'foo', $route);
+ $this->assertAttributeSame('red', 'color', $route);
+ $this->assertAttributeSame(42, 'number', $route);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Route values should be an array, not a string
+ */
+ public function testConstructionInvalidArgument()
+ {
+ new Route('foo');
+ }
+}
diff --git a/tests/Router/Routes/GlobTest.php b/tests/Router/Routes/GlobTest.php
index 3ed4d21..5efa77f 100644
--- a/tests/Router/Routes/GlobTest.php
+++ b/tests/Router/Routes/GlobTest.php
@@ -3,13 +3,17 @@
namespace Jasny\Router\Routes;
use Jasny\Router\Routes\Glob;
+use Jasny\Router\Route;
use Psr\Http\Message\ServerRequestInterface;
use ArrayObject;
use BadMethodCallException;
use InvalidArgumentException;
-use AppendIterator;
+/**
+ * @covers Jasny\Router\Routes\Glob
+ * @covers Jasny\Router\UrlParsing
+ */
class GlobTest extends \PHPUnit_Framework_TestCase
{
/**
@@ -17,63 +21,55 @@ class GlobTest extends \PHPUnit_Framework_TestCase
*/
public function testConstructor()
{
- #Test empty constructor
$glob = new Glob();
$this->assertInstanceOf('ArrayObject', $glob, "Should be an instance of 'ArrayObject'");
$this->assertEquals(0, $glob->count(), "Default count is not empty");
$this->assertEquals(0, $glob->getFlags(), "Default flags are not empty");
$this->assertEquals('ArrayIterator', $glob->getIteratorClass(), "Default iterator class is not correct");
- #Actual check for public values
+ // Actual check for available routes
$count = 0;
foreach ($glob as $value) {
$count++;
break;
}
- $this->assertEquals(0, $count);
+ $this->assertEquals(0, $count);
}
public function testConstructorWithArguments()
{
- #Test with params
$values = [
'/foo/bar' => ['controller' => 'value1'],
'/foo/*' => ['fn' => 'value3'],
'/foo/*/bar' => ['file' => 'value5'],
];
- $glob = new Glob($values, ArrayObject::ARRAY_AS_PROPS, AppendIterator::class);
+ $glob = new Glob($values, ArrayObject::ARRAY_AS_PROPS);
- $this->assertEquals(count($values), $glob->count(), "Routes count is not match");
+ $this->assertCount(3, $glob, "Routes count do not match");
$this->assertEquals(ArrayObject::ARRAY_AS_PROPS, $glob->getFlags(), "Flags are not correct");
- $this->assertEquals(AppendIterator::class, $glob->getIteratorClass(), "Iterator class is not correct");
- foreach ($values as $pattern => $options) {
- $this->assertTrue($glob->offsetExists($pattern), "Key '$pattern' is missing");
+ foreach ($glob as $pattern => $route) {
+ $this->assertInstanceof(Route::class, $route);
+ $this->assertArrayHasKey($pattern, $values);
+ $this->assertArraysEqual($values[$pattern], (array)$route);
}
+
+ return $glob;
}
-
+
/**
- * Test ArrayObject::exchangeArray method
+ * @depends testConstructorWithArguments
*
- * @dataProvider exchangeArrayProvider
+ * @param Glob $original
*/
- public function testExchangeArray($set, $reset)
+ public function testConstructorTraversable(Glob $original)
{
- $glob = new Glob($set);
- $old = $glob->exchangeArray($reset);
-
- $this->assertEquals(count($set), count($old), "Old routes count is not match");
- $this->assertEquals(count($reset), $glob->count(), "Routes count is not match");
-
- foreach ($reset as $pattern => $options) {
- $this->assertTrue($glob->offsetExists($pattern), "Key is missing");
- }
- foreach ($set as $pattern => $options) {
- $this->assertTrue(!empty($old[$pattern]), "Old key is missing");
- $this->assertFalse($glob->offsetExists($pattern), "Key exists, but should not");
- }
+ $glob = new Glob($original);
+
+ $this->assertCount(3, $glob, "Routes count do not match");
+ $this->assertEquals($original->getArrayCopy(), $glob->getArrayCopy());
}
/**
@@ -98,70 +94,93 @@ class GlobTest extends \PHPUnit_Framework_TestCase
}
/**
- * Test ArrayObject::offsetSet method
+ * Test ArrayObject::exchangeArray method
*
- * @dataProvider offsetSetProvider
- * @param string $pattern
- * @param array $options
- * @param string $exception
+ * @dataProvider exchangeArrayProvider
*/
- public function testOffsetSet($pattern, $options, $exception)
+ public function testExchangeArray($set, $reset)
{
- if ($exception) $this->expectException($exception);
-
- $glob = new Glob();
- $glob->offsetSet($pattern, $options);
+ $glob = new Glob($set);
+ $old = $glob->exchangeArray($reset);
- if ($exception) return;
+ $this->assertEquals(count($set), count($old), "Old routes count do not match");
+ $this->assertEquals(count($reset), $glob->count(), "Routes count do not match");
- $this->assertEquals(1, $glob->count(), "Routes count is not match");
- $this->assertTrue($glob->offsetExists($pattern), "Key is missing");
-
- #Verify that value was set correctly
- $value = (array)$glob->offsetGet($pattern);
- $this->assertEmpty(array_diff($options, $value), "Route was not set correct");
+ foreach ($reset as $pattern => $options) {
+ $this->assertTrue($glob->offsetExists($pattern), "Key is missing");
+ }
+ foreach ($set as $pattern => $options) {
+ $this->assertTrue(!empty($old[$pattern]), "Old key is missing");
+ $this->assertFalse($glob->offsetExists($pattern), "Key exists, but should not");
+ }
}
+
/**
* Provide data for testOffsetSet()
*/
public function offsetSetProvider()
{
return [
- ['/foo/*', ['controller' => 'bar'], ''],
- ['/foo/*', ['fn' => 'bar'], ''],
- ['/foo/*', ['file' => 'bar'], ''],
- ['', ['controller' => 'bar'], BadMethodCallException::class],
- ['foo', 'bar', InvalidArgumentException::class],
- ['', '', BadMethodCallException::class]
+ ['/foo/*', ['controller' => 'bar']],
+ ['/foo/*', ['fn' => 'bar']],
+ ['/foo/*', ['file' => 'bar']],
+ ['/foo/*', $this->getMockBuilder(Route::class)->setConstructorArgs([['controller' => 'bar']])->getMock()]
];
}
+
+ /**
+ * Test ArrayObject::offsetSet method
+ * @dataProvider offsetSetProvider
+ *
+ * @param string $pattern
+ * @param array $options
+ */
+ public function testOffsetSet($pattern, $options)
+ {
+ $glob = new Glob();
+ $glob[$pattern] = $options;
+ $this->assertCount(1, $glob);
+ $this->assertTrue(isset($glob[$pattern]));
+
+ $route = $glob[$pattern];
+ $this->assertInstanceOf(Route::class, $route);
+
+ if ($options instanceof Route) {
+ $this->assertSame($options, $route);
+ } else {
+ $this->assertEquals([], array_diff($options, (array)$route));
+ }
+ }
+
/**
- * Test ArrayObject::append method
- *
* @expectedException BadMethodCallException
*/
- public function testAppend()
+ public function testOffsetSetInvalidPattern()
{
$glob = new Glob();
- $glob->append(['controller' => 'bar']);
+ $glob[''] = ['controller' => 'bar'];
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testOffsetSetInvalidRoute()
+ {
+ $glob = new Glob();
+ $glob['/foo'] = 'bar';
}
/**
- * Test matching of url pattern to given uri
+ * Test ArrayObject::append method
*
- * @dataProvider fnMatchProvider
- * @param string $pattern
- * @param string $uri
- * @param boolean $positive
+ * @expectedException BadMethodCallException
*/
- public function testFnMatch($pattern, $uri, $positive)
- {
+ public function testAppend()
+ {
$glob = new Glob();
-
- $this->assertEquals($positive, $glob->fnmatch($pattern, $uri),
- "Pattern and uri should " . ($positive ? "" : "not") . " match");
+ $glob->append(['controller' => 'bar']);
}
/**
@@ -205,12 +224,28 @@ class GlobTest extends \PHPUnit_Framework_TestCase
}
/**
- * Testing getting route and it's existense
+ * Test matching of url pattern to given uri
+ * @dataProvider fnMatchProvider
*
+ * @param string $pattern
+ * @param string $uri
+ * @param boolean $positive
+ */
+ public function testFnMatch($pattern, $uri, $positive)
+ {
+ $glob = new Glob();
+
+ $this->assertEquals($positive, $glob->fnmatch($pattern, $uri),
+ "Pattern and uri should " . ($positive ? "" : "not") . " match");
+ }
+
+ /**
+ * Testing getting route and it's existense
* @dataProvider getHasRouteProvider
- * @param string $uri Uri of ServerRequest
- * @param string $method Query method name
- * @param boolean $positive If the test should be positive or negative
+ *
+ * @param string $uri Uri of ServerRequest
+ * @param string $method Query method name
+ * @param boolean $positive If the test should be positive or negative
*/
public function testGetHasRoute($uri, $method, $positive)
{
@@ -241,7 +276,7 @@ class GlobTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($exist, "Route not exists");
$this->assertTrue((bool)$match, "Found no match of uri with patterns");
- $this->assertEquals($values[$match]['controller'], $route['controller'], "False route obtained");
+ $this->assertEquals($values[$match]['controller'], $route->controller, "False route obtained");
}
/**
@@ -295,152 +330,6 @@ class GlobTest extends \PHPUnit_Framework_TestCase
}
/**
- * Test binding simple string when getting route
- */
- public function testBindVarString()
- {
- $uri = '/foo/bar';
- $values = [$uri => ['controller' => 'value1', 'check' => 'value1']];
-
- $glob = new Glob($values);
- $request = $this->getServerRequest($uri);
- $route = $glob->getRoute($request);
-
- $this->assertEquals($route['check'], $values[$uri]['check'], "Option value is not correct");
- }
-
- /**
- * Test binding single url part to route option
- * @dataProvider bindVarSingleUrlPartProvider
- * @param string $patter
- * @param string $uri
- * @param array $options Route options
- */
- public function testBindVarSingleUrlPart($pattern, $uri, $options)
- {
- $values = [$pattern => $options];
-
- $glob = new Glob($values);
- $request = $this->getServerRequest($uri);
- $route = $glob->getRoute($request);
-
- $this->assertTrue((bool)$route, "Route not found");
-
- if (!empty($options['check'])) {
- $this->assertEquals('test', $route['check'], "Single pocket did not match");
- } elseif(empty($options['check2'])) {
- $this->assertEquals('test1/test2', $route['check1'], "Single compound pocket did not match");
- } else {
- $this->assertEquals('test1', $route['check1'], "First of two pockets did not match");
- $this->assertEquals('test2', $route['check2'], "Second of two pockets did not match");
- }
- }
-
- /**
- * Provide uri's and corresponding patterns for testBindVarSingleUrlPart()
- */
- public function bindVarSingleUrlPartProvider()
- {
- return [
- ['/*', '/test', ['controller' => 'value', 'check' => '$1']],
- ['/foo/*/bar', '/foo/test/bar', ['controller' => 'value', 'check' => '$2']],
- ['/foo/bar/*', '/foo/bar/test', ['controller' => 'value', 'check' => '$3']],
- ['/foo/bar/*/zet/*', '/foo/bar/test1/zet/test2', ['controller' => 'value', 'check1' => '$3', 'check2' => '$5']],
- ['/foo/bar/*/zet/*', '/foo/bar/test1/zet/test2', ['controller' => 'value', 'check1' => '~$3~/~$5~']]
- ];
- }
-
- /**
- * Test binding multyple url parts to route option
- *
- * @dataProvider bindVarMultipleUrlPartsProvider
- * @param string $uri
- * @param array $options Route options
- * @param boolean $positive
- * @param string $exception
- */
- public function testBindVarMultipleUrlParts($uri, $options, $positive, $exception)
- {
- if ($exception) $this->expectException(InvalidArgumentException::class);
-
- $values = [$uri => $options];
- $glob = new Glob($values);
- $request = $this->getServerRequest($uri);
- $route = $glob->getRoute($request);
-
- if ($exception) return;
-
- $values = explode('/', trim($uri, '/'));
- $this->assertTrue((bool)$route, "Route not found");
-
- $positive ?
- $this->assertArraysEqual($values, $route['check'], "Multyple url parts are not picked correctly") :
- $this->assertEmpty($route['check'], "Multyple parts element should be empty");
-
- if (!empty($options['check2'])) {
- array_shift($values);
- $this->assertArraysEqual($values, $route['check2'], "Secondary multyple url parts are not picked correctly");
- }
- }
-
- /**
- * Provide uri's and corresponding patterns for testBindVarMultipleUrlParts()
- */
- public function bindVarMultipleUrlPartsProvider()
- {
- return [
- ['/foo', ['controller' => 'value', 'check' => '$1...'], false, InvalidArgumentException::class],
- ['/', ['controller' => 'value', 'check' => ['$1...']], false, ''],
- ['/foo', ['controller' => 'value', 'check' => ['$1...']], true, ''],
- ['/foo/bar', ['controller' => 'value', 'check' => ['$1...'], 'check2' => ['$2...']], true, '']
- ];
- }
-
- /**
- * Test binding element of superglobal array to route option
- *
- * @dataProvider bindVarSuperGlobalProvider
- * @param string $uri
- * @param array $options
- * @param string $type ('get', 'post', 'cookie')
- */
- public function testBindVarSuperGlobal($uri, $options, $type)
- {
- $test = ['check' => 'test'];
- $glob = new Glob([$uri => $options]);
- $request = $this->getServerRequest($uri, 'GET', [$type => $test]);
- $route = $glob->getRoute($request);
-
- $this->assertEquals($test['check'], $route['check'], "Did not obtaine value for superglobal '$type'");
- }
-
- /**
- * Provide uri's and corresponding patterns for testBindVarMultipleUrlParts()
- */
- public function bindVarSuperGlobalProvider()
- {
- return [
- ['/foo', ['controller' => 'value', 'check' => '$_GET[check]'], 'get'],
- ['/foo', ['controller' => 'value', 'check' => '$_POST[check]'], 'post'],
- ['/foo', ['controller' => 'value', 'check' => '$_COOKIE[check]'], 'cookie']
- ];
- }
-
- /**
- * Test binding element of superglobal array to route option
- */
- public function testBindVarRequestHeader()
- {
- $uri = '/foo/bar';
- $test = 'test_header_value';
- $glob = new Glob([$uri => ['controller' => 'value', 'check' => '$HTTP_REFERER']]);
- $request = $this->getServerRequest($uri, 'GET', [], $test);
- $route = $glob->getRoute($request);
-
- $this->assertEquals($test, $route['check'], "Did not obtaine value for header");
- }
-
- /**
* Get ServerRequestInterface object
*
* @param string $uri
@@ -469,7 +358,7 @@ class GlobTest extends \PHPUnit_Framework_TestCase
*/
public function assertArraysEqual(array $array1, array $array2)
{
- $this->assertEquals(count($array1), count($array2));
- $this->assertEmpty(array_diff($array1, $array2));
+ $this->assertEmpty(array_diff($array2, $array1), 'Missing items');
+ $this->assertEmpty(array_diff($array1, $array2), 'Additional items');
}
}
diff --git a/tests/Router/Routes/RouteBindingTest.php b/tests/Router/Routes/RouteBindingTest.php
new file mode 100644
index 0000000..96536ac
--- /dev/null
+++ b/tests/Router/Routes/RouteBindingTest.php
@@ -0,0 +1,263 @@
+<?php
+
+namespace Jasny\Router\Routes;
+
+use Jasny\Router\Routes\Glob;
+use Jasny\Router\Route;
+use Psr\Http\Message\ServerRequestInterface;
+
+use InvalidArgumentException;
+
+/**
+ * @covers Jasny\Router\Routes\RouteBinding
+ */
+class RouteBindingTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * Test binding simple string when getting route
+ */
+ public function testBindVarString()
+ {
+ $uri = '/foo/bar';
+ $values = [$uri => ['controller' => 'value1', 'check' => 'value1']];
+
+ $glob = new Glob($values);
+ $request = $this->getServerRequest($uri);
+ $route = $glob->getRoute($request);
+
+ $this->assertEquals($values[$uri]['check'], $route->check);
+ }
+
+ /**
+ * Provide uri's and corresponding patterns for testBindVarSingleUrlPart()
+ */
+ public function bindVarSingleUrlPartProvider()
+ {
+ return [
+ ['/*', '/test', ['check' => '$1'], 'test'],
+ ['/', '/', ['check' => '$1|test'], 'test'],
+ ['/foo/*/bar', '/foo/test/bar', ['check' => '$2'], 'test'],
+ ['/foo/bar/*', '/foo/bar/test', ['check' => '$3'], 'test'],
+ ['/foo/bar/*/zet/*', '/foo/bar/test1/zet/test2', ['check' => '$3', 'checkB' => '$5'], 'test1', 'test2'],
+ ['/foo/bar/*/zet/*', '/foo/bar/test1/zet/test2', ['check' => '~$3~/~$5~'], 'test1/test2'],
+ ['/', '/', ['check' => '$foo'], null],
+ ['/', '/', ['check' => 'test', 'checkB' => null], 'test', null]
+ ];
+ }
+
+ /**
+ * Test binding single url part to route option
+ * @dataProvider bindVarSingleUrlPartProvider
+ *
+ * @param string $pattern
+ * @param string $uri
+ * @param array $options Route options
+ * @param string $check Expected value for `check`
+ * @param string $checkB Expected value for `checkB`
+ */
+ public function testBindVarSingleUrlPart($pattern, $uri, $options, $check, $checkB = null)
+ {
+ $values = [$pattern => $options];
+
+ $glob = new Glob($values);
+ $request = $this->getServerRequest($uri);
+ $route = $glob->getRoute($request);
+
+ $this->assertNotNull($route, "Route not found");
+ $this->assertInstanceOf(Route::class, $route);
+
+ $this->assertEquals($check, $route->check);
+
+ if (isset($checkB)) {
+ $this->assertEquals($checkB, $route->checkB);
+ } else {
+ $this->assertObjectNotHasAttribute('checkB', $route);
+ }
+ }
+
+ public function testBindVarWithObject()
+ {
+ $object = new \Exception(); // Could be anything, just not stdClass
+ $glob = new Glob(['/' => ['object' => $object]]);
+
+ $request = $this->getServerRequest('/');
+ $route = $glob->getRoute($request);
+
+ $this->assertNotNull($route, "Route not found");
+ $this->assertInstanceOf(Route::class, $route);
+
+ $this->assertSame($object, $route->object);
+ }
+
+ public function bindVarWithSubProvider()
+ {
+ return [
+ [['group' => ['check' => '$1']], 'array'],
+ [['group' => (object)['check' => '$1']], 'object'],
+ [['group' => ['sub' => (object)['check' => '$1']]], 'array', 'object'],
+ [['group' => (object)['sub' => ['check' => '$1']]], 'object', 'array']
+ ];
+ }
+
+ /**
+ * @dataProvider bindVarWithSubProvider
+ *
+ * @param array $options
+ * @param string $type
+ * @param string $subtype
+ */
+ public function testBindVarWithSub(array $options, $type, $subtype = null)
+ {
+ $glob = new Glob(['/*' => $options]);
+
+ $request = $this->getServerRequest('/test');
+ $route = $glob->getRoute($request);
+
+ $this->assertNotNull($route, "Route not found");
+ $this->assertInstanceOf(Route::class, $route);
+
+ $this->assertInternalType($type, $route->group);
+
+ $group = (array)$route->group;
+
+ if (isset($subtype)) {
+ $this->assertArrayHasKey('sub', $group);
+ $this->assertInternalType($subtype, $group['sub']);
+
+ $group = (array)$group['sub'];
+ }
+
+ $this->assertEquals($group, ['check' => 'test']);
+ }
+
+
+ /**
+ * Provide uri's and corresponding patterns for testBindVarMultipleUrlParts()
+ */
+ public function bindVarMultipleUrlPartsProvider()
+ {
+ return [
+ ['/foo', ['check' => '$1...'], false, InvalidArgumentException::class],
+ ['/', ['check' => ['$1...']], false],
+ ['/foo', ['check' => ['$1...']], true],
+ ['/foo/bar', ['check' => ['$1...'], 'checkB' => ['$2...']],
+ InvalidArgumentException::class]
+ ];
+ }
+
+ /**
+ * Test binding multyple url parts to route option
+ * @dataProvider bindVarMultipleUrlPartsProvider
+ *
+ * @param string $uri
+ * @param array $options Route options
+ * @param boolean $positive
+ * @param string $exception
+ */
+ public function testBindVarMultipleUrlParts($uri, $options, $positive, $exception = false)
+ {
+ if ($exception) {
+ $this->expectException($exception);
+ }
+
+ $glob = new Glob([$uri => $options]);
+ $request = $this->getServerRequest($uri);
+ $route = $glob->getRoute($request);
+
+ if ($exception) return;
+
+ $this->assertNotNull($route, "Route not found");
+ $this->assertInstanceOf(Route::class, $route);
+
+ $values = explode('/', trim($uri, '/'));
+
+ $positive ?
+ $this->assertArraysEqual($values, $route->check, "Multyple url parts are not picked correctly") :
+ $this->assertEmpty($route->check, "Multyple parts element should be empty");
+
+ if (!empty($options->checkB)) {
+ array_shift($values);
+ $this->assertArraysEqual($values, $route->checkB, "Secondary multyple url parts are not picked correctly");
+ }
+ }
+
+ /**
+ * Provide uri's and corresponding patterns for testBindVarMultipleUrlParts()
+ */
+ public function bindVarSuperGlobalProvider()
+ {
+ return [
+ ['/foo', ['check' => '$_GET[check]'], 'get'],
+ ['/foo', ['check' => '$_POST[check]'], 'post'],
+ ['/foo', ['check' => '$_COOKIE[check]'], 'cookie']
+ ];
+ }
+
+ /**
+ * Test binding element of superglobal array to route option
+ * @dataProvider bindVarSuperGlobalProvider
+ *
+ * @param string $uri
+ * @param array $options
+ * @param string $type ('get', 'post', 'cookie')
+ */
+ public function testBindVarSuperGlobal($uri, $options, $type)
+ {
+ $test = ['check' => 'test'];
+ $glob = new Glob([$uri => $options]);
+ $request = $this->getServerRequest($uri, 'GET', [$type => $test]);
+ $route = $glob->getRoute($request);
+
+ $this->assertEquals($test['check'], $route->check, "Did not obtaine value for superglobal '$type'");
+ }
+
+ /**
+ * Test binding element of superglobal array to route option
+ */
+ public function testBindVarRequestHeader()
+ {
+ $uri = '/foo/bar';
+ $test = 'test_header_value';
+
+ $glob = new Glob([$uri => ['check' => '$HTTP_REFERER']]);
+ $request = $this->getServerRequest($uri, 'GET', [], $test);
+
+ $route = $glob->getRoute($request);
+ $this->assertNotNull($route, "Route not found");
+
+ $this->assertEquals($test, $route->check);
+ }
+
+ /**
+ * Get ServerRequestInterface object
+ *
+ * @param string $uri
+ * @param string $method Http query method
+ * @return ServerRequestInterface
+ */
+ public function getServerRequest($uri, $method = 'GET', $globals = [], $header = '')
+ {
+ $request = $this->createMock(ServerRequestInterface::class);
+ $request->method('getUri')->willReturn($uri);
+ $request->method('getMethod')->willReturn($method);
+ $request->method('getQueryParams')->willReturn(isset($globals['get']) ? $globals['get'] : []);
+ $request->method('getParsedBody')->willReturn(isset($globals['post']) ? $globals['post'] : []);
+ $request->method('getCookieParams')->willReturn(isset($globals['cookie']) ? $globals['cookie'] : []);
+ $request->method('getHeaderLine')->willReturn($header);
+
+ return $request;
+ }
+
+ /**
+ * Assert that two 1-dimensional arrays are equal.
+ * Use if array elements are scalar values, or objects with __toString() method
+ *
+ * @param array $array1
+ * @param array $array2
+ */
+ public function assertArraysEqual(array $array1, array $array2)
+ {
+ $this->assertEmpty(array_diff($array2, $array1), 'Missing items');
+ $this->assertEmpty(array_diff($array1, $array2), 'Additional items');
+ }
+}
diff --git a/tests/Router/Runner/CallbackTest.php b/tests/Router/Runner/CallbackTest.php
index 8a31794..39c2798 100644
--- a/tests/Router/Runner/CallbackTest.php
+++ b/tests/Router/Runner/CallbackTest.php
@@ -1,64 +1,73 @@
<?php
+namespace Jasny\Router;
+
use Jasny\Router\Route;
use Jasny\Router\Runner\Callback;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
-class CallbackTest extends PHPUnit_Framework_TestCase
+use Jasny\Router\TestHelpers;
+
+/**
+ * @covers Jasny\Router\Runner\Callback
+ */
+class CallbackTest extends \PHPUnit_Framework_TestCase
{
+ use TestHelpers;
+
/**
* Test creating Callback runner
- *
- * @dataProvider callbackProvider
- * @param Route $route
- * @param boolean $positive
*/
- public function testCallback($route, $positive)
+ public function testCallback()
{
- $runner = new Callback($route);
-
$request = $this->createMock(ServerRequestInterface::class);
$response = $this->createMock(ResponseInterface::class);
- $request->expects($this->once())->method('getAttribute')->with($this->equalTo('route'))->will($this->returnValue($route));
-
- if (!$positive) $this->expectException(\RuntimeException::class);
- $result = $runner->run($request, $response);
-
- if (!$positive) return;
-
- $this->assertEquals($request, $result['request'], "Request object was not passed correctly to result");
- $this->assertEquals($response, $result['response'], "Response object was not passed correctly to result");
+ $finalResponse = $this->createMock(ResponseInterface::class);
+
+ $route = $this->createMock(Route::class);
+ $route->fn = $this->createCallbackMock($this->once(), [$request, $response], $finalResponse);
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = new Callback($route);
+ $result = $runner($request, $response);
+
+ $this->assertSame($finalResponse, $result);
}
-
-
+
/**
- * Provide data fpr testing 'create' method
+ * @expectedException RuntimeException
+ * @expectedExceptionMessage 'fn' property of route shoud be a callable
*/
- public function callbackProvider()
+ public function testNoCallback()
{
- $callback = function($request, $response) {
- return ['request' => $request, 'response' => $response];
- };
-
- return [
- [Route::create(['fn' => $callback, 'value' => 'test']), true],
- [Route::create(['fn' => [$this, 'getCallback'], 'value' => 'test']), true],
- [Route::create(['controller' => 'TestController', 'value' => 'test']), false],
- [Route::create(['file' => 'some_file.php', 'value' => 'test']), false],
- [Route::create(['test' => 'test']), false],
- ];
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+
+ $route = $this->createMock(Route::class);
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = new Callback($route);
+ $runner($request, $response);
}
-
+
/**
- * Testable callback for creating Route
- *
- * @param ServerRequestInterface $request
- * @param ResponseInterface $response
- * @return array
+ * @expectedException RuntimeException
+ * @expectedExceptionMessage 'fn' property of route shoud be a callable
*/
- public function getCallback($request, $response)
+ public function testInvalidCallback()
{
- return ['request' => $request, 'response' => $response];
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+
+ $route = $this->createMock(Route::class);
+ $route->fn = 'foo bar zoo';
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = new Callback($route);
+ $runner($request, $response);
}
}
diff --git a/tests/Router/Runner/ControllerTest.php b/tests/Router/Runner/ControllerTest.php
index 433d36d..694fe5b 100644
--- a/tests/Router/Runner/ControllerTest.php
+++ b/tests/Router/Runner/ControllerTest.php
@@ -1,140 +1,80 @@
<?php
+namespace Jasny\Router;
+
use Jasny\Router\Route;
-use Jasny\Router\Runner\Controller;
+use Jasny\Router\Runner;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
-class ControllerTest extends PHPUnit_Framework_TestCase
-{
- /**
- * Tmp scripts
- * @var array
- **/
- public static $files = [];
-
- /**
- * Test creating Controller runner
- *
- * @dataProvider phpScriptProvider
- * @param Route $route
- * @param boolean $positive
- */
- public function testPhpScript($route, $positive)
- {
- $runner = new Controller($route);
+use Jasny\Router\TestHelpers;
+/**
+ * @covers Jasny\Router\Runner\Controller;
+ */
+class ControllerTest extends \PHPUnit_Framework_TestCase
+{
+ use TestHelpers;
+
+ public function testInvoke()
+ {
$request = $this->createMock(ServerRequestInterface::class);
$response = $this->createMock(ResponseInterface::class);
- $request->expects($this->once())->method('getAttribute')->with($this->equalTo('route'))->will($this->returnValue($route));
-
- if (!$positive) $this->expectException(\RuntimeException::class);
- $result = $runner->run($request, $response);
-
- $this->assertEquals($request, $result['request'], "Request object was not passed correctly to result");
- $this->assertEquals($response, $result['response'], "Response object was not passed correctly to result");
+ $finalResponse = $this->createMock(ResponseInterface::class);
+
+ $controller = $this->createCallbackMock($this->once(), [$request, $response], $finalResponse);
+ $class = get_class($controller);
+
+ $route = $this->createMock(Route::class);
+ $route->controller = $class;
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = $this->getMockBuilder(Runner\Controller::class)->setMethods(['instantiate'])->getMock();
+ $runner->expects($this->once())->method('instantiate')->with($class)->willReturn($controller);
+
+ $result = $runner($request, $response);
+
+ $this->assertSame($finalResponse, $result);
}
-
- /**
- * Provide data for testing 'create' method
- */
- public function phpScriptProvider()
- {
- foreach (['noInvoke', 'withInvoke'] as $type) {
- list($class, $path) = static::createTmpScript($type);
- static::$files[$type] = compact('class', 'path');
- }
-
- return [
- [Route::create(['test' => 'test']), false],
- [Route::create(['fn' => 'testFunction', 'value' => 'test']), false],
- [Route::create(['controller' => 'TestController', 'value' => 'test']), false],
- [Route::create(['controller' => '', 'value' => 'test']), false],
- [Route::create(['controller' => static::$files['noInvoke']['class'], 'path' => static::$files['noInvoke']['path']]), false],
- [Route::create(['controller' => static::$files['withInvoke']['class'], 'path' => static::$files['withInvoke']['path']]), true],
- ];
- }
-
- /**
- * Delete tmp test scripts
- */
- public static function tearDownAfterClass()
- {
- foreach (static::$files as $path) {
- unlink($path['path']);
- }
- }
-
+
/**
- * Create single tmp script file for testing
- *
- * @param string $type ('returnTrue', 'returnNotTrue')
- * @return string $path
+ * @expectedException RuntimeException
+ * @expectedExceptionMessage Can not route to controller 'FooBarZoo': class not exists
*/
- public static function createTmpScript($type)
- {
- $dir = rtrim(sys_get_temp_dir(), '/');
-
- do {
- $name = static::getRandomString() . '-test-script.php';
- $path = $dir . '/' . $name;
-
- if (!file_exists($path)) break;
- } while (true);
-
- if ($type === 'noInvoke') {
- $class = 'RunnerTestConrtollerInvalid';
- $content =
-<<<CONTENT
-<?php
-
-class $class {
- public \$route = null;
-
- public function __construct(\$route)
+ public function testInvalidClass()
{
- \$this->route = \$route;
- }
-}
-CONTENT;
- } else {
- $class = 'RunnerTestConrtoller';
- $content =
-<<<CONTENT
-<?php
-
-class $class {
- public \$route = null;
-
- public function __construct(\$route)
- {
- \$this->route = \$route;
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+
+ $route = $this->createMock(Route::class);
+ $route->controller = 'foo-bar-zoo';
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = $this->getMockBuilder(Runner\Controller::class)->setMethods(['instantiate'])->getMock();
+ $runner->expects($this->never())->method('instantiate');
+
+ $runner($request, $response);
}
- public function __invoke(Psr\Http\Message\ServerRequestInterface \$request, Psr\Http\Message\ResponseInterface \$response)
- {
- return ['request' => \$request, 'response' => \$response];
- }
-}
-CONTENT;
- }
-
- $bytes = file_put_contents($path, $content);
- static::assertTrue((int)$bytes > 0);
-
- require_once $path;
-
- return [$class, $path];
- }
-
/**
- * Get random string of given length (no more then length of md5 hash)
- *
- * @param int $length
- * @return string
+ * @expectedException RuntimeException
+ * @expectedExceptionMessage Can not route to controller 'StdClass': class does not have '__invoke' method
*/
- public static function getRandomString($length = 10)
- {
- return substr(md5(microtime(true) * mt_rand()), 0, $length);
+ public function testInvokeNotCallable()
+ {
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+
+ $route = $this->createMock(Route::class);
+ $route->controller = 'std-class';
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = $this->getMockBuilder(Runner\Controller::class)->setMethods(['instantiate'])->getMock();
+ $runner->expects($this->never())->method('instantiate');
+
+ $runner($request, $response);
}
}
diff --git a/tests/Router/Runner/PhpScriptTest.php b/tests/Router/Runner/PhpScriptTest.php
index 2f31f73..658998b 100644
--- a/tests/Router/Runner/PhpScriptTest.php
+++ b/tests/Router/Runner/PhpScriptTest.php
@@ -1,90 +1,128 @@
<?php
+namespace Jasny\Router;
+
use Jasny\Router\Route;
-use Jasny\Router\Runner\PhpScript;
+use Jasny\Router\Runner;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
-class PhpScriptTest extends PHPUnit_Framework_TestCase
+use org\bovigo\vfs\vfsStream;
+use org\bovigo\vfs\vfsStreamDirectory;
+
+/**
+ * @covers Jasny\Router\Runner\PhpScript
+ */
+class PhpScriptTest extends \PHPUnit_Framework_TestCase
{
/**
- * Test creating PhpScript runner
- *
- * @dataProvider phpScriptProvider
- * @param Route $route
- * @param boolean $positive
+ * @var vfsStreamDirectory
*/
- public function testPhpScript($route, $positive)
- {
- $runner = new PhpScript($route);
+ protected $root;
+
+ public function setUp()
+ {
+ $this->root = vfsStream::setup('root');
+ $this->root->addChild(vfsStream::newFile('true.php')->setContent('<?php ?>'));
+ $this->root->addChild(vfsStream::newFile('foo.php')->setContent('<?php return "foo"; ?>'));
+ }
+ public function testInvoke()
+ {
$request = $this->createMock(ServerRequestInterface::class);
$response = $this->createMock(ResponseInterface::class);
- $request->expects($this->once())->method('getAttribute')->with($this->equalTo('route'))->will($this->returnValue($route));
-
- if (!$positive) $this->expectException(\RuntimeException::class);
- $result = $runner->run($request, $response);
+ $finalResponse = $this->createMock(ResponseInterface::class);
- if ($route->type === 'returnTrue') {
- $this->assertEquals($response, $result, "Request object was not returned as result");
- } else {
- $this->assertEquals($request, $result['request'], "Request object was not passed correctly to result");
- $this->assertEquals($response, $result['response'], "Response object was not passed correctly to result");
- }
+ $route = $this->createMock(Route::class);
+ $route->file = vfsStream::url('root/foo.php');
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = $this->getMockBuilder(Runner\PhpScript::class)->setMethods(['includeScript'])->getMock();
+ $runner->expects($this->once())->method('includeScript')
+ ->with(vfsStream::url('root/foo.php'), $request, $response)
+ ->willReturn($finalResponse);
- unlink($route->file);
+ $result = $runner($request, $response);
+
+ $this->assertSame($finalResponse, $result);
}
-
- /**
- * Provide data fpr testing 'create' method
- */
+
public function phpScriptProvider()
{
+ $routeTrue = $this->createMock(Route::class);
+ $routeTrue->file = vfsStream::url('root/true.php');
+
+ $routeFoo = $this->createMock(Route::class);
+ $routeFoo->file = vfsStream::url('root/foo.php');
+
return [
- [Route::create(['test' => 'test']), false],
- [Route::create(['fn' => 'testFunction', 'value' => 'test']), false],
- [Route::create(['controller' => 'TestController', 'value' => 'test']), false],
- [Route::create(['file' => '', 'value' => 'test']), false],
- [Route::create(['file' => 'some_file.php', 'value' => 'test']), false],
- [Route::create(['file' => '../' . basename(getcwd()), 'value' => 'test']), false],
- [Route::create(['file' => $this->createTmpScript('returnTrue'), 'type' => 'returnTrue']), true],
- [Route::create(['file' => $this->createTmpScript('returnNotTrue'), 'type' => 'returnNotTrue']), true]
+ [$routeTrue, 1],
+ [$routeFoo, 'foo']
];
}
-
+
/**
- * Create single tmp script file for testing
- *
- * @param string $type ('returnTrue', 'returnNotTrue')
- * @return string $path
+ * @dataProvider phpScriptProvider
+ *
+ * @param Route $route
+ * @param mixed $expected
*/
- public function createTmpScript($type)
+ public function testInvokeIncludeScript($route, $expected)
{
- $dir = rtrim(sys_get_temp_dir(), '/');
-
- do {
- $name = $this->getRandomString() . '-test-script.php';
- $path = $dir . '/' . $name;
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+ $request->expects($this->once())->method('getAttribute')->with($this->equalTo('route'))->will($this->returnValue($route));
- if (!file_exists($path)) break;
- } while (true);
+ $runner = new Runner\PhpScript($route);
+
+ if ($expected === 1) {
+ $expected = $response;
+ }
+
+ $result = $runner->run($request, $response);
+
+ $this->assertSame($expected, $result);
+ }
- $content = $type === 'returnTrue' ? "<?php\n return true;" : "<?php\n return ['request' => \$request, 'response' => \$response];";
- $bytes = file_put_contents($path, $content);
+ /**
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage Failed to route using 'vfs://root/bar.php': File doesn't exist
+ */
+ public function testInvokeWithNonExistingFile()
+ {
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
- $this->assertTrue((int)$bytes > 0);
+ $route = $this->createMock(Route::class);
+ $route->file = vfsStream::url('root/bar.php');
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = $this->getMockBuilder(Runner\PhpScript::class)->setMethods(['includeScript'])->getMock();
+ $runner->expects($this->never())->method('includeScript');
- return $path;
+ $runner($request, $response);
}
/**
- * Get random string of given length (no more then length of md5 hash)
- *
- * @param int $length
- * @return string
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage Won't route to 'vfs://root/../bar.php': '~', '..' are not allowed in filename
*/
- public function getRandomString($length = 10)
- {
- return substr(md5(microtime(true) * mt_rand()), 0, $length);
+ public function testInvokeWithIlligalFilename()
+ {
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+
+ $route = $this->createMock(Route::class);
+ $route->file = vfsStream::url('root/../bar.php');
+
+ $request->expects($this->once())->method('getAttribute')->with('route')->willReturn($route);
+
+ $runner = $this->getMockBuilder(Runner\PhpScript::class)->setMethods(['includeScript'])->getMock();
+ $runner->expects($this->never())->method('includeScript');
+
+ $runner($request, $response);
}
+
}
diff --git a/tests/Router/Runner/RunnerFactoryTest.php b/tests/Router/Runner/RunnerFactoryTest.php
deleted file mode 100644
index c18656d..0000000
--- a/tests/Router/Runner/RunnerFactoryTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-use Jasny\Router\Route;
-use Jasny\Router\Runner\RunnerFactory;
-use Jasny\Router\Runner\Controller;
-use Jasny\Router\Runner\Callback;
-use Jasny\Router\Runner\PhpScript;
-
-class RunnerFactoryTest extends PHPUnit_Framework_TestCase
-{
- /**
- * Test creating Runner object using factory
- *
- * @dataProvider createProvider
- * @param Route $route
- * @param string $class Runner class to use
- * @param boolean $positive
- */
- public function testCreate($route, $class, $positive)
- {
- if (!$positive) $this->expectException(\InvalidArgumentException::class);
-
- $factory = new RunnerFactory();
- $runner = $factory($route);
-
- $this->assertInstanceOf($class, $runner, "Runner object has invalid class");
- }
-
- /**
- * Provide data fpr testing 'create' method
- */
- public function createProvider()
- {
- return [
- [Route::create(['controller' => 'TestController', 'value' => 'test']), Controller::class, true],
- [Route::create(['fn' => 'testFunction', 'value' => 'test']), Callback::class, true],
- [Route::create(['file' => 'some_file.php', 'value' => 'test']), PhpScript::class, true],
- [Route::create(['test' => 'test']), '', false],
- ];
- }
-}
diff --git a/tests/Router/RunnerFactoryTest.php b/tests/Router/RunnerFactoryTest.php
new file mode 100644
index 0000000..a9fbe92
--- /dev/null
+++ b/tests/Router/RunnerFactoryTest.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Jasny\Router;
+
+use Jasny\Router\RunnerFactory;
+use Jasny\Router\Route;
+use Jasny\Router\Runner;
+
+class RunnerFactoryTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * Provide data fpr testing 'create' method
+ */
+ public function createProvider()
+ {
+ $routeController = $this->createMock(Route::class);
+ $routeController->controller = 'foo-bar';
+
+ $routeCallback = $this->createMock(Route::class);
+ $routeCallback->fn = function() {};
+
+ $routePhpScript = $this->createMock(Route::class);
+ $routePhpScript->file = 'some_file.php';
+
+ return [
+ [$routeController, Runner\Controller::class],
+ [$routeCallback, Runner\Callback::class],
+ [$routePhpScript, Runner\PhpScript::class],
+ ];
+ }
+
+ /**
+ * Test creating Runner object using factory
+ * @dataProvider createProvider
+ *
+ * @param Route $route
+ * @param string $class Runner class to use
+ */
+ public function testCreate($route, $class)
+ {
+ $factory = new RunnerFactory();
+ $runner = $factory($route);
+
+ $this->assertInstanceOf($class, $runner, "Runner object has invalid class");
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage Route has neither 'controller', 'fn' or 'file' defined
+ */
+ public function testCreatWithInvalideRoute()
+ {
+ $route = $this->createMock(Route::class);
+
+ $factory = new RunnerFactory();
+ $factory($route);
+ }
+}
diff --git a/tests/Router/RunnerTest.php b/tests/Router/RunnerTest.php
index 7db4c02..3e558b4 100644
--- a/tests/Router/RunnerTest.php
+++ b/tests/Router/RunnerTest.php
@@ -1,46 +1,39 @@
<?php
-use Jasny\Router\Route;
use Jasny\Router\Runner;
-use Jasny\Router\Runner\Controller;
-use Jasny\Router\Runner\Callback;
-use Jasny\Router\Runner\PhpScript;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
+use Jasny\Router\TestHelpers;
+
+/**
+ * @covers Jasny\Router\Runner
+ */
class RunnerTest extends PHPUnit_Framework_TestCase
{
+ use TestHelpers;
+
/**
* Test runner __invoke method
*/
public function testInvoke()
{
- $runner = $this->getMockBuilder(Runner::class)->disableOriginalConstructor()->getMockForAbstractClass();
- $queries = [
- 'request' => $this->createMock(ServerRequestInterface::class),
- 'response' => $this->createMock(ResponseInterface::class)
- ];
-
- #Test that 'run' receives correct arguments inside '__invoke'
- $runner->method('run')->will($this->returnCallback(function($arg1, $arg2) {
- return ['request' => $arg1, 'response' => $arg2];
- }));
-
- $result = $runner($queries['request'], $queries['response']);
- $this->assertEquals($result['request'], $queries['request'], "Request was not returned correctly from 'run'");
- $this->assertEquals($result['response'], $queries['response'], "Response was not returned correctly from 'run'");
-
- #The same test with calling 'next' callback
- $result = $runner($queries['request'], $queries['response'], function($request, $prevResponse) use ($queries) {
- $this->assertEquals($request, $queries['request'], "Request is not correct in 'next'");
- $this->assertEquals($prevResponse['request'], $queries['request'], "Prev response was not passed correctly to 'next'");
- $this->assertEquals($prevResponse['response'], $queries['response'], "Prev response was not passed correctly to 'next'");
-
- return $queries + ['next_called' => true];
- });
+ $runner = $this->getMockBuilder(Runner::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+
+ $request = $this->createMock(ServerRequestInterface::class);
+
+ $response = $this->createMock(ResponseInterface::class);
+ $runResponse = $this->createMock(ResponseInterface::class);
+ $finalResponse = $this->createMock(ResponseInterface::class);
- $this->assertTrue($result['next_called'], "'Next' callback was not called");
- $this->assertEquals($result['request'], $queries['request'], "Request was not returned correctly from 'run' with 'next'");
- $this->assertEquals($result['response'], $queries['response'], "Request was not returned correctly from 'run' with 'next'");
+ $runner->expects($this->once())->method('run')
+ ->with($request, $response)
+ ->willReturn($runResponse);
+
+ $next = $this->createCallbackMock($this->once(), [$request, $runResponse], $finalResponse);
+
+ $runner($request, $response, $next);
}
}