first commit

This commit is contained in:
2026-08-14 23:41:57 +08:00
commit 086803a8dd
471 changed files with 91938 additions and 0 deletions
+176
View File
@@ -0,0 +1,176 @@
package config
import (
"os"
"path/filepath"
"reflect"
"testing"
)
func TestFileConfigPath_XDGOverride(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", "/tmp/xdgroot")
got := FileConfigPath()
want := filepath.Join("/tmp/xdgroot", "pigo", "config.toml")
if got != want {
t.Fatalf("FileConfigPath() = %q, want %q", got, want)
}
}
func TestFileConfigPath_DefaultHome(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", "")
home, err := os.UserHomeDir()
if err != nil {
t.Skip("no home dir")
}
got := FileConfigPath()
want := filepath.Join(home, ".config", "pigo", "config.toml")
if got != want {
t.Fatalf("FileConfigPath() = %q, want %q", got, want)
}
}
func TestLoadFileConfig_Missing(t *testing.T) {
cfg, err := LoadFileConfig(filepath.Join(t.TempDir(), "does-not-exist.toml"))
if err != nil {
t.Fatalf("missing file should not error, got %v", err)
}
if !reflect.DeepEqual(cfg, FileConfig{}) {
t.Fatalf("missing file should yield zero config, got %+v", cfg)
}
}
func TestLoadFileConfig_EmptyPath(t *testing.T) {
cfg, err := LoadFileConfig("")
if err != nil {
t.Fatalf("empty path should not error, got %v", err)
}
if !reflect.DeepEqual(cfg, FileConfig{}) {
t.Fatalf("empty path should yield zero config, got %+v", cfg)
}
}
func TestLoadFileConfig_Valid(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.toml")
content := `
model = "claude-opus-4-8"
base_url = "https://example.com"
api_key = "sk-test"
protocol = "anthropic"
provider = "deepseek"
thinking_level = "high"
output_format = "stream-json"
no_tools = true
no_skills = true
approve = true
system_prompt = "be terse"
`
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
t.Fatal(err)
}
cfg, err := LoadFileConfig(path)
if err != nil {
t.Fatalf("valid file should parse, got %v", err)
}
want := FileConfig{
Model: "claude-opus-4-8",
BaseURL: "https://example.com",
APIKey: "sk-test",
Protocol: "anthropic",
Provider: "deepseek",
ThinkingLevel: "high",
OutputFormat: "stream-json",
NoTools: true,
NoSkills: true,
Approve: true,
SystemPrompt: "be terse",
}
if !reflect.DeepEqual(cfg, want) {
t.Fatalf("parsed config = %+v, want %+v", cfg, want)
}
}
func TestLoadFileConfig_Malformed(t *testing.T) {
path := filepath.Join(t.TempDir(), "bad.toml")
if err := os.WriteFile(path, []byte("model = = ="), 0o600); err != nil {
t.Fatal(err)
}
if _, err := LoadFileConfig(path); err == nil {
t.Fatal("malformed file should error")
}
}
func TestLoadFileConfigPromptsArray(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.toml")
content := "prompts = [\"./my-prompts\", \"/abs/x.md\"]\n"
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
t.Fatal(err)
}
cfg, err := LoadFileConfig(path)
if err != nil {
t.Fatalf("LoadFileConfig: %v", err)
}
if len(cfg.Prompts) != 2 || cfg.Prompts[0] != "./my-prompts" || cfg.Prompts[1] != "/abs/x.md" {
t.Errorf("Prompts = %v, want [./my-prompts /abs/x.md]", cfg.Prompts)
}
}
// TestGenericBaseURLEnvVar verifies the <PROVIDER>_BASE_URL name derivation,
// especially the hyphen→underscore conversion and uppercasing.
func TestGenericBaseURLEnvVar(t *testing.T) {
cases := []struct {
name string
want string
}{
{"deepseek", "DEEPSEEK_BASE_URL"},
{"zai-coding-cn", "ZAI_CODING_CN_BASE_URL"},
{"vercel-ai-gateway", "VERCEL_AI_GATEWAY_BASE_URL"},
{"", ""},
}
for _, c := range cases {
if got := GenericBaseURLEnvVar(c.name); got != c.want {
t.Errorf("GenericBaseURLEnvVar(%q) = %q, want %q", c.name, got, c.want)
}
}
}
func TestLoadFileConfig_DreamTable(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.toml")
content := `
[dream]
enabled = false
interval_days = 14
recent_sessions = 50
`
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
t.Fatal(err)
}
cfg, err := LoadFileConfig(path)
if err != nil {
t.Fatalf("LoadFileConfig: %v", err)
}
if cfg.Dream.Enabled == nil || *cfg.Dream.Enabled {
t.Errorf("Dream.Enabled = %v, want explicit false", cfg.Dream.Enabled)
}
if cfg.Dream.IntervalDays != 14 {
t.Errorf("Dream.IntervalDays = %d, want 14", cfg.Dream.IntervalDays)
}
if cfg.Dream.RecentSessions != 50 {
t.Errorf("Dream.RecentSessions = %d, want 50", cfg.Dream.RecentSessions)
}
}
func TestLoadFileConfig_DreamTableAbsent(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.toml")
if err := os.WriteFile(path, []byte("model = \"foo\"\n"), 0o600); err != nil {
t.Fatal(err)
}
cfg, err := LoadFileConfig(path)
if err != nil {
t.Fatalf("LoadFileConfig: %v", err)
}
// Absent [dream] table: Enabled pointer nil (→ default true downstream),
// ints zero (→ defaults downstream). Parsing must not error.
if cfg.Dream.Enabled != nil || cfg.Dream.IntervalDays != 0 || cfg.Dream.RecentSessions != 0 {
t.Errorf("absent dream table = %+v, want zero-value", cfg.Dream)
}
}