ebf246beb0
- 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>
122 lines
2.8 KiB
Go
122 lines
2.8 KiB
Go
package infra
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestConfigFromEnv(t *testing.T) {
|
|
t.Run("populate string field desde env", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Host string `env:"CFE_HOST"`
|
|
}
|
|
t.Setenv("CFE_HOST", "myhost")
|
|
var c Cfg
|
|
if err := ConfigFromEnv(&c); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if c.Host != "myhost" {
|
|
t.Errorf("expected myhost, got %q", c.Host)
|
|
}
|
|
})
|
|
|
|
t.Run("populate int field con conversion", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Port int `env:"CFE_PORT"`
|
|
}
|
|
t.Setenv("CFE_PORT", "9090")
|
|
var c Cfg
|
|
if err := ConfigFromEnv(&c); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if c.Port != 9090 {
|
|
t.Errorf("expected 9090, got %d", c.Port)
|
|
}
|
|
})
|
|
|
|
t.Run("populate bool field con conversion", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Debug bool `env:"CFE_DEBUG"`
|
|
}
|
|
t.Setenv("CFE_DEBUG", "true")
|
|
var c Cfg
|
|
if err := ConfigFromEnv(&c); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if !c.Debug {
|
|
t.Error("expected Debug=true")
|
|
}
|
|
})
|
|
|
|
t.Run("populate float64 field", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Ratio float64 `env:"CFE_RATIO"`
|
|
}
|
|
t.Setenv("CFE_RATIO", "3.14")
|
|
var c Cfg
|
|
if err := ConfigFromEnv(&c); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if c.Ratio < 3.13 || c.Ratio > 3.15 {
|
|
t.Errorf("expected ~3.14, got %f", c.Ratio)
|
|
}
|
|
})
|
|
|
|
t.Run("populate slice string comma-separated", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Tags []string `env:"CFE_TAGS"`
|
|
}
|
|
t.Setenv("CFE_TAGS", "a,b,c")
|
|
var c Cfg
|
|
if err := ConfigFromEnv(&c); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if len(c.Tags) != 3 || c.Tags[0] != "a" || c.Tags[2] != "c" {
|
|
t.Errorf("unexpected tags: %v", c.Tags)
|
|
}
|
|
})
|
|
|
|
t.Run("valor default usado cuando env no seteada", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Port int `env:"CFE_PORT_DEFAULT" default:"8080"`
|
|
}
|
|
var c Cfg
|
|
if err := ConfigFromEnv(&c); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if c.Port != 8080 {
|
|
t.Errorf("expected default 8080, got %d", c.Port)
|
|
}
|
|
})
|
|
|
|
t.Run("required sin valor retorna error", func(t *testing.T) {
|
|
type Cfg struct {
|
|
APIKey string `env:"CFE_API_KEY_REQUIRED" required:"true"`
|
|
}
|
|
var c Cfg
|
|
err := ConfigFromEnv(&c)
|
|
if err == nil {
|
|
t.Error("expected error for missing required var")
|
|
}
|
|
})
|
|
|
|
t.Run("int invalido retorna error descriptivo", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Port int `env:"CFE_PORT_BAD"`
|
|
}
|
|
t.Setenv("CFE_PORT_BAD", "not-a-number")
|
|
var c Cfg
|
|
err := ConfigFromEnv(&c)
|
|
if err == nil {
|
|
t.Error("expected error for invalid int")
|
|
}
|
|
})
|
|
|
|
t.Run("puntero nil retorna error", func(t *testing.T) {
|
|
var p *struct{ X string }
|
|
err := ConfigFromEnv(p)
|
|
if err == nil {
|
|
t.Error("expected error for nil pointer")
|
|
}
|
|
})
|
|
}
|