resume/tests/Silex/Tests/ApplicationTest.php

702 lines
21 KiB
PHP

<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Silex\Tests;
use Silex\Application;
use Silex\ControllerCollection;
use Silex\Api\ControllerProviderInterface;
use Silex\Route;
use Silex\Provider\MonologServiceProvider;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\Routing\RouteCollection;
/**
* Application test cases.
*
* @author Igor Wiedler <igor@wiedler.ch>
*/
class ApplicationTest extends \PHPUnit_Framework_TestCase
{
public function testMatchReturnValue()
{
$app = new Application();
$returnValue = $app->match('/foo', function () {});
$this->assertInstanceOf('Silex\Controller', $returnValue);
$returnValue = $app->get('/foo', function () {});
$this->assertInstanceOf('Silex\Controller', $returnValue);
$returnValue = $app->post('/foo', function () {});
$this->assertInstanceOf('Silex\Controller', $returnValue);
$returnValue = $app->put('/foo', function () {});
$this->assertInstanceOf('Silex\Controller', $returnValue);
$returnValue = $app->patch('/foo', function () {});
$this->assertInstanceOf('Silex\Controller', $returnValue);
$returnValue = $app->delete('/foo', function () {});
$this->assertInstanceOf('Silex\Controller', $returnValue);
}
public function testConstructorInjection()
{
// inject a custom parameter
$params = array('param' => 'value');
$app = new Application($params);
$this->assertSame($params['param'], $app['param']);
// inject an existing parameter
$params = array('locale' => 'value');
$app = new Application($params);
$this->assertSame($params['locale'], $app['locale']);
}
public function testGetRequest()
{
$request = Request::create('/');
$app = new Application();
$app->get('/', function (Request $req) use ($request) {
return $request === $req ? 'ok' : 'ko';
});
$this->assertEquals('ok', $app->handle($request)->getContent());
}
public function testGetRoutesWithNoRoutes()
{
$app = new Application();
$routes = $app['routes'];
$this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $routes);
$this->assertEquals(0, count($routes->all()));
}
public function testGetRoutesWithRoutes()
{
$app = new Application();
$app->get('/foo', function () {
return 'foo';
});
$app->get('/bar')->run(function () {
return 'bar';
});
$routes = $app['routes'];
$this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $routes);
$this->assertEquals(0, count($routes->all()));
$app->flush();
$this->assertEquals(2, count($routes->all()));
}
public function testOnCoreController()
{
$app = new Application();
$app->get('/foo/{foo}', function (\ArrayObject $foo) {
return $foo['foo'];
})->convert('foo', function ($foo) { return new \ArrayObject(array('foo' => $foo)); });
$response = $app->handle(Request::create('/foo/bar'));
$this->assertEquals('bar', $response->getContent());
$app->get('/foo/{foo}/{bar}', function (\ArrayObject $foo) {
return $foo['foo'];
})->convert('foo', function ($foo, Request $request) { return new \ArrayObject(array('foo' => $foo.$request->attributes->get('bar'))); });
$response = $app->handle(Request::create('/foo/foo/bar'));
$this->assertEquals('foobar', $response->getContent());
}
public function testOn()
{
$app = new Application();
$app['pass'] = false;
$app->on('test', function (Event $e) use ($app) {
$app['pass'] = true;
});
$app['dispatcher']->dispatch('test');
$this->assertTrue($app['pass']);
}
public function testAbort()
{
$app = new Application();
try {
$app->abort(404);
$this->fail();
} catch (HttpException $e) {
$this->assertEquals(404, $e->getStatusCode());
}
}
/**
* @dataProvider escapeProvider
*/
public function testEscape($expected, $text)
{
$app = new Application();
$this->assertEquals($expected, $app->escape($text));
}
public function escapeProvider()
{
return array(
array('&lt;', '<'),
array('&gt;', '>'),
array('&quot;', '"'),
array("'", "'"),
array('abc', 'abc'),
);
}
public function testControllersAsMethods()
{
$app = new Application();
$app->get('/{name}', 'Silex\Tests\FooController::barAction');
$this->assertEquals('Hello Fabien', $app->handle(Request::create('/Fabien'))->getContent());
}
public function testApplicationTypeHintWorks()
{
$app = new SpecialApplication();
$app->get('/{name}', 'Silex\Tests\FooController::barSpecialAction');
$this->assertEquals('Hello Fabien in Silex\Tests\SpecialApplication', $app->handle(Request::create('/Fabien'))->getContent());
}
public function testHttpSpec()
{
$app = new Application();
$app['charset'] = 'ISO-8859-1';
$app->get('/', function () {
return 'hello';
});
// content is empty for HEAD requests
$response = $app->handle(Request::create('/', 'HEAD'));
$this->assertEquals('', $response->getContent());
// charset is appended to Content-Type
$response = $app->handle(Request::create('/'));
$this->assertEquals('text/html; charset=ISO-8859-1', $response->headers->get('Content-Type'));
}
public function testRoutesMiddlewares()
{
$app = new Application();
$test = $this;
$middlewareTarget = array();
$beforeMiddleware1 = function (Request $request) use (&$middlewareTarget, $test) {
$test->assertEquals('/reached', $request->getRequestUri());
$middlewareTarget[] = 'before_middleware1_triggered';
};
$beforeMiddleware2 = function (Request $request) use (&$middlewareTarget, $test) {
$test->assertEquals('/reached', $request->getRequestUri());
$middlewareTarget[] = 'before_middleware2_triggered';
};
$beforeMiddleware3 = function (Request $request) use (&$middlewareTarget, $test) {
throw new \Exception('This middleware shouldn\'t run!');
};
$afterMiddleware1 = function (Request $request, Response $response) use (&$middlewareTarget, $test) {
$test->assertEquals('/reached', $request->getRequestUri());
$middlewareTarget[] = 'after_middleware1_triggered';
};
$afterMiddleware2 = function (Request $request, Response $response) use (&$middlewareTarget, $test) {
$test->assertEquals('/reached', $request->getRequestUri());
$middlewareTarget[] = 'after_middleware2_triggered';
};
$afterMiddleware3 = function (Request $request, Response $response) use (&$middlewareTarget, $test) {
throw new \Exception('This middleware shouldn\'t run!');
};
$app->get('/reached', function () use (&$middlewareTarget) {
$middlewareTarget[] = 'route_triggered';
return 'hello';
})
->before($beforeMiddleware1)
->before($beforeMiddleware2)
->after($afterMiddleware1)
->after($afterMiddleware2);
$app->get('/never-reached', function () use (&$middlewareTarget) {
throw new \Exception('This route shouldn\'t run!');
})
->before($beforeMiddleware3)
->after($afterMiddleware3);
$result = $app->handle(Request::create('/reached'));
$this->assertSame(array('before_middleware1_triggered', 'before_middleware2_triggered', 'route_triggered', 'after_middleware1_triggered', 'after_middleware2_triggered'), $middlewareTarget);
$this->assertEquals('hello', $result->getContent());
}
public function testRoutesBeforeMiddlewaresWithResponseObject()
{
$app = new Application();
$app->get('/foo', function () {
throw new \Exception('This route shouldn\'t run!');
})
->before(function () {
return new Response('foo');
});
$request = Request::create('/foo');
$result = $app->handle($request);
$this->assertEquals('foo', $result->getContent());
}
public function testRoutesAfterMiddlewaresWithResponseObject()
{
$app = new Application();
$app->get('/foo', function () {
return new Response('foo');
})
->after(function () {
return new Response('bar');
});
$request = Request::create('/foo');
$result = $app->handle($request);
$this->assertEquals('bar', $result->getContent());
}
public function testRoutesBeforeMiddlewaresWithRedirectResponseObject()
{
$app = new Application();
$app->get('/foo', function () {
throw new \Exception('This route shouldn\'t run!');
})
->before(function () use ($app) {
return $app->redirect('/bar');
});
$request = Request::create('/foo');
$result = $app->handle($request);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $result);
$this->assertEquals('/bar', $result->getTargetUrl());
}
public function testRoutesBeforeMiddlewaresTriggeredAfterSilexBeforeFilters()
{
$app = new Application();
$middlewareTarget = array();
$middleware = function (Request $request) use (&$middlewareTarget) {
$middlewareTarget[] = 'middleware_triggered';
};
$app->get('/foo', function () use (&$middlewareTarget) {
$middlewareTarget[] = 'route_triggered';
})
->before($middleware);
$app->before(function () use (&$middlewareTarget) {
$middlewareTarget[] = 'before_triggered';
});
$app->handle(Request::create('/foo'));
$this->assertSame(array('before_triggered', 'middleware_triggered', 'route_triggered'), $middlewareTarget);
}
public function testRoutesAfterMiddlewaresTriggeredBeforeSilexAfterFilters()
{
$app = new Application();
$middlewareTarget = array();
$middleware = function (Request $request) use (&$middlewareTarget) {
$middlewareTarget[] = 'middleware_triggered';
};
$app->get('/foo', function () use (&$middlewareTarget) {
$middlewareTarget[] = 'route_triggered';
})
->after($middleware);
$app->after(function () use (&$middlewareTarget) {
$middlewareTarget[] = 'after_triggered';
});
$app->handle(Request::create('/foo'));
$this->assertSame(array('route_triggered', 'middleware_triggered', 'after_triggered'), $middlewareTarget);
}
public function testFinishFilter()
{
$containerTarget = array();
$app = new Application();
$app->finish(function () use (&$containerTarget) {
$containerTarget[] = '4_filterFinish';
});
$app->get('/foo', function () use (&$containerTarget) {
$containerTarget[] = '1_routeTriggered';
return new StreamedResponse(function () use (&$containerTarget) {
$containerTarget[] = '3_responseSent';
});
});
$app->after(function () use (&$containerTarget) {
$containerTarget[] = '2_filterAfter';
});
$app->run(Request::create('/foo'));
$this->assertSame(array('1_routeTriggered', '2_filterAfter', '3_responseSent', '4_filterFinish'), $containerTarget);
}
/**
* @expectedException \RuntimeException
*/
public function testNonResponseAndNonNullReturnFromRouteBeforeMiddlewareShouldThrowRuntimeException()
{
$app = new Application();
$middleware = function (Request $request) {
return 'string return';
};
$app->get('/', function () {
return 'hello';
})
->before($middleware);
$app->handle(Request::create('/'), HttpKernelInterface::MASTER_REQUEST, false);
}
/**
* @expectedException \RuntimeException
*/
public function testNonResponseAndNonNullReturnFromRouteAfterMiddlewareShouldThrowRuntimeException()
{
$app = new Application();
$middleware = function (Request $request) {
return 'string return';
};
$app->get('/', function () {
return 'hello';
})
->after($middleware);
$app->handle(Request::create('/'), HttpKernelInterface::MASTER_REQUEST, false);
}
public function testSubRequest()
{
$app = new Application();
$app->get('/sub', function (Request $request) {
return new Response('foo');
});
$app->get('/', function (Request $request) use ($app) {
return $app->handle(Request::create('/sub'), HttpKernelInterface::SUB_REQUEST);
});
$this->assertEquals('foo', $app->handle(Request::create('/'))->getContent());
}
public function testRegisterShouldReturnSelf()
{
$app = new Application();
$provider = $this->getMock('Pimple\ServiceProviderInterface');
$this->assertSame($app, $app->register($provider));
}
public function testMountShouldReturnSelf()
{
$app = new Application();
$mounted = new ControllerCollection(new Route());
$mounted->get('/{name}', function ($name) { return new Response($name); });
$this->assertSame($app, $app->mount('/hello', $mounted));
}
public function testMountPreservesOrder()
{
$app = new Application();
$mounted = new ControllerCollection(new Route());
$mounted->get('/mounted')->bind('second');
$app->get('/before')->bind('first');
$app->mount('/', $mounted);
$app->get('/after')->bind('third');
$app->flush();
$this->assertEquals(array('first', 'second', 'third'), array_keys(iterator_to_array($app['routes'])));
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage The "mount" method takes either a "ControllerCollection" instance, "ControllerProviderInterface" instance, or a callable.
*/
public function testMountNullException()
{
$app = new Application();
$app->mount('/exception', null);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage The method "Silex\Tests\IncorrectControllerCollection::connect" must return a "ControllerCollection" instance. Got: "NULL"
*/
public function testMountWrongConnectReturnValueException()
{
$app = new Application();
$app->mount('/exception', new IncorrectControllerCollection());
}
public function testMountCallable()
{
$app = new Application();
$app->mount('/prefix', function (ControllerCollection $coll) {
$coll->get('/path');
});
$app->flush();
$this->assertEquals(1, $app['routes']->count());
}
public function testSendFile()
{
$app = new Application();
$response = $app->sendFile(__FILE__, 200, array('Content-Type: application/php'));
$this->assertInstanceOf('Symfony\Component\HttpFoundation\BinaryFileResponse', $response);
$this->assertEquals(__FILE__, (string) $response->getFile());
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage The "homepage" route must have code to run when it matches.
*/
public function testGetRouteCollectionWithRouteWithoutController()
{
$app = new Application();
unset($app['exception_handler']);
$app->match('/')->bind('homepage');
$app->handle(Request::create('/'));
}
public function testRedirectDoesNotRaisePHPNoticesWhenMonologIsRegistered()
{
$app = new Application();
ErrorHandler::register(null, false);
$app['monolog.logfile'] = 'php://memory';
$app->register(new MonologServiceProvider());
$app->get('/foo/', function () { return 'ok'; });
$response = $app->handle(Request::create('/foo'));
$this->assertEquals(301, $response->getStatusCode());
}
public function testBeforeFilterOnMountedControllerGroupIsolatedToGroup()
{
$app = new Application();
$app->match('/', function () { return new Response('ok'); });
$mounted = $app['controllers_factory'];
$mounted->before(function () { return new Response('not ok'); });
$app->mount('/group', $mounted);
$response = $app->handle(Request::create('/'));
$this->assertEquals('ok', $response->getContent());
}
public function testViewListenerWithPrimitive()
{
$app = new Application();
$app->get('/foo', function () { return 123; });
$app->view(function ($view, Request $request) {
return new Response($view);
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('123', $response->getContent());
}
public function testViewListenerWithArrayTypeHint()
{
$app = new Application();
$app->get('/foo', function () { return array('ok'); });
$app->view(function (array $view) {
return new Response($view[0]);
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('ok', $response->getContent());
}
public function testViewListenerWithObjectTypeHint()
{
$app = new Application();
$app->get('/foo', function () { return (object) array('name' => 'world'); });
$app->view(function (\stdClass $view) {
return new Response('Hello '.$view->name);
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('Hello world', $response->getContent());
}
public function testViewListenerWithCallableTypeHint()
{
$app = new Application();
$app->get('/foo', function () { return function () { return 'world'; }; });
$app->view(function (callable $view) {
return new Response('Hello '.$view());
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('Hello world', $response->getContent());
}
public function testViewListenersCanBeChained()
{
$app = new Application();
$app->get('/foo', function () { return (object) array('name' => 'world'); });
$app->view(function (\stdClass $view) {
return array('msg' => 'Hello '.$view->name);
});
$app->view(function (array $view) {
return $view['msg'];
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('Hello world', $response->getContent());
}
public function testViewListenersAreIgnoredIfNotSuitable()
{
$app = new Application();
$app->get('/foo', function () { return 'Hello world'; });
$app->view(function (\stdClass $view) {
throw new \Exception('View listener was called');
});
$app->view(function (array $view) {
throw new \Exception('View listener was called');
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('Hello world', $response->getContent());
}
public function testViewListenersResponsesAreNotUsedIfNull()
{
$app = new Application();
$app->get('/foo', function () { return 'Hello world'; });
$app->view(function ($view) {
return 'Hello view listener';
});
$app->view(function ($view) {
return;
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('Hello view listener', $response->getContent());
}
public function testDefaultRoutesFactory()
{
$app = new Application();
$this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $app['routes']);
}
public function testOverriddenRoutesFactory()
{
$app = new Application();
$app['routes_factory'] = $app->factory(function () {
return new RouteCollectionSubClass();
});
$this->assertInstanceOf('Silex\Tests\RouteCollectionSubClass', $app['routes']);
}
}
class FooController
{
public function barAction(Application $app, $name)
{
return 'Hello '.$app->escape($name);
}
public function barSpecialAction(SpecialApplication $app, $name)
{
return 'Hello '.$app->escape($name).' in '.get_class($app);
}
}
class IncorrectControllerCollection implements ControllerProviderInterface
{
public function connect(Application $app)
{
return;
}
}
class RouteCollectionSubClass extends RouteCollection
{
}
class SpecialApplication extends Application
{
}