添加新的工具功能和测试覆盖:
- 注册 `LsTool` 和 `BashTool` 工具,支持目录操作和命令执行 - 增强工具调用逻辑,添加日志记录以提升调试能力 - 增加 `ToolRegistry` 和 `RunLoop` 的增量累积与排序优化 - 完善单元测试覆盖新工具的执行与行为验证
This commit is contained in:
189
tests/Unit/LsToolTest.php
Normal file
189
tests/Unit/LsToolTest.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Services\Tool\Tools\LsTool;
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class LsToolTest extends TestCase
|
||||
{
|
||||
private string $tempDirectory;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$base = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR);
|
||||
$this->tempDirectory = $base.DIRECTORY_SEPARATOR.'ls-tool-'.bin2hex(random_bytes(8));
|
||||
|
||||
if (! mkdir($this->tempDirectory, 0777, true) && ! is_dir($this->tempDirectory)) {
|
||||
$this->fail('无法创建临时目录:'.$this->tempDirectory);
|
||||
}
|
||||
|
||||
file_put_contents($this->tempDirectory.DIRECTORY_SEPARATOR.'a.txt', 'a');
|
||||
file_put_contents($this->tempDirectory.DIRECTORY_SEPARATOR.'b.php', '<?php echo 1;');
|
||||
file_put_contents($this->tempDirectory.DIRECTORY_SEPARATOR.'.env', 'KEY=VALUE');
|
||||
|
||||
mkdir($this->tempDirectory.DIRECTORY_SEPARATOR.'dir', 0777, true);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->deleteDirectory($this->tempDirectory);
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_execute_lists_entries_in_directory(): void
|
||||
{
|
||||
$tool = new LsTool;
|
||||
$result = $tool->execute(['directory' => $this->tempDirectory]);
|
||||
|
||||
$this->assertSame($this->tempDirectory, $result['directory']);
|
||||
$this->assertSame(['.env', 'a.txt', 'b.php', 'dir'], $result['entries']);
|
||||
}
|
||||
|
||||
public function test_execute_can_exclude_hidden_entries(): void
|
||||
{
|
||||
$tool = new LsTool;
|
||||
$result = $tool->execute([
|
||||
'directory' => $this->tempDirectory,
|
||||
'include_hidden' => false,
|
||||
]);
|
||||
|
||||
$this->assertSame(['a.txt', 'b.php', 'dir'], $result['entries']);
|
||||
}
|
||||
|
||||
public function test_execute_can_filter_files_only(): void
|
||||
{
|
||||
$tool = new LsTool;
|
||||
$result = $tool->execute([
|
||||
'directory' => $this->tempDirectory,
|
||||
'filter' => 'files',
|
||||
]);
|
||||
|
||||
$this->assertSame(['.env', 'a.txt', 'b.php'], $result['entries']);
|
||||
}
|
||||
|
||||
public function test_execute_can_filter_directories_only(): void
|
||||
{
|
||||
$tool = new LsTool;
|
||||
$result = $tool->execute([
|
||||
'directory' => $this->tempDirectory,
|
||||
'filter' => 'directories',
|
||||
]);
|
||||
|
||||
$this->assertSame(['dir'], $result['entries']);
|
||||
}
|
||||
|
||||
public function test_execute_can_match_glob_pattern(): void
|
||||
{
|
||||
$tool = new LsTool;
|
||||
$result = $tool->execute([
|
||||
'directory' => $this->tempDirectory,
|
||||
'match' => '*.php',
|
||||
]);
|
||||
|
||||
$this->assertSame(['b.php'], $result['entries']);
|
||||
}
|
||||
|
||||
public function test_execute_can_return_details(): void
|
||||
{
|
||||
$tool = new LsTool;
|
||||
$result = $tool->execute([
|
||||
'directory' => $this->tempDirectory,
|
||||
'details' => true,
|
||||
]);
|
||||
|
||||
$this->assertCount(4, $result['entries']);
|
||||
|
||||
$fileEntry = $this->findEntry($result['entries'], 'a.txt');
|
||||
$this->assertSame('file', $fileEntry['type']);
|
||||
$this->assertIsInt($fileEntry['size']);
|
||||
$this->assertIsInt($fileEntry['modified_at']);
|
||||
|
||||
$dirEntry = $this->findEntry($result['entries'], 'dir');
|
||||
$this->assertSame('directory', $dirEntry['type']);
|
||||
$this->assertNull($dirEntry['size']);
|
||||
}
|
||||
|
||||
public function test_execute_can_sort_by_mtime_desc(): void
|
||||
{
|
||||
$mtimeDirectory = $this->tempDirectory.DIRECTORY_SEPARATOR.'mtime';
|
||||
mkdir($mtimeDirectory, 0777, true);
|
||||
|
||||
$older = $mtimeDirectory.DIRECTORY_SEPARATOR.'older.txt';
|
||||
$newer = $mtimeDirectory.DIRECTORY_SEPARATOR.'newer.txt';
|
||||
|
||||
file_put_contents($older, 'old');
|
||||
file_put_contents($newer, 'new');
|
||||
|
||||
$now = time();
|
||||
touch($older, $now - 10);
|
||||
touch($newer, $now - 5);
|
||||
|
||||
$tool = new LsTool;
|
||||
$result = $tool->execute([
|
||||
'directory' => $mtimeDirectory,
|
||||
'include_hidden' => false,
|
||||
'sort' => 'mtime_desc',
|
||||
'filter' => 'files',
|
||||
'match' => '*.txt',
|
||||
]);
|
||||
|
||||
$this->assertSame(['newer.txt', 'older.txt'], $result['entries']);
|
||||
}
|
||||
|
||||
public function test_execute_throws_when_directory_is_invalid(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
||||
$tool = new LsTool;
|
||||
$tool->execute(['directory' => $this->tempDirectory.DIRECTORY_SEPARATOR.'missing']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $entries
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function findEntry(array $entries, string $name): array
|
||||
{
|
||||
foreach ($entries as $entry) {
|
||||
if (($entry['name'] ?? null) === $name) {
|
||||
return $entry;
|
||||
}
|
||||
}
|
||||
|
||||
$this->fail('未找到条目:'.$name);
|
||||
}
|
||||
|
||||
private function deleteDirectory(string $directory): void
|
||||
{
|
||||
if (! is_dir($directory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$items = scandir($directory);
|
||||
if ($items === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item === '.' || $item === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $directory.DIRECTORY_SEPARATOR.$item;
|
||||
if (is_dir($path)) {
|
||||
$this->deleteDirectory($path);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@unlink($path);
|
||||
}
|
||||
|
||||
@rmdir($directory);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user