all repos — llm_aggregator @ 7208dd81944bf3bb82070208a69ea5d1d083dd01

A CLI tool to aggregate RSS feeds and summarise them with LLMs

internal/config/config_test.go (view raw)

  1package config
  2
  3import (
  4	"os"
  5	"path/filepath"
  6	"testing"
  7)
  8
  9func TestDefaultConfig(t *testing.T) {
 10	cfg := DefaultConfig()
 11	
 12	if cfg.MaxArticlesPerFeed != 10 {
 13		t.Errorf("Expected MaxArticlesPerFeed = 10, got %d", cfg.MaxArticlesPerFeed)
 14	}
 15	
 16	if cfg.MaxDaysOld != 7 {
 17		t.Errorf("Expected MaxDaysOld = 7, got %d", cfg.MaxDaysOld)
 18	}
 19	
 20	if cfg.MaxTotalArticles != 20 {
 21		t.Errorf("Expected MaxTotalArticles = 20, got %d", cfg.MaxTotalArticles)
 22	}
 23	
 24	if cfg.Model != "deepseek-chat" {
 25		t.Errorf("Expected Model = 'deepseek-chat', got %s", cfg.Model)
 26	}
 27	
 28	if cfg.MaxTokens != 4000 {
 29		t.Errorf("Expected MaxTokens = 4000, got %d", cfg.MaxTokens)
 30	}
 31	
 32	if cfg.Temperature != 0.7 {
 33		t.Errorf("Expected Temperature = 0.7, got %f", cfg.Temperature)
 34	}
 35	
 36	expectedPrompt := `You are an expert analyst and summariser.
 37You analyse content from multiple sources and provide
 38concise, insightful summaries based on user requests.
 39Focus on key points, trends, and important information.`
 40	
 41	if cfg.SystemPrompt != expectedPrompt {
 42		t.Errorf("SystemPrompt doesn't match expected default")
 43	}
 44	
 45	if cfg.Output != "text" {
 46		t.Errorf("Expected Output = 'text', got %s", cfg.Output)
 47	}
 48}
 49
 50func TestConfigPath(t *testing.T) {
 51	path, err := GetConfigPath()
 52	if err != nil {
 53		t.Fatalf("Failed to get config path: %v", err)
 54	}
 55	
 56	// Should end with .config/llm_aggregator/config.toml
 57	expectedSuffix := filepath.Join(".config", "llm_aggregator", "config.toml")
 58	if !hasSuffix(path, expectedSuffix) {
 59		t.Errorf("Config path %s doesn't end with %s", path, expectedSuffix)
 60	}
 61}
 62
 63func TestConfigSaveAndLoad(t *testing.T) {
 64	// Create temporary directory for test
 65	tempDir := t.TempDir()
 66	oldEnv := os.Getenv("XDG_CONFIG_HOME")
 67	os.Setenv("XDG_CONFIG_HOME", tempDir)
 68	defer os.Setenv("XDG_CONFIG_HOME", oldEnv)
 69	
 70	cfg := DefaultConfig()
 71	cfg.SystemPrompt = "Test system prompt"
 72	cfg.Model = "test-model"
 73	cfg.MaxTokens = 1234
 74	
 75	// Save config
 76	if err := cfg.Save(); err != nil {
 77		t.Fatalf("Failed to save config: %v", err)
 78	}
 79	
 80	// Verify file exists
 81	configPath, err := GetConfigPath()
 82	if err != nil {
 83		t.Fatalf("Failed to get config path: %v", err)
 84	}
 85	
 86	if _, err := os.Stat(configPath); os.IsNotExist(err) {
 87		t.Fatalf("Config file not created at %s", configPath)
 88	}
 89	
 90	// Load config
 91	loadedCfg, err := Load()
 92	if err != nil {
 93		t.Fatalf("Failed to load config: %v", err)
 94	}
 95	
 96	if !loadedCfg.IsLoaded() {
 97		t.Error("Config should be marked as loaded")
 98	}
 99	
100	if loadedCfg.SystemPrompt != cfg.SystemPrompt {
101		t.Errorf("SystemPrompt mismatch: expected %q, got %q", cfg.SystemPrompt, loadedCfg.SystemPrompt)
102	}
103	
104	if loadedCfg.Model != cfg.Model {
105		t.Errorf("Model mismatch: expected %s, got %s", cfg.Model, loadedCfg.Model)
106	}
107	
108	if loadedCfg.MaxTokens != cfg.MaxTokens {
109		t.Errorf("MaxTokens mismatch: expected %d, got %d", cfg.MaxTokens, loadedCfg.MaxTokens)
110	}
111}
112
113func TestEnvironmentVariables(t *testing.T) {
114	// Create temporary directory for test
115	tempDir := t.TempDir()
116	oldEnv := os.Getenv("XDG_CONFIG_HOME")
117	os.Setenv("XDG_CONFIG_HOME", tempDir)
118	defer os.Setenv("XDG_CONFIG_HOME", oldEnv)
119	
120	// Set environment variables
121	os.Setenv("LLM_AGGREGATOR_SYSTEM_PROMPT", "Env system prompt")
122	os.Setenv("LLM_AGGREGATOR_MODEL", "env-model")
123	os.Setenv("LLM_AGGREGATOR_MAX_TOKENS", "9999")
124	defer func() {
125		os.Unsetenv("LLM_AGGREGATOR_SYSTEM_PROMPT")
126		os.Unsetenv("LLM_AGGREGATOR_MODEL")
127		os.Unsetenv("LLM_AGGREGATOR_MAX_TOKENS")
128	}()
129	
130	// Load config (should pick up env vars)
131	cfg, err := Load()
132	if err != nil {
133		t.Fatalf("Failed to load config: %v", err)
134	}
135	
136	if cfg.SystemPrompt != "Env system prompt" {
137		t.Errorf("SystemPrompt should be from env var, got %q", cfg.SystemPrompt)
138	}
139	
140	if cfg.Model != "env-model" {
141		t.Errorf("Model should be from env var, got %s", cfg.Model)
142	}
143	
144	if cfg.MaxTokens != 9999 {
145		t.Errorf("MaxTokens should be from env var, got %d", cfg.MaxTokens)
146	}
147}
148
149func TestConfigExists(t *testing.T) {
150	// Create temporary directory for test
151	tempDir := t.TempDir()
152	oldEnv := os.Getenv("XDG_CONFIG_HOME")
153	os.Setenv("XDG_CONFIG_HOME", tempDir)
154	defer os.Setenv("XDG_CONFIG_HOME", oldEnv)
155	
156	// Get config path to verify
157	configPath, err := GetConfigPath()
158	if err != nil {
159		t.Fatalf("Failed to get config path: %v", err)
160	}
161	
162	// Ensure it's in our temp directory
163	if !contains(configPath, tempDir) {
164		t.Logf("Config path %s not in temp dir %s", configPath, tempDir)
165	}
166	
167	// Initially should not exist
168	exists, err := ConfigExists()
169	if err != nil {
170		t.Fatalf("Failed to check config existence: %v", err)
171	}
172	
173	if exists {
174		// Config exists, maybe from previous test run
175		t.Logf("Config exists at %s, removing...", configPath)
176		os.Remove(configPath)
177		// Check again
178		exists, err = ConfigExists()
179		if err != nil {
180			t.Fatalf("Failed to check config existence after removal: %v", err)
181		}
182		if exists {
183			t.Error("Config should not exist after removal")
184		}
185	}
186	
187	// Create config
188	cfg := DefaultConfig()
189	if err := cfg.Save(); err != nil {
190		t.Fatalf("Failed to save config: %v", err)
191	}
192	
193	// Now should exist
194	exists, err = ConfigExists()
195	if err != nil {
196		t.Fatalf("Failed to check config existence: %v", err)
197	}
198	
199	if !exists {
200		t.Error("Config should exist after saving")
201	}
202}
203
204// Helper function to check if path has suffix
205func hasSuffix(path, suffix string) bool {
206	if len(path) < len(suffix) {
207		return false
208	}
209	return path[len(path)-len(suffix):] == suffix
210}
211
212// Helper function to check if string contains substring
213func contains(s, substr string) bool {
214	return len(s) >= len(substr) && (s == substr || len(substr) == 0 || 
215		(s[0:len(substr)] == substr || contains(s[1:], substr)))
216}