CodeIgniter4/tests/system/CodeIgniterTest.php

511 lines
15 KiB
PHP
Raw Normal View History

2021-06-07 00:15:28 +08:00
<?php
2021-07-19 21:32:33 +08:00
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
2021-06-07 00:15:28 +08:00
namespace CodeIgniter;
2021-07-03 00:56:44 +08:00
use CodeIgniter\Config\Services;
use CodeIgniter\HTTP\Response;
use CodeIgniter\Router\RouteCollection;
2021-02-28 06:57:05 +07:00
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockCodeIgniter;
use Config\App;
2021-02-28 06:57:05 +07:00
use Config\Modules;
2021-09-24 17:31:19 +09:00
use Tests\Support\Filters\Customfilter;
/**
* @backupGlobals enabled
*
* @internal
*/
final class CodeIgniterTest extends CIUnitTestCase
{
protected CodeIgniter $codeigniter;
2021-06-04 22:51:52 +08:00
protected $routes;
protected function setUp(): void
{
parent::setUp();
$this->resetServices();
2021-06-04 22:51:52 +08:00
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
2021-06-25 23:35:25 +08:00
$this->codeigniter = new MockCodeIgniter(new App());
2021-06-04 22:51:52 +08:00
}
protected function tearDown(): void
2021-06-04 22:51:52 +08:00
{
parent::tearDown();
2021-06-25 23:35:25 +08:00
if (count(ob_list_handlers()) > 1) {
2021-06-04 22:51:52 +08:00
ob_end_clean();
}
$this->resetServices();
2021-06-04 22:51:52 +08:00
}
public function testRunEmptyDefaultRoute()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php'];
2021-06-04 22:51:52 +08:00
$_SERVER['argc'] = 1;
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString('Welcome to CodeIgniter', $output);
}
public function testRunClosureRoute()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', 'pages/about'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['REQUEST_URI'] = '/pages/about';
// Inject mock router.
$routes = Services::routes();
$routes->add('pages/(:segment)', static function ($segment) {
2021-06-04 22:51:52 +08:00
echo 'You want to see "' . esc($segment) . '" page.';
});
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString('You want to see "about" page.', $output);
}
public function testRun404Override()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', '/'];
2021-06-04 22:51:52 +08:00
$_SERVER['argc'] = 2;
// Inject mock router.
$routes = Services::routes();
$routes->setAutoRoute(false);
2022-02-17 09:17:54 +09:00
$routes->set404Override('Tests\Support\Controllers\Hello::index');
2021-06-04 22:51:52 +08:00
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
2022-02-17 09:17:54 +09:00
$this->codeigniter->useSafeOutput(true)->run($routes);
2021-06-04 22:51:52 +08:00
$output = ob_get_clean();
2022-02-17 09:17:54 +09:00
$this->assertStringContainsString('Hello', $output);
2021-06-04 22:51:52 +08:00
}
public function testRun404OverrideControllerReturnsResponse()
{
$_SERVER['argv'] = ['index.php', '/'];
$_SERVER['argc'] = 2;
// Inject mock router.
$routes = Services::routes();
$routes->setAutoRoute(false);
$routes->set404Override('Tests\Support\Controllers\Popcorn::pop');
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run($routes);
$output = ob_get_clean();
$this->assertStringContainsString('Oops', $output);
}
2021-06-04 22:51:52 +08:00
public function testRun404OverrideByClosure()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', '/'];
2021-06-04 22:51:52 +08:00
$_SERVER['argc'] = 2;
// Inject mock router.
$routes = new RouteCollection(Services::locator(), new Modules());
$routes->setAutoRoute(false);
$routes->set404Override(static function () {
2021-06-04 22:51:52 +08:00
echo '404 Override by Closure.';
});
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run($routes);
$output = ob_get_clean();
$this->assertStringContainsString('404 Override by Closure.', $output);
}
public function testControllersCanReturnString()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', 'pages/about'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['REQUEST_URI'] = '/pages/about';
// Inject mock router.
$routes = Services::routes();
2021-12-14 11:19:51 +07:00
$routes->add('pages/(:segment)', static fn ($segment) => 'You want to see "' . esc($segment) . '" page.');
2021-06-04 22:51:52 +08:00
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString('You want to see "about" page.', $output);
}
public function testControllersCanReturnResponseObject()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', 'pages/about'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['REQUEST_URI'] = '/pages/about';
// Inject mock router.
$routes = Services::routes();
$routes->add('pages/(:segment)', static function ($segment) {
2021-06-04 22:51:52 +08:00
$response = Services::response();
$string = "You want to see 'about' page.";
2021-06-04 22:51:52 +08:00
return $response->setBody($string);
});
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString("You want to see 'about' page.", $output);
}
2021-09-24 17:31:19 +09:00
public function testControllersRunFilterByClassName()
{
$_SERVER['argv'] = ['index.php', 'pages/about'];
$_SERVER['argc'] = 2;
$_SERVER['REQUEST_URI'] = '/pages/about';
// Inject mock router.
$routes = Services::routes();
2021-12-14 11:19:51 +07:00
$routes->add('pages/about', static fn () => Services::request()->url, ['filter' => Customfilter::class]);
2021-09-24 17:31:19 +09:00
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString('http://hellowworld.com', $output);
}
2021-06-04 22:51:52 +08:00
public function testResponseConfigEmpty()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', '/'];
2021-06-04 22:51:52 +08:00
$_SERVER['argc'] = 2;
$response = Services::response(null, false);
$this->assertInstanceOf(Response::class, $response);
2021-06-04 22:51:52 +08:00
}
public function testRoutesIsEmpty()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', '/'];
2021-06-04 22:51:52 +08:00
$_SERVER['argc'] = 2;
// Inject mock router.
$router = Services::router(null, Services::request(), false);
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString('Welcome to CodeIgniter', $output);
}
public function testTransfersCorrectHTTPVersion()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', '/'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/2.0';
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
2021-06-04 22:51:52 +08:00
$response = $this->getPrivateProperty($this->codeigniter, 'response');
2021-06-25 23:35:25 +08:00
$this->assertSame('2.0', $response->getProtocolVersion());
2021-06-04 22:51:52 +08:00
}
public function testIgnoringErrorSuppressedByAt()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', '/'];
2021-06-04 22:51:52 +08:00
$_SERVER['argc'] = 2;
ob_start();
@unlink('inexistent-file');
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString('Welcome to CodeIgniter', $output);
}
public function testRunForceSecure()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', '/'];
2021-06-04 22:51:52 +08:00
$_SERVER['argc'] = 2;
2021-06-25 23:35:25 +08:00
$config = new App();
2021-06-04 22:51:52 +08:00
$config->forceGlobalSecureRequests = true;
2021-06-25 23:35:25 +08:00
$codeigniter = new MockCodeIgniter($config);
$codeigniter->setContext('web');
2021-06-04 22:51:52 +08:00
$this->getPrivateMethodInvoker($codeigniter, 'getRequestObject')();
$this->getPrivateMethodInvoker($codeigniter, 'getResponseObject')();
$response = $this->getPrivateProperty($codeigniter, 'response');
$this->assertNull($response->header('Location'));
ob_start();
$codeigniter->useSafeOutput(true)->run();
ob_get_clean();
2021-06-04 22:51:52 +08:00
2021-06-25 23:35:25 +08:00
$this->assertSame('https://example.com/', $response->header('Location')->getValue());
2021-06-04 22:51:52 +08:00
}
public function testRunRedirectionWithNamed()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', 'example'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['REQUEST_URI'] = '/example';
// Inject mock router.
$routes = Services::routes();
$routes->add('pages/named', static function () {
2021-06-04 22:51:52 +08:00
}, ['as' => 'name']);
$routes->addRedirect('example', 'name');
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
$response = $this->getPrivateProperty($this->codeigniter, 'response');
2021-06-25 23:35:25 +08:00
$this->assertSame('http://example.com/pages/named', $response->header('Location')->getValue());
2021-06-04 22:51:52 +08:00
}
public function testRunRedirectionWithURI()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', 'example'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['REQUEST_URI'] = '/example';
// Inject mock router.
$routes = Services::routes();
$routes->add('pages/uri', static function () {
2021-06-04 22:51:52 +08:00
});
$routes->addRedirect('example', 'pages/uri');
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
$response = $this->getPrivateProperty($this->codeigniter, 'response');
2021-06-25 23:35:25 +08:00
$this->assertSame('http://example.com/pages/uri', $response->header('Location')->getValue());
2021-06-04 22:51:52 +08:00
}
/**
* @see https://github.com/codeigniter4/CodeIgniter4/issues/3041
*/
public function testRunRedirectionWithURINotSet()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', 'example'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['REQUEST_URI'] = '/example';
// Inject mock router.
$routes = Services::routes();
$routes->addRedirect('example', 'pages/notset');
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
$response = $this->getPrivateProperty($this->codeigniter, 'response');
2021-06-25 23:35:25 +08:00
$this->assertSame('http://example.com/pages/notset', $response->header('Location')->getValue());
2021-06-04 22:51:52 +08:00
}
public function testRunRedirectionWithHTTPCode303()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', 'example'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['REQUEST_URI'] = '/example';
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
$_SERVER['REQUEST_METHOD'] = 'POST';
// Inject mock router.
$routes = Services::routes();
$routes->addRedirect('example', 'pages/notset', 301);
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
2021-06-25 23:35:25 +08:00
2021-06-04 22:51:52 +08:00
$response = $this->getPrivateProperty($this->codeigniter, 'response');
2021-06-25 23:35:25 +08:00
$this->assertSame(303, $response->getStatusCode());
2021-06-04 22:51:52 +08:00
}
2021-09-15 01:47:19 +00:00
public function testStoresPreviousURL()
{
$_SERVER['argv'] = ['index.php', '/'];
$_SERVER['argc'] = 2;
// Inject mock router.
$router = Services::router(null, Services::request(), false);
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
$this->assertArrayHasKey('_ci_previous_url', $_SESSION);
$this->assertSame('http://example.com/index.php', $_SESSION['_ci_previous_url']);
}
public function testNotStoresPreviousURL()
2021-06-04 22:51:52 +08:00
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', 'example'];
$_SERVER['argc'] = 2;
2021-06-04 22:51:52 +08:00
$_SERVER['REQUEST_URI'] = '/example';
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
$_SERVER['REQUEST_METHOD'] = 'GET';
// Inject mock router.
$routes = Services::routes();
$routes->addRedirect('example', 'pages/notset', 301);
$router = Services::router($routes, Services::request());
Services::injectMock('router', $router);
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
2021-09-15 01:47:19 +00:00
$this->assertArrayNotHasKey('_ci_previous_url', $_SESSION);
2021-06-04 22:51:52 +08:00
}
/**
* The method after all test, reset Servces:: config
* Can't use static::tearDownAfterClass. This will cause a buffer exception
* need improve
*/
public function testRunDefaultRoute()
{
2021-06-25 23:35:25 +08:00
$_SERVER['argv'] = ['index.php', '/'];
2021-06-04 22:51:52 +08:00
$_SERVER['argc'] = 2;
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString('Welcome to CodeIgniter', $output);
}
public function testRunCLIRoute()
{
$_SERVER['argv'] = ['index.php', 'cli'];
$_SERVER['argc'] = 2;
$_SERVER['REQUEST_URI'] = '/cli';
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
$_SERVER['REQUEST_METHOD'] = 'CLI';
$routes = Services::routes();
$routes->cli('cli', '\Tests\Support\Controllers\Popcorn::index');
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
$output = ob_get_clean();
$this->assertStringContainsString('Method Not Allowed', $output);
}
public function testSpoofRequestMethodCanUsePUT()
{
$_SERVER['argv'] = ['index.php'];
$_SERVER['argc'] = 1;
$_SERVER['REQUEST_URI'] = '/';
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST['_method'] = 'PUT';
$routes = \Config\Services::routes();
$routes->setDefaultNamespace('App\Controllers');
$routes->resetRoutes();
$routes->post('/', 'Home::index');
$routes->put('/', 'Home::index');
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
$this->assertSame('put', Services::request()->getMethod());
}
public function testSpoofRequestMethodCannotUseGET()
{
$_SERVER['argv'] = ['index.php'];
$_SERVER['argc'] = 1;
$_SERVER['REQUEST_URI'] = '/';
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST['_method'] = 'GET';
$routes = \Config\Services::routes();
$routes->setDefaultNamespace('App\Controllers');
$routes->resetRoutes();
$routes->post('/', 'Home::index');
$routes->get('/', 'Home::index');
ob_start();
$this->codeigniter->useSafeOutput(true)->run();
ob_get_clean();
$this->assertSame('post', Services::request()->getMethod());
}
}