504 lines
11 KiB
Go
504 lines
11 KiB
Go
package ezconf
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// testConfig is a Config struct used by multiple tests
|
|
type testConfig struct {
|
|
LogLevel string `ezconf:"LOG_LEVEL,description:Log level for the application,default:info"`
|
|
LogOutput string `ezconf:"LOG_OUTPUT,description:Output destination,default:console"`
|
|
DatabaseURL string `ezconf:"DATABASE_URL,description:Database connection string,required"`
|
|
}
|
|
|
|
func TestNew(t *testing.T) {
|
|
loader := New()
|
|
if loader == nil {
|
|
t.Fatal("New() returned nil")
|
|
}
|
|
|
|
if loader.configFuncs == nil {
|
|
t.Error("configFuncs map is nil")
|
|
}
|
|
if loader.configStructs == nil {
|
|
t.Error("configStructs slice is nil")
|
|
}
|
|
if loader.extraEnvVars == nil {
|
|
t.Error("extraEnvVars slice is nil")
|
|
}
|
|
if loader.configs == nil {
|
|
t.Error("configs map is nil")
|
|
}
|
|
}
|
|
|
|
func TestAddConfigFunc(t *testing.T) {
|
|
loader := New()
|
|
|
|
testFunc := func() (interface{}, error) {
|
|
return "test config", nil
|
|
}
|
|
|
|
err := loader.AddConfigFunc("test", testFunc)
|
|
if err != nil {
|
|
t.Errorf("AddConfigFunc failed: %v", err)
|
|
}
|
|
|
|
if len(loader.configFuncs) != 1 {
|
|
t.Errorf("expected 1 config func, got %d", len(loader.configFuncs))
|
|
}
|
|
}
|
|
|
|
func TestAddConfigFunc_NilFunction(t *testing.T) {
|
|
loader := New()
|
|
|
|
err := loader.AddConfigFunc("test", nil)
|
|
if err == nil {
|
|
t.Error("expected error for nil function")
|
|
}
|
|
}
|
|
|
|
func TestAddConfigFunc_EmptyName(t *testing.T) {
|
|
loader := New()
|
|
|
|
testFunc := func() (interface{}, error) {
|
|
return "test config", nil
|
|
}
|
|
|
|
err := loader.AddConfigFunc("", testFunc)
|
|
if err == nil {
|
|
t.Error("expected error for empty name")
|
|
}
|
|
}
|
|
|
|
func TestAddConfigStruct(t *testing.T) {
|
|
loader := New()
|
|
|
|
err := loader.AddConfigStruct(&testConfig{}, "Test")
|
|
if err != nil {
|
|
t.Errorf("AddConfigStruct failed: %v", err)
|
|
}
|
|
|
|
if len(loader.configStructs) != 1 {
|
|
t.Errorf("expected 1 config struct, got %d", len(loader.configStructs))
|
|
}
|
|
}
|
|
|
|
func TestAddConfigStruct_NilPointer(t *testing.T) {
|
|
loader := New()
|
|
|
|
err := loader.AddConfigStruct(nil, "Test")
|
|
if err == nil {
|
|
t.Error("expected error for nil pointer")
|
|
}
|
|
}
|
|
|
|
func TestAddConfigStruct_EmptyGroupName(t *testing.T) {
|
|
loader := New()
|
|
|
|
err := loader.AddConfigStruct(&testConfig{}, "")
|
|
if err != nil {
|
|
t.Errorf("AddConfigStruct failed: %v", err)
|
|
}
|
|
|
|
// Should default to "Other"
|
|
if loader.configStructs[0].groupName != "Other" {
|
|
t.Errorf("expected group name 'Other', got %s", loader.configStructs[0].groupName)
|
|
}
|
|
}
|
|
|
|
func TestAddEnvVar(t *testing.T) {
|
|
loader := New()
|
|
|
|
envVar := EnvVar{
|
|
Name: "TEST_VAR",
|
|
Description: "Test variable",
|
|
Required: true,
|
|
Default: "default_value",
|
|
}
|
|
|
|
loader.AddEnvVar(envVar)
|
|
|
|
if len(loader.extraEnvVars) != 1 {
|
|
t.Errorf("expected 1 extra env var, got %d", len(loader.extraEnvVars))
|
|
}
|
|
|
|
if loader.extraEnvVars[0].Name != "TEST_VAR" {
|
|
t.Errorf("expected TEST_VAR, got %s", loader.extraEnvVars[0].Name)
|
|
}
|
|
}
|
|
|
|
func TestLoad(t *testing.T) {
|
|
loader := New()
|
|
|
|
// Add a test config function
|
|
testCfg := struct {
|
|
Value string
|
|
}{Value: "test"}
|
|
|
|
loader.AddConfigFunc("test", func() (interface{}, error) {
|
|
return testCfg, nil
|
|
})
|
|
|
|
// Add config struct for tag parsing
|
|
loader.AddConfigStruct(&testConfig{}, "Test")
|
|
|
|
// Add an extra env var
|
|
loader.AddEnvVar(EnvVar{
|
|
Name: "EXTRA_VAR",
|
|
Description: "Extra test variable",
|
|
Default: "extra",
|
|
})
|
|
|
|
err := loader.Load()
|
|
if err != nil {
|
|
t.Fatalf("Load failed: %v", err)
|
|
}
|
|
|
|
// Check that config was loaded
|
|
cfg, ok := loader.GetConfig("test")
|
|
if !ok {
|
|
t.Error("test config not loaded")
|
|
}
|
|
if cfg == nil {
|
|
t.Error("test config is nil")
|
|
}
|
|
|
|
// Check that env vars were extracted
|
|
envVars := loader.GetEnvVars()
|
|
if len(envVars) == 0 {
|
|
t.Error("expected at least one env var")
|
|
}
|
|
|
|
// Check for extra var
|
|
foundExtra := false
|
|
for _, ev := range envVars {
|
|
if ev.Name == "EXTRA_VAR" {
|
|
foundExtra = true
|
|
break
|
|
}
|
|
}
|
|
if !foundExtra {
|
|
t.Error("extra env var not found")
|
|
}
|
|
}
|
|
|
|
func TestLoad_ConfigFuncError(t *testing.T) {
|
|
loader := New()
|
|
|
|
loader.AddConfigFunc("error", func() (interface{}, error) {
|
|
return nil, os.ErrNotExist
|
|
})
|
|
|
|
err := loader.Load()
|
|
if err == nil {
|
|
t.Error("expected error from failing config func")
|
|
}
|
|
}
|
|
|
|
func TestGetConfig(t *testing.T) {
|
|
loader := New()
|
|
|
|
testCfg := "test config"
|
|
loader.configs["test"] = testCfg
|
|
|
|
cfg, ok := loader.GetConfig("test")
|
|
if !ok {
|
|
t.Error("expected to find test config")
|
|
}
|
|
if cfg != testCfg {
|
|
t.Error("config value mismatch")
|
|
}
|
|
|
|
// Test non-existent config
|
|
_, ok = loader.GetConfig("nonexistent")
|
|
if ok {
|
|
t.Error("expected not to find nonexistent config")
|
|
}
|
|
}
|
|
|
|
func TestGetAllConfigs(t *testing.T) {
|
|
loader := New()
|
|
|
|
loader.configs["test1"] = "config1"
|
|
loader.configs["test2"] = "config2"
|
|
|
|
allConfigs := loader.GetAllConfigs()
|
|
if len(allConfigs) != 2 {
|
|
t.Errorf("expected 2 configs, got %d", len(allConfigs))
|
|
}
|
|
|
|
if allConfigs["test1"] != "config1" {
|
|
t.Error("test1 config mismatch")
|
|
}
|
|
if allConfigs["test2"] != "config2" {
|
|
t.Error("test2 config mismatch")
|
|
}
|
|
}
|
|
|
|
func TestGetEnvVars(t *testing.T) {
|
|
loader := New()
|
|
|
|
loader.envVars = []EnvVar{
|
|
{Name: "VAR1", Description: "Variable 1"},
|
|
{Name: "VAR2", Description: "Variable 2"},
|
|
}
|
|
|
|
envVars := loader.GetEnvVars()
|
|
if len(envVars) != 2 {
|
|
t.Errorf("expected 2 env vars, got %d", len(envVars))
|
|
}
|
|
}
|
|
|
|
func TestParseEnvVars(t *testing.T) {
|
|
loader := New()
|
|
|
|
// Add a test config function
|
|
loader.AddConfigFunc("test", func() (interface{}, error) {
|
|
return "test config", nil
|
|
})
|
|
|
|
// Add config struct for tag parsing
|
|
loader.AddConfigStruct(&testConfig{}, "Test")
|
|
|
|
// Add an extra env var
|
|
loader.AddEnvVar(EnvVar{
|
|
Name: "EXTRA_VAR",
|
|
Description: "Extra test variable",
|
|
Default: "extra",
|
|
})
|
|
|
|
err := loader.ParseEnvVars()
|
|
if err != nil {
|
|
t.Fatalf("ParseEnvVars failed: %v", err)
|
|
}
|
|
|
|
// Check that env vars were extracted
|
|
envVars := loader.GetEnvVars()
|
|
if len(envVars) == 0 {
|
|
t.Error("expected at least one env var")
|
|
}
|
|
|
|
// Check for extra var
|
|
foundExtra := false
|
|
for _, ev := range envVars {
|
|
if ev.Name == "EXTRA_VAR" {
|
|
foundExtra = true
|
|
break
|
|
}
|
|
}
|
|
if !foundExtra {
|
|
t.Error("extra env var not found")
|
|
}
|
|
|
|
// Check that configs are NOT loaded (should be empty)
|
|
configs := loader.GetAllConfigs()
|
|
if len(configs) != 0 {
|
|
t.Errorf("expected no configs loaded after ParseEnvVars, got %d", len(configs))
|
|
}
|
|
}
|
|
|
|
func TestLoadConfigs(t *testing.T) {
|
|
loader := New()
|
|
|
|
// Add a test config function
|
|
testCfg := struct {
|
|
Value string
|
|
}{Value: "test"}
|
|
|
|
loader.AddConfigFunc("test", func() (interface{}, error) {
|
|
return testCfg, nil
|
|
})
|
|
|
|
// Manually set some env vars (simulating ParseEnvVars already called)
|
|
loader.envVars = []EnvVar{
|
|
{Name: "TEST_VAR", Description: "Test variable"},
|
|
}
|
|
|
|
err := loader.LoadConfigs()
|
|
if err != nil {
|
|
t.Fatalf("LoadConfigs failed: %v", err)
|
|
}
|
|
|
|
// Check that config was loaded
|
|
cfg, ok := loader.GetConfig("test")
|
|
if !ok {
|
|
t.Error("test config not loaded")
|
|
}
|
|
if cfg == nil {
|
|
t.Error("test config is nil")
|
|
}
|
|
_ = cfg // Use the variable to avoid unused variable error
|
|
|
|
// Check that env vars are NOT modified (should remain as set)
|
|
envVars := loader.GetEnvVars()
|
|
if len(envVars) != 1 {
|
|
t.Errorf("expected 1 env var, got %d", len(envVars))
|
|
}
|
|
}
|
|
|
|
func TestLoadConfigs_Error(t *testing.T) {
|
|
loader := New()
|
|
|
|
loader.AddConfigFunc("error", func() (interface{}, error) {
|
|
return nil, os.ErrNotExist
|
|
})
|
|
|
|
err := loader.LoadConfigs()
|
|
if err == nil {
|
|
t.Error("expected error from failing config func")
|
|
}
|
|
}
|
|
|
|
func TestParseEnvVars_Then_LoadConfigs(t *testing.T) {
|
|
loader := New()
|
|
|
|
// Add a test config function
|
|
testCfg := struct {
|
|
Value string
|
|
}{Value: "test"}
|
|
|
|
loader.AddConfigFunc("test", func() (interface{}, error) {
|
|
return testCfg, nil
|
|
})
|
|
|
|
// Add config struct for tag parsing
|
|
loader.AddConfigStruct(&testConfig{}, "Test")
|
|
|
|
// Add an extra env var
|
|
loader.AddEnvVar(EnvVar{
|
|
Name: "EXTRA_VAR",
|
|
Description: "Extra test variable",
|
|
Default: "extra",
|
|
})
|
|
|
|
// First parse env vars
|
|
err := loader.ParseEnvVars()
|
|
if err != nil {
|
|
t.Fatalf("ParseEnvVars failed: %v", err)
|
|
}
|
|
|
|
// Check env vars are extracted but configs are not loaded
|
|
envVars := loader.GetEnvVars()
|
|
if len(envVars) == 0 {
|
|
t.Error("expected env vars to be extracted")
|
|
}
|
|
|
|
configs := loader.GetAllConfigs()
|
|
if len(configs) != 0 {
|
|
t.Error("expected no configs loaded yet")
|
|
}
|
|
|
|
// Then load configs
|
|
err = loader.LoadConfigs()
|
|
if err != nil {
|
|
t.Fatalf("LoadConfigs failed: %v", err)
|
|
}
|
|
|
|
// Check both env vars and configs are loaded
|
|
_, ok := loader.GetConfig("test")
|
|
if !ok {
|
|
t.Error("test config not loaded after LoadConfigs")
|
|
}
|
|
|
|
configs = loader.GetAllConfigs()
|
|
if len(configs) != 1 {
|
|
t.Errorf("expected 1 config loaded, got %d", len(configs))
|
|
}
|
|
}
|
|
|
|
func TestParseEnvVars_GroupName(t *testing.T) {
|
|
loader := New()
|
|
|
|
loader.AddConfigStruct(&testConfig{}, "MyGroup")
|
|
|
|
err := loader.ParseEnvVars()
|
|
if err != nil {
|
|
t.Fatalf("ParseEnvVars failed: %v", err)
|
|
}
|
|
|
|
envVars := loader.GetEnvVars()
|
|
for _, ev := range envVars {
|
|
if ev.Group != "MyGroup" {
|
|
t.Errorf("expected group 'MyGroup', got '%s' for var %s", ev.Group, ev.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseEnvVars_CurrentValues(t *testing.T) {
|
|
loader := New()
|
|
|
|
loader.AddConfigStruct(&testConfig{}, "Test")
|
|
|
|
// Set an env var
|
|
t.Setenv("LOG_LEVEL", "debug")
|
|
|
|
err := loader.ParseEnvVars()
|
|
if err != nil {
|
|
t.Fatalf("ParseEnvVars failed: %v", err)
|
|
}
|
|
|
|
envVars := loader.GetEnvVars()
|
|
for _, ev := range envVars {
|
|
if ev.Name == "LOG_LEVEL" {
|
|
if ev.CurrentValue != "debug" {
|
|
t.Errorf("expected CurrentValue 'debug', got '%s'", ev.CurrentValue)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
t.Error("LOG_LEVEL not found in env vars")
|
|
}
|
|
|
|
func TestParseEnvVars_GenerateEnvFile_Integration(t *testing.T) {
|
|
loader := New()
|
|
|
|
// Add config struct for tag parsing
|
|
loader.AddConfigStruct(&testConfig{}, "Test")
|
|
|
|
// Parse env vars
|
|
if err := loader.ParseEnvVars(); err != nil {
|
|
t.Fatalf("ParseEnvVars failed: %v", err)
|
|
}
|
|
|
|
envVars := loader.GetEnvVars()
|
|
if len(envVars) == 0 {
|
|
t.Error("expected env vars from config struct")
|
|
}
|
|
|
|
// Now test that we can generate an env file without calling Load()
|
|
tempDir := t.TempDir()
|
|
envFile := tempDir + "/test-generated.env"
|
|
|
|
err := loader.GenerateEnvFile(envFile, false)
|
|
if err != nil {
|
|
t.Fatalf("GenerateEnvFile failed: %v", err)
|
|
}
|
|
|
|
// Verify the file was created and contains expected content
|
|
content, err := os.ReadFile(envFile)
|
|
if err != nil {
|
|
t.Fatalf("failed to read generated file: %v", err)
|
|
}
|
|
|
|
output := string(content)
|
|
if !strings.Contains(output, "# Environment Configuration") {
|
|
t.Error("expected header in generated file")
|
|
}
|
|
|
|
// Should contain environment variables from config struct
|
|
foundVar := false
|
|
for _, ev := range envVars {
|
|
if strings.Contains(output, ev.Name) {
|
|
foundVar = true
|
|
break
|
|
}
|
|
}
|
|
if !foundVar {
|
|
t.Error("expected to find at least one environment variable in generated file")
|
|
}
|
|
|
|
t.Logf("Successfully generated env file with %d variables", len(envVars))
|
|
}
|