CodeIgniter4/tests/system/CommonFunctionsTest.php

522 lines
15 KiB
PHP
Raw Normal View History

<?php
2016-07-12 10:11:17 -07:00
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.
*/
namespace CodeIgniter;
use CodeIgniter\Config\BaseService;
use CodeIgniter\Config\Services;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\Response;
use CodeIgniter\HTTP\URI;
use CodeIgniter\HTTP\UserAgent;
use CodeIgniter\Router\RouteCollection;
use CodeIgniter\Session\Handlers\FileHandler;
2021-02-28 08:28:54 +07:00
use CodeIgniter\Session\Session;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockIncomingRequest;
use CodeIgniter\Test\Mock\MockSession;
use CodeIgniter\Test\TestLogger;
use Config\App;
use Config\Logger;
2021-02-28 06:57:05 +07:00
use Config\Modules;
2021-02-28 08:28:54 +07:00
use InvalidArgumentException;
2021-02-28 06:57:05 +07:00
use RuntimeException;
2021-02-28 08:28:54 +07:00
use stdClass;
2020-10-15 18:34:52 +00:00
use Tests\Support\Autoloader\FatalLocator;
2020-04-17 17:27:16 +07:00
use Tests\Support\Models\JobModel;
2018-06-07 02:56:46 -07:00
/**
* @backupGlobals enabled
*
* @internal
*/
final class CommonFunctionsTest extends CIUnitTestCase
2016-07-12 10:11:17 -07:00
{
2021-06-04 22:51:52 +08:00
protected function setUp(): void
{
parent::setUp();
$renderer = Services::renderer();
$renderer->resetData();
unset($_ENV['foo'], $_SERVER['foo']);
}
public function testStringifyAttributes()
{
2021-06-25 23:35:25 +08:00
$this->assertSame(' class="foo" id="bar"', stringify_attributes(['class' => 'foo', 'id' => 'bar']));
2021-06-04 22:51:52 +08:00
$atts = new stdClass();
2021-06-04 22:51:52 +08:00
$atts->class = 'foo';
$atts->id = 'bar';
2021-06-25 23:35:25 +08:00
$this->assertSame(' class="foo" id="bar"', stringify_attributes($atts));
2021-06-04 22:51:52 +08:00
$atts = new stdClass();
2021-06-25 23:35:25 +08:00
$this->assertSame('', stringify_attributes($atts));
2021-06-04 22:51:52 +08:00
2021-06-25 23:35:25 +08:00
$this->assertSame(' class="foo" id="bar"', stringify_attributes('class="foo" id="bar"'));
2021-06-04 22:51:52 +08:00
2021-06-25 23:35:25 +08:00
$this->assertSame('', stringify_attributes([]));
2021-06-04 22:51:52 +08:00
}
public function testStringifyJsAttributes()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('width=800,height=600', stringify_attributes(['width' => '800', 'height' => '600'], true));
2021-06-04 22:51:52 +08:00
$atts = new stdClass();
2021-06-04 22:51:52 +08:00
$atts->width = 800;
$atts->height = 600;
2021-06-25 23:35:25 +08:00
$this->assertSame('width=800,height=600', stringify_attributes($atts, true));
2021-06-04 22:51:52 +08:00
}
public function testEnvReturnsDefault()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('baz', env('foo', 'baz'));
2021-06-04 22:51:52 +08:00
}
public function testEnvGetsFromSERVER()
{
$_SERVER['foo'] = 'bar';
2021-06-25 23:35:25 +08:00
$this->assertSame('bar', env('foo', 'baz'));
2021-06-04 22:51:52 +08:00
}
public function testEnvGetsFromENV()
{
$_ENV['foo'] = 'bar';
2021-06-25 23:35:25 +08:00
$this->assertSame('bar', env('foo', 'baz'));
2021-06-04 22:51:52 +08:00
}
public function testEnvBooleans()
{
$_ENV['p1'] = 'true';
$_ENV['p2'] = 'false';
$_ENV['p3'] = 'empty';
$_ENV['p4'] = 'null';
$this->assertTrue(env('p1'));
$this->assertFalse(env('p2'));
$this->assertEmpty(env('p3'));
$this->assertNull(env('p4'));
}
public function testRedirectReturnsRedirectResponse()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$response = $this->createMock(Response::class);
$routes = new RouteCollection(
2021-06-16 00:50:52 +08:00
Services::locator(),
new Modules()
2021-06-04 22:51:52 +08:00
);
\CodeIgniter\Services::injectMock('response', $response);
\CodeIgniter\Services::injectMock('routes', $routes);
$routes->add('home/base', 'Controller::index', ['as' => 'base']);
2021-06-24 23:29:53 +08:00
$response->method('redirect')->willReturnArgument(0);
2021-06-04 22:51:52 +08:00
$this->assertInstanceOf(RedirectResponse::class, redirect('base'));
}
public function testRedirectDefault()
{
$this->assertInstanceOf(RedirectResponse::class, redirect());
}
public function testView()
{
$data = [
2021-06-04 22:51:52 +08:00
'testString' => 'bar',
'bar' => 'baz',
];
$expected = '<h1>bar</h1>';
$this->assertStringContainsString($expected, view('\Tests\Support\View\Views\simple', $data));
}
public function testViewSavedData()
{
$data = [
2021-06-04 22:51:52 +08:00
'testString' => 'bar',
'bar' => 'baz',
];
$expected = '<h1>bar</h1>';
$this->assertStringContainsString($expected, view('\Tests\Support\View\Views\simple', $data, ['saveData' => true]));
$this->assertStringContainsString($expected, view('\Tests\Support\View\Views\simple'));
}
public function testViewCell()
{
$expected = 'Hello';
2021-06-25 23:35:25 +08:00
$this->assertSame($expected, view_cell('\Tests\Support\View\SampleClass::hello'));
2021-06-04 22:51:52 +08:00
}
public function testEscapeWithDifferentEncodings()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('&lt;x', esc('<x', 'html', 'utf-8'));
$this->assertSame('&lt;x', esc('<x', 'html', 'iso-8859-1'));
$this->assertSame('&lt;x', esc('<x', 'html', 'windows-1251'));
2021-06-04 22:51:52 +08:00
}
public function testEscapeBadContext()
{
$this->expectException(InvalidArgumentException::class);
esc(['width' => '800', 'height' => '600'], 'bogus');
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testSessionInstance()
{
$this->injectSessionMock();
$this->assertInstanceOf(Session::class, session());
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testSessionVariable()
{
$this->injectSessionMock();
$_SESSION['notbogus'] = 'Hi there';
2021-06-25 23:35:25 +08:00
$this->assertSame('Hi there', session('notbogus'));
2021-06-04 22:51:52 +08:00
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testSessionVariableNotThere()
{
$this->injectSessionMock();
$_SESSION['bogus'] = 'Hi there';
$this->assertNull(session('notbogus'));
2021-06-04 22:51:52 +08:00
}
public function testRouteTo()
{
// prime the pump
$routes = service('routes');
$routes->add('path/(:any)/to/(:num)', 'myController::goto/$1/$2');
2021-06-25 23:35:25 +08:00
$this->assertSame('/path/string/to/13', route_to('myController::goto', 'string', 13));
2021-06-04 22:51:52 +08:00
}
public function testInvisible()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('Javascript', remove_invisible_characters("Java\0script"));
2021-06-04 22:51:52 +08:00
}
public function testInvisibleEncoded()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('Javascript', remove_invisible_characters('Java%0cscript'));
2021-06-04 22:51:52 +08:00
}
public function testAppTimezone()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('America/Chicago', app_timezone());
2021-06-04 22:51:52 +08:00
}
public function testCSRFToken()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('csrf_test_name', csrf_token());
2021-06-04 22:51:52 +08:00
}
public function testCSRFHeader()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('X-CSRF-TOKEN', csrf_header());
2021-06-04 22:51:52 +08:00
}
public function testHash()
{
2021-06-25 23:35:25 +08:00
$this->assertSame(32, strlen(csrf_hash()));
2021-06-04 22:51:52 +08:00
}
public function testCSRFField()
{
$this->assertStringContainsString('<input type="hidden" ', csrf_field());
}
public function testCSRFMeta()
{
$this->assertStringContainsString('<meta name="X-CSRF-TOKEN" ', csrf_meta());
}
public function testModelNotExists()
{
$this->assertNull(model(UnexsistenceClass::class));
}
public function testModelExistsBasename()
{
$this->assertInstanceOf(JobModel::class, model('JobModel'));
}
public function testModelExistsClassname()
{
$this->assertInstanceOf(JobModel::class, model(JobModel::class));
}
public function testModelExistsAbsoluteClassname()
{
$this->assertInstanceOf(JobModel::class, model('\Tests\Support\Models\JobModel'));
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testOldInput()
{
$this->injectSessionMock();
// setup from RedirectResponseTest...
$_SERVER['REQUEST_METHOD'] = 'GET';
$this->config = new App();
$this->config->baseURL = 'http://example.com/';
$this->routes = new RouteCollection(Services::locator(), new Modules());
Services::injectMock('routes', $this->routes);
$this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent());
Services::injectMock('request', $this->request);
// setup & ask for a redirect...
$_SESSION = [];
$_GET = ['foo' => 'bar'];
$_POST = [
'bar' => 'baz',
'zibble' => serialize('fritz'),
];
$response = new RedirectResponse(new App());
$response->withInput();
2021-06-04 22:51:52 +08:00
2021-06-25 23:35:25 +08:00
$this->assertSame('bar', old('foo')); // regular parameter
$this->assertSame('doo', old('yabba dabba', 'doo')); // non-existing parameter
$this->assertSame('fritz', old('zibble')); // serialized parameter
2021-06-04 22:51:52 +08:00
}
/**
* @see https://github.com/codeigniter4/CodeIgniter4/issues/1492
2021-06-04 22:51:52 +08:00
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testOldInputArray()
{
$this->injectSessionMock();
// setup from RedirectResponseTest...
$_SERVER['REQUEST_METHOD'] = 'GET';
$this->config = new App();
$this->config->baseURL = 'http://example.com/';
$this->routes = new RouteCollection(Services::locator(), new Modules());
Services::injectMock('routes', $this->routes);
$this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent());
Services::injectMock('request', $this->request);
$locations = [
'AB' => 'Alberta',
'BC' => 'British Columbia',
'SK' => 'Saskatchewan',
];
// setup & ask for a redirect...
$_SESSION = [];
$_GET = [];
$_POST = ['location' => $locations];
$response = new RedirectResponse(new App());
$response->withInput();
2021-06-04 22:51:52 +08:00
2021-06-25 23:35:25 +08:00
$this->assertSame($locations, old('location'));
2021-06-04 22:51:52 +08:00
}
public function testReallyWritable()
{
// cannot test fully on *nix
$this->assertTrue(is_really_writable(WRITEPATH));
}
public function testSlashItem()
{
2021-06-25 23:35:25 +08:00
$this->assertSame('/', slash_item('cookiePath')); // slash already there
$this->assertSame('', slash_item('cookieDomain')); // empty, so untouched
$this->assertSame('en/', slash_item('defaultLocale')); // slash appended
2021-06-04 22:51:52 +08:00
}
protected function injectSessionMock()
{
$defaults = [
'sessionDriver' => 'CodeIgniter\Session\Handlers\FileHandler',
'sessionCookieName' => 'ci_session',
'sessionExpiration' => 7200,
'sessionSavePath' => null,
'sessionMatchIP' => false,
'sessionTimeToUpdate' => 300,
'sessionRegenerateDestroy' => false,
'cookieDomain' => '',
'cookiePrefix' => '',
'cookiePath' => '/',
'cookieSecure' => false,
'cookieSameSite' => 'Lax',
];
$appConfig = new App();
2021-06-07 19:06:26 +08:00
foreach ($defaults as $key => $config) {
$appConfig->{$key} = $config;
2021-06-04 22:51:52 +08:00
}
$session = new MockSession(new FileHandler($appConfig, '127.0.0.1'), $appConfig);
$session->setLogger(new TestLogger(new Logger()));
BaseService::injectMock('session', $session);
}
// Make sure cookies are set by RedirectResponse this way
// See https://github.com/codeigniter4/CodeIgniter4/issues/1393
public function testRedirectResponseCookies1()
{
$loginTime = time();
$routes = service('routes');
$routes->add('user/login', 'Auth::verify', ['as' => 'login']);
$answer1 = redirect()->route('login')
->setCookie('foo', 'onething', YEAR)
->setCookie('login_time', $loginTime, YEAR);
2021-06-04 22:51:52 +08:00
$this->assertTrue($answer1->hasCookie('foo', 'onething'));
$this->assertTrue($answer1->hasCookie('login_time'));
}
public function testTrace()
{
ob_start();
trace();
$content = ob_get_clean();
$this->assertStringContainsString('Debug Backtrace', $content);
}
public function testViewNotSaveData()
{
$data = [
'testString' => 'bar',
'bar' => 'baz',
];
$this->assertStringContainsString('<h1>bar</h1>', view('\Tests\Support\View\Views\simples', $data, ['saveData' => false]));
$this->assertStringContainsString('<h1>is_not</h1>', view('\Tests\Support\View\Views\simples'));
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testForceHttpsNullRequestAndResponse()
{
$this->assertNull(Services::response()->header('Location'));
force_https();
2021-06-25 23:35:25 +08:00
$this->assertSame('https://example.com/', Services::response()->header('Location')->getValue());
2021-06-04 22:51:52 +08:00
}
/**
* @dataProvider dirtyPathsProvider
2021-07-24 19:30:51 +08:00
*
* @param mixed $input
* @param mixed $expected
2021-06-04 22:51:52 +08:00
*/
public function testCleanPathActuallyCleaningThePaths($input, $expected)
{
2021-06-25 23:35:25 +08:00
$this->assertSame($expected, clean_path($input));
2021-06-04 22:51:52 +08:00
}
public function dirtyPathsProvider()
{
$ds = DIRECTORY_SEPARATOR;
return [
[
ROOTPATH . 'spark',
'ROOTPATH' . $ds . 'spark',
],
[
APPPATH . 'Config' . $ds . 'App.php',
'APPPATH' . $ds . 'Config' . $ds . 'App.php',
],
[
SYSTEMPATH . 'CodeIgniter.php',
'SYSTEMPATH' . $ds . 'CodeIgniter.php',
],
[
VENDORPATH . 'autoload.php',
'VENDORPATH' . $ds . 'autoload.php',
],
[
FCPATH . 'index.php',
'FCPATH' . $ds . 'index.php',
],
];
}
public function testHelperWithFatalLocatorThrowsException()
{
// Replace the locator with one that will fail if it is called
$locator = new FatalLocator(Services::autoloader());
Services::injectMock('locator', $locator);
2021-06-07 19:06:26 +08:00
try {
2021-06-04 22:51:52 +08:00
helper('baguette');
$exception = false;
2021-06-07 19:06:26 +08:00
} catch (RuntimeException $e) {
2021-06-04 22:51:52 +08:00
$exception = true;
}
$this->assertTrue($exception);
Services::reset();
}
public function testHelperLoadsOnce()
{
// Load it the first time
helper('baguette');
// Replace the locator with one that will fail if it is called
$locator = new FatalLocator(Services::autoloader());
Services::injectMock('locator', $locator);
2021-06-07 19:06:26 +08:00
try {
2021-06-04 22:51:52 +08:00
helper('baguette');
$exception = false;
2021-06-07 19:06:26 +08:00
} catch (RuntimeException $e) {
2021-06-04 22:51:52 +08:00
$exception = true;
}
$this->assertFalse($exception);
Services::reset();
}
public function testIsCli()
{
$this->assertIsBool(is_cli());
$this->assertTrue(is_cli());
}
2016-07-12 10:11:17 -07:00
}