Bicycle/tests/Unit/ProfilerToolbarTest.php
Egor Isaev 9e20ae6c5f dev
2026-08-07 14:01:09 +03:00

165 lines
5.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use Services\Auth;
use Services\Database;
use Services\DataBase\Classes\Profiler;
use System\Classes\Config;
use System\Classes\MyException;
use System\Classes\ProfilerToolbar;
use System\Classes\Session;
class ProfilerToolbarTest extends TestCase
{
private string $users_file;
protected function setUp(): void
{
$this->users_file = sys_get_temp_dir() . '/bicycle_toolbar_users_' . uniqid('', true) . '.php';
file_put_contents($this->users_file, '<?php return ' . var_export([
'admin' => ['password' => password_hash('x', PASSWORD_DEFAULT), 'role' => 'admin'],
'bob' => ['password' => password_hash('x', PASSWORD_DEFAULT), 'role' => 'manager'],
], true) . ';');
Config::set('auth', ['driver' => 'file', 'users_file' => $this->users_file, 'session_key' => 'auth_user']);
// Другие тесты пишут в этот же статический реестр, если есть живое подключение к БД.
Profiler::reset();
}
protected function tearDown(): void
{
unlink($this->users_file);
Session::instance()->destroy();
Profiler::reset();
foreach ([Session::class, Auth::class] as $class) {
$ref = new ReflectionClass($class);
$prop = $ref->getProperty($class === Session::class ? 'instances' : '_instances');
$prop->setAccessible(true);
$prop->setValue(null, []);
}
$ref = new ReflectionClass(Config::class);
$prop = $ref->getProperty('config');
$prop->setAccessible(true);
$prop->setValue(null, null);
$ref = new ReflectionClass(ProfilerToolbar::class);
$prop = $ref->getProperty('_custom');
$prop->setAccessible(true);
$prop->setValue(null, []);
$ref = new ReflectionClass(Database::class);
$prop = $ref->getProperty('_instances');
$prop->setAccessible(true);
$prop->setValue(null, []);
}
public function testReturnsEmptyStringForGuest(): void
{
$this->assertSame('', ProfilerToolbar::render());
}
public function testReturnsEmptyStringForNonAdminRole(): void
{
Session::instance()->set('auth_user', 'bob');
$this->assertSame('', ProfilerToolbar::render());
}
public function testRendersPanelForAdmin(): void
{
Session::instance()->set('auth_user', 'admin');
$html = ProfilerToolbar::render();
$this->assertStringContainsString('Profiler', $html);
$this->assertStringContainsString('SQL', $html);
}
public function testIncludesProfilerEntries(): void
{
Session::instance()->set('auth_user', 'admin');
Profiler::log('SELECT * FROM users WHERE id = ?', [42], 1.23);
$html = ProfilerToolbar::render();
$this->assertStringContainsString('SELECT * FROM users WHERE id = ?', $html);
$this->assertStringContainsString('42', $html);
}
public function testHasVarsFilesAndRouteTabs(): void
{
Session::instance()->set('auth_user', 'admin');
$html = ProfilerToolbar::render();
$this->assertStringContainsString('Vars', $html);
$this->assertStringContainsString('Files', $html);
$this->assertStringContainsString('Route', $html);
}
public function testVarsTabMasksSensitiveKeys(): void
{
Session::instance()->set('auth_user', 'admin');
$_POST['password'] = 'super-secret';
$html = ProfilerToolbar::render();
$this->assertStringNotContainsString('super-secret', $html);
$this->assertStringContainsString('***', $html);
unset($_POST['password']);
}
public function testExplainShownForRealSelect(): void
{
try {
Database::instance()->exec('DROP TABLE IF EXISTS profiler_toolbar_test');
Database::instance()->exec('CREATE TABLE profiler_toolbar_test (id INT PRIMARY KEY)');
} catch (MyException $e) {
$this->markTestSkipped('Нет живого подключения к MariaDB: ' . $e->getMessage());
}
Session::instance()->set('auth_user', 'admin');
Database::instance()->query('SELECT * FROM profiler_toolbar_test WHERE id = ?', [1]);
$html = ProfilerToolbar::render();
Database::instance()->exec('DROP TABLE IF EXISTS profiler_toolbar_test');
$this->assertStringContainsString('ptb-explain', $html);
$this->assertStringContainsString('select_type', $html);
}
public function testExplainSkippedForNonSelect(): void
{
Session::instance()->set('auth_user', 'admin');
Profiler::log('DELETE FROM users WHERE id = ?', [1], 0.5);
$html = ProfilerToolbar::render();
// 'ptb-explain' сам по себе — ещё и имя CSS-класса в <style>, оно есть всегда;
// маркер реального EXPLAIN-результата — заголовок его колонки 'select_type'.
$this->assertStringNotContainsString('select_type', $html);
}
public function testCustomTabAppearsOnlyWhenDataAdded(): void
{
Session::instance()->set('auth_user', 'admin');
$this->assertStringNotContainsString('Custom', ProfilerToolbar::render());
ProfilerToolbar::addData(['foo' => 'bar'], 'my-debug');
$html = ProfilerToolbar::render();
$this->assertStringContainsString('Custom', $html);
$this->assertStringContainsString('my-debug', $html);
$this->assertStringContainsString('foo', $html);
}
}