Files
Cyrene_v2/internal/runtime/memory/rules_test.go
T
AskaEth 61cf80d5ee
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(comments): 注释中文化 · internal/runtime/memory(31 文件,纯替换)
- 只翻注释/文档字符串:820 增 / 820 删 严格 1:1;剥掉整行注释与行尾注释尾巴后,
  逐文件与 HEAD 比对「代码部分差异 = 0」;裁决/design 编号计数逐项与 HEAD 一致
- 保留可执行 SQL 样例、SQLite 报错原文、pgvector/HNSW/ANN/BLOB 等技术词原文
- 复核:go build 绿 + memory/projectindex/vector 三包测试绿;gofmt 仅剩 2 个既有未格式化文件(改动前即如此,未顺手修)
2026-10-04 13:32:54 +08:00

218 lines
6.4 KiB
Go

package memory
import (
"context"
"errors"
"testing"
)
func TestStore_ListScope_User_全局共享(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
for _, p := range []string{"persona.a", "persona.b"} {
if _, err := s.AddScoped(ctx, p, MemoryItem{
PersonaID: p, Scope: ScopeUser, Kind: KindRelationship,
Content: "用户习惯-" + p,
}); err != nil {
t.Fatalf("AddScoped user for %s: %v", p, err)
}
}
// persona.a 能看到两个角色的用户作用域条目(全局共享)。
items, err := s.ListScope(ctx, ScopeUser, "persona.a")
if err != nil {
t.Fatalf("ListScope user: %v", err)
}
if len(items) != 2 {
t.Fatalf("ListScope(user) = %d items, want 2 (globally shared)", len(items))
}
}
func TestStore_ListScope_Persona_其他角色只读(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
if _, err := s.AddScoped(ctx, "persona.a", MemoryItem{
Scope: ScopePersona, Kind: KindWorldEvent, Content: "a的日常",
}); err != nil {
t.Fatalf("AddScoped persona.a: %v", err)
}
// persona.b 可以读 persona.a 的角色作用域条目(只读规则)。
items, err := s.ListScope(ctx, ScopePersona, "persona.b")
if err != nil {
t.Fatalf("ListScope persona for b: %v", err)
}
if len(items) != 1 || items[0].PersonaID != "persona.a" {
t.Fatalf("ListScope(persona) for persona.b = %+v, want persona.a's item", items)
}
// AddScoped 用实施动作者自动填充了 PersonaID。
if items[0].PersonaID != "persona.a" {
t.Errorf("owner persona = %q, want persona.a", items[0].PersonaID)
}
}
func TestStore_AddScoped_Persona_跨角色写_异常(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
if _, err := s.AddScoped(ctx, "persona.a", MemoryItem{
Scope: ScopePersona, Kind: KindRelationship, Content: "a的日常",
}); err != nil {
t.Fatalf("AddScoped persona.a: %v", err)
}
// persona.b 不能写 persona.a 的角色作用域条目。
_, err := s.AddScoped(ctx, "persona.b", MemoryItem{
PersonaID: "persona.a", Scope: ScopePersona, Kind: KindRelationship,
Content: "b想改a的日常",
})
if !errors.Is(err, ErrReadOnly) {
t.Fatalf("AddScoped cross-persona err = %v, want wrap of ErrReadOnly", err)
}
}
func TestStore_AddScoped_UserProject_人人写(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
// 任何角色都可以写用户或项目作用域的条目。
for _, sc := range []Scope{ScopeUser, ScopeProject} {
item, err := s.AddScoped(ctx, "persona.b", MemoryItem{
Scope: sc, Kind: KindWorldEvent, Content: "共享-" + string(sc),
})
if err != nil {
t.Fatalf("AddScoped %s: %v", sc, err)
}
// PersonaID 已用实施动作者自动填充。
if item.PersonaID != "persona.b" {
t.Errorf("AddScoped %s owner = %q, want persona.b", sc, item.PersonaID)
}
}
}
func TestStore_AddScoped_MissingActor_异常(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
if _, err := s.AddScoped(ctx, "", MemoryItem{
Content: "x", Scope: ScopeUser,
}); !errors.Is(err, ErrMissingPersona) {
t.Fatalf("AddScoped(empty actor) err = %v, want ErrMissingPersona", err)
}
}
func TestStore_AddScoped_InvalidScope_异常(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
if _, err := s.AddScoped(ctx, "persona.a", MemoryItem{
Content: "x", Scope: "bogus",
}); !errors.Is(err, ErrInvalidScope) {
t.Fatalf("AddScoped(bogus scope) err = %v, want ErrInvalidScope", err)
}
}
func TestStore_ListScope_前置校验_异常(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
if _, err := s.ListScope(ctx, ScopeUser, ""); !errors.Is(err, ErrMissingPersona) {
t.Fatalf("ListScope(empty persona) err = %v, want ErrMissingPersona", err)
}
if _, err := s.ListScope(ctx, "bogus", "persona.a"); !errors.Is(err, ErrInvalidScope) {
t.Fatalf("ListScope(bogus scope) err = %v, want ErrInvalidScope", err)
}
}
func TestStore_DeleteScoped_跨角色_异常(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
stored, err := s.AddScoped(ctx, "persona.a", MemoryItem{
Scope: ScopePersona, Kind: KindRelationship, Content: "a的日常",
})
if err != nil {
t.Fatalf("AddScoped persona.a: %v", err)
}
// persona.a 删除自己的条目。
if err := s.DeleteScoped(ctx, "persona.a", stored.ID); err != nil {
t.Fatalf("DeleteScoped owner: %v", err)
}
// 重新添加,然后 persona.b 不能删除 persona.a 的条目。
stored2, err := s.AddScoped(ctx, "persona.a", MemoryItem{
Scope: ScopePersona, Kind: KindRelationship, Content: "a的日常2",
})
if err != nil {
t.Fatalf("AddScoped persona.a: %v", err)
}
if err := s.DeleteScoped(ctx, "persona.b", stored2.ID); !errors.Is(err, ErrReadOnly) {
t.Fatalf("DeleteScoped cross-persona err = %v, want ErrReadOnly", err)
}
// 他人的条目依然存在。
if _, err := s.Get(ctx, stored2.ID); err != nil {
t.Fatalf("foreign item removed: %v", err)
}
}
func TestStore_DeleteScoped_BlankActor_异常(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
if err := s.DeleteScoped(ctx, "", "some-id"); !errors.Is(err, ErrMissingPersona) {
t.Fatalf("DeleteScoped(empty actor) err = %v, want ErrMissingPersona", err)
}
}
func TestStore_ListProject_项目记忆(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
if _, err := s.AddScoped(ctx, "persona.a", MemoryItem{
Scope: ScopeProject, Kind: KindWorldEvent, Content: "项目Alpha事实",
ProjectID: "project.alpha",
}); err != nil {
t.Fatalf("AddScoped project: %v", err)
}
if _, err := s.AddScoped(ctx, "persona.b", MemoryItem{
Scope: ScopeProject, Kind: KindWorldEvent, Content: "项目Beta事实",
ProjectID: "project.beta",
}); err != nil {
t.Fatalf("AddScoped project: %v", err)
}
items, err := s.ListProject(ctx, "project.alpha")
if err != nil {
t.Fatalf("ListProject: %v", err)
}
if len(items) != 1 || items[0].ProjectID != "project.alpha" {
t.Fatalf("ListProject(alpha) = %+v, want only alpha item", items)
}
if items[0].Content != "项目Alpha事实" {
t.Errorf("item content = %q, want the alpha item", items[0].Content)
}
}
func TestStore_ListProject_BlankID_异常(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newTestStore(t)
if _, err := s.ListProject(ctx, ""); !errors.Is(err, ErrMissingProjectID) {
t.Fatalf("ListProject(blank) err = %v, want ErrMissingProjectID", err)
}
}