e3.0.0 Added env variable support, improved cli arg, added tests, updated documentation.
This commit is contained in:
310
cmd/main.go
310
cmd/main.go
@ -1,310 +0,0 @@
|
||||
// Test program for the config package
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors" // Import errors package
|
||||
"fmt"
|
||||
"log" // Using standard log for simplicity
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/LixenWraith/config" // Assuming this is the correct import path after potential renaming/moving
|
||||
)
|
||||
|
||||
// LogConfig represents logging configuration parameters
|
||||
type LogConfig struct {
|
||||
// Basic settings
|
||||
Level int64 `toml:"level"`
|
||||
Name string `toml:"name"`
|
||||
Directory string `toml:"directory"`
|
||||
Format string `toml:"format"` // "txt" or "json"
|
||||
Extension string `toml:"extension"`
|
||||
// Formatting
|
||||
ShowTimestamp bool `toml:"show_timestamp"`
|
||||
ShowLevel bool `toml:"show_level"`
|
||||
// Buffer and size limits
|
||||
BufferSize int64 `toml:"buffer_size"` // Channel buffer size
|
||||
MaxSizeMB int64 `toml:"max_size_mb"` // Max size per log file
|
||||
MaxTotalSizeMB int64 `toml:"max_total_size_mb"` // Max total size of all logs in dir
|
||||
MinDiskFreeMB int64 `toml:"min_disk_free_mb"` // Minimum free disk space required
|
||||
// Timers
|
||||
FlushIntervalMs int64 `toml:"flush_interval_ms"` // Interval for flushing file buffer
|
||||
TraceDepth int64 `toml:"trace_depth"` // Default trace depth (0-10)
|
||||
RetentionPeriodHrs float64 `toml:"retention_period_hrs"` // Hours to keep logs (0=disabled)
|
||||
RetentionCheckMins float64 `toml:"retention_check_mins"` // How often to check retention
|
||||
// Disk check settings
|
||||
DiskCheckIntervalMs int64 `toml:"disk_check_interval_ms"` // Base interval for disk checks
|
||||
EnableAdaptiveInterval bool `toml:"enable_adaptive_interval"` // Adjust interval based on log rate
|
||||
MinCheckIntervalMs int64 `toml:"min_check_interval_ms"` // Minimum adaptive interval
|
||||
MaxCheckIntervalMs int64 `toml:"max_check_interval_ms"` // Maximum adaptive interval
|
||||
}
|
||||
|
||||
// Define default configuration values
|
||||
var defaultLogConfig = LogConfig{
|
||||
// Basic settings
|
||||
Level: 1,
|
||||
Name: "default_logger",
|
||||
Directory: "./logs",
|
||||
Format: "txt",
|
||||
Extension: ".log",
|
||||
// Formatting
|
||||
ShowTimestamp: true,
|
||||
ShowLevel: true,
|
||||
// Buffer and size limits
|
||||
BufferSize: 1000,
|
||||
MaxSizeMB: 10,
|
||||
MaxTotalSizeMB: 100,
|
||||
MinDiskFreeMB: 500,
|
||||
// Timers
|
||||
FlushIntervalMs: 1000,
|
||||
TraceDepth: 3,
|
||||
RetentionPeriodHrs: 24.0,
|
||||
RetentionCheckMins: 15.0,
|
||||
// Disk check settings
|
||||
DiskCheckIntervalMs: 60000,
|
||||
EnableAdaptiveInterval: false,
|
||||
MinCheckIntervalMs: 5000,
|
||||
MaxCheckIntervalMs: 300000,
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Create a temporary file path for our test
|
||||
tempDir := os.TempDir()
|
||||
configPath := filepath.Join(tempDir, "logconfig_test_enhanced.toml")
|
||||
|
||||
// Clean up any existing file from previous runs
|
||||
os.Remove(configPath)
|
||||
defer os.Remove(configPath) // Ensure cleanup even on error exit
|
||||
|
||||
fmt.Println("=== Enhanced LogConfig Test Program ===")
|
||||
fmt.Printf("Using temporary config file: %s\n\n", configPath)
|
||||
|
||||
// 1. Initialize the Config instance
|
||||
cfg := config.New()
|
||||
|
||||
// 2. Register default values using RegisterStruct
|
||||
fmt.Println("Registering default values using RegisterStruct...")
|
||||
err := cfg.RegisterStruct("log.", defaultLogConfig) // Note the "log." prefix
|
||||
if err != nil {
|
||||
log.Fatalf("FATAL: Error registering defaults: %v\n", err)
|
||||
}
|
||||
fmt.Println("Defaults registered.")
|
||||
|
||||
// 3. Load configuration (file doesn't exist yet)
|
||||
fmt.Println("\nAttempting initial load (expecting file not found)...")
|
||||
err = cfg.Load(configPath, nil) // No CLI args yet
|
||||
if err != nil {
|
||||
// Check specifically for ErrConfigNotFound
|
||||
if errors.Is(err, config.ErrConfigNotFound) {
|
||||
fmt.Println("SUCCESS: Correctly detected config file not found.")
|
||||
} else {
|
||||
// Any other error during initial load is unexpected here
|
||||
log.Fatalf("FATAL: Unexpected error loading initial config: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
log.Fatalf("FATAL: Expected an error (ErrConfigNotFound) during initial load, but got nil")
|
||||
}
|
||||
|
||||
// 4. Unmarshal defaults into LogConfig struct
|
||||
var currentConfig LogConfig
|
||||
fmt.Println("\nUnmarshaling current config (should be defaults)...")
|
||||
err = cfg.Scan("log", ¤tConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("FATAL: Error unmarshaling default config: %v\n", err)
|
||||
}
|
||||
|
||||
// Print default values
|
||||
fmt.Println("\n=== Current Configuration (Defaults) ===")
|
||||
printLogConfig(currentConfig)
|
||||
|
||||
// 5. Modify some values using Set
|
||||
fmt.Println("\n=== Modifying Configuration Values via Set ===")
|
||||
fmt.Println("Changing:")
|
||||
fmt.Println(" - log.name: default_logger → saved_logger")
|
||||
fmt.Println(" - log.max_size_mb: 10 → 50")
|
||||
fmt.Println(" - log.retention_period_hrs: 24.0 → 48.0") // Different from CLI override later
|
||||
|
||||
cfg.Set("log.name", "saved_logger") // This will be saved to file
|
||||
cfg.Set("log.max_size_mb", int64(50))
|
||||
cfg.Set("log.retention_period_hrs", 48.0)
|
||||
|
||||
// 6. Save the configuration
|
||||
fmt.Println("\nSaving configuration to file...")
|
||||
err = cfg.Save(configPath)
|
||||
if err != nil {
|
||||
log.Fatalf("FATAL: Error saving config: %v\n", err)
|
||||
}
|
||||
fmt.Printf("Saved configuration to: %s\n", configPath)
|
||||
|
||||
// Optional: Read and print file contents
|
||||
// fileBytes, _ := os.ReadFile(configPath)
|
||||
// fmt.Println("\n=== Saved TOML File Contents ===")
|
||||
// fmt.Println(string(fileBytes))
|
||||
|
||||
// 7. Define some command-line arguments for override testing
|
||||
fmt.Println("\n=== Preparing Command-Line Overrides ===")
|
||||
// Simulate os.Args[1:]
|
||||
cliArgs := []string{
|
||||
"--log.level", "3", // Override default 1
|
||||
"--log.name", "cli_logger", // Override value set before save ("saved_logger")
|
||||
"--log.show_timestamp=false", // Override default true
|
||||
"--log.retention_period_hrs", "72.5", // Override value set before save (48.0)
|
||||
"--other.value", "test", // An unregistered key (should be ignored by Load logic)
|
||||
"--invalid-key", // Invalid key format (test error handling if desired)
|
||||
}
|
||||
fmt.Printf("Simulated CLI Args: %v\n", cliArgs)
|
||||
|
||||
// 8. Load again, now with file and CLI overrides
|
||||
// Create a *new* config instance to simulate a fresh application start
|
||||
// that loads existing file + CLI args over defaults.
|
||||
fmt.Println("\nCreating NEW config instance and loading with file and CLI args...")
|
||||
cfg2 := config.New()
|
||||
fmt.Println("Registering defaults for new instance...")
|
||||
err = cfg2.RegisterStruct("log.", defaultLogConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("FATAL: Error registering defaults for cfg2: %v\n", err)
|
||||
}
|
||||
|
||||
fmt.Println("Loading config with file and CLI...")
|
||||
err = cfg2.Load(configPath, cliArgs)
|
||||
if err != nil {
|
||||
// Note: If "--invalid-key" is included above, Load should return ErrCLIParse.
|
||||
// Handle or remove the invalid key for a successful load test.
|
||||
// Example check:
|
||||
if errors.Is(err, config.ErrCLIParse) {
|
||||
fmt.Printf("INFO: Expected CLI parsing error detected: %v\n", err)
|
||||
// Decide how to proceed - maybe exit or remove the offending arg and retry
|
||||
// For this example, we'll filter the bad arg and try again
|
||||
var validArgs []string
|
||||
for _, arg := range cliArgs {
|
||||
if !strings.HasPrefix(arg, "--invalid") {
|
||||
validArgs = append(validArgs, arg)
|
||||
}
|
||||
}
|
||||
fmt.Println("Retrying load with filtered CLI args...")
|
||||
err = cfg2.Load(configPath, validArgs)
|
||||
if err != nil {
|
||||
log.Fatalf("FATAL: Error loading config even after filtering CLI args: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
log.Fatalf("FATAL: Unexpected error loading config with file and CLI: %v\n", err)
|
||||
}
|
||||
}
|
||||
fmt.Println("Load successful.")
|
||||
|
||||
// 9. Unmarshal the final configuration state
|
||||
var finalConfig LogConfig
|
||||
fmt.Println("\nUnmarshaling final config state...")
|
||||
err = cfg2.Scan("log", &finalConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("FATAL: Error unmarshaling final config: %v\n", err)
|
||||
}
|
||||
|
||||
fmt.Println("\n=== Final Configuration (Defaults + File + CLI) ===")
|
||||
printLogConfig(finalConfig)
|
||||
|
||||
// 10. Verify final values (Defaults < File < CLI)
|
||||
fmt.Println("\n=== Final Verification ===")
|
||||
verifyFinalConfig(finalConfig)
|
||||
|
||||
// 11. Demonstrate typed accessors on the final state
|
||||
fmt.Println("\n=== Demonstrating Typed Accessors ===")
|
||||
level, err := cfg2.Int64("log.level")
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR getting log.level via Int64(): %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("SUCCESS: cfg2.Int64(\"log.level\") = %d (matches expected CLI override)\n", level)
|
||||
}
|
||||
|
||||
name, err := cfg2.String("log.name")
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR getting log.name via String(): %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("SUCCESS: cfg2.String(\"log.name\") = %q (matches expected CLI override)\n", name)
|
||||
}
|
||||
|
||||
showTS, err := cfg2.Bool("log.show_timestamp")
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR getting log.show_timestamp via Bool(): %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("SUCCESS: cfg2.Bool(\"log.show_timestamp\") = %t (matches expected CLI override)\n", showTS)
|
||||
}
|
||||
|
||||
// Try getting an unregistered value (should fail)
|
||||
_, err = cfg2.String("other.value")
|
||||
if err == nil {
|
||||
fmt.Println("ERROR: Expected error when getting unregistered key 'other.value', but got nil")
|
||||
} else {
|
||||
fmt.Printf("SUCCESS: Correctly got error for unregistered key 'other.value': %v\n", err)
|
||||
}
|
||||
|
||||
fmt.Println("\n=== Test Complete ===")
|
||||
}
|
||||
|
||||
// printLogConfig prints the values of a LogConfig struct
|
||||
func printLogConfig(cfg LogConfig) {
|
||||
fmt.Println(" Basic:")
|
||||
fmt.Printf(" Level: %d, Name: %s, Dir: %s, Format: %s, Ext: %s\n",
|
||||
cfg.Level, cfg.Name, cfg.Directory, cfg.Format, cfg.Extension)
|
||||
fmt.Println(" Formatting:")
|
||||
fmt.Printf(" ShowTimestamp: %t, ShowLevel: %t\n", cfg.ShowTimestamp, cfg.ShowLevel)
|
||||
fmt.Println(" Limits:")
|
||||
fmt.Printf(" BufferSize: %d, MaxSizeMB: %d, MaxTotalSizeMB: %d, MinDiskFreeMB: %d\n",
|
||||
cfg.BufferSize, cfg.MaxSizeMB, cfg.MaxTotalSizeMB, cfg.MinDiskFreeMB)
|
||||
fmt.Println(" Timers:")
|
||||
fmt.Printf(" FlushIntervalMs: %d, TraceDepth: %d, RetentionPeriodHrs: %.1f, RetentionCheckMins: %.1f\n",
|
||||
cfg.FlushIntervalMs, cfg.TraceDepth, cfg.RetentionPeriodHrs, cfg.RetentionCheckMins)
|
||||
fmt.Println(" Disk Check:")
|
||||
fmt.Printf(" DiskCheckIntervalMs: %d, EnableAdaptive: %t, MinCheckMs: %d, MaxCheckMs: %d\n",
|
||||
cfg.DiskCheckIntervalMs, cfg.EnableAdaptiveInterval, cfg.MinCheckIntervalMs, cfg.MaxCheckIntervalMs)
|
||||
}
|
||||
|
||||
// verifyFinalConfig checks if the final values reflect the merge order: Default < File < CLI
|
||||
func verifyFinalConfig(cfg LogConfig) {
|
||||
allCorrect := true
|
||||
fmt.Println("Verifying values reflect merge order (Default < File < CLI)...")
|
||||
|
||||
// Value overridden by CLI
|
||||
if cfg.Level != 3 {
|
||||
fmt.Printf(" ERROR: Level is %d, expected 3 (from CLI)\n", cfg.Level)
|
||||
allCorrect = false
|
||||
}
|
||||
// Value overridden by CLI (overriding file value)
|
||||
if cfg.Name != "cli_logger" {
|
||||
fmt.Printf(" ERROR: Name is %s, expected 'cli_logger' (from CLI)\n", cfg.Name)
|
||||
allCorrect = false
|
||||
}
|
||||
// Value overridden by CLI
|
||||
if cfg.ShowTimestamp != false {
|
||||
fmt.Printf(" ERROR: ShowTimestamp is %t, expected false (from CLI)\n", cfg.ShowTimestamp)
|
||||
allCorrect = false
|
||||
}
|
||||
// Value overridden by CLI (float)
|
||||
if cfg.RetentionPeriodHrs != 72.5 {
|
||||
fmt.Printf(" ERROR: RetentionPeriodHrs is %.1f, expected 72.5 (from CLI)\n", cfg.RetentionPeriodHrs)
|
||||
allCorrect = false
|
||||
}
|
||||
|
||||
// Value overridden by File (not present in CLI)
|
||||
if cfg.MaxSizeMB != 50 {
|
||||
fmt.Printf(" ERROR: MaxSizeMB is %d, expected 50 (from File)\n", cfg.MaxSizeMB)
|
||||
allCorrect = false
|
||||
}
|
||||
|
||||
// Value from Default (not in File or CLI)
|
||||
if cfg.Directory != "./logs" {
|
||||
fmt.Printf(" ERROR: Directory is %s, expected './logs' (from Default)\n", cfg.Directory)
|
||||
allCorrect = false
|
||||
}
|
||||
if cfg.BufferSize != 1000 {
|
||||
fmt.Printf(" ERROR: BufferSize is %d, expected 1000 (from Default)\n", cfg.BufferSize)
|
||||
allCorrect = false
|
||||
}
|
||||
|
||||
if allCorrect {
|
||||
fmt.Println(" SUCCESS: All verified configuration values match expected final state!")
|
||||
} else {
|
||||
fmt.Println(" FAILURE: Some configuration values don't match expected final state!")
|
||||
}
|
||||
}
|
||||
301
cmd/test/main.go
Normal file
301
cmd/test/main.go
Normal file
@ -0,0 +1,301 @@
|
||||
// File: lixenwraith/cmd/test/main.go
|
||||
// Test program for the config package
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/lixenwraith/config"
|
||||
)
|
||||
|
||||
// AppConfig represents a simple application configuration
|
||||
type AppConfig struct {
|
||||
Server struct {
|
||||
Host string `toml:"host"`
|
||||
Port int `toml:"port"`
|
||||
} `toml:"server"`
|
||||
Database struct {
|
||||
URL string `toml:"url"`
|
||||
MaxConns int `toml:"max_conns"`
|
||||
} `toml:"database"`
|
||||
API struct {
|
||||
Key string `toml:"key" env:"CUSTOM_API_KEY"` // Custom env mapping
|
||||
Timeout int `toml:"timeout"`
|
||||
} `toml:"api"`
|
||||
Debug bool `toml:"debug"`
|
||||
LogFile string `toml:"log_file"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Config Package Feature Test ===\n")
|
||||
|
||||
// Test directories
|
||||
tempDir := os.TempDir()
|
||||
configPath := filepath.Join(tempDir, "test_config.toml")
|
||||
defer os.Remove(configPath)
|
||||
|
||||
// Set up test environment variables
|
||||
setupEnvironment()
|
||||
defer cleanupEnvironment()
|
||||
|
||||
// Run feature tests
|
||||
testQuickStart()
|
||||
testBuilder()
|
||||
testSourceTracking()
|
||||
testEnvironmentFeatures()
|
||||
testValidation()
|
||||
testUtilities()
|
||||
|
||||
fmt.Println("\n=== All Tests Complete ===")
|
||||
}
|
||||
|
||||
func testQuickStart() {
|
||||
fmt.Println("=== Test 1: Quick Start ===")
|
||||
|
||||
// Define defaults
|
||||
defaults := AppConfig{}
|
||||
defaults.Server.Host = "localhost"
|
||||
defaults.Server.Port = 8080
|
||||
defaults.Database.URL = "postgres://localhost/testdb"
|
||||
defaults.Database.MaxConns = 10
|
||||
defaults.Debug = false
|
||||
|
||||
// Quick initialization
|
||||
cfg, err := config.Quick(defaults, "TEST_", "")
|
||||
if err != nil {
|
||||
log.Fatalf("Quick init failed: %v", err)
|
||||
}
|
||||
|
||||
// Access values
|
||||
host, _ := cfg.String("server.host")
|
||||
port, _ := cfg.Int64("server.port")
|
||||
fmt.Printf("Quick config - Host: %s, Port: %d\n", host, port)
|
||||
|
||||
// Verify env override (TEST_DEBUG=true was set)
|
||||
debug, _ := cfg.Bool("debug")
|
||||
fmt.Printf("Debug from env: %v (should be true)\n", debug)
|
||||
}
|
||||
|
||||
func testBuilder() {
|
||||
fmt.Println("\n=== Test 2: Builder Pattern ===")
|
||||
|
||||
defaults := AppConfig{}
|
||||
defaults.Server.Port = 8080
|
||||
defaults.API.Timeout = 30
|
||||
|
||||
// Custom precedence: Env > File > CLI > Default
|
||||
cfg, err := config.NewBuilder().
|
||||
WithDefaults(defaults).
|
||||
WithEnvPrefix("APP_").
|
||||
WithSources(
|
||||
config.SourceEnv,
|
||||
config.SourceFile,
|
||||
config.SourceCLI,
|
||||
config.SourceDefault,
|
||||
).
|
||||
WithArgs([]string{"--server.port=9999"}).
|
||||
Build()
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Builder failed: %v", err)
|
||||
}
|
||||
|
||||
// ENV should win over CLI due to custom precedence
|
||||
port, _ := cfg.Int64("server.port")
|
||||
fmt.Printf("Port with Env > CLI precedence: %d (should be 7070 from env)\n", port)
|
||||
}
|
||||
|
||||
func testSourceTracking() {
|
||||
fmt.Println("\n=== Test 3: Source Tracking ===")
|
||||
|
||||
cfg := config.New()
|
||||
cfg.Register("test.value", "default")
|
||||
|
||||
// Set from multiple sources
|
||||
cfg.SetSource("test.value", config.SourceFile, "from-file")
|
||||
cfg.SetSource("test.value", config.SourceEnv, "from-env")
|
||||
cfg.SetSource("test.value", config.SourceCLI, "from-cli")
|
||||
|
||||
// Show all sources
|
||||
sources := cfg.GetSources("test.value")
|
||||
fmt.Println("All sources for test.value:")
|
||||
for source, value := range sources {
|
||||
fmt.Printf(" %s: %v\n", source, value)
|
||||
}
|
||||
|
||||
// Get from specific source
|
||||
envVal, exists := cfg.GetSource("test.value", config.SourceEnv)
|
||||
fmt.Printf("Value from env source: %v (exists: %v)\n", envVal, exists)
|
||||
|
||||
// Current value (default precedence)
|
||||
current, _ := cfg.String("test.value")
|
||||
fmt.Printf("Current value: %s (should be from-cli)\n", current)
|
||||
}
|
||||
|
||||
func testEnvironmentFeatures() {
|
||||
fmt.Println("\n=== Test 4: Environment Features ===")
|
||||
|
||||
cfg := config.New()
|
||||
cfg.Register("api.key", "")
|
||||
cfg.Register("api.secret", "")
|
||||
cfg.Register("database.host", "localhost")
|
||||
|
||||
// Test 4a: Custom env transform
|
||||
fmt.Println("\n4a. Custom Environment Transform:")
|
||||
opts := config.LoadOptions{
|
||||
Sources: []config.Source{config.SourceEnv, config.SourceDefault},
|
||||
EnvTransform: func(path string) string {
|
||||
switch path {
|
||||
case "api.key":
|
||||
return "CUSTOM_API_KEY"
|
||||
case "database.host":
|
||||
return "DB_HOST"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
},
|
||||
}
|
||||
cfg.LoadWithOptions("", nil, opts)
|
||||
|
||||
apiKey, _ := cfg.String("api.key")
|
||||
fmt.Printf("API Key from CUSTOM_API_KEY: %s\n", apiKey)
|
||||
|
||||
// Test 4b: Discover environment variables
|
||||
fmt.Println("\n4b. Environment Discovery:")
|
||||
cfg2 := config.New()
|
||||
cfg2.Register("server.port", 8080)
|
||||
cfg2.Register("debug", false)
|
||||
cfg2.Register("api.timeout", 30)
|
||||
|
||||
discovered := cfg2.DiscoverEnv("TEST_")
|
||||
fmt.Println("Discovered env vars with TEST_ prefix:")
|
||||
for path, envVar := range discovered {
|
||||
fmt.Printf(" %s -> %s\n", path, envVar)
|
||||
}
|
||||
|
||||
// Test 4c: Export configuration as env vars
|
||||
fmt.Println("\n4c. Export as Environment:")
|
||||
cfg2.Set("server.port", 3000)
|
||||
cfg2.Set("debug", true)
|
||||
|
||||
exports := cfg2.ExportEnv("EXPORT_")
|
||||
fmt.Println("Non-default values exported:")
|
||||
for env, value := range exports {
|
||||
fmt.Printf(" export %s=%s\n", env, value)
|
||||
}
|
||||
|
||||
// Test 4d: RegisterWithEnv
|
||||
fmt.Println("\n4d. RegisterWithEnv:")
|
||||
cfg3 := config.New()
|
||||
err := cfg3.RegisterWithEnv("special.value", "default", "SPECIAL_ENV_VAR")
|
||||
if err != nil {
|
||||
fmt.Printf("RegisterWithEnv error: %v\n", err)
|
||||
}
|
||||
special, _ := cfg3.String("special.value")
|
||||
fmt.Printf("Value from SPECIAL_ENV_VAR: %s\n", special)
|
||||
}
|
||||
|
||||
func testValidation() {
|
||||
fmt.Println("\n=== Test 5: Validation ===")
|
||||
|
||||
cfg := config.New()
|
||||
cfg.RegisterRequired("api.key", "")
|
||||
cfg.RegisterRequired("database.url", "")
|
||||
cfg.Register("optional.setting", "default")
|
||||
|
||||
// Should fail validation
|
||||
err := cfg.Validate("api.key", "database.url")
|
||||
if err != nil {
|
||||
fmt.Printf("Validation failed as expected: %v\n", err)
|
||||
}
|
||||
|
||||
// Set required values
|
||||
cfg.Set("api.key", "secret-key")
|
||||
cfg.Set("database.url", "postgres://localhost/db")
|
||||
|
||||
// Should pass validation
|
||||
err = cfg.Validate("api.key", "database.url")
|
||||
if err == nil {
|
||||
fmt.Println("Validation passed after setting required values")
|
||||
}
|
||||
}
|
||||
|
||||
func testUtilities() {
|
||||
fmt.Println("\n=== Test 6: Utility Features ===")
|
||||
|
||||
// Create config with some data
|
||||
cfg := config.New()
|
||||
cfg.Register("app.name", "testapp")
|
||||
cfg.Register("app.version", "1.0.0")
|
||||
cfg.Register("server.port", 8080)
|
||||
|
||||
cfg.SetSource("app.version", config.SourceFile, "1.1.0")
|
||||
cfg.SetSource("server.port", config.SourceEnv, 9090)
|
||||
|
||||
// Test 6a: Debug output
|
||||
fmt.Println("\n6a. Debug Output:")
|
||||
debug := cfg.Debug()
|
||||
fmt.Printf("Debug info (first 200 chars): %.200s...\n", debug)
|
||||
|
||||
// Test 6b: Clone
|
||||
fmt.Println("\n6b. Clone Configuration:")
|
||||
clone := cfg.Clone()
|
||||
clone.Set("app.name", "cloned-app")
|
||||
|
||||
original, _ := cfg.String("app.name")
|
||||
cloned, _ := clone.String("app.name")
|
||||
fmt.Printf("Original app.name: %s, Cloned: %s\n", original, cloned)
|
||||
|
||||
// Test 6c: Reset source
|
||||
fmt.Println("\n6c. Reset Sources:")
|
||||
sources := cfg.GetSources("server.port")
|
||||
fmt.Printf("Sources before reset: %v\n", sources)
|
||||
|
||||
cfg.ResetSource(config.SourceEnv)
|
||||
sources = cfg.GetSources("server.port")
|
||||
fmt.Printf("Sources after env reset: %v\n", sources)
|
||||
|
||||
// Test 6d: Save and load specific source
|
||||
fmt.Println("\n6d. Save/Load Specific Source:")
|
||||
tempFile := filepath.Join(os.TempDir(), "source_test.toml")
|
||||
defer os.Remove(tempFile)
|
||||
|
||||
err := cfg.SaveSource(tempFile, config.SourceFile)
|
||||
if err != nil {
|
||||
fmt.Printf("SaveSource error: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("Saved SourceFile values to temp file")
|
||||
}
|
||||
|
||||
// Test 6e: GetRegisteredPaths
|
||||
fmt.Println("\n6e. Registered Paths:")
|
||||
paths := cfg.GetRegisteredPaths("app.")
|
||||
fmt.Printf("Paths with 'app.' prefix: %v\n", paths)
|
||||
|
||||
pathsWithDefaults := cfg.GetRegisteredPathsWithDefaults("app.")
|
||||
for path, def := range pathsWithDefaults {
|
||||
fmt.Printf(" %s: %v\n", path, def)
|
||||
}
|
||||
}
|
||||
|
||||
func setupEnvironment() {
|
||||
// Set test environment variables
|
||||
os.Setenv("TEST_DEBUG", "true")
|
||||
os.Setenv("TEST_SERVER_PORT", "6666")
|
||||
os.Setenv("APP_SERVER_PORT", "7070")
|
||||
os.Setenv("CUSTOM_API_KEY", "env-api-key")
|
||||
os.Setenv("DB_HOST", "env-db-host")
|
||||
os.Setenv("SPECIAL_ENV_VAR", "special-value")
|
||||
}
|
||||
|
||||
func cleanupEnvironment() {
|
||||
os.Unsetenv("TEST_DEBUG")
|
||||
os.Unsetenv("TEST_SERVER_PORT")
|
||||
os.Unsetenv("APP_SERVER_PORT")
|
||||
os.Unsetenv("CUSTOM_API_KEY")
|
||||
os.Unsetenv("DB_HOST")
|
||||
os.Unsetenv("SPECIAL_ENV_VAR")
|
||||
}
|
||||
Reference in New Issue
Block a user