c3b007a4e7
- ConfigError y ConfigValidation como tipos producto con sus .md en types/infra/ - config_validate: validacion con tags required/format/min/max/oneof via reflection - config_merge: merge no-mutante de map[string]string con precedencia de override - config_dump: serializacion de structs a map con mascara *** para campos secret - 17 tests unitarios, todos PASS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package infra
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestConfigValidate(t *testing.T) {
|
|
t.Run("struct valido retorna IsValid true", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Host string `required:"true"`
|
|
Port int `required:"true"`
|
|
}
|
|
got := ConfigValidate(Cfg{Host: "localhost", Port: 8080})
|
|
if !got.IsValid {
|
|
t.Errorf("expected IsValid=true, errors: %v", got.Errors)
|
|
}
|
|
if len(got.Errors) != 0 {
|
|
t.Errorf("expected no errors, got %v", got.Errors)
|
|
}
|
|
})
|
|
|
|
t.Run("campo required vacio acumula error", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Host string `required:"true"`
|
|
Key string `required:"true"`
|
|
}
|
|
got := ConfigValidate(Cfg{})
|
|
if got.IsValid {
|
|
t.Error("expected IsValid=false")
|
|
}
|
|
if len(got.Errors) != 2 {
|
|
t.Errorf("expected 2 errors, got %d: %v", len(got.Errors), got.Errors)
|
|
}
|
|
for _, e := range got.Errors {
|
|
if e.Tag != "required" {
|
|
t.Errorf("expected tag 'required', got %q", e.Tag)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("format email invalido produce error", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Email string `format:"email"`
|
|
}
|
|
got := ConfigValidate(Cfg{Email: "not-an-email"})
|
|
if got.IsValid {
|
|
t.Error("expected IsValid=false")
|
|
}
|
|
if len(got.Errors) == 0 || got.Errors[0].Tag != "format" {
|
|
t.Errorf("expected format error, got %v", got.Errors)
|
|
}
|
|
})
|
|
|
|
t.Run("format email valido pasa", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Email string `format:"email"`
|
|
}
|
|
got := ConfigValidate(Cfg{Email: "user@example.com"})
|
|
if !got.IsValid {
|
|
t.Errorf("expected IsValid=true, errors: %v", got.Errors)
|
|
}
|
|
})
|
|
|
|
t.Run("format url invalido produce error", func(t *testing.T) {
|
|
type Cfg struct {
|
|
BaseURL string `format:"url"`
|
|
}
|
|
got := ConfigValidate(Cfg{BaseURL: "ftp://bad.url"})
|
|
if got.IsValid {
|
|
t.Error("expected IsValid=false")
|
|
}
|
|
if len(got.Errors) == 0 || got.Errors[0].Tag != "format" {
|
|
t.Errorf("expected format error, got %v", got.Errors)
|
|
}
|
|
})
|
|
|
|
t.Run("puntero a struct funciona igual", func(t *testing.T) {
|
|
type Cfg struct {
|
|
Name string `required:"true"`
|
|
}
|
|
got := ConfigValidate(&Cfg{Name: "test"})
|
|
if !got.IsValid {
|
|
t.Errorf("expected IsValid=true, errors: %v", got.Errors)
|
|
}
|
|
})
|
|
|
|
t.Run("todos los errores acumulados aunque falle el primero", func(t *testing.T) {
|
|
type Cfg struct {
|
|
A string `required:"true"`
|
|
B string `required:"true"`
|
|
C string `required:"true"`
|
|
}
|
|
got := ConfigValidate(Cfg{})
|
|
if len(got.Errors) != 3 {
|
|
t.Errorf("expected 3 errors, got %d", len(got.Errors))
|
|
}
|
|
})
|
|
}
|