cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm leaflet readability golang
at main 318 lines 8.1 kB view raw
1package handlers 2 3import ( 4 "bytes" 5 "io" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 11 "github.com/stormlightlabs/noteleaf/internal/shared" 12 "github.com/stormlightlabs/noteleaf/internal/store" 13) 14 15func TestConfigHandler(t *testing.T) { 16 t.Run("Get", func(t *testing.T) { 17 tempDir, cleanup := shared.CreateTempDir("noteleaf-config-handler-get-test-*", t) 18 defer cleanup() 19 20 customConfigPath := filepath.Join(tempDir, "test-config.toml") 21 originalEnv := os.Getenv("NOTELEAF_CONFIG") 22 os.Setenv("NOTELEAF_CONFIG", customConfigPath) 23 defer os.Setenv("NOTELEAF_CONFIG", originalEnv) 24 25 config := store.DefaultConfig() 26 config.ColorScheme = "test-scheme" 27 config.Editor = "vim" 28 if err := store.SaveConfig(config); err != nil { 29 t.Fatalf("Failed to save config: %v", err) 30 } 31 32 t.Run("Get all config values", func(t *testing.T) { 33 handler, err := NewConfigHandler() 34 if err != nil { 35 t.Fatalf("Failed to create handler: %v", err) 36 } 37 38 oldStdout := os.Stdout 39 r, w, _ := os.Pipe() 40 os.Stdout = w 41 42 err = handler.Get("") 43 if err != nil { 44 t.Fatalf("Get failed: %v", err) 45 } 46 47 w.Close() 48 os.Stdout = oldStdout 49 50 var buf bytes.Buffer 51 io.Copy(&buf, r) 52 output := buf.String() 53 54 if !strings.Contains(output, "color_scheme") { 55 t.Error("Output should contain color_scheme") 56 } 57 if !strings.Contains(output, "test-scheme") { 58 t.Error("Output should contain test-scheme value") 59 } 60 }) 61 62 t.Run("Get specific config value", func(t *testing.T) { 63 handler, err := NewConfigHandler() 64 if err != nil { 65 t.Fatalf("Failed to create handler: %v", err) 66 } 67 68 oldStdout := os.Stdout 69 r, w, _ := os.Pipe() 70 os.Stdout = w 71 72 err = handler.Get("editor") 73 if err != nil { 74 t.Fatalf("Get failed: %v", err) 75 } 76 77 w.Close() 78 os.Stdout = oldStdout 79 80 var buf bytes.Buffer 81 io.Copy(&buf, r) 82 output := buf.String() 83 84 if !strings.Contains(output, "editor = vim") { 85 t.Errorf("Output should contain 'editor = vim', got: %s", output) 86 } 87 }) 88 89 t.Run("Get unknown config key", func(t *testing.T) { 90 handler, err := NewConfigHandler() 91 if err != nil { 92 t.Fatalf("Failed to create handler: %v", err) 93 } 94 95 err = handler.Get("nonexistent_key") 96 if err == nil { 97 t.Error("Get should fail for unknown key") 98 } 99 if !strings.Contains(err.Error(), "unknown config key") { 100 t.Errorf("Error should mention unknown config key, got: %v", err) 101 } 102 }) 103 }) 104 105 t.Run("Set", func(t *testing.T) { 106 tempDir, cleanup := shared.CreateTempDir("noteleaf-config-handler-set-test-*", t) 107 defer cleanup() 108 109 customConfigPath := filepath.Join(tempDir, "test-config.toml") 110 originalEnv := os.Getenv("NOTELEAF_CONFIG") 111 os.Setenv("NOTELEAF_CONFIG", customConfigPath) 112 defer os.Setenv("NOTELEAF_CONFIG", originalEnv) 113 114 t.Run("Set string config value", func(t *testing.T) { 115 handler, err := NewConfigHandler() 116 if err != nil { 117 t.Fatalf("Failed to create handler: %v", err) 118 } 119 120 oldStdout := os.Stdout 121 r, w, _ := os.Pipe() 122 os.Stdout = w 123 124 err = handler.Set("editor", "emacs") 125 if err != nil { 126 t.Fatalf("Set failed: %v", err) 127 } 128 129 w.Close() 130 os.Stdout = oldStdout 131 132 var buf bytes.Buffer 133 io.Copy(&buf, r) 134 output := buf.String() 135 136 if !strings.Contains(output, "Set editor = emacs") { 137 t.Errorf("Output should confirm setting, got: %s", output) 138 } 139 140 loadedConfig, err := store.LoadConfig() 141 if err != nil { 142 t.Fatalf("Failed to load config: %v", err) 143 } 144 145 if loadedConfig.Editor != "emacs" { 146 t.Errorf("Expected editor 'emacs', got '%s'", loadedConfig.Editor) 147 } 148 }) 149 150 t.Run("Set boolean config value", func(t *testing.T) { 151 handler, err := NewConfigHandler() 152 if err != nil { 153 t.Fatalf("Failed to create handler: %v", err) 154 } 155 156 err = handler.Set("auto_archive", "true") 157 if err != nil { 158 t.Fatalf("Set failed: %v", err) 159 } 160 161 loadedConfig, err := store.LoadConfig() 162 if err != nil { 163 t.Fatalf("Failed to load config: %v", err) 164 } 165 166 if !loadedConfig.AutoArchive { 167 t.Error("Expected auto_archive to be true") 168 } 169 }) 170 171 t.Run("Set boolean config value with various formats", func(t *testing.T) { 172 tc := []struct { 173 value string 174 expected bool 175 }{ 176 {"true", true}, 177 {"1", true}, 178 {"yes", true}, 179 {"false", false}, 180 {"0", false}, 181 {"no", false}, 182 } 183 184 for _, tt := range tc { 185 handler, err := NewConfigHandler() 186 if err != nil { 187 t.Fatalf("Failed to create handler: %v", err) 188 } 189 190 err = handler.Set("sync_enabled", tt.value) 191 if err != nil { 192 t.Fatalf("Set failed for value '%s': %v", tt.value, err) 193 } 194 195 loadedConfig, err := store.LoadConfig() 196 if err != nil { 197 t.Fatalf("Failed to load config: %v", err) 198 } 199 200 if loadedConfig.SyncEnabled != tt.expected { 201 t.Errorf("For value '%s', expected sync_enabled %v, got %v", tt.value, tt.expected, loadedConfig.SyncEnabled) 202 } 203 } 204 }) 205 206 t.Run("Set unknown config key", func(t *testing.T) { 207 handler, err := NewConfigHandler() 208 if err != nil { 209 t.Fatalf("Failed to create handler: %v", err) 210 } 211 212 err = handler.Set("nonexistent_key", "value") 213 if err == nil { 214 t.Error("Set should fail for unknown key") 215 } 216 if !strings.Contains(err.Error(), "unknown config key") { 217 t.Errorf("Error should mention unknown config key, got: %v", err) 218 } 219 }) 220 }) 221 t.Run("Path", func(t *testing.T) { 222 tempDir, cleanup := shared.CreateTempDir("noteleaf-config-handler-path-test-*", t) 223 defer cleanup() 224 225 customConfigPath := filepath.Join(tempDir, "my-config.toml") 226 originalEnv := os.Getenv("NOTELEAF_CONFIG") 227 os.Setenv("NOTELEAF_CONFIG", customConfigPath) 228 defer os.Setenv("NOTELEAF_CONFIG", originalEnv) 229 230 t.Run("Path returns correct config file path", func(t *testing.T) { 231 handler, err := NewConfigHandler() 232 if err != nil { 233 t.Fatalf("Failed to create handler: %v", err) 234 } 235 236 oldStdout := os.Stdout 237 r, w, _ := os.Pipe() 238 os.Stdout = w 239 240 err = handler.Path() 241 if err != nil { 242 t.Fatalf("Path failed: %v", err) 243 } 244 245 w.Close() 246 os.Stdout = oldStdout 247 248 var buf bytes.Buffer 249 io.Copy(&buf, r) 250 output := strings.TrimSpace(buf.String()) 251 252 if output != customConfigPath { 253 t.Errorf("Expected path '%s', got '%s'", customConfigPath, output) 254 } 255 }) 256 }) 257 258 t.Run("Reset", func(t *testing.T) { 259 tempDir, cleanup := shared.CreateTempDir("noteleaf-config-handler-reset-test-*", t) 260 defer cleanup() 261 262 customConfigPath := filepath.Join(tempDir, "test-config.toml") 263 originalEnv := os.Getenv("NOTELEAF_CONFIG") 264 os.Setenv("NOTELEAF_CONFIG", customConfigPath) 265 defer os.Setenv("NOTELEAF_CONFIG", originalEnv) 266 267 t.Run("Reset restores default config", func(t *testing.T) { 268 config := store.DefaultConfig() 269 config.ColorScheme = "custom" 270 config.AutoArchive = true 271 config.Editor = "emacs" 272 if err := store.SaveConfig(config); err != nil { 273 t.Fatalf("Failed to save config: %v", err) 274 } 275 276 handler, err := NewConfigHandler() 277 if err != nil { 278 t.Fatalf("Failed to create handler: %v", err) 279 } 280 281 oldStdout := os.Stdout 282 r, w, _ := os.Pipe() 283 os.Stdout = w 284 285 err = handler.Reset() 286 if err != nil { 287 t.Fatalf("Reset failed: %v", err) 288 } 289 290 w.Close() 291 os.Stdout = oldStdout 292 293 var buf bytes.Buffer 294 io.Copy(&buf, r) 295 output := buf.String() 296 297 if !strings.Contains(output, "reset to defaults") { 298 t.Errorf("Output should confirm reset, got: %s", output) 299 } 300 301 loadedConfig, err := store.LoadConfig() 302 if err != nil { 303 t.Fatalf("Failed to load config: %v", err) 304 } 305 306 defaultConfig := store.DefaultConfig() 307 if loadedConfig.ColorScheme != defaultConfig.ColorScheme { 308 t.Errorf("ColorScheme should be reset to default '%s', got '%s'", defaultConfig.ColorScheme, loadedConfig.ColorScheme) 309 } 310 if loadedConfig.AutoArchive != defaultConfig.AutoArchive { 311 t.Errorf("AutoArchive should be reset to default %v, got %v", defaultConfig.AutoArchive, loadedConfig.AutoArchive) 312 } 313 if loadedConfig.Editor != defaultConfig.Editor { 314 t.Errorf("Editor should be reset to default '%s', got '%s'", defaultConfig.Editor, loadedConfig.Editor) 315 } 316 }) 317 }) 318}