Files
2026-08-14 23:41:57 +08:00

117 lines
3.8 KiB
Go

package prompts
// Tests for --prompt-template (CLI tier) and --no-prompt-templates (US-008,
// #339): CLI paths load at the CLI tier, --no-prompt-templates suppresses all
// prompt-template discovery while leaving built-ins, and a global template
// overrides a same-named CLI one (global tier wins, CLI shadowed).
import (
"os"
"path/filepath"
"testing"
"github.com/smallnest/pigo/internal/cli"
"github.com/smallnest/pigo/internal/cli/testutil"
"github.com/smallnest/pigo/internal/runtime"
)
func TestBuildSlashRegistryLoadsCLIPrompts(t *testing.T) {
home := t.TempDir()
t.Setenv("PIGO_HOME", home)
// file entry
filePath := filepath.Join(home, "single.md")
if err := os.WriteFile(filePath, []byte("Single: $ARGUMENTS"), 0o644); err != nil {
t.Fatal(err)
}
// dir entry
dirPath := filepath.Join(home, "clidir")
if err := os.MkdirAll(dirPath, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dirPath, "a.md"), []byte("A: $1"), 0o644); err != nil {
t.Fatal(err)
}
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
PromptTemplateSources{CLI: []string{filePath, dirPath}})
if err != nil {
t.Fatalf("BuildSlashRegistry: %v", err)
}
out, err := reg.ResolveOutcome("/single hi")
if err != nil {
t.Fatalf("ResolveOutcome /single: %v", err)
}
if !out.Handled || out.Prompt != "Single: hi" {
t.Errorf("/single = handled=%v prompt=%q, want \"Single: hi\"", out.Handled, out.Prompt)
}
out2, err := reg.ResolveOutcome("/a x")
if err != nil {
t.Fatalf("ResolveOutcome /a: %v", err)
}
if !out2.Handled || out2.Prompt != "A: x" {
t.Errorf("/a = handled=%v prompt=%q, want \"A: x\"", out2.Handled, out2.Prompt)
}
}
func TestBuildSlashRegistryNoPromptTemplatesDisables(t *testing.T) {
home := t.TempDir()
t.Setenv("PIGO_HOME", home)
// A global prompt that should NOT load under --no-prompt-templates.
testutil.WritePrompt(t, home, "prompts", "review.md", "Review: $ARGUMENTS")
// A CLI path that should also be ignored under --no-prompt-templates.
cliFile := filepath.Join(home, "cli.md")
if err := os.WriteFile(cliFile, []byte("CLI: $ARGUMENTS"), 0o644); err != nil {
t.Fatal(err)
}
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
PromptTemplateSources{Disable: true, CLI: []string{cliFile}})
if err != nil {
t.Fatalf("BuildSlashRegistry: %v", err)
}
if _, ok := reg.Lookup("review"); ok {
t.Error("/review should NOT be registered under --no-prompt-templates")
}
if _, ok := reg.Lookup("cli"); ok {
t.Error("/cli should NOT be registered under --no-prompt-templates")
}
// Built-in slash commands are unaffected: the registry is non-empty.
if len(reg.List()) == 0 {
t.Error("built-in slash commands should still be registered under --no-prompt-templates")
}
}
func TestBuildSlashRegistryGlobalOverridesCLI(t *testing.T) {
home := t.TempDir()
t.Setenv("PIGO_HOME", home)
// global prompt (TierGlobal) under ~/.pigo/prompts.
testutil.WritePrompt(t, home, "prompts", "dup.md", "FROM GLOBAL")
// CLI-tier file of the same name at the home root (not under prompts/).
cliFile := filepath.Join(home, "dup.md")
if err := os.WriteFile(cliFile, []byte("FROM CLI"), 0o644); err != nil {
t.Fatal(err)
}
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
PromptTemplateSources{CLI: []string{cliFile}})
if err != nil {
t.Fatalf("BuildSlashRegistry: %v", err)
}
cmd, ok := reg.Lookup("dup")
if !ok {
t.Fatal("/dup not found")
}
if got := cmd.Expand(""); got != "FROM GLOBAL" {
t.Errorf("global should override CLI, got %q", got)
}
found := false
for _, e := range reg.Shadowed() {
if e.Name == "dup" && e.Tier == runtime.TierCLI {
found = true
}
}
if !found {
t.Errorf("CLI dup should be shadowed with TierCLI, got %v", reg.Shadowed())
}
}