test: 按模块导出接口重写黑盒判据(批次 8:embedding / generation / text / social)

4 个文件全部在 `<module>/test/`,源码目录仍零 `_test.go`。
共 18 条判据,只调导出接口,输入 → 可观察输出。

## pkg/embedding —— 注册表 + 校验

    TestRegisterThenOpen                 注册 → Names/Open → Info/Embed 输出
    TestOpenUnknownProviderReportsError  未注册名报错且可诊断
    TestValidateInfo                     维度/指纹真值表
    TestValidateVector                   维度不符 / NaN / Inf 必拒

## pkg/generation —— 注册表

    TestRegisterThenOpen                 注册 → Names/Open → Info/Generate 输出
    TestOpenUnknownProviderReportsError  未注册名报错

## internal/memory/text —— 真实临时目录

    TestAppendThenRecentEvents           Append → RecentEvents 读回内容
    TestReplayVisitsAppendedEvents       Replay 收到全部事件
    TestFileCountAndStats                写后文件数/统计可用

## internal/memory/social —— 真实内存图库

    TestNilDBReportsError                无图库时写操作报错(不静默)
    TestSetTraitThenGetTrait             特质往返
    TestSetTraitOverwrites               同键覆盖
    TestAddRelationThenGetRelations      关系往返
    TestListPersons                      人物列表含已写入的人

## 变异验证(改回旧实现必须红)

    embedding 非有限值检查留 NaN 通过 → ★ 非法向量被接受:[NaN 2 3]
    generation 未注册名静默返回 nil   → ★ 未注册 provider 的报错不可诊断
    text       Append 不写盘          → ★ RecentEvents = 0 条
    social     SetTrait 不写          → ★ 无图库却 SetTrait 成功

前两条第一版变异分别造成「编译失败(math 未使用)」和「panic」,
不是干净的断言红 —— 改成只改行为、仍能编译的变异后确认有效。

## 验证

    go build ./...                            PASS
    go vet ./...                              PASS
    gofmt -l                                  干净
    python3 .github/scripts/check-ci-gates.py PASS
    go test ./... -count=1                    32 个测试包 / 100 包无测试 / 0 FAIL
    4 个新包 -race                            全绿
    源码目录 _test.go                         0
This commit is contained in:
JianFeeeee
2026-11-09 13:55:15 +08:00
parent 379300d89c
commit ac525670d1
4 changed files with 307 additions and 0 deletions

View File

@ -0,0 +1,94 @@
package test
// pkg/embedding 的黑盒判据:Register → Names/Open → 输出;Validate* 的输入→输出。
// 不碰 registry map。
import (
"context"
"math"
"strings"
"testing"
"github.com/JianFeeeee/HologramAgent/pkg/embedding"
)
type stubProvider struct{ dim int }
func (p *stubProvider) Embed(ctx context.Context, in embedding.Input) ([]float64, error) {
return make([]float64, p.dim), nil
}
func (p *stubProvider) Info() embedding.Info {
return embedding.Info{Dimension: p.dim, Fingerprint: "stub-fp"}
}
func (p *stubProvider) Close() {}
// TestRegisterThenOpen:注册后 Names/Open 能取回该 provider,且 Info 正确。
func TestRegisterThenOpen(t *testing.T) {
const name = "contract-embed-provider"
embedding.Register(name, func(cfg embedding.Config) (embedding.Provider, error) {
return &stubProvider{dim: 8}, nil
})
found := false
for _, n := range embedding.Names() {
if n == name {
found = true
}
}
if !found {
t.Fatal("★ Names() 里没有刚注册的 provider")
}
p, err := embedding.Open(name, embedding.Config{})
if err != nil {
t.Fatalf("Open: %v", err)
}
defer p.Close()
if got := p.Info().Dimension; got != 8 {
t.Fatalf("★ Info.Dimension = %d,期望 8", got)
}
vec, err := p.Embed(context.Background(), embedding.Input{Text: "x"})
if err != nil || len(vec) != 8 {
t.Fatalf("★ Embed = %v / %v", vec, err)
}
}
// TestOpenUnknownProviderReportsError:未注册名字报错且列出可用项。
func TestOpenUnknownProviderReportsError(t *testing.T) {
_, err := embedding.Open("definitely-not-registered-xyz", embedding.Config{})
if err == nil {
t.Fatal("★ 未注册 provider 却 Open 成功")
}
if !strings.Contains(err.Error(), "unknown provider") {
t.Fatalf("★ 报错信息不可诊断:%v", err)
}
}
// TestValidateInfo:维度/指纹的输入→输出。
func TestValidateInfo(t *testing.T) {
cases := []struct {
info embedding.Info
wantErr bool
}{
{embedding.Info{Dimension: 3, Fingerprint: "fp"}, false},
{embedding.Info{Dimension: 0, Fingerprint: "fp"}, true},
{embedding.Info{Dimension: -1, Fingerprint: "fp"}, true},
{embedding.Info{Dimension: 3, Fingerprint: " "}, true},
}
for _, c := range cases {
err := embedding.ValidateInfo(c.info)
if (err != nil) != c.wantErr {
t.Errorf("★ ValidateInfo(%+v) err=%v,wantErr=%v", c.info, err, c.wantErr)
}
}
}
// TestValidateVector:维度不符 / NaN / Inf 必须报错。
func TestValidateVector(t *testing.T) {
if err := embedding.ValidateVector([]float64{1, 2, 3}, 3); err != nil {
t.Fatalf("★ 合法向量被拒:%v", err)
}
for _, bad := range [][]float64{{1, 2}, {math.NaN(), 2, 3}, {math.Inf(1), 2, 3}} {
if err := embedding.ValidateVector(bad, 3); err == nil {
t.Fatalf("★ 非法向量被接受:%v", bad)
}
}
}