package services import ( "os" "path/filepath" "testing" ) func TestConfigManager_ListEmpty(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) configs, err := cm.List() if err != nil { t.Fatalf("List() error = %v", err) } if len(configs) != 0 { t.Errorf("List() returned %d configs, want 0", len(configs)) } } func TestConfigManager_CreateAndGet(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) if err := cm.Create("server", "host = 0.0.0.0"); err != nil { t.Fatalf("Create() error = %v", err) } content, err := cm.Get("server") if err != nil { t.Fatalf("Get() error = %v", err) } if content != "host = 0.0.0.0" { t.Errorf("Get() = %q, want %q", content, "host = 0.0.0.0") } } func TestConfigManager_CreateDuplicate(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) cm.Create("server", "content") err := cm.Create("server", "content2") if err == nil { t.Error("Create() should fail for existing config") } } func TestConfigManager_Update(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) cm.Create("server", "old") if err := cm.Update("server", "new"); err != nil { t.Fatalf("Update() error = %v", err) } content, _ := cm.Get("server") if content != "new" { t.Errorf("Get() after Update() = %q, want %q", content, "new") } } func TestConfigManager_Delete(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) cm.Create("server", "content") if err := cm.Delete("server"); err != nil { t.Fatalf("Delete() error = %v", err) } _, err := cm.Get("server") if err == nil { t.Error("Get() should fail after Delete()") } } func TestConfigManager_Duplicate(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) cm.Create("server", "host = 0.0.0.0") if err := cm.Duplicate("server", "backup"); err != nil { t.Fatalf("Duplicate() error = %v", err) } content, _ := cm.Get("backup") if content != "host = 0.0.0.0" { t.Errorf("Get(backup) = %q, want %q", content, "host = 0.0.0.0") } configs, _ := cm.List() if len(configs) != 2 { t.Errorf("List() returned %d configs, want 2", len(configs)) } } func TestConfigManager_ListWithMultipleFiles(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) cm.Create("server", "s") cm.Create("difficulty", "d") os.WriteFile(filepath.Join(dir, "notacfg.txt"), []byte("txt"), 0644) configs, err := cm.List() if err != nil { t.Fatalf("List() error = %v", err) } if len(configs) != 2 { t.Errorf("List() returned %d configs, want 2 (should exclude non-.cfg)", len(configs)) } } func TestConfigManager_GetNotFound(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) _, err := cm.Get("nonexistent") if err == nil { t.Error("Get() should fail for nonexistent config") } } func TestConfigManager_CreateWithPathTraversal(t *testing.T) { dir := t.TempDir() cm := NewConfigManager(dir) // Attempt to create with path traversal err := cm.Create("../../etc/passwd", "content") if err != nil { t.Fatalf("Create() error = %v", err) } // Verify it was sanitized to just "passwd.cfg" in the cfgDir path := filepath.Join(dir, "passwd.cfg") if _, err := os.Stat(path); os.IsNotExist(err) { t.Error("File should be created with sanitized name in cfgDir") } } func TestSanitizeConfigName(t *testing.T) { tests := []struct { input string want string }{ {"server", "server"}, {"../etc/passwd", "passwd"}, {"../../secret.cfg", "secret"}, {"server.cfg", "server"}, } for _, tt := range tests { got := sanitizeConfigName(tt.input) if got != tt.want { t.Errorf("sanitizeConfigName(%q) = %q, want %q", tt.input, got, tt.want) } } }