Files
BlackBean/pigo/internal/cli/prompts/prompts_project_test.go
T
2026-08-14 23:41:57 +08:00

140 lines
4.6 KiB
Go

package prompts
// Tests for project-level .pigo/prompts (US-006, #337): loaded at the project
// tier only when the project is trusted, overrides global same-name templates,
// and is suppressed by --no-prompt-templates.
import (
"path/filepath"
"testing"
"github.com/smallnest/pigo/internal/cli"
"github.com/smallnest/pigo/internal/cli/testutil"
"github.com/smallnest/pigo/internal/runtime"
)
// TestBuildSlashRegistryLoadsProjectPromptsTrusted: with the project trusted,
// .pigo/prompts/*.md loads at the project tier.
func TestBuildSlashRegistryLoadsProjectPromptsTrusted(t *testing.T) {
home := t.TempDir()
t.Setenv("PIGO_HOME", home) // empty global
cwdTmp := t.TempDir()
testutil.WritePrompt(t, cwdTmp, filepath.Join(".pigo", "prompts"), "review.md", "Review: $ARGUMENTS")
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
PromptTemplateSources{
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
ProjectTrusted: true,
})
if err != nil {
t.Fatalf("BuildSlashRegistry: %v", err)
}
out, err := reg.ResolveOutcome("/review diff")
if err != nil {
t.Fatalf("ResolveOutcome: %v", err)
}
if !out.Handled || out.Prompt != "Review: diff" {
t.Errorf("/review = handled=%v prompt=%q, want \"Review: diff\"", out.Handled, out.Prompt)
}
}
// TestBuildSlashRegistryProjectPromptsUntrustedSkipped: when the project is not
// trusted, .pigo/prompts is not loaded.
func TestBuildSlashRegistryProjectPromptsUntrustedSkipped(t *testing.T) {
home := t.TempDir()
t.Setenv("PIGO_HOME", home)
cwdTmp := t.TempDir()
testutil.WritePrompt(t, cwdTmp, filepath.Join(".pigo", "prompts"), "review.md", "Review: $ARGUMENTS")
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
PromptTemplateSources{
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
ProjectTrusted: false,
})
if err != nil {
t.Fatalf("BuildSlashRegistry: %v", err)
}
if _, ok := reg.Lookup("review"); ok {
t.Error("/review should NOT load from an untrusted project")
}
}
// TestBuildSlashRegistryProjectMissingDirNoError: a missing .pigo/prompts is
// not an error (most projects don't have one).
func TestBuildSlashRegistryProjectMissingDirNoError(t *testing.T) {
home := t.TempDir()
t.Setenv("PIGO_HOME", home)
cwdTmp := t.TempDir() // no .pigo/prompts created
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
PromptTemplateSources{
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
ProjectTrusted: true,
})
if err != nil {
t.Fatalf("missing .pigo/prompts should not error, got %v", err)
}
if reg == nil {
t.Fatal("registry is nil")
}
}
// TestBuildSlashRegistryProjectOverridesGlobal: a project template overrides a
// same-named global one (project tier wins, global shadowed).
func TestBuildSlashRegistryProjectOverridesGlobal(t *testing.T) {
home := t.TempDir()
t.Setenv("PIGO_HOME", home)
// global
testutil.WritePrompt(t, home, "prompts", "dup.md", "FROM GLOBAL")
// project
cwdTmp := t.TempDir()
testutil.WritePrompt(t, cwdTmp, filepath.Join(".pigo", "prompts"), "dup.md", "FROM PROJECT")
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
PromptTemplateSources{
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
ProjectTrusted: true,
})
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 PROJECT" {
t.Errorf("project should override global, got %q", got)
}
found := false
for _, e := range reg.Shadowed() {
if e.Name == "dup" && e.Tier == runtime.TierGlobal {
found = true
}
}
if !found {
t.Errorf("global dup should be shadowed with TierGlobal, got %v", reg.Shadowed())
}
}
// TestBuildSlashRegistryNoPromptTemplatesDisablesProject: --no-prompt-templates
// suppresses project prompts too.
func TestBuildSlashRegistryNoPromptTemplatesDisablesProject(t *testing.T) {
home := t.TempDir()
t.Setenv("PIGO_HOME", home)
cwdTmp := t.TempDir()
testutil.WritePrompt(t, cwdTmp, filepath.Join(".pigo", "prompts"), "review.md", "Review: $ARGUMENTS")
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
PromptTemplateSources{
Disable: true,
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
ProjectTrusted: true,
})
if err != nil {
t.Fatalf("BuildSlashRegistry: %v", err)
}
if _, ok := reg.Lookup("review"); ok {
t.Error("/review should NOT load under --no-prompt-templates")
}
}