// skill_prompt_test.go - 14.P1-B IsSkillPrompt 测试. // // 覆盖场景: // - /skill-name 命令展开后 isSkillPrompt=true // - 未知斜杠命令不展开(委派消费层) // - 非斜杠命令不影响 isSkillPrompt // - runConfig.isSkillPrompt 初始值为 false package engine import ( "testing" "git.flytoex.net/yuanwei/flyto-agent/pkg/execenv" "git.flytoex.net/yuanwei/flyto-agent/pkg/hooks" ) // TestRunConfig_IsSkillPrompt_Default isSkillPrompt 默认为 false. func TestRunConfig_IsSkillPrompt_Default(t *testing.T) { cfg := &runConfig{} if cfg.isSkillPrompt { t.Error("isSkillPrompt 默认应为 false") } } // TestRunConfig_WithSessionHooks_Nil nil sessionHooks 不应 panic. func TestRunConfig_WithSessionHooks_Nil(t *testing.T) { cfg := &runConfig{} opt := WithSessionHooks(nil) opt(cfg) if cfg.sessionHooks != nil { t.Error("nil sessionHooks 应保持 nil") } } // TestSkillExpansion_InRunConfig 模拟 runConfig 中 isSkillPrompt 被设置的流程. // // 精妙之处(CLEVER): 不需要真实的 Engine(避免 API key,网络依赖)-- // 直接测试 runConfig.isSkillPrompt 字段的设置语义, // 以及 SkillRegistry.Get 返回 Skill 时的展开逻辑. // 集成测试(真实 Engine + real Run)由 E2E 测试覆盖. func TestSkillExpansion_InRunConfig(t *testing.T) { // 验证 isSkillPrompt 可以被正确设置 cfg := &runConfig{} r := newSkillRegistry(nil) r.RegisterBuiltin(&Skill{ Name: "commit", Content: "Create a git commit for: $ARGUMENTS", UserInvocable: true, }) // 模拟 runLoop 中的 Skill 展开逻辑 skill, ok := r.Get("commit") if !ok { t.Fatal("Skill 'commit' 未找到") } expandedPrompt := skill.ExpandPrompt("feat: add login", "test-session") if expandedPrompt == "" { t.Fatal("ExpandPrompt 返回空字符串") } // 模拟设置标志位 cfg.isSkillPrompt = true if !cfg.isSkillPrompt { t.Error("isSkillPrompt 应为 true") } // 验证展开内容正确 expected := "Create a git commit for: feat: add login" if expandedPrompt != expected { t.Errorf("展开内容错误: got %q, want %q", expandedPrompt, expected) } } // TestSkillExpansion_EmptyContent Skill 内容为空时不触发展开. func TestSkillExpansion_EmptyContent(t *testing.T) { r := newSkillRegistry(nil) r.RegisterBuiltin(&Skill{ Name: "empty-skill", Content: "", // 空内容 }) skill, ok := r.Get("empty-skill") if !ok { t.Fatal("Skill 'empty-skill' 未找到") } expanded := skill.ExpandPrompt("args", "sess") // 空内容时展开结果也为空,不应触发 Skill 展开 if expanded != "" { t.Errorf("空内容 Skill 展开应为空,got %q", expanded) } } // TestWithSessionHooks_SetInRunConfig WithSessionHooks 正确设置到 runConfig. func TestWithSessionHooks_SetInRunConfig(t *testing.T) { // 这里只测 runConfig 结构,不涉及 Manager 执行 cfg := &runConfig{} // 创建一个有效的 Manager mgr := hooks.NewManager(nil, execenv.DefaultExecutor{}) opt := WithSessionHooks(mgr) opt(cfg) if cfg.sessionHooks != mgr { t.Error("WithSessionHooks 应将 Manager 设置到 cfg.sessionHooks") } }