- Introduce tests for analyze, recipe, workon commands - Expand scaffold tests with language detection and context harvesting - Add tests for config getters, git utilities (tags, logs, diff) - Enhance linter with primary language detection tests - Cover logger level setting branches - New prompts loading tests with local/global fallback - Todo bootstrap and structure tests - Comprehensive workon flow tests including file moves, git integration, README updates - Update README coverage from 54% to 62%
163 lines
4.4 KiB
Go
163 lines
4.4 KiB
Go
package prompts
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestLoadAnalysisPromptProjectLocal(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
promptDir := filepath.Join(tmpDir, ".grokkit", "prompts")
|
|
if err := os.MkdirAll(promptDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "You are a Go expert educator."
|
|
if err := os.WriteFile(filepath.Join(promptDir, "go.md"), []byte(expected), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
path, content, err := LoadAnalysisPrompt(tmpDir, "go")
|
|
if err != nil {
|
|
t.Fatalf("LoadAnalysisPrompt failed: %v", err)
|
|
}
|
|
if content != expected {
|
|
t.Errorf("content = %q, want %q", content, expected)
|
|
}
|
|
if !filepath.IsAbs(path) || path == "" {
|
|
// path should be meaningful
|
|
t.Logf("returned path: %s", path)
|
|
}
|
|
}
|
|
|
|
func TestLoadAnalysisPromptGlobalFallback(t *testing.T) {
|
|
projectDir := t.TempDir() // no .grokkit/prompts here
|
|
globalDir := t.TempDir()
|
|
|
|
promptDir := filepath.Join(globalDir, ".config", "grokkit", "prompts")
|
|
if err := os.MkdirAll(promptDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "You are a Python expert."
|
|
if err := os.WriteFile(filepath.Join(promptDir, "python.md"), []byte(expected), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Override HOME to point to our temp global dir
|
|
oldHome := os.Getenv("HOME")
|
|
defer func() { _ = os.Setenv("HOME", oldHome) }()
|
|
_ = os.Setenv("HOME", globalDir)
|
|
|
|
path, content, err := LoadAnalysisPrompt(projectDir, "python")
|
|
if err != nil {
|
|
t.Fatalf("LoadAnalysisPrompt (global fallback) failed: %v", err)
|
|
}
|
|
if content != expected {
|
|
t.Errorf("content = %q, want %q", content, expected)
|
|
}
|
|
_ = path
|
|
}
|
|
|
|
func TestLoadAnalysisPromptProjectOverridesGlobal(t *testing.T) {
|
|
projectDir := t.TempDir()
|
|
globalDir := t.TempDir()
|
|
|
|
// Create both project-local and global prompts
|
|
localPromptDir := filepath.Join(projectDir, ".grokkit", "prompts")
|
|
if err := os.MkdirAll(localPromptDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(localPromptDir, "go.md"), []byte("local prompt"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
globalPromptDir := filepath.Join(globalDir, ".config", "grokkit", "prompts")
|
|
if err := os.MkdirAll(globalPromptDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(globalPromptDir, "go.md"), []byte("global prompt"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
oldHome := os.Getenv("HOME")
|
|
defer func() { _ = os.Setenv("HOME", oldHome) }()
|
|
_ = os.Setenv("HOME", globalDir)
|
|
|
|
_, content, err := LoadAnalysisPrompt(projectDir, "go")
|
|
if err != nil {
|
|
t.Fatalf("LoadAnalysisPrompt failed: %v", err)
|
|
}
|
|
if content != "local prompt" {
|
|
t.Errorf("expected project-local to override global, got: %q", content)
|
|
}
|
|
}
|
|
|
|
func TestLoadAnalysisPromptNotFound(t *testing.T) {
|
|
projectDir := t.TempDir()
|
|
emptyHome := t.TempDir()
|
|
|
|
oldHome := os.Getenv("HOME")
|
|
defer func() { _ = os.Setenv("HOME", oldHome) }()
|
|
_ = os.Setenv("HOME", emptyHome)
|
|
|
|
_, _, err := LoadAnalysisPrompt(projectDir, "rust")
|
|
if err == nil {
|
|
t.Fatal("expected error when no prompt found, got nil")
|
|
}
|
|
if !os.IsNotExist(err) {
|
|
t.Errorf("expected os.ErrNotExist, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadAnalysisPromptDefaultsToGo(t *testing.T) {
|
|
projectDir := t.TempDir()
|
|
promptDir := filepath.Join(projectDir, ".grokkit", "prompts")
|
|
if err := os.MkdirAll(promptDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(promptDir, "go.md"), []byte("go prompt"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
language string
|
|
}{
|
|
{"empty string defaults to go", ""},
|
|
{"unknown defaults to go", "unknown"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
_, content, err := LoadAnalysisPrompt(projectDir, tt.language)
|
|
if err != nil {
|
|
t.Fatalf("LoadAnalysisPrompt(%q) failed: %v", tt.language, err)
|
|
}
|
|
if content != "go prompt" {
|
|
t.Errorf("expected go prompt, got: %q", content)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadAnalysisPromptNormalizesCase(t *testing.T) {
|
|
projectDir := t.TempDir()
|
|
promptDir := filepath.Join(projectDir, ".grokkit", "prompts")
|
|
if err := os.MkdirAll(promptDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(promptDir, "python.md"), []byte("python prompt"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, content, err := LoadAnalysisPrompt(projectDir, "Python")
|
|
if err != nil {
|
|
t.Fatalf("LoadAnalysisPrompt with uppercase failed: %v", err)
|
|
}
|
|
if content != "python prompt" {
|
|
t.Errorf("expected case-insensitive match, got: %q", content)
|
|
}
|
|
}
|