Files
golib/ezconf/ezconf_test.go
2026-01-21 19:23:12 +11:00

489 lines
10 KiB
Go

package ezconf
import (
"os"
"path/filepath"
"strings"
"testing"
)
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.packagePaths == nil {
t.Error("packagePaths 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 TestAddPackagePath(t *testing.T) {
loader := New()
// Use current directory as test path
err := loader.AddPackagePath(".")
if err != nil {
t.Errorf("AddPackagePath failed: %v", err)
}
if len(loader.packagePaths) != 1 {
t.Errorf("expected 1 package path, got %d", len(loader.packagePaths))
}
}
func TestAddPackagePath_InvalidPath(t *testing.T) {
loader := New()
err := loader.AddPackagePath("/nonexistent/path")
if err == nil {
t.Error("expected error for nonexistent path")
}
}
func TestAddPackagePath_EmptyPath(t *testing.T) {
loader := New()
err := loader.AddPackagePath("")
if err == nil {
t.Error("expected error for empty path")
}
}
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 current package path
loader.AddPackagePath(".")
// 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 current package path
loader.AddPackagePath(".")
// 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 current package path
loader.AddPackagePath(".")
// 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 TestLoad_Integration(t *testing.T) {
// Integration test with real hlog package
hlogPath := filepath.Join("..", "hlog")
if _, err := os.Stat(hlogPath); os.IsNotExist(err) {
t.Skip("hlog package not found, skipping integration test")
}
loader := New()
// Add hlog package
if err := loader.AddPackagePath(hlogPath); err != nil {
t.Fatalf("failed to add hlog package: %v", err)
}
// Load without config function (just parse)
if err := loader.Load(); err != nil {
t.Fatalf("Load failed: %v", err)
}
envVars := loader.GetEnvVars()
if len(envVars) == 0 {
t.Error("expected env vars from hlog package")
}
t.Logf("Found %d environment variables from hlog", len(envVars))
for _, ev := range envVars {
t.Logf(" %s: %s (default: %s, required: %t)", ev.Name, ev.Description, ev.Default, ev.Required)
}
}
func TestParseEnvVars_GenerateEnvFile_Integration(t *testing.T) {
// Test the new separated ParseEnvVars functionality
hlogPath := filepath.Join("..", "hlog")
if _, err := os.Stat(hlogPath); os.IsNotExist(err) {
t.Skip("hlog package not found, skipping integration test")
}
loader := New()
// Add hlog package
if err := loader.AddPackagePath(hlogPath); err != nil {
t.Fatalf("failed to add hlog package: %v", err)
}
// Parse env vars without loading configs (this should work even if required env vars are missing)
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 hlog package")
}
// Now test that we can generate an env file without calling Load()
tempDir := t.TempDir()
envFile := filepath.Join(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 hlog
foundHlogVar := false
for _, ev := range envVars {
if strings.Contains(output, ev.Name) {
foundHlogVar = true
break
}
}
if !foundHlogVar {
t.Error("expected to find at least one hlog environment variable in generated file")
}
t.Logf("Successfully generated env file with %d variables", len(envVars))
}