Files
HomeAgent/pkg/embedding/test/registry_contract_test.go
JianFeeeee ac525670d1 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
2026-11-09 13:55:15 +08:00

95 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
}
}