Add application config loading
This commit is contained in:
177
internal/config/config_test.go
Normal file
177
internal/config/config_test.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
renderformat "gitea.maximumdirect.net/eric/scriptorium/internal/format"
|
||||
)
|
||||
|
||||
func TestLoadConfigMissingImplicitPathUsesBuiltInDefaults(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
missing := filepath.Join(tmp, "missing.yml")
|
||||
|
||||
got, err := LoadConfig(missing, false)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
want := BuiltInDefaults()
|
||||
if got != want {
|
||||
t.Fatalf("unexpected settings: got=%+v want=%+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigMissingExplicitPathReturnsError(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
missing := filepath.Join(tmp, "missing.yml")
|
||||
|
||||
_, err := LoadConfig(missing, true)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing explicit config")
|
||||
}
|
||||
if !errors.Is(err, ErrConfigNotFound) {
|
||||
t.Fatalf("expected ErrConfigNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigInvalidYAMLReturnsError(t *testing.T) {
|
||||
path := writeConfigFile(t, "config.yml", "prompt_dir: [")
|
||||
|
||||
_, err := LoadConfig(path, true)
|
||||
if err == nil {
|
||||
t.Fatal("expected invalid YAML error")
|
||||
}
|
||||
if !errors.Is(err, ErrInvalidConfigYAML) {
|
||||
t.Fatalf("expected ErrInvalidConfigYAML, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigUnknownFieldReturnsError(t *testing.T) {
|
||||
path := writeConfigFile(t, "config.yml", "unknown_field: true\n")
|
||||
|
||||
_, err := LoadConfig(path, true)
|
||||
if err == nil {
|
||||
t.Fatal("expected unknown field error")
|
||||
}
|
||||
if !errors.Is(err, ErrInvalidConfigYAML) {
|
||||
t.Fatalf("expected ErrInvalidConfigYAML, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigAPIKeyFieldIsRejectedAsUnknown(t *testing.T) {
|
||||
path := writeConfigFile(t, "config.yml", "api_key: secret\n")
|
||||
|
||||
_, err := LoadConfig(path, true)
|
||||
if err == nil {
|
||||
t.Fatal("expected unknown field error for api_key")
|
||||
}
|
||||
if !errors.Is(err, ErrInvalidConfigYAML) {
|
||||
t.Fatalf("expected ErrInvalidConfigYAML, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigValidConfigSetsDirectoriesAndServerAddr(t *testing.T) {
|
||||
path := writeConfigFile(t, "config.yml", `
|
||||
prompt_dir: ./prompts
|
||||
profile_dir: ./profiles
|
||||
schema_dir: ./schemas
|
||||
server:
|
||||
addr: 127.0.0.1:9090
|
||||
defaults:
|
||||
render_format: json
|
||||
`)
|
||||
|
||||
got, err := LoadConfig(path, true)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
if got.PromptDir != filepath.Clean("./prompts") {
|
||||
t.Fatalf("unexpected prompt_dir: %q", got.PromptDir)
|
||||
}
|
||||
if got.ProfileDir != filepath.Clean("./profiles") {
|
||||
t.Fatalf("unexpected profile_dir: %q", got.ProfileDir)
|
||||
}
|
||||
if got.SchemaDir != filepath.Clean("./schemas") {
|
||||
t.Fatalf("unexpected schema_dir: %q", got.SchemaDir)
|
||||
}
|
||||
if got.ServerAddr != "127.0.0.1:9090" {
|
||||
t.Fatalf("unexpected server.addr: %q", got.ServerAddr)
|
||||
}
|
||||
if got.DefaultRenderFormat != renderformat.PreparedRunFormatJSON {
|
||||
t.Fatalf("unexpected defaults.render_format: %q", got.DefaultRenderFormat)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigEmptyFileResolvesToBuiltInDefaults(t *testing.T) {
|
||||
path := writeConfigFile(t, "config.yml", "")
|
||||
|
||||
got, err := LoadConfig(path, true)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
want := BuiltInDefaults()
|
||||
if got != want {
|
||||
t.Fatalf("unexpected settings: got=%+v want=%+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCLIOverridesAppliesPrecedence(t *testing.T) {
|
||||
base := AppSettings{
|
||||
PromptDir: "/from/config/prompts",
|
||||
ProfileDir: "/from/config/profiles",
|
||||
SchemaDir: "/from/config/schemas",
|
||||
ServerAddr: ":1234",
|
||||
DefaultRenderFormat: renderformat.PreparedRunFormatJSON,
|
||||
}
|
||||
|
||||
got, err := ApplyCLIOverrides(base, CLIOverrides{
|
||||
PromptDir: "./prompts-cli",
|
||||
ProfileDir: "./profiles-cli",
|
||||
SchemaDir: "./schemas-cli",
|
||||
ServerAddr: ":8081",
|
||||
RenderFormat: "text",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
if got.PromptDir != filepath.Clean("./prompts-cli") {
|
||||
t.Fatalf("unexpected prompt dir: %q", got.PromptDir)
|
||||
}
|
||||
if got.ProfileDir != filepath.Clean("./profiles-cli") {
|
||||
t.Fatalf("unexpected profile dir: %q", got.ProfileDir)
|
||||
}
|
||||
if got.SchemaDir != filepath.Clean("./schemas-cli") {
|
||||
t.Fatalf("unexpected schema dir: %q", got.SchemaDir)
|
||||
}
|
||||
if got.ServerAddr != ":8081" {
|
||||
t.Fatalf("unexpected server addr: %q", got.ServerAddr)
|
||||
}
|
||||
if got.DefaultRenderFormat != renderformat.PreparedRunFormatText {
|
||||
t.Fatalf("unexpected render format: %q", got.DefaultRenderFormat)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCLIOverridesInvalidRenderFormatReturnsError(t *testing.T) {
|
||||
_, err := ApplyCLIOverrides(BuiltInDefaults(), CLIOverrides{RenderFormat: "yaml"})
|
||||
if err == nil {
|
||||
t.Fatal("expected invalid render format error")
|
||||
}
|
||||
if !errors.Is(err, ErrInvalidConfig) {
|
||||
t.Fatalf("expected ErrInvalidConfig, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeConfigFile(t *testing.T, name, content string) string {
|
||||
t.Helper()
|
||||
path := filepath.Join(t.TempDir(), name)
|
||||
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
||||
t.Fatalf("failed to write config file: %v", err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
Reference in New Issue
Block a user