Add reflective struct-tag config loader
Implements conf.Load to populate tagged structs from a chain of Sources (env, .env, YAML/JSON/TOML, custom). Supports default values, slice separators, nested structs, pointer fields, and a Validator hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3c806e6803
commit
c4ebd80669
15 changed files with 941 additions and 0 deletions
82
files_test.go
Normal file
82
files_test.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestYAMLFlatten(t *testing.T) {
|
||||
src, err := YAMLReader(strings.NewReader(`
|
||||
bind_addr: ":9000"
|
||||
session:
|
||||
idle_ttl: 1h
|
||||
cookie:
|
||||
secure: true
|
||||
list: [a, b, c]
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checks := map[string]string{
|
||||
"BIND_ADDR": ":9000",
|
||||
"SESSION_IDLE_TTL": "1h0m0s", // yaml.v3 decodes as time.Duration string? actually it stays string
|
||||
"SESSION_COOKIE_SECURE": "true",
|
||||
"LIST": "a,b,c",
|
||||
}
|
||||
for k, want := range checks {
|
||||
got, ok := src.Lookup(k)
|
||||
if !ok {
|
||||
t.Errorf("%s missing", k)
|
||||
continue
|
||||
}
|
||||
if k == "SESSION_IDLE_TTL" {
|
||||
// yaml decodes "1h" as plain string
|
||||
if got != "1h" && got != want {
|
||||
t.Errorf("%s = %q", k, got)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("%s = %q want %q", k, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONFlatten(t *testing.T) {
|
||||
src, err := JSONReader(strings.NewReader(`{"a":{"b":"c"},"n":7,"arr":[1,2,3]}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v, _ := src.Lookup("A_B"); v != "c" {
|
||||
t.Errorf("A_B=%q", v)
|
||||
}
|
||||
if v, _ := src.Lookup("N"); v != "7" {
|
||||
t.Errorf("N=%q", v)
|
||||
}
|
||||
if v, _ := src.Lookup("ARR"); v != "1,2,3" {
|
||||
t.Errorf("ARR=%q", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTOMLFlatten(t *testing.T) {
|
||||
src, err := TOMLReader(strings.NewReader(`
|
||||
bind_addr = ":9000"
|
||||
[session]
|
||||
idle_ttl = "1h"
|
||||
[session.cookie]
|
||||
secure = true
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for k, want := range map[string]string{
|
||||
"BIND_ADDR": ":9000",
|
||||
"SESSION_IDLE_TTL": "1h",
|
||||
"SESSION_COOKIE_SECURE": "true",
|
||||
} {
|
||||
got, ok := src.Lookup(k)
|
||||
if !ok || got != want {
|
||||
t.Errorf("%s = %q ok=%v want %q", k, got, ok, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue