Files
fn_registry/functions/infra/config_from_env_test.go
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

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")
}
})
}