mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-10-30 01:18:22 +08:00
82 lines
3.9 KiB
PHP
82 lines
3.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace tests\Unit;
|
||
|
||
use app\admin\service\AdminUpdateService;
|
||
use PHPUnit\Framework\TestCase;
|
||
|
||
/**
|
||
* AdminUpdateServiceBase::testIsOptionalFiles 分类矩阵单元测试(纯单元,不触 DB).
|
||
*
|
||
* 锚定 .agents 项目自维护文件改判"可选更新"的行为:
|
||
* - .agents/PROJECT.md(精确匹配)与 .agents/rules/project- 前缀文件属项目自维护,
|
||
* 升级时必须判为可选(optional=true),防止被强制覆盖/强制删除
|
||
* - .agents 其余内容(ulthon-* 规则、skills、非精确路径、无连字符文件名)保持强制(false)
|
||
*
|
||
* 22 用例 = 可选 12 + 强制 10。用 PHPUnit 10 属性式 DataProvider(不支持 @dataProvider 注解),
|
||
* 每个用例独立成测试,红/绿状态可逐例观察。
|
||
*/
|
||
class AdminUpdateServiceOptionalFilesTest extends TestCase
|
||
{
|
||
/**
|
||
* 通过匿名类暴露 protected testIsOptionalFiles(构造函数仅设常量属性,无副作用).
|
||
*/
|
||
private function makeExposer(): object
|
||
{
|
||
return new class extends AdminUpdateService {
|
||
public function expose(string $path): bool
|
||
{
|
||
return $this->testIsOptionalFiles($path);
|
||
}
|
||
};
|
||
}
|
||
|
||
public static function classificationProvider(): iterable
|
||
{
|
||
// 可选(true) 12 例:既有规则覆盖 8 例 + .agents 项目自维护新规则 4 例
|
||
yield 'optional: root AGENTS.md' => ['AGENTS.md', true];
|
||
yield 'optional: root composer.json' => ['composer.json', true];
|
||
yield 'optional: root .php-cs-fixer.php' => ['.php-cs-fixer.php', true];
|
||
yield 'optional: app prefix' => ['app/common/service/X.php', true];
|
||
yield 'optional: config prefix' => ['config/app.php', true];
|
||
yield 'optional: route prefix' => ['route/app.php', true];
|
||
yield 'optional: source/docker prefix' => ['source/docker/Dockerfile', true];
|
||
yield 'optional: extend/think prefix' => ['extend/think/store/X.php', true];
|
||
yield 'optional: .agents/PROJECT.md exact' => ['.agents/PROJECT.md', true];
|
||
yield 'optional: project rule flat' => ['.agents/rules/project-dev-runtime-deploy.md', true];
|
||
yield 'optional: project rule flat 2' => ['.agents/rules/project-account-system.md', true];
|
||
yield 'optional: project rule nested' => ['.agents/rules/project-deploy-detail/sub.md', true];
|
||
|
||
// 强制(false) 10 例:核心入口、框架内核、静态资源、迁移、.agents 其余内容
|
||
yield 'force: think entry' => ['think', false];
|
||
yield 'force: extend/base kernel' => ['extend/base/admin/service/AdminUpdateServiceBase.php', false];
|
||
yield 'force: public static' => ['public/static/common/css/a.css', false];
|
||
yield 'force: database migrations' => ['database/migrations/2024.php', false];
|
||
yield 'force: ulthon rule' => ['.agents/rules/ulthon-naming-convention.md', false];
|
||
yield 'force: ulthon skill' => ['.agents/skills/ulthon-timer/SKILL.md', false];
|
||
yield 'force: project skill (skills 始终强制)' => ['.agents/skills/project-x/SKILL.md', false];
|
||
yield 'force: project.md 无连字符不匹配前缀' => ['.agents/rules/project.md', false];
|
||
yield 'force: .agents/PROJECT 非精确不匹配' => ['.agents/PROJECT/about.md', false];
|
||
yield 'force: .agents/rules/.README' => ['.agents/rules/.README', false];
|
||
}
|
||
|
||
#[\PHPUnit\Framework\Attributes\DataProvider('classificationProvider')]
|
||
public function test_classification(string $path, bool $expectedOptional): void
|
||
{
|
||
$exposer = $this->makeExposer();
|
||
|
||
$this->assertSame(
|
||
$expectedOptional,
|
||
$exposer->expose($path),
|
||
sprintf(
|
||
'路径 %s 分类不符:预期%s,实际%s',
|
||
$path,
|
||
$expectedOptional ? '可选(true)' : '强制(false)',
|
||
$expectedOptional ? '强制(false)' : '可选(true)'
|
||
)
|
||
);
|
||
}
|
||
}
|