package config import ( "bytes" "errors" "reflect" "strings" "testing" configkit "gitea.maximumdirect.net/eric/ConfigKit" ) func loadDocumentBytes(content string) (*configkit.Result[Document], error) { return configkit.Load(configkit.Bytes("application.yml", []byte(content)), configkit.Options[Document]{ Definition: documentDefinition(), }) } func TestDocumentDefaultsAndExplicitValues(t *testing.T) { defaultsOnly, err := configkit.Load(configkit.NoSource(), configkit.Options[Document]{Definition: documentDefinition()}) if err != nil { t.Fatalf("defaults-only load: %v", err) } if !reflect.DeepEqual(defaultsOnly.Config, documentDefaults()) || len(defaultsOnly.Sources()) != 0 { t.Fatalf("unexpected defaults-only result: %+v sources=%+v", defaultsOnly.Config, defaultsOnly.Sources()) } result, err := loadDocumentBytes(`prompt_dir: "" profile_dir: "" schema_dir: "" transient_retries: 0 server: addr: "" artifact_root: "" max_request_bytes: 0 max_artifact_bytes: 0 max_response_bytes: 0 defaults: render_format: " JSON " backends: local: endpoint: "http://fixture.invalid/v1" queue_capacity: 0 extra_params: sample_count: 23 `) if err != nil { t.Fatalf("explicit-value load: %v", err) } config := result.Config if config.SchemaDir != "" || config.Server.Addr != "" || config.Server.MaxRequestBytes != 0 || config.Server.MaxArtifactBytes != 0 || config.Server.MaxResponseBytes != 0 { t.Fatalf("explicit empty and zero values did not replace defaults: %+v", config) } if config.TransientRetries == nil || *config.TransientRetries != 0 { t.Fatalf("explicit zero retry budget lost: %+v", config.TransientRetries) } if backend := config.Backends["local"]; backend.QueueCapacity == nil || *backend.QueueCapacity != 0 || backend.ExtraParams["sample_count"] != int64(23) { t.Fatalf("backend presence or dynamic integer changed: %+v", backend) } if config.Defaults.RenderFormat != "json" { t.Fatalf("render format normalization failed: %q", config.Defaults.RenderFormat) } nullable, err := loadDocumentBytes("transient_retries: null\nbackends:\n local:\n queue_capacity: null\n") if err != nil { t.Fatalf("nullable-value load: %v", err) } if nullable.Config.TransientRetries != nil || nullable.Config.Backends["local"].QueueCapacity != nil { t.Fatalf("nullable fields did not remain nil: %+v", nullable.Config) } nullBackends, err := loadDocumentBytes("backends: null\n") if err != nil || nullBackends.Config.Backends != nil { t.Fatalf("nullable backend map did not remain nil: %+v error=%v", nullBackends, err) } } func TestDocumentRecordsEffectiveNormalization(t *testing.T) { result, err := loadDocumentBytes(`prompt_dir: " ./one/../two " profile_dir: " " server: artifact_root: " ./data/../artifacts " addr: " :9000 " defaults: render_format: " JSON " `) if err != nil { t.Fatalf("load normalized document: %v", err) } if result.Config.PromptDir != "two" || result.Config.ProfileDir != "" || result.Config.Server.ArtifactRoot != "artifacts" || result.Config.Server.Addr != ":9000" { t.Fatalf("unexpected normalized values: %+v", result.Config) } var effective bytes.Buffer if err := result.WriteEffective(&effective); err != nil { t.Fatalf("write effective configuration: %v", err) } for _, fragment := range []string{"prompt_dir: two", "profile_dir: ''", "artifact_root: artifacts", "addr: :9000", "render_format: json"} { if !strings.Contains(effective.String(), fragment) { t.Fatalf("effective output omitted %q: %s", fragment, effective.String()) } } explanation, known := result.Explain(configkit.Keys("prompt_dir")) if !known || explanation.Effective.YAML != "two\n" { t.Fatalf("explanation does not agree with effective value: %+v known=%t", explanation, known) } found := false for _, change := range explanation.History { if change.Origin.Operation == configkit.ChangeNormalization { found = true } } if !found { t.Fatalf("normalization was not recorded: %+v", explanation.History) } } func TestDocumentValidationIsSafeAndPathSpecific(t *testing.T) { for _, tc := range []struct{ name, content, path string }{ {"negative retry", "transient_retries: -9173\n", "/transient_retries"}, {"negative request limit", "server:\n max_request_bytes: -9173\n", "/server/max_request_bytes"}, {"negative artifact limit", "server:\n max_artifact_bytes: -9173\n", "/server/max_artifact_bytes"}, {"negative response limit", "server:\n max_response_bytes: -9173\n", "/server/max_response_bytes"}, {"empty format", "defaults:\n render_format: \"\"\n", "/defaults/render_format"}, {"unknown format", "defaults:\n render_format: private-invalid-value\n", "/defaults/render_format"}, } { t.Run(tc.name, func(t *testing.T) { _, err := loadDocumentBytes(tc.content) var loadError *configkit.LoadError if !errors.As(err, &loadError) { t.Fatalf("expected typed validation error, got %v", err) } found := false for _, diagnostic := range loadError.Diagnostics() { if diagnostic.Code == configkit.CodeValidateError && diagnostic.Path.String() == tc.path { found = true } if strings.Contains(diagnostic.Message, "9173") || strings.Contains(diagnostic.Message, "private-invalid-value") { t.Fatalf("diagnostic disclosed rejected value: %+v", diagnostic) } } if !found { t.Fatalf("expected validation at %s, got %+v", tc.path, loadError.Diagnostics()) } }) } } func TestDocumentRejectsNativeShapeErrors(t *testing.T) { for _, content := range []string{ "server: null\n", "defaults: null\n", "server:\n addr: null\n", "server:\n max_request_bytes: null\n", "defaults:\n render_format: null\n", "server:\n unknown_field: 1\n", "backends:\n local:\n unknown_field: 1\n", } { _, err := loadDocumentBytes(content) if err == nil { t.Fatalf("unexpected acceptance of %q", content) } } }