165 lines
5.6 KiB
PHP
165 lines
5.6 KiB
PHP
<?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() . '.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);
|
||
}
|
||
}
|