CodeIgniter4/tests/system/CommonHelperTest.php
2025-01-13 11:15:24 +08:00

183 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
/**
* 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\Autoloader\Autoloader;
use CodeIgniter\Autoloader\FileLocator;
use CodeIgniter\Exceptions\RuntimeException;
use CodeIgniter\Files\Exceptions\FileNotFoundException;
use CodeIgniter\Test\CIUnitTestCase;
use Config\Services;
use PHPUnit\Framework\Attributes\CoversFunction;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\Support\Autoloader\FatalLocator;
/**
* @internal
*/
#[CoversFunction('helper')]
#[Group('Others')]
final class CommonHelperTest extends CIUnitTestCase
{
private array $dummyHelpers = [
APPPATH . 'Helpers' . DIRECTORY_SEPARATOR . 'foobarbaz_helper.php',
SYSTEMPATH . 'Helpers' . DIRECTORY_SEPARATOR . 'foobarbaz_helper.php',
];
protected function setUp(): void
{
$this->resetServices();
parent::setUp();
$this->cleanUpDummyHelpers();
}
protected function tearDown(): void
{
parent::tearDown();
$this->cleanUpDummyHelpers();
$this->resetServices();
}
private function createDummyHelpers(): void
{
$text = <<<'PHP'
<?php
if (! function_exists('foo_bar_baz')) {
function foo_bar_baz(): string
{
return __FILE__;
}
}
PHP;
foreach ($this->dummyHelpers as $helper) {
file_put_contents($helper, $text);
}
}
private function cleanUpDummyHelpers(): void
{
foreach ($this->dummyHelpers as $helper) {
if (is_file($helper)) {
unlink($helper);
}
}
}
/**
* @return FileLocator&MockObject
*/
private function getMockLocator()
{
return $this->getMockBuilder(FileLocator::class)
->setConstructorArgs([service('autoloader')])
->onlyMethods(['search'])
->getMock();
}
public function testHelperWithFatalLocatorThrowsException(): void
{
// Replace the locator with one that will fail if it is called
$locator = new FatalLocator(service('autoloader'));
Services::injectMock('locator', $locator);
try {
helper('baguette');
$exception = false;
} catch (RuntimeException) {
$exception = true;
}
$this->assertTrue($exception);
}
public function testHelperLoadsOnce(): void
{
// Load it the first time
helper('baguette');
// Replace the locator with one that will fail if it is called
$locator = new FatalLocator(service('autoloader'));
Services::injectMock('locator', $locator);
try {
helper('baguette');
$exception = false;
} catch (RuntimeException) {
$exception = true;
}
$this->assertFalse($exception);
}
public function testHelperLoadsAppHelperFirst(): void
{
foreach ($this->dummyHelpers as $helper) {
$this->assertFileDoesNotExist($helper, sprintf(
'The dummy helper file "%s" should not be existing before it is tested.',
$helper,
));
}
$this->createDummyHelpers();
$locator = $this->getMockLocator();
$locator->method('search')->with('Helpers/foobarbaz_helper')->willReturn($this->dummyHelpers);
Services::injectMock('locator', $locator);
helper('foobarbaz');
// this chunk is not needed really; just added so that IDEs will be happy
if (! function_exists('foo_bar_baz')) {
function foo_bar_baz(): string // @phpstan-ignore function.inner
{
return __FILE__;
}
}
$this->assertSame($this->dummyHelpers[0], foo_bar_baz()); // @phpstan-ignore function.notFound
}
public function testNamespacedHelperNotFound(): void
{
$this->expectException(FileNotFoundException::class);
$locator = $this->getMockLocator();
Services::injectMock('locator', $locator);
helper('foo\barbaz');
}
public function testNamespacedHelperFound(): void
{
$autoloader = new Autoloader();
$autoloader->addNamespace('Tests\Support\Helpers', TESTPATH . '_support/Helpers');
$locator = new FileLocator($autoloader);
Services::injectMock('locator', $locator);
$found = true;
try {
helper('Tests\Support\Helpers\baguette');
} catch (FileNotFoundException) {
$found = false;
}
$this->assertTrue($found);
}
}