GIF89a;
| Direktori : /home/serb/www/api/vendor/slim/slim/tests/ |
| Current File : /home/serb/www/api/vendor/slim/slim/tests/SlimTest.php |
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.6.1
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//Mock custom view
class CustomView extends \Slim\View
{
public function render($template, $data = null) { echo "Custom view"; }
}
//Echo Logger
class EchoErrorLogger
{
public function error($object) { echo get_class($object) .':'.$object->getMessage(); }
}
//Mock extending class
class Derived extends \Slim\Slim
{
public static function getDefaultSettings()
{
return array_merge(
array("late-static-binding" => true)
, parent::getDefaultSettings());
}
}
//Mock middleware
class CustomMiddleware extends \Slim\Middleware
{
public function call()
{
$env = $this->app->environment();
$res = $this->app->response();
$env['slim.test'] = 'Hello';
$this->next->call();
$res->header('X-Slim-Test', 'Hello');
$res->write('Hello');
}
}
class SlimTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
//Remove environment mode if set
unset($_ENV['SLIM_MODE']);
//Reset session
$_SESSION = array();
//Prepare default environment variables
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
'QUERY_STRING' => 'one=foo&two=bar',
'SERVER_NAME' => 'slimframework.com',
));
}
/************************************************
* INSTANTIATION
************************************************/
/**
* Test version constant is string
*/
public function testHasVersionConstant()
{
$this->assertTrue(is_string(\Slim\Slim::VERSION));
}
/**
* Test default instance properties
*/
public function testDefaultInstanceProperties()
{
$s = new \Slim\Slim();
$this->assertInstanceOf('\Slim\Http\Request', $s->request());
$this->assertInstanceOf('\Slim\Http\Response', $s->response());
$this->assertInstanceOf('\Slim\Router', $s->router());
$this->assertInstanceOf('\Slim\View', $s->view());
$this->assertInstanceOf('\Slim\Log', $s->getLog());
$this->assertEquals(\Slim\Log::DEBUG, $s->getLog()->getLevel());
$this->assertTrue($s->getLog()->getEnabled());
$this->assertInstanceOf('\Slim\Environment', $s->environment());
}
/**
* Test get default instance
*/
public function testGetDefaultInstance()
{
$s = new \Slim\Slim();
$s->setName('default'); //We must do this manually since a default app is already set in prev tests
$this->assertEquals('default', $s->getName());
$this->assertInstanceOf('\Slim\Slim', \Slim\Slim::getInstance());
$this->assertSame($s, \Slim\Slim::getInstance());
}
/**
* Test get named instance
*/
public function testGetNamedInstance()
{
$s = new \Slim\Slim();
$s->setName('foo');
$this->assertSame($s, \Slim\Slim::getInstance('foo'));
}
/**
* Test Slim autoloader ignores non-Slim classes
*
* Pre-conditions:
* Instantiate a non-Slim class;
*
* Post-conditions:
* Slim autoloader returns without requiring a class file;
*/
public function testSlimAutoloaderIgnoresNonSlimClass()
{
$foo = new Foo();
}
/************************************************
* SETTINGS
************************************************/
/**
* Test get setting that exists
*/
public function testGetSettingThatExists()
{
$s = new \Slim\Slim();
$this->assertEquals('./templates', $s->config('templates.path'));
}
/**
* Test get setting that does not exist
*/
public function testGetSettingThatDoesNotExist()
{
$s = new \Slim\Slim();
$this->assertNull($s->config('foo'));
}
/**
* Test set setting
*/
public function testSetSetting()
{
$s = new \Slim\Slim();
$this->assertEquals('./templates', $s->config('templates.path'));
$s->config('templates.path', './tmpl');
$this->assertEquals('./tmpl', $s->config('templates.path'));
}
/**
* Test batch set settings
*/
public function testBatchSetSettings()
{
$s = new \Slim\Slim();
$this->assertEquals('./templates', $s->config('templates.path'));
$this->assertTrue($s->config('debug'));
$s->config(array(
'templates.path' => './tmpl',
'debug' => false
));
$this->assertEquals('./tmpl', $s->config('templates.path'));
$this->assertFalse($s->config('debug'));
}
/**
* Test set settings recursively
*/
public function testSetSettingsRecursively()
{
$config = array(
'my_module' => array(
'paths' => array(
'./my_module/path/1',
),
)
);
$s = new \Slim\Slim($config);
$override = array(
'my_module' => array(
'paths' => array(
'./my_module/path/2',
'./my_module/path/3',
),
)
);
// Test recursive batch behaviour
$s->config($override, true);
$expected = array(
'paths' => array(
'./my_module/path/1',
'./my_module/path/2',
'./my_module/path/3',
),
);
$this->assertEquals($expected, $s->config('my_module'));
// Test default batch behaviour
$s = new \Slim\Slim($config);
$s->config($override);
$this->assertNotEquals($expected, $s->config('my_module'));
}
/************************************************
* MODES
************************************************/
/**
* Test default mode
*/
public function testGetDefaultMode()
{
$s = new \Slim\Slim();
$this->assertEquals('development', $s->getMode());
}
/**
* Test custom mode from environment
*/
public function testGetModeFromEnvironment()
{
$_ENV['SLIM_MODE'] = 'production';
$s = new \Slim\Slim();
$this->assertEquals('production', $s->getMode());
}
/**
* Test custom mode from app settings
*/
public function testGetModeFromSettings()
{
$s = new \Slim\Slim(array(
'mode' => 'test'
));
$this->assertEquals('test', $s->getMode());
}
/**
* Test mode configuration
*/
public function testModeConfiguration()
{
$flag = 0;
$configureTest = function () use (&$flag) {
$flag = 'test';
};
$configureProduction = function () use (&$flag) {
$flag = 'production';
};
$s = new \Slim\Slim(array('mode' => 'test'));
$s->configureMode('test', $configureTest);
$s->configureMode('production', $configureProduction);
$this->assertEquals('test', $flag);
}
/**
* Test mode configuration when mode does not match
*/
public function testModeConfigurationWhenModeDoesNotMatch()
{
$flag = 0;
$configureTest = function () use (&$flag) {
$flag = 'test';
};
$s = new \Slim\Slim(array('mode' => 'production'));
$s->configureMode('test', $configureTest);
$this->assertEquals(0, $flag);
}
/**
* Test mode configuration when not callable
*/
public function testModeConfigurationWhenNotCallable()
{
$flag = 0;
$s = new \Slim\Slim(array('mode' => 'production'));
$s->configureMode('production', 'foo');
$this->assertEquals(0, $flag);
}
/**
* Test custom mode from getenv()
*/
public function testGetModeFromGetEnv()
{
putenv('SLIM_MODE=production');
$s = new \Slim\Slim();
$this->assertEquals('production', $s->getMode());
}
/************************************************
* ROUTING
************************************************/
/**
* Test GENERIC route
*/
public function testGenericRoute()
{
$s = new \Slim\Slim();
$callable = function () { echo "foo"; };
$route = $s->map('/bar', $callable);
$this->assertInstanceOf('\Slim\Route', $route);
$this->assertEmpty($route->getHttpMethods());
}
/**
* Test GET routes also get mapped as a HEAD route
*/
public function testGetRouteIsAlsoMappedAsHead()
{
$s = new \Slim\Slim();
$route = $s->get('/foo', function () {});
$this->assertTrue($route->supportsHttpMethod(\Slim\Http\Request::METHOD_GET));
$this->assertTrue($route->supportsHttpMethod(\Slim\Http\Request::METHOD_HEAD));
}
/**
* Test GET route
*/
public function testGetRoute()
{
$s = new \Slim\Slim();
$mw1 = function () { echo "foo"; };
$mw2 = function () { echo "bar"; };
$callable = function () { echo "xyz"; };
$route = $s->get('/bar', $mw1, $mw2, $callable);
$s->call();
$this->assertEquals('foobarxyz', $s->response()->body());
$this->assertEquals('/bar', $route->getPattern());
$this->assertSame($callable, $route->getCallable());
}
/**
* Test POST route
*/
public function testPostRoute()
{
\Slim\Environment::mock(array(
'REQUEST_METHOD' => 'POST',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$mw1 = function () { echo "foo"; };
$mw2 = function () { echo "bar"; };
$callable = function () { echo "xyz"; };
$route = $s->post('/bar', $mw1, $mw2, $callable);
$s->call();
$this->assertEquals('foobarxyz', $s->response()->body());
$this->assertEquals('/bar', $route->getPattern());
$this->assertSame($callable, $route->getCallable());
}
/**
* Test PUT route
*/
public function testPutRoute()
{
\Slim\Environment::mock(array(
'REQUEST_METHOD' => 'PUT',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$mw1 = function () { echo "foo"; };
$mw2 = function () { echo "bar"; };
$callable = function () { echo "xyz"; };
$route = $s->put('/bar', $mw1, $mw2, $callable);
$s->call();
$this->assertEquals('foobarxyz', $s->response()->body());
$this->assertEquals('/bar', $route->getPattern());
$this->assertSame($callable, $route->getCallable());
}
/**
* Test PATCH route
*/
public function testPatchRoute()
{
\Slim\Environment::mock(array(
'REQUEST_METHOD' => 'PATCH',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$mw1 = function () { echo "foo"; };
$mw2 = function () { echo "bar"; };
$callable = function () { echo "xyz"; };
$route = $s->patch('/bar', $mw1, $mw2, $callable);
$s->call();
$this->assertEquals('foobarxyz', $s->response()->body());
$this->assertEquals('/bar', $route->getPattern());
$this->assertSame($callable, $route->getCallable());
}
/**
* Test DELETE route
*/
public function testDeleteRoute()
{
\Slim\Environment::mock(array(
'REQUEST_METHOD' => 'DELETE',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$mw1 = function () { echo "foo"; };
$mw2 = function () { echo "bar"; };
$callable = function () { echo "xyz"; };
$route = $s->delete('/bar', $mw1, $mw2, $callable);
$s->call();
$this->assertEquals('foobarxyz', $s->response()->body());
$this->assertEquals('/bar', $route->getPattern());
$this->assertSame($callable, $route->getCallable());
}
/**
* Test OPTIONS route
*/
public function testOptionsRoute()
{
\Slim\Environment::mock(array(
'REQUEST_METHOD' => 'OPTIONS',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$mw1 = function () { echo "foo"; };
$mw2 = function () { echo "bar"; };
$callable = function () { echo "xyz"; };
$route = $s->options('/bar', $mw1, $mw2, $callable);
$s->call();
$this->assertEquals('foobarxyz', $s->response()->body());
$this->assertEquals('/bar', $route->getPattern());
$this->assertSame($callable, $route->getCallable());
}
/**
* Test route groups
*/
public function testRouteGroups()
{
\Slim\Environment::mock(array(
'REQUEST_METHOD' => 'GET',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar/baz', //<-- Virtual'
));
$s = new \Slim\Slim();
$mw1 = function () { echo "foo"; };
$mw2 = function () { echo "bar"; };
$callable = function () { echo "xyz"; };
$s->group('/bar', $mw1, function () use ($s, $mw2, $callable) {
$s->get('/baz', $mw2, $callable);
});
$s->call();
$this->assertEquals('foobarxyz', $s->response()->body());
}
/*
* Test ANY route
*/
public function testAnyRoute()
{
$mw1 = function () { echo "foo"; };
$mw2 = function () { echo "bar"; };
$callable = function () { echo "xyz"; };
$methods = array('GET', 'POST', 'PUT', 'DELETE', 'OPTIONS');
foreach ($methods as $i => $method) {
\Slim\Environment::mock(array(
'REQUEST_METHOD' => $method,
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$route = $s->any('/bar', $mw1, $mw2, $callable);
$s->call();
$this->assertEquals('foobarxyz', $s->response()->body());
$this->assertEquals('/bar', $route->getPattern());
$this->assertSame($callable, $route->getCallable());
}
}
/**
* Test if route does NOT expect trailing slash and URL has one
*/
public function testRouteWithoutSlashAndUrlWithOne()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar/', //<-- Virtual
));
$s = new \Slim\Slim();
$s->get('/bar', function () { echo "xyz"; });
$s->call();
$this->assertEquals(404, $s->response()->status());
}
/**
* Tests if route will match in case-insensitive manner if configured to do so
*/
public function testRouteMatchesInCaseInsensitiveMannerIfConfigured()
{
\Slim\Environment::mock(array(
'PATH_INFO' => '/BaR', // Does not match route case
));
$s = new \Slim\Slim(array('routes.case_sensitive' => false));
$route = $s->get('/bar', function () { echo "xyz"; });
$s->call();
$this->assertEquals(200, $s->response()->status());
$this->assertEquals('xyz', $s->response()->body());
$this->assertEquals('/bar', $route->getPattern());
}
/**
* Test if route contains URL encoded characters
*/
public function testRouteWithUrlEncodedCharacters()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar/jo%20hn/smi%20th', //<-- Virtual
));
$s = new \Slim\Slim();
$s->get('/bar/:one/:two', function ($one, $two) { echo $one . $two; });
$s->call();
$this->assertEquals('jo hnsmi th', $s->response()->body());
}
/************************************************
* VIEW
************************************************/
/**
* Test set view with string class name
*/
public function testSetSlimViewFromString()
{
$s = new \Slim\Slim();
$this->assertInstanceOf('\Slim\View', $s->view());
$s->view('CustomView');
$this->assertInstanceOf('CustomView', $s->view());
}
/**
* Test set view with object instance
*/
public function testSetSlimViewFromInstance()
{
$s = new \Slim\Slim();
$this->assertInstanceOf('\Slim\View', $s->view());
$s->view(new CustomView());
$this->assertInstanceOf('CustomView', $s->view());
}
/**
* Test view data is transferred to newer view
*/
public function testViewDataTransfer()
{
$data = array('foo' => 'bar');
$s = new \Slim\Slim();
$s->view()->setData($data);
$s->view('CustomView');
$this->assertSame($data, $s->view()->getData());
}
/************************************************
* RENDERING
************************************************/
/**
* Test template path is passed to view
*/
public function testViewGetsTemplatesPath()
{
$path = dirname(__FILE__) . '/templates';
$s = new \Slim\Slim(array('templates.path' => $path));
$this->assertEquals($s->view->getTemplatesDirectory(), $path);
}
/**
* Test render with template and data
*/
public function testRenderTemplateWithData()
{
$s = new \Slim\Slim(array('templates.path' => dirname(__FILE__) . '/templates'));
$s->get('/bar', function () use ($s) {
$s->render('test.php', array('foo' => 'bar'));
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertEquals(200, $status);
$this->assertEquals('test output bar', $body);
}
/**
* Test render with template and data and status
*/
public function testRenderTemplateWithDataAndStatus()
{
$s = new \Slim\Slim(array('templates.path' => dirname(__FILE__) . '/templates'));
$s->get('/bar', function () use ($s) {
$s->render('test.php', array('foo' => 'bar'), 500);
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertEquals(500, $status);
$this->assertEquals('test output bar', $body);
}
/************************************************
* LOG
************************************************/
/**
* Test get log
*
* This asserts that a Slim app has a default Log
* upon instantiation. The Log itself is tested
* separately in another file.
*/
public function testGetLog()
{
$s = new \Slim\Slim();
$this->assertInstanceOf('\Slim\Log', $s->getLog());
}
/************************************************
* HTTP CACHING
************************************************/
/**
* Test Last-Modified match
*/
public function testLastModifiedMatch()
{
\Slim\Environment::mock(array(
'REQUEST_METHOD' => 'GET',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
'HTTP_IF_MODIFIED_SINCE' => 'Sun, 03 Oct 2010 21:00:52 GMT',
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->lastModified(1286139652);
});
$s->call();
$this->assertEquals(304, $s->response()->status());
}
/**
* Test Last-Modified match
*/
public function testLastModifiedDoesNotMatch()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
'IF_MODIFIED_SINCE' => 'Sun, 03 Oct 2010 21:00:52 GMT',
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->lastModified(1286139250);
});
$s->call();
$this->assertEquals(200, $s->response()->status());
}
public function testLastModifiedOnlyAcceptsIntegers()
{
$this->setExpectedException('\InvalidArgumentException');
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->lastModified('Test');
});
$s->call();
}
/**
* Test Last Modified header format
*/
public function testLastModifiedHeaderFormat()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->lastModified(1286139652);
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertTrue(isset($header['Last-Modified']));
$this->assertEquals('Sun, 03 Oct 2010 21:00:52 GMT', $header['Last-Modified']);
}
/**
* Test ETag matches
*/
public function testEtagMatches()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
'HTTP_IF_NONE_MATCH' => '"abc123"',
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->etag('abc123');
});
$s->call();
$this->assertEquals(304, $s->response()->status());
}
/**
* Test ETag does not match
*/
public function testEtagDoesNotMatch()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
'IF_NONE_MATCH' => '"abc1234"',
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->etag('abc123');
});
$s->call();
$this->assertEquals(200, $s->response()->status());
}
/**
* Test ETag with invalid type
*/
public function testETagWithInvalidType()
{
$this->setExpectedException('\InvalidArgumentException');
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
'IF_NONE_MATCH' => '"abc1234"',
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->etag('123','foo');
});
$s->call();
}
/**
* Test Expires
*/
public function testExpiresAsString()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->expires('5 days');
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertTrue(isset($header['Expires']));
$this->assertEquals(
strtotime('5 days'),
strtotime($header['Expires']),
1 // delta
);
}
/**
* Test Expires
*/
public function testExpiresAsInteger()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$fiveDaysFromNow = time() + (60 * 60 * 24 * 5);
$expectedDate = gmdate('D, d M Y H:i:s T', $fiveDaysFromNow);
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s, $fiveDaysFromNow) {
$s->expires($fiveDaysFromNow);
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertTrue(isset($header['Expires']));
$this->assertEquals($header['Expires'], $expectedDate);
}
/************************************************
* COOKIES
************************************************/
/**
* Set cookie
*
* This tests that the Slim application instance sets
* a cookie in the HTTP response header. This does NOT
* test the implementation of setting the cookie; that is
* tested in a separate file.
*/
public function testSetCookie()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->setCookie('foo', 'bar', '2 days');
$s->setCookie('foo1', 'bar1', '2 days');
});
$s->call();
$cookie1 = $s->response->cookies->get('foo');
$cookie2 = $s->response->cookies->get('foo1');
$this->assertEquals(2, count($s->response->cookies));
$this->assertEquals('bar', $cookie1['value']);
$this->assertEquals('bar1', $cookie2['value']);
}
/**
* Test get cookie
*
* This method ensures that the `Cookie:` HTTP request
* header is parsed if present, and made accessible via the
* Request object.
*/
public function testGetCookie()
{
\Slim\Environment::mock(array(
'REQUEST_METHOD' => 'GET',
'REMOTE_ADDR' => '127.0.0.1',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
'QUERY_STRING' => 'one=foo&two=bar',
'SERVER_NAME' => 'slimframework.com',
'SERVER_PORT' => 80,
'HTTP_COOKIE' => 'foo=bar; foo2=bar2',
'slim.url_scheme' => 'http',
'slim.input' => '',
'slim.errors' => @fopen('php://stderr', 'w')
));
$s = new \Slim\Slim();
$this->assertEquals('bar', $s->getCookie('foo'));
$this->assertEquals('bar2', $s->getCookie('foo2'));
}
/**
* Test get cookie when cookie does not exist
*/
public function testGetCookieThatDoesNotExist()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
));
$s = new \Slim\Slim();
$this->assertNull($s->getCookie('foo'));
}
/**
* Test delete cookie
*
* This method ensures that the `Set-Cookie:` HTTP response
* header is set. The implementation of setting the response
* cookie is tested separately in another file.
*/
public function testDeleteCookie()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
'COOKIE' => 'foo=bar; foo2=bar2',
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->setCookie('foo', 'bar');
$s->deleteCookie('foo');
});
$s->call();
$cookie = $s->response->cookies->get('foo');
$this->assertEquals(1, count($s->response->cookies));
$this->assertEquals('', $cookie['value']);
$this->assertLessThan(time(), $cookie['expires']);
}
/************************************************
* HELPERS
************************************************/
/**
* Test get filesystem path to Slim app root directory
*/
public function testGetRoot()
{
$_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__); //<-- No trailing slash
$s = new \Slim\Slim();
$this->assertEquals($_SERVER['DOCUMENT_ROOT'] . '/foo/', $s->root()); //<-- Appends physical app path with trailing slash
}
/**
* Test stop
*/
public function testStop()
{
$this->setExpectedException('\Slim\Exception\Stop');
$s = new \Slim\Slim();
$s->stop();
}
/**
* Test stop with subsequent output
*/
public function testStopWithSubsequentOutput()
{
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
echo "Foo"; //<-- Should be in response body!
$s->stop();
echo "Bar"; //<-- Should not be in response body!
});
$s->call();
$this->assertEquals('Foo', $s->response()->body());
}
/**
* Test stop with output buffer on and pre content
*/
public function testStopOutputWithOutputBufferingOnAndPreContent()
{
$this->expectOutputString('1.2.Foo.3'); //<-- PHP unit uses OB here
echo "1.";
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
echo "Foo";
$s->stop();
});
echo "2.";
$s->run(); //<-- Needs to be run to actually echo body
echo ".3";
}
/**
* Test stop does not leave output buffers open
*/
public function testStopDoesNotLeaveOutputBuffersOpen()
{
$level_start = ob_get_level();
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->stop();
});
$s->run();
$this->assertEquals($level_start, ob_get_level());
}
/**
* Test halt
*/
public function testHalt()
{
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
echo "Foo!"; //<-- Should not be in response body!
$s->halt(500, 'Something broke');
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertEquals(500, $status);
$this->assertEquals('Something broke', $body);
}
/**
* Test halt with output buffering and pre content
*/
public function testHaltOutputWithOutputBufferingOnAndPreContent()
{
$this->expectOutputString('1.2.Something broke.3'); //<-- PHP unit uses OB here
echo "1.";
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
echo "Foo!"; //<-- Should not be in response body!
$s->halt(500, 'Something broke');
});
echo "2.";
$s->run();
echo ".3";
}
/**
* Test halt does not leave output buffers open
*/
public function testHaltDoesNotLeaveOutputBuffersOpen()
{
$level_start = ob_get_level();
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->halt(500, '');
});
$s->run();
$this->assertEquals($level_start, ob_get_level());
}
/**
* Test pass cleans buffer and throws exception
*/
public function testPass()
{
ob_start();
$s = new \Slim\Slim();
echo "Foo";
try {
$s->pass();
$this->fail('Did not catch Slim_Exception_Pass');
} catch ( \Slim\Exception\Pass $e ) {}
$output = ob_get_clean();
$this->assertEquals('', $output);
}
/**
* Test pass when there is a subsequent fallback route
*/
public function testPassWithSubsequentRoute()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/name/Frank', //<-- Virtual
));
$s = new \Slim\Slim();
$s->get('/name/Frank', function () use ($s) {
echo "Fail"; //<-- Should not be in response body!
$s->pass();
});
$s->get('/name/:name', function ($name) {
echo $name; //<-- Should be in response body!
});
$s->call();
$this->assertEquals('Frank', $s->response()->body());
}
/**
* Test pass when there is not a subsequent fallback route
*/
public function testPassWithoutSubsequentRoute()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/name/Frank', //<-- Virtual
));
$s = new \Slim\Slim();
$s->get('/name/Frank', function () use ($s) {
echo "Fail"; //<-- Should not be in response body!
$s->pass();
});
$s->call();
$this->assertEquals(404, $s->response()->status());
}
/**
* Test content type
*/
public function testContentType()
{
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->contentType('application/json');
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertEquals('application/json', $header['Content-Type']);
}
/**
* Test status
*/
public function testStatus()
{
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->status(403);
});
$s->call();
$this->assertEquals(403, $s->response()->status());
}
/**
* Test URL for
*/
public function testSlimUrlFor()
{
$s = new \Slim\Slim();
$s->get('/hello/:name', function () {})->name('hello');
$this->assertEquals('/foo/hello/Josh', $s->urlFor('hello', array('name' => 'Josh'))); //<-- Prepends physical path!
}
/**
* Test redirect sets status and header
*/
public function testRedirect()
{
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
echo "Foo"; //<-- Should not be in response body!
$s->redirect('/somewhere/else', 303);
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertEquals(303, $status);
$this->assertEquals('/somewhere/else', $header['Location']);
$this->assertEquals('', $body);
}
/************************************************
* RUNNER
************************************************/
/**
* Test that runner sends headers and body
*/
public function testRun()
{
$this->expectOutputString('Foo');
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
echo "Foo";
});
$s->run();
}
/**
* Test runner output with output buffering on and pre content
*/
public function testRunOutputWithOutputBufferingOnAndPreContent()
{
$this->expectOutputString('1.2.Foo.3'); //<-- PHP unit uses OB here
$s = new \Slim\Slim();
echo "1.";
$s->get('/bar', function () use ($s) {
echo "Foo";
});
echo "2.";
$s->run();
echo ".3";
}
/**
* Test that runner does not leave output buffers open
*/
public function testRunDoesNotLeaveAnyOutputBuffersOpen()
{
$level_start = ob_get_level();
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {});
$s->run();
$this->assertEquals($level_start, ob_get_level());
}
/************************************************
* MIDDLEWARE
************************************************/
/**
* Test add middleware
*
* This asserts that middleware are queued and called
* in sequence. This also asserts that the environment
* variables are passed by reference.
*/
public function testAddMiddleware()
{
$this->expectOutputString('FooHello');
$s = new \Slim\Slim();
$s->add(new CustomMiddleware()); //<-- See top of this file for class definition
$s->get('/bar', function () {
echo 'Foo';
});
$s->run();
$this->assertEquals('Hello', $s->response()->header('X-Slim-Test'));
}
/**
* Test exception when adding circular middleware queues
*
* This asserts that the same middleware can NOT be queued twice (usually by accident).
* Circular middleware stack causes a troublesome to debug PHP Fatal error:
*
* > Fatal error: Maximum function nesting level of '100' reached. aborting!
*/
public function testFailureWhenAddingCircularMiddleware()
{
$this->setExpectedException('\RuntimeException');
$middleware = new CustomMiddleware;
$s = new \Slim\Slim;
$s->add($middleware);
$s->add(new CustomMiddleware);
$s->add($middleware);
$s->run();
}
/************************************************
* FLASH MESSAGING
************************************************/
public function testSetFlashForNextRequest()
{
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->flash('info', 'bar');
});
$this->assertFalse(isset($_SESSION['slim.flash']));
$s->run();
$this->assertEquals('bar', $_SESSION['slim.flash']['info']);
}
public function testSetFlashForCurrentRequest()
{
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->flashNow('info', 'bar');
});
$s->run();
$env = $s->environment();
$this->assertEquals('bar', $env['slim.flash']['info']);
}
public function testKeepFlashForNextRequest()
{
$_SESSION['slim.flash'] = array('info' => 'Foo');
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->flashKeep();
});
$s->run();
$this->assertEquals('Foo', $_SESSION['slim.flash']['info']);
}
public function testFlashData()
{
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
$s->flashNow('info', 'bar');
});
$s->run();
$this->assertEquals(array('info' => 'bar'), $s->flashData());
}
/************************************************
* NOT FOUND HANDLING
************************************************/
/**
* Test custom Not Found handler
*/
public function testNotFound()
{
$s = new \Slim\Slim();
$s->notFound(function () {
echo "Not Found";
});
$s->get('/foo', function () {});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertEquals(404, $status);
$this->assertEquals('Not Found', $body);
}
/************************************************
* ERROR HANDLING
************************************************/
/**
* Test default and custom error handlers
*
* Pre-conditions:
* Invoked app route calls default error handler;
*
* Post-conditions:
* Response status code is 500;
*/
public function testSlimError()
{
$s = new \Slim\Slim(array(
"log.enabled" => false
));
$s->get('/bar', function () use ($s) {
$s->error();
});
$s->call();
$this->assertEquals(500, $s->response()->status());
}
/**
* Test default error handler logs the error when debug is false.
*
* Pre-conditions:
* Invoked app route calls default error handler;
*
* Post-conditions:
* Error log is called
*/
public function testDefaultHandlerLogsTheErrorWhenDebugIsFalse()
{
$s = new \Slim\Slim(array('debug' => false));
$s->container->singleton('log', function ($c) {
return new EchoErrorLogger();
});
$s->get('/bar', function () use ($s) {
throw new \InvalidArgumentException('my specific error message');
});
ob_start();
$s->run();
$output = ob_get_clean();
$this->assertTrue(strpos($output, 'InvalidArgumentException:my specific error message') !== false);
}
/**
* Test triggered errors are converted to ErrorExceptions
*
* Pre-conditions:
* Custom error handler defined;
* Invoked app route triggers error;
*
* Post-conditions:
* Response status is 500;
* Response body is equal to triggered error message;
* Error handler's argument is ErrorException instance;
*/
public function DISABLEDtestTriggeredErrorsAreConvertedToErrorExceptions()
{
$s = new \Slim\Slim(array(
'debug' => false
));
$s->error(function ( $e ) {
if ($e instanceof \ErrorException) {
echo $e->getMessage();
}
});
$s->get('/bar', function () {
trigger_error('Foo I say!');
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertEquals(500, $status);
$this->assertEquals('Foo I say!', $body);
}
/**
* Test error triggered with multiple applications
*
* Pre-conditions:
* Multiple Slim apps are instantiated;
* Both apps are run;
* One app returns 200 OK;
* One app triggers an error;
*
* Post-conditions:
* One app returns 200 OK with no Exceptions;
* One app returns 500 Error;
* Error triggered does not affect other app;
*/
public function testErrorWithMultipleApps()
{
$s1 = new \Slim\Slim(array(
'debug' => false,
'log.enabled' => false
));
$s2 = new \Slim\Slim();
$s1->get('/bar', function () use ($s1) {
$s1->error();
});
$s2->get('/bar', function () {
echo 'success';
});
$s1->call();
$s2->call();
$this->assertEquals(500, $s1->response()->status());
$this->assertEquals(200, $s2->response()->status());
}
/**
* Test custom error handler uses existing Response object
*/
public function testErrorHandlerUsesCurrentResponseObject()
{
$s = new \Slim\Slim(array(
'debug' => false
));
$s->error(function ( \Exception $e ) use ($s) {
$r = $s->response();
$r->status(503);
$r->write('Foo');
$r['X-Powered-By'] = 'Slim';
echo 'Bar';
});
$s->get('/bar', function () {
throw new \Exception('Foo');
});
$s->call();
list($status, $header, $body) = $s->response()->finalize();
$this->assertEquals(503, $status);
$this->assertEquals('FooBar', $body);
$this->assertEquals('Slim', $header['X-Powered-By']);
}
/**
* Test custom global error handler
*/
public function testHandleErrors()
{
$defaultErrorReporting = error_reporting();
// Test 1
error_reporting(E_ALL ^ E_NOTICE); // <-- Report all errors EXCEPT notices
try {
\Slim\Slim::handleErrors(E_NOTICE, 'test error', 'Slim.php', 119);
} catch (\ErrorException $e) {
$this->fail('Slim::handleErrors reported a disabled error level.');
}
// Test 2
error_reporting(E_ALL | E_STRICT); // <-- Report all errors, including E_STRICT
try {
\Slim\Slim::handleErrors(E_STRICT, 'test error', 'Slim.php', 119);
$this->fail('Slim::handleErrors didn\'t report a enabled error level');
} catch (\ErrorException $e) {}
error_reporting($defaultErrorReporting);
}
/**
* Slim should keep reference to a callable error callback
*/
public function testErrorHandler() {
$s = new \Slim\Slim();
$errCallback = function () { echo "404"; };
$s->error($errCallback);
$this->assertSame($errCallback, PHPUnit_Framework_Assert::readAttribute($s, 'error'));
}
/**
* Slim should throw a Slim_Exception_Stop if error callback is not callable
*/
public function testErrorHandlerIfNotCallable() {
$this->setExpectedException('\Slim\Exception\Stop');
$s = new \Slim\Slim(array("log.enabled" => false));
$errCallback = 'foo';
$s->error($errCallback);
}
/**
* Slim should keep reference to a callable NotFound callback
*/
public function testNotFoundHandler() {
$s = new \Slim\Slim();
$notFoundCallback = function () { echo "404"; };
$s->notFound($notFoundCallback);
$this->assertSame($notFoundCallback, PHPUnit_Framework_Assert::readAttribute($s, 'notFound'));
}
/**
* Slim should throw a Slim_Exception_Stop if NotFound callback is not callable
*/
public function testNotFoundHandlerIfNotCallable() {
$this->setExpectedException('\Slim\Exception\Stop');
$s = new \Slim\Slim();
$notFoundCallback = 'foo';
$s->notFound($notFoundCallback);
}
/************************************************
* HOOKS
************************************************/
/**
* Test hook listener
*
* Pre-conditions:
* Slim app instantiated;
* Hook name does not exist;
* Listeners are callable objects;
*
* Post-conditions:
* Callables are invoked in expected order;
*/
public function testRegistersAndCallsHooksByPriority()
{
$this->expectOutputString('barfoo');
$app = new \Slim\Slim();
$callable1 = function () { echo "foo"; };
$callable2 = function () { echo "bar"; };
$app->hook('test.hook.one', $callable1); //default is 10
$app->hook('test.hook.one', $callable2, 8);
$hooks = $app->getHooks();
$this->assertEquals(7, count($hooks)); //6 default, 1 custom
$app->applyHook('test.hook.one');
}
/**
* Test hook listener if listener is not callable
*
* Pre-conditions:
* Slim app instantiated;
* Hook name does not exist;
* Listener is NOT a callable object;
*
* Post-conditions:
* Hook is created;
* Callable is NOT assigned to hook;
*/
public function testHookInvalidCallable()
{
$app = new \Slim\Slim();
$callable = 'test'; //NOT callable
$app->hook('test.hook.one', $callable);
$this->assertEquals(array(array()), $app->getHooks('test.hook.one'));
}
/**
* Test hook invocation if hook does not exist
*
* Pre-conditions:
* Slim app instantiated;
* Hook name does not exist;
*
* Post-conditions:
* Hook is created;
* Hook initialized with empty array;
*/
public function testHookInvocationIfNotExists()
{
$app = new \Slim\Slim();
$app->applyHook('test.hook.one');
$this->assertEquals(array(array()), $app->getHooks('test.hook.one'));
}
/**
* Test clear hooks
*
* Pre-conditions:
* Slim app instantiated;
* Two hooks exist, each with one listener;
*
* Post-conditions:
* Case A: Listeners for 'test.hook.one' are cleared;
* Case B: Listeners for all hooks are cleared;
*/
public function testHookClear()
{
$app = new \Slim\Slim();
$app->hook('test.hook.one', function () {});
$app->hook('test.hook.two', function () {});
$app->clearHooks('test.hook.two');
$this->assertEquals(array(array()), $app->getHooks('test.hook.two'));
$hookOne = $app->getHooks('test.hook.one');
$this->assertTrue(count($hookOne[10]) === 1);
$app->clearHooks();
$this->assertEquals(array(array()), $app->getHooks('test.hook.one'));
}
/**
* Test hooks accept multiple arguments
*
* Pre-conditions:
* Slim app instantiated;
* Hook name does not exist;
* Listener is a callable object;
*
* Post-conditions:
* Callable invoked with 2 arguments
*/
public function testHooksMultipleArguments()
{
$testArgA = 'argumentA';
$testArgB = 'argumentB';
$this->expectOutputString($testArgA . $testArgB);
$app = new \Slim\Slim();
$app->hook('test.hook.one', function ($argA, $argB) {
echo $argA . $argB;
});
$app->applyHook('test.hook.one', $testArgA, $testArgB);
}
/**
* Test late static binding
*
* Pre-conditions:
* Slim app is extended by Derived class and instantiated;
* Derived class overrides the 'getDefaultSettings' function and adds an extra default config value
* Test that the new config value exists
*
* Post-conditions:
* Config value exists and is equal to expected value
*/
public function testDerivedClassCanOverrideStaticFunction()
{
$app = new Derived();
$this->assertEquals($app->config("late-static-binding"), true);
}
}