package config import ( "os" "path/filepath" "strings" "testing" ) func writeFile(t *testing.T, name string, mode os.FileMode, content string) string { t.Helper() path := filepath.Join(t.TempDir(), name) if err := os.WriteFile(path, []byte(content), mode); err != nil { t.Fatal(err) } return path } func TestLoadEnvOnly(t *testing.T) { t.Setenv("MRED_URL", "https://redmine.example/") t.Setenv("MRED_KEY", "k1") cfg, src, err := Load("") if err != nil { t.Fatalf("Load: %v", err) } if cfg.BaseURL != "https://redmine.example" { t.Errorf("BaseURL = %q, want trailing slash trimmed", cfg.BaseURL) } if cfg.APIKey != "k1" { t.Errorf("APIKey = %q", cfg.APIKey) } if src.Env == "" { t.Errorf("source env = %q, want a key name", src.Env) } } func TestLoadFileOnly(t *testing.T) { path := writeFile(t, "env", 0o600, "MRED_URL=https://r.example\nMRED_KEY=k2\n") cfg, _, err := Load(path) if err != nil { t.Fatalf("Load: %v", err) } if cfg.BaseURL != "https://r.example" || cfg.APIKey != "k2" { t.Errorf("cfg = %+v", cfg) } } func TestLoadEnvWinsOverFile(t *testing.T) { t.Setenv("MRED_KEY", "envkey") path := writeFile(t, "env", 0o600, "MRED_URL=https://r.example\nMRED_KEY=filekey\n") cfg, src, err := Load(path) if err != nil { t.Fatalf("Load: %v", err) } if cfg.APIKey != "envkey" { t.Errorf("APIKey = %q, want env value to win", cfg.APIKey) } if src.File != "" && src.Env != "MRED_KEY" { t.Errorf("source = %+v", src) } } func TestLoadRejectsLooseFile(t *testing.T) { path := writeFile(t, "env", 0o644, "MRED_URL=https://r.example\nMRED_KEY=k\n") _, _, err := Load(path) if err == nil || !strings.Contains(err.Error(), "insecure mode") { t.Fatalf("err = %v, want insecure-mode rejection", err) } } func TestLoadMissingEverything(t *testing.T) { _, _, err := Load(filepath.Join(t.TempDir(), "absent")) if err == nil || !strings.Contains(err.Error(), "MRED_URL") { t.Fatalf("err = %v, want guidance naming MRED_URL/MRED_KEY", err) } } func TestLoadKeyAbsent(t *testing.T) { t.Setenv("MRED_URL", "https://r.example") path := writeFile(t, "env", 0o600, "# nothing useful\n") _, _, err := Load(path) if err == nil || !strings.Contains(err.Error(), "MRED_KEY") { t.Fatalf("err = %v, want MRED_KEY named", err) } } func TestLoadMalformedLineReportsNumberOnly(t *testing.T) { path := writeFile(t, "env", 0o600, "MRED_URL=https://r.example\nMRED_KEY=sekrit-value\nBROKEN LINE HERE\n") _, _, err := Load(path) if err == nil || !strings.Contains(err.Error(), "line 3") { t.Fatalf("err = %v, want line-number-only diagnostic", err) } if err != nil && strings.Contains(err.Error(), "sekrit-value") { t.Fatalf("err = %v leaks file contents", err) } } func TestLoadQuotedAndExported(t *testing.T) { path := writeFile(t, "env", 0o600, "export MRED_URL=\"https://r.example\"\nexport MRED_KEY='k3'\n") cfg, _, err := Load(path) if err != nil { t.Fatalf("Load: %v", err) } if cfg.BaseURL != "https://r.example" || cfg.APIKey != "k3" { t.Errorf("cfg = %+v, want quotes stripped", cfg) } }