mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-03-17 20:54:52 +08:00
commit
1e037b9610
@ -31,7 +31,9 @@
|
||||
"require-dev": {
|
||||
"brainmaestro/composer-git-hooks": "^3.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.2 != 3.7.0",
|
||||
"jangregor/phpstan-prophecy": "^1.0",
|
||||
"jetbrains/phpstorm-attributes": "^1.0",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"phpspec/prophecy": "1.x-dev",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan": "^1.1",
|
||||
|
||||
@ -129,9 +129,6 @@ class FileSystem
|
||||
$tokens = \PhpToken::tokenize(file_get_contents($path));
|
||||
$found = false;
|
||||
foreach ($tokens as $token) {
|
||||
if (!$token instanceof \PhpToken) {
|
||||
continue;
|
||||
}
|
||||
if ($token->is(T_CLASS)) {
|
||||
$found = true;
|
||||
break;
|
||||
|
||||
@ -11,7 +11,7 @@ class CatCode
|
||||
/**
|
||||
* 从 MessageSegment 转换为 CatCode 字符串
|
||||
*/
|
||||
public static function fromSegment(mixed $message_segment): string
|
||||
public static function fromSegment(array|MessageSegment|string $message_segment): string
|
||||
{
|
||||
// 传入的必须是段数组或段对象
|
||||
if (is_array($message_segment)) {
|
||||
@ -24,13 +24,12 @@ class CatCode
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
if ($message_segment instanceof MessageSegment) {
|
||||
return self::segment2CatCode($message_segment);
|
||||
}
|
||||
if (is_string($message_segment)) {
|
||||
return $message_segment;
|
||||
}
|
||||
return '';
|
||||
|
||||
return $message_segment;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -4,8 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\Trait;
|
||||
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\Prophet;
|
||||
use Psr\Log\AbstractLogger;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* 模拟 Logger 行为
|
||||
@ -36,9 +38,21 @@ trait HasLogger
|
||||
private function startMockLogger(): void
|
||||
{
|
||||
$logger = $this->prophet->prophesize(AbstractLogger::class);
|
||||
$logger->log()->will(function ($args) {
|
||||
$this->mockLog(...$args);
|
||||
});
|
||||
$levels = [
|
||||
LogLevel::EMERGENCY,
|
||||
LogLevel::ALERT,
|
||||
LogLevel::CRITICAL,
|
||||
LogLevel::ERROR,
|
||||
LogLevel::WARNING,
|
||||
LogLevel::NOTICE,
|
||||
LogLevel::INFO,
|
||||
LogLevel::DEBUG,
|
||||
];
|
||||
$log_it = fn (...$args) => $this->mockLog(...$args);
|
||||
foreach ($levels as $level) {
|
||||
$logger->{$level}(Argument::type('string'), Argument::any())->will(fn ($args) => $log_it($level, ...$args));
|
||||
}
|
||||
$logger->log(Argument::in($levels), Argument::type('string'), Argument::any())->will(fn ($args) => $log_it(...$args));
|
||||
ob_logger_register($logger->reveal());
|
||||
}
|
||||
}
|
||||
|
||||
18
tests/Trait/HasVirtualFileSystem.php
Normal file
18
tests/Trait/HasVirtualFileSystem.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Trait;
|
||||
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
use org\bovigo\vfs\vfsStreamDirectory;
|
||||
|
||||
trait HasVirtualFileSystem
|
||||
{
|
||||
private vfsStreamDirectory $vfs;
|
||||
|
||||
private function setUpVfs(string $dir = 'root'): void
|
||||
{
|
||||
$this->vfs = vfsStream::setup($dir);
|
||||
}
|
||||
}
|
||||
133
tests/ZM/Store/FileSystemTest.php
Normal file
133
tests/ZM/Store/FileSystemTest.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\ZM\Store;
|
||||
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
use Tests\TestCase;
|
||||
use Tests\Trait\HasLogger;
|
||||
use Tests\Trait\HasVirtualFileSystem;
|
||||
use ZM\Store\FileSystem;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class FileSystemTest extends TestCase
|
||||
{
|
||||
use HasVirtualFileSystem;
|
||||
use HasLogger;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->setUpVfs();
|
||||
$this->startMockLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideTestDetermineRelativePath
|
||||
*/
|
||||
public function testDetermineRelativePath(string $path, bool $expected): void
|
||||
{
|
||||
$this->assertSame($expected, FileSystem::isRelativePath($path));
|
||||
}
|
||||
|
||||
public function provideTestDetermineRelativePath(): array
|
||||
{
|
||||
return [
|
||||
'relative' => ['relative/path', true],
|
||||
'absolute' => ['/absolute/path', false],
|
||||
'windows' => ['C:\Windows', !(DIRECTORY_SEPARATOR === '\\')],
|
||||
];
|
||||
}
|
||||
|
||||
public function testCreateDirectoryWithNoPerm(): void
|
||||
{
|
||||
$old_perm = $this->vfs->getPermissions();
|
||||
$this->vfs->chmod(0000);
|
||||
$this->assertFalse($this->vfs->hasChild('test'));
|
||||
$this->expectExceptionMessageMatches('/无法建立目录/');
|
||||
FileSystem::createDir($this->vfs->url() . '/test');
|
||||
$this->vfs->chmod($old_perm);
|
||||
}
|
||||
|
||||
public function testCreateDirectory(): void
|
||||
{
|
||||
$this->assertFalse($this->vfs->hasChild('test'));
|
||||
FileSystem::createDir($this->vfs->url() . '/test');
|
||||
$this->assertTrue($this->vfs->hasChild('test'));
|
||||
}
|
||||
|
||||
public function testGetReloadableFiles(): void
|
||||
{
|
||||
$files = FileSystem::getReloadableFiles();
|
||||
$this->assertIsArray($files);
|
||||
$this->assertNotEmpty($files);
|
||||
}
|
||||
|
||||
public function testGetClassesPsr4(): void
|
||||
{
|
||||
vfsStream::create([
|
||||
'Foo' => [
|
||||
'Bar.php' => '<?php namespace Foo; class Bar {}',
|
||||
'Baz.php' => '<?php namespace Foo; class Baz {}',
|
||||
'Qux' => [
|
||||
'Quux.php' => '<?php namespace Bar\Qux; class Quux {}',
|
||||
],
|
||||
],
|
||||
'Chore' => [
|
||||
'global.php' => '<?php function global_function() {}',
|
||||
'global_classes.php' => '<?php class GlobalClass {}',
|
||||
],
|
||||
'Baz.php.ignore' => '',
|
||||
], $this->vfs);
|
||||
$classes = FileSystem::getClassesPsr4($this->vfs->url(), '');
|
||||
$this->assertSame([
|
||||
'\Foo\Bar',
|
||||
'\Foo\Qux\Quux',
|
||||
], $classes);
|
||||
}
|
||||
|
||||
public function testGetClassesPsr4WithCustomRule(): void
|
||||
{
|
||||
vfsStream::create([
|
||||
'Foo' => [
|
||||
'Bar.php' => '<?php namespace Foo; class Bar {}',
|
||||
'Baz.php' => '<?php namespace Foo; class Baz {}',
|
||||
],
|
||||
], $this->vfs);
|
||||
$classes = FileSystem::getClassesPsr4($this->vfs->url(), '', fn (string $dir, array $pathinfo) => $pathinfo['filename'] === 'Bar');
|
||||
$this->assertSame(['\Foo\Bar'], $classes);
|
||||
}
|
||||
|
||||
public function testGetClassesPsr4WithReturnPath(): void
|
||||
{
|
||||
vfsStream::create([
|
||||
'Foo' => [
|
||||
'Bar.php' => '<?php namespace Foo; class Bar {}',
|
||||
'Baz.php' => '<?php namespace Foo; class Baz {}',
|
||||
],
|
||||
], $this->vfs);
|
||||
$classes = FileSystem::getClassesPsr4($this->vfs->url(), '', return_path_value: 'my_path');
|
||||
$this->assertSame([
|
||||
'\Foo\Bar' => 'my_path/Foo/Bar.php',
|
||||
'\Foo\Baz' => 'my_path/Foo/Baz.php',
|
||||
], $classes);
|
||||
}
|
||||
|
||||
public function testScanDirFilesWithNotExistsDir(): void
|
||||
{
|
||||
FileSystem::scanDirFiles($this->vfs->url() . '/not_exists');
|
||||
$this->assertLogged('warning', zm_internal_errcode('E00080') . '扫描目录失败,目录不存在');
|
||||
}
|
||||
|
||||
public function testScanDirFilesWithNoPerm(): void
|
||||
{
|
||||
$old_perm = $this->vfs->getPermissions();
|
||||
$this->vfs->chmod(0000);
|
||||
FileSystem::scanDirFiles($this->vfs->url());
|
||||
$this->assertLogged('warning', zm_internal_errcode('E00080') . '扫描目录失败,目录无法读取: ' . $this->vfs->url());
|
||||
$this->vfs->chmod($old_perm);
|
||||
}
|
||||
}
|
||||
74
tests/ZM/Utils/CatCodeTest.php
Normal file
74
tests/ZM/Utils/CatCodeTest.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\ZM\Utils;
|
||||
|
||||
use OneBot\V12\Object\MessageSegment;
|
||||
use Tests\TestCase;
|
||||
use ZM\Utils\CatCode;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class CatCodeTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideTestConvertFromSegment
|
||||
*/
|
||||
public function testConvertFromSegment(mixed $segment, string $expected): void
|
||||
{
|
||||
$this->assertSame($expected, CatCode::fromSegment($segment));
|
||||
}
|
||||
|
||||
public function provideTestConvertFromSegment(): array
|
||||
{
|
||||
return [
|
||||
'string' => ['[CatCode:mention,user_id=123456789]', '[CatCode:mention,user_id=123456789]'],
|
||||
'segment instance' => [new MessageSegment('mention', ['user_id' => '123456789']), '[CatCode:mention,user_id=123456789]'],
|
||||
'multiple segment instance' => [
|
||||
[
|
||||
new MessageSegment('mention', ['user_id' => '123456789']),
|
||||
new MessageSegment('text', ['text' => 'Hello']),
|
||||
],
|
||||
'[CatCode:mention,user_id=123456789]Hello',
|
||||
],
|
||||
'array contains non-segment' => [
|
||||
[
|
||||
new MessageSegment('mention', ['user_id' => '123456789']),
|
||||
'Hello',
|
||||
],
|
||||
'',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideTestEscapeText
|
||||
*/
|
||||
public function testEscapeText(string $text): void
|
||||
{
|
||||
$encoded = CatCode::encode($text);
|
||||
$decoded = CatCode::decode($encoded);
|
||||
$this->assertSame($text, $decoded);
|
||||
}
|
||||
|
||||
public function provideTestEscapeText(): array
|
||||
{
|
||||
return [
|
||||
["前缀是'['后缀是']', 还有以及一个特殊的&"],
|
||||
["[前缀是'['后缀是']', 还有以及一个特殊的&"],
|
||||
["前缀是'['后缀是']', 还有以及一个特殊的"],
|
||||
["&前缀是'['后缀是']', 还有以及一个特殊的"],
|
||||
["&前缀是'['后缀是']', 还有以及一个特殊的]"],
|
||||
];
|
||||
}
|
||||
|
||||
public function testEscapeTextForContent(): void
|
||||
{
|
||||
$text = "前缀是'['后缀是']', 还有以及一个特殊的&";
|
||||
$encoded = CatCode::encode($text, true);
|
||||
$decoded = CatCode::decode($encoded, true);
|
||||
$this->assertSame($text, $decoded);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user