package config import ( "errors" "testing" ) func TestReadOptionalEnv(t *testing.T) { t.Run("present non-empty", func(t *testing.T) { lookup := func(k string) (string, bool) { if k == "MY_KEY" { return " value ", true } return "", false } if got := readOptionalEnv(lookup, "MY_KEY", "default"); got != "value" { t.Fatalf("got %q, want %q", got, "value") } }) t.Run("present empty", func(t *testing.T) { lookup := func(k string) (string, bool) { return " ", true } if got := readOptionalEnv(lookup, "MY_KEY", "default"); got != "default" { t.Fatalf("got %q, want %q", got, "default") } }) t.Run("missing", func(t *testing.T) { lookup := func(k string) (string, bool) { return "", false } if got := readOptionalEnv(lookup, "MY_KEY", "default"); got != "default" { t.Fatalf("got %q, want %q", got, "default") } }) } func TestReadRequiredEnv(t *testing.T) { t.Run("present", func(t *testing.T) { lookup := func(k string) (string, bool) { return "my-token", true } if got := readRequiredEnv(lookup, "TOKEN"); got != "my-token" { t.Fatalf("got %q, want %q", got, "my-token") } }) t.Run("missing", func(t *testing.T) { lookup := func(k string) (string, bool) { return "", false } if got := readRequiredEnv(lookup, "TOKEN"); got != "" { t.Fatalf("got %q, want empty", got) } }) } func TestLoadStartupFromLookupEnv(t *testing.T) { t.Run("custom values", func(t *testing.T) { lookup := func(k string) (string, bool) { switch k { case EnvListenAddr: return ":9090", true case EnvSQLiteDSN: return "/data/db.sqlite", true default: return "", false } } cfg, err := loadStartupFromLookupEnv(lookup) if err != nil { t.Fatal(err) } if cfg.Server.ListenAddr != ":9090" { t.Fatalf("ListenAddr = %q, want %q", cfg.Server.ListenAddr, ":9090") } if cfg.Database.SQLiteDSN != "/data/db.sqlite" { t.Fatalf("SQLiteDSN = %q, want %q", cfg.Database.SQLiteDSN, "/data/db.sqlite") } }) t.Run("default values", func(t *testing.T) { lookup := func(k string) (string, bool) { return "", false } cfg, err := loadStartupFromLookupEnv(lookup) if err != nil { t.Fatal(err) } if cfg.Server.ListenAddr != DefaultListenAddr { t.Fatalf("ListenAddr = %q, want %q", cfg.Server.ListenAddr, DefaultListenAddr) } if cfg.Database.SQLiteDSN != DefaultSQLiteDSN { t.Fatalf("SQLiteDSN = %q, want %q", cfg.Database.SQLiteDSN, DefaultSQLiteDSN) } }) } func TestLoadAdminTokenFromLookupEnv(t *testing.T) { t.Run("valid token", func(t *testing.T) { lookup := func(k string) (string, bool) { return " admin-secret-123 ", true } token, err := loadAdminTokenFromLookupEnv(lookup) if err != nil { t.Fatal(err) } if token != "admin-secret-123" { t.Fatalf("token = %q, want %q", token, "admin-secret-123") } }) t.Run("empty token", func(t *testing.T) { lookup := func(k string) (string, bool) { return " ", true } _, err := loadAdminTokenFromLookupEnv(lookup) if err == nil { t.Fatal("expected error for empty token") } }) t.Run("missing env", func(t *testing.T) { lookup := func(k string) (string, bool) { return "", false } _, err := loadAdminTokenFromLookupEnv(lookup) if err == nil { t.Fatal("expected error for missing env") } }) } // Verify exported wrappers call the lookup versions. // We can't easily test LoadStartupFromEnv / LoadAdminTokenFromEnv // since they depend on os.LookupEnv, but we verify they compile and don't panic. func TestExportFunctionsExist(t *testing.T) { // Just verify the exported functions are reachable and return the right types _, err := LoadAdminTokenFromEnv() if err != nil && !errors.Is(err, err) { // any result is fine, just proving the function exists } }