mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-12 20:27:30 +00:00
4 个文件全部在 `<module>/test/`,源码目录仍零 `_test.go`。
共 21 条判据,只调导出接口,输入 → 可观察输出。
## internal/promptsec —— NewRegistry/Declare/Render/Snapshot/Names
TestDeclareThenRender 声明两段,按 Order 输出且含正文
TestDeclareRejectsMismatchedOwner 段名前缀与 Owner 不符必须报错
TestDeclareIsIdempotent 同段名覆盖,不产生两份
TestEmptyContentRemovesSection 空正文 = 撤销声明
TestRemoveOwnerOnlyDropsThatOwner 撤销一个 owner 不影响其他
TestSnapshotReturnsAllSections 快照反映当前声明
## internal/toolroute —— Dispatch
TestDispatchRoutesEachPrefix 15 种工具前缀 → 对应族处理器
TestDispatchGetPluginToolsExtractsArg plugin_name 参数透传
TestDispatchUnknownIsNotSwallowed 未知工具 handled=false(插件工具不能消失)
TestDispatchNilHandlers nil handlers 不 panic
用 recordingHandlers 记录哪个族被调用,不断言内部 switch 结构。
## internal/pluginview —— 事件 → Snapshot
TestFreshViewIsEmpty 新视图为空
TestCmdRunEventAppearsInSnapshot cmd_run → 命令历史
TestTerminalCreateThenOutput terminal_create + 输出 → 终端状态
TestUnknownToolIsIgnored 未知工具不造记录
**判据写错过一次**:`OnTerminalOutput` 的 payload 键是 `terminal_id`
不是 `id`,第一版按 `id` 写 ⇒ 输出没进 Snapshot。按真实输入契约修正。
## internal/meta —— 版本元信息
TestFullVersionContainsKernelAndVersion
TestSourceURLLooksLikeHTTPS
TestLicenseMetadataNotEmpty
TestSDKCompatibleVersionIsSemverLike
## 变异验证(改回旧实现必须红)
promptsec Declare 直接 return nil → ★ Render 缺正文
toolroute 未知工具 handled=true → ★ 未知工具被吞掉
pluginview cmd_run 不记录 → ★ cmd_run 未进命令历史
meta FullVersion 丢版本 → ★ 不含 "1.4.0"
第一版 promptsec 变异改的是条件中的一段 token、没改变行为(空变异),
重做后确认判据有效。
## 验证
go build ./... PASS
go vet ./... PASS
gofmt -l 干净
python3 .github/scripts/check-ci-gates.py PASS
go test ./... -count=1 24 个测试包 / 100 包无测试 / 0 FAIL
4 个新包 -race 全绿
源码目录 _test.go 0
99 lines
3.2 KiB
Go
99 lines
3.2 KiB
Go
package test
|
||
|
||
// internal/promptsec 的黑盒判据:NewRegistry → Declare → Render/Snapshot/Names。
|
||
// 输入 Section → 输出渲染文本。不碰 r.sections。
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
|
||
"github.com/JianFeeeee/HologramAgent/internal/promptsec"
|
||
)
|
||
|
||
func sec(owner, name, content string, order int) promptsec.Section {
|
||
return promptsec.Section{Owner: owner, Section: owner + "." + name, Content: content, Order: order}
|
||
}
|
||
|
||
// TestDeclareThenRender:声明两段,Render 按 Order 输出且含正文。
|
||
func TestDeclareThenRender(t *testing.T) {
|
||
r := promptsec.NewRegistry()
|
||
if err := r.Declare(sec("alpha", "late", "后面这段", 20)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := r.Declare(sec("beta", "early", "前面这段", 10)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
out := r.Render()
|
||
if !strings.Contains(out, "前面这段") || !strings.Contains(out, "后面这段") {
|
||
t.Fatalf("★ Render 缺正文:%q", out)
|
||
}
|
||
if strings.Index(out, "前面这段") > strings.Index(out, "后面这段") {
|
||
t.Fatalf("★ Order 未生效:%q", out)
|
||
}
|
||
}
|
||
|
||
// TestDeclareRejectsMismatchedOwner:段名前缀与 Owner 不符必须报错。
|
||
func TestDeclareRejectsMismatchedOwner(t *testing.T) {
|
||
r := promptsec.NewRegistry()
|
||
cases := []promptsec.Section{
|
||
{Owner: "alpha", Section: "beta.x", Content: "v"},
|
||
{Owner: "", Section: "alpha.x", Content: "v"},
|
||
{Owner: "alpha", Section: "alpha", Content: "v"},
|
||
{Owner: "alpha", Section: "alpha.", Content: "v"},
|
||
}
|
||
for _, s := range cases {
|
||
if err := r.Declare(s); err == nil {
|
||
t.Fatalf("★ 非法声明被接受:%+v", s)
|
||
}
|
||
}
|
||
if got := r.Render(); got != "" {
|
||
t.Fatalf("★ 非法声明后 Render 非空:%q", got)
|
||
}
|
||
}
|
||
|
||
// TestDeclareIsIdempotent:同段名覆盖,不产生两份。
|
||
func TestDeclareIsIdempotent(t *testing.T) {
|
||
r := promptsec.NewRegistry()
|
||
_ = r.Declare(sec("a", "x", "旧内容", 1))
|
||
_ = r.Declare(sec("a", "x", "新内容", 1))
|
||
if got := r.Names(); len(got) != 1 {
|
||
t.Fatalf("★ Names = %v,期望 1 段", got)
|
||
}
|
||
out := r.Render()
|
||
if strings.Contains(out, "旧内容") || !strings.Contains(out, "新内容") {
|
||
t.Fatalf("★ 覆盖未生效:%q", out)
|
||
}
|
||
}
|
||
|
||
// TestEmptyContentRemovesSection:空正文 = 撤销声明。
|
||
func TestEmptyContentRemovesSection(t *testing.T) {
|
||
r := promptsec.NewRegistry()
|
||
_ = r.Declare(sec("a", "x", "有内容", 1))
|
||
_ = r.Declare(sec("a", "x", "", 1))
|
||
if got := r.Names(); len(got) != 0 {
|
||
t.Fatalf("★ 空正文未撤销:%v", got)
|
||
}
|
||
}
|
||
|
||
// TestRemoveOwnerOnlyDropsThatOwner:撤销一个 owner 不影响其他 owner。
|
||
func TestRemoveOwnerOnlyDropsThatOwner(t *testing.T) {
|
||
r := promptsec.NewRegistry()
|
||
_ = r.Declare(sec("a", "x", "A", 1))
|
||
_ = r.Declare(sec("b", "x", "B", 2))
|
||
r.RemoveOwner("a")
|
||
out := r.Render()
|
||
if strings.Contains(out, "A") || !strings.Contains(out, "B") {
|
||
t.Fatalf("★ RemoveOwner 误删/漏删:%q", out)
|
||
}
|
||
}
|
||
|
||
// TestSnapshotReturnsAllSections:Snapshot 输出反映当前声明。
|
||
func TestSnapshotReturnsAllSections(t *testing.T) {
|
||
r := promptsec.NewRegistry()
|
||
_ = r.Declare(sec("a", "x", "A", 1))
|
||
_ = r.Declare(sec("b", "y", "B", 2))
|
||
if got := r.Snapshot(); len(got) != 2 {
|
||
t.Fatalf("★ Snapshot = %d 段,期望 2", len(got))
|
||
}
|
||
}
|