Files
egutierrez ebf246beb0 feat(infra): funciones impuras Go para carga de env/config (dotenv, env_require, config_from_env, config_from_file)
- dotenv_load: parser .env con no-sobreescritura y soporte de comillas
- env_require: os.Getenv con error descriptivo fail-fast
- env_require_all: verifica multiples vars y lista todas las faltantes
- config_from_env: reflection sobre struct tags env/default/required/secret, 5 tipos soportados
- config_from_file: JSON via stdlib, YAML stub con not-implemented
- 25 tests unitarios, todos PASS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 02:01:50 +02:00

98 lines
2.6 KiB
Go

package infra
import (
"os"
"path/filepath"
"testing"
)
func TestDotenvLoad(t *testing.T) {
// helper to write a temp .env file
writeEnv := func(t *testing.T, content string) string {
t.Helper()
dir := t.TempDir()
p := filepath.Join(dir, ".env")
if err := os.WriteFile(p, []byte(content), 0o600); err != nil {
t.Fatal(err)
}
return p
}
t.Run("parsea KEY=VALUE y setea variable", func(t *testing.T) {
p := writeEnv(t, "DOTENV_TEST_FOO=hello\n")
t.Setenv("DOTENV_TEST_FOO", "") // ensure unset
os.Unsetenv("DOTENV_TEST_FOO")
if err := DotenvLoad(p); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := os.Getenv("DOTENV_TEST_FOO"); got != "hello" {
t.Errorf("expected DOTENV_TEST_FOO=hello, got %q", got)
}
})
t.Run("ignora lineas comentario y vacias", func(t *testing.T) {
content := "# this is a comment\n\nDOTENV_TEST_BAR=world\n"
p := writeEnv(t, content)
os.Unsetenv("DOTENV_TEST_BAR")
if err := DotenvLoad(p); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := os.Getenv("DOTENV_TEST_BAR"); got != "world" {
t.Errorf("expected world, got %q", got)
}
})
t.Run("no sobreescribe variables ya seteadas", func(t *testing.T) {
p := writeEnv(t, "DOTENV_TEST_EXISTING=new\n")
t.Setenv("DOTENV_TEST_EXISTING", "original")
if err := DotenvLoad(p); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := os.Getenv("DOTENV_TEST_EXISTING"); got != "original" {
t.Errorf("expected original (not overwritten), got %q", got)
}
})
t.Run("valores con comillas dobles se stripean", func(t *testing.T) {
p := writeEnv(t, `DOTENV_TEST_QUOTED="quoted value"`)
os.Unsetenv("DOTENV_TEST_QUOTED")
if err := DotenvLoad(p); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := os.Getenv("DOTENV_TEST_QUOTED"); got != "quoted value" {
t.Errorf("expected 'quoted value', got %q", got)
}
})
t.Run("valores con comillas simples se stripean", func(t *testing.T) {
p := writeEnv(t, "DOTENV_TEST_SINGLE='single quoted'")
os.Unsetenv("DOTENV_TEST_SINGLE")
if err := DotenvLoad(p); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := os.Getenv("DOTENV_TEST_SINGLE"); got != "single quoted" {
t.Errorf("expected 'single quoted', got %q", got)
}
})
t.Run("archivo inexistente retorna error", func(t *testing.T) {
err := DotenvLoad("/nonexistent/.env.does.not.exist")
if err == nil {
t.Error("expected error for missing file")
}
})
t.Run("linea sin signo igual retorna error", func(t *testing.T) {
p := writeEnv(t, "INVALID_LINE\n")
err := DotenvLoad(p)
if err == nil {
t.Error("expected error for line without '='")
}
})
}