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)) }