Files
Cyrene_v2/internal/services/gateway/admin_write_persona_thinking_test.go
AskaEth 074ffc4ebf
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(gateway): gateway 剩余文件注释改中文(逐行 1:1,代码零字节改动)
主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批:
已推库 16 个文件 + 本批剩余文件)。
校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0);
全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
2026-10-03 22:28:25 +08:00

103 lines
3.9 KiB
Go

package gateway
import (
"strings"
"testing"
"gopkg.in/yaml.v3"
"git.yeij.top/AskaEth/Cyrene_v2/internal/persona/loader"
)
// TestPersonaUpsertRequest_ThinkingRoundTripsThroughYAML 钉住管理侧人格
// 写路径对可选 `thinking` 块的处理:手写 DTO 映射进
// loader 结构体,yaml.Marshal 输出文档化的键,重载
// 该 YAML 得到相同的值 —— 即该字段真的往返成功,
// 而不是被未列入白名单的 DTO 丢弃。
func TestPersonaUpsertRequest_ThinkingRoundTripsThroughYAML(t *testing.T) {
t.Parallel()
show := false
req := personaUpsertRequest{
ID: "xilian", Name: "昔涟", Role: "r", SystemPrompt: "s",
Thinking: &personaThinkingRequest{BudgetTokens: 4096, Effort: " medium ", ShowToUser: &show, Mode: " on "},
}
p := personaFromRequest(req)
if err := p.ValidateThinking(); err != nil {
t.Fatalf("ValidateThinking() error: %v", err)
}
data, err := yaml.Marshal(p)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
back := &loader.Persona{}
if err := yaml.Unmarshal(data, back); err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if back.Thinking.BudgetTokens != 4096 || back.Thinking.Mode != loader.ThinkingModeOn || back.Thinking.Effort != "medium" {
t.Fatalf("thinking = %+v, want 4096/on/medium", back.Thinking)
}
if back.Thinking.ShowToUser == nil || *back.Thinking.ShowToUser {
t.Fatalf("showToUser = %v, want an explicit false", back.Thinking.ShowToUser)
}
}
// TestPersonaUpsertRequest_ThinkingInvalidRejected 断言非法的 thinking
// 块会经由 loader 所用的同一套校验被拒绝,因此管理 API
// 无法持久化运行时拒绝加载的模式。
func TestPersonaUpsertRequest_ThinkingInvalidRejected(t *testing.T) {
t.Parallel()
p := personaFromRequest(personaUpsertRequest{
ID: "x", Name: "x", Role: "r", Thinking: &personaThinkingRequest{Mode: "always"},
})
err := p.ValidateThinking()
if err == nil {
t.Fatal("ValidateThinking() = nil, want an error")
}
if !strings.Contains(err.Error(), "always") {
t.Fatalf("error %q does not name the offending mode", err)
}
}
// TestPersonaUpsertRequest_NoThinkingBlockOmitsTheKey 断言不带 thinking
// 块的请求在 YAML 中不产出它,因此既有人格文件不会多出
// 一段噪声。
func TestPersonaUpsertRequest_NoThinkingBlockOmitsTheKey(t *testing.T) {
t.Parallel()
data, err := yaml.Marshal(personaFromRequest(personaUpsertRequest{ID: "x", Name: "x", Role: "r", SystemPrompt: "s"}))
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if strings.Contains(string(data), "thinking") {
t.Fatalf("marshaled persona carries a thinking block:\n%s", data)
}
}
// TestApplyThinkingEdit_PreservesOnOmission 是非破坏性更新规则:
// 省略 `thinking` 的客户端保留已存块,显式给出块则替换
// 它,全默认值的块清除它。
func TestApplyThinkingEdit_PreservesOnOmission(t *testing.T) {
t.Parallel()
show := false
stored := &loader.Persona{Thinking: loader.ThinkingParams{BudgetTokens: 8192, Mode: loader.ThinkingModeOn, ShowToUser: &show}}
kept := applyThinkingEdit(nil, stored)
if kept.BudgetTokens != 8192 || kept.Mode != loader.ThinkingModeOn || kept.ShowToUser == nil {
t.Fatalf("applyThinkingEdit(nil, stored) = %+v, want the stored block", kept)
}
replaced := applyThinkingEdit(&personaThinkingRequest{BudgetTokens: 1024, Mode: "off"}, stored)
if replaced.BudgetTokens != 1024 || replaced.Mode != loader.ThinkingModeOff || replaced.ShowToUser != nil {
t.Fatalf("applyThinkingEdit(explicit, stored) = %+v, want the request block", replaced)
}
cleared := applyThinkingEdit(&personaThinkingRequest{}, stored)
if cleared.BudgetTokens != 0 || cleared.Mode != "" || cleared.ShowToUser != nil {
t.Fatalf("applyThinkingEdit(empty object, stored) = %+v, want the zero block", cleared)
}
if created := applyThinkingEdit(nil, nil); created.BudgetTokens != 0 || created.ShowToUser != nil {
t.Fatalf("applyThinkingEdit(nil, nil) = %+v, want the zero block (create path)", created)
}
}