package config import ( "os" "path/filepath" "strings" "testing" ) func TestLoadDotEnvLoadsWorkingDirectoryFileWithoutOverridingExistingEnv(t *testing.T) { dir := t.TempDir() oldWD, err := os.Getwd() if err != nil { t.Fatalf("getwd: %v", err) } if err := os.Chdir(dir); err != nil { t.Fatalf("chdir temp dir: %v", err) } t.Cleanup(func() { _ = os.Chdir(oldWD) }) const newKey = "DS2API_TEST_DOTENV_NEW" const keepKey = "DS2API_TEST_DOTENV_KEEP" const quotedKey = "DS2API_TEST_DOTENV_QUOTED" unsetEnv(t, newKey) unsetEnv(t, quotedKey) t.Setenv(keepKey, "from-env") content := "DS2API_TEST_DOTENV_NEW=from-file\n" + "DS2API_TEST_DOTENV_KEEP=from-file\n" + "DS2API_TEST_DOTENV_QUOTED=\"line1\\nline2\"\n" if err := os.WriteFile(filepath.Join(dir, ".env"), []byte(content), 0o644); err != nil { t.Fatalf("write .env: %v", err) } if err := LoadDotEnv(); err != nil { t.Fatalf("LoadDotEnv() error: %v", err) } if got := os.Getenv(newKey); got != "from-file" { t.Fatalf("expected %s from .env, got %q", newKey, got) } if got := os.Getenv(keepKey); got != "from-env" { t.Fatalf("expected existing env to win, got %q", got) } if got := os.Getenv(quotedKey); got != "line1\nline2" { t.Fatalf("expected quoted newline decoding, got %q", got) } } func TestLoadDotEnvIgnoresMissingFile(t *testing.T) { dir := t.TempDir() oldWD, err := os.Getwd() if err != nil { t.Fatalf("getwd: %v", err) } if err := os.Chdir(dir); err != nil { t.Fatalf("chdir temp dir: %v", err) } t.Cleanup(func() { _ = os.Chdir(oldWD) }) if err := LoadDotEnv(); err != nil { t.Fatalf("expected missing .env to be ignored, got %v", err) } } func TestLoadDotEnvStripsInlineCommentsFromUnquotedValues(t *testing.T) { dir := t.TempDir() oldWD, err := os.Getwd() if err != nil { t.Fatalf("getwd: %v", err) } if err := os.Chdir(dir); err != nil { t.Fatalf("chdir temp dir: %v", err) } t.Cleanup(func() { _ = os.Chdir(oldWD) }) const plainKey = "DS2API_TEST_DOTENV_PLAIN" const hashKey = "DS2API_TEST_DOTENV_HASH" const quotedKey = "DS2API_TEST_DOTENV_QUOTED_COMMENT" const exportKey = "DS2API_TEST_DOTENV_EXPORT" unsetEnv(t, plainKey) unsetEnv(t, hashKey) unsetEnv(t, quotedKey) unsetEnv(t, exportKey) content := strings.Join([]string{ plainKey + "=5001 # local", hashKey + "=5001#local", quotedKey + `="5001 # local" # keep the inner hash`, "export " + exportKey + "=enabled # exported", }, "\n") + "\n" if err := os.WriteFile(filepath.Join(dir, ".env"), []byte(content), 0o644); err != nil { t.Fatalf("write .env: %v", err) } if err := LoadDotEnv(); err != nil { t.Fatalf("LoadDotEnv() error: %v", err) } if got := os.Getenv(plainKey); got != "5001" { t.Fatalf("expected inline comment to be stripped, got %q", got) } if got := os.Getenv(hashKey); got != "5001#local" { t.Fatalf("expected hash without preceding whitespace to remain, got %q", got) } if got := os.Getenv(quotedKey); got != "5001 # local" { t.Fatalf("expected quoted value to preserve hash text, got %q", got) } if got := os.Getenv(exportKey); got != "enabled" { t.Fatalf("expected export syntax to load, got %q", got) } } func unsetEnv(t *testing.T, key string) { t.Helper() old, had := os.LookupEnv(key) if err := os.Unsetenv(key); err != nil { t.Fatalf("unset %s: %v", key, err) } t.Cleanup(func() { if had { _ = os.Setenv(key, old) return } _ = os.Unsetenv(key) }) }