package config import ( "os" "testing" ) // TestGetEnv tests the getEnv helper function func TestGetEnv(t *testing.T) { // Test with default value when env var not set result := getEnv("TEST_NONEXISTENT_VAR_12345", "default") if result != "default" { t.Errorf("Expected 'default', got '%s'", result) } // Test with set env var os.Setenv("TEST_ENV_VAR", "custom_value") defer os.Unsetenv("TEST_ENV_VAR") result = getEnv("TEST_ENV_VAR", "default") if result != "custom_value" { t.Errorf("Expected 'custom_value', got '%s'", result) } } // TestGetEnvInt tests the getEnvInt helper function func TestGetEnvInt(t *testing.T) { tests := []struct { name string envValue string defaultValue int expected int }{ {"default when not set", "", 100, 100}, {"parse valid int", "42", 0, 42}, {"parse zero", "0", 100, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.envValue != "" { os.Setenv("TEST_INT_VAR", tt.envValue) defer os.Unsetenv("TEST_INT_VAR") } else { os.Unsetenv("TEST_INT_VAR") } result := getEnvInt("TEST_INT_VAR", tt.defaultValue) if result != tt.expected { t.Errorf("Expected %d, got %d", tt.expected, result) } }) } } // TestGetEnvBool tests the getEnvBool helper function func TestGetEnvBool(t *testing.T) { tests := []struct { name string envValue string defaultValue bool expected bool }{ {"default when not set", "", true, true}, {"default false when not set", "", false, false}, {"parse true", "true", false, true}, {"parse 1", "1", false, true}, {"parse yes", "yes", false, true}, {"parse false", "false", true, false}, {"parse 0", "0", true, false}, {"parse no", "no", true, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.envValue != "" { os.Setenv("TEST_BOOL_VAR", tt.envValue) defer os.Unsetenv("TEST_BOOL_VAR") } else { os.Unsetenv("TEST_BOOL_VAR") } result := getEnvBool("TEST_BOOL_VAR", tt.defaultValue) if result != tt.expected { t.Errorf("Expected %v, got %v", tt.expected, result) } }) } } // TestParseCommaSeparated tests the parseCommaSeparated helper function func TestParseCommaSeparated(t *testing.T) { tests := []struct { name string input string expected []string }{ {"empty string", "", []string{}}, {"single value", "value1", []string{"value1"}}, {"multiple values", "value1,value2,value3", []string{"value1", "value2", "value3"}}, {"with spaces", "value1, value2, value3", []string{"value1", "value2", "value3"}}, {"with trailing comma", "value1,value2,", []string{"value1", "value2"}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := parseCommaSeparated(tt.input) if len(result) != len(tt.expected) { t.Errorf("Expected length %d, got %d", len(tt.expected), len(result)) return } for i := range result { if result[i] != tt.expected[i] { t.Errorf("At index %d: expected '%s', got '%s'", i, tt.expected[i], result[i]) } } }) } } // TestConfigEnvironmentDefaults tests default environment values func TestConfigEnvironmentDefaults(t *testing.T) { // Clear any existing env vars that might interfere varsToUnset := []string{ "PORT", "ENVIRONMENT", "DATABASE_URL", "JWT_SECRET", "JWT_REFRESH_SECRET", } for _, v := range varsToUnset { os.Unsetenv(v) } // Set required vars os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test") os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here") defer func() { os.Unsetenv("DATABASE_URL") os.Unsetenv("JWT_SECRET") }() cfg, err := Load() if err != nil { t.Fatalf("Failed to load config: %v", err) } // Test defaults if cfg.Port != "8080" { t.Errorf("Expected default port '8080', got '%s'", cfg.Port) } if cfg.Environment != "development" { t.Errorf("Expected default environment 'development', got '%s'", cfg.Environment) } } // TestConfigLoadWithEnvironment tests loading config with different environments func TestConfigLoadWithEnvironment(t *testing.T) { // Set required vars os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test") os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here") defer func() { os.Unsetenv("DATABASE_URL") os.Unsetenv("JWT_SECRET") }() tests := []struct { name string environment string }{ {"development", "development"}, {"staging", "staging"}, {"production", "production"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { os.Setenv("ENVIRONMENT", tt.environment) defer os.Unsetenv("ENVIRONMENT") cfg, err := Load() if err != nil { t.Fatalf("Failed to load config: %v", err) } if cfg.Environment != tt.environment { t.Errorf("Expected environment '%s', got '%s'", tt.environment, cfg.Environment) } }) } } // TestConfigMissingRequiredVars tests that missing required vars return errors func TestConfigMissingRequiredVars(t *testing.T) { // Clear all env vars os.Unsetenv("DATABASE_URL") os.Unsetenv("JWT_SECRET") _, err := Load() if err == nil { t.Error("Expected error when DATABASE_URL is missing") } // Set DATABASE_URL but not JWT_SECRET os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test") defer os.Unsetenv("DATABASE_URL") _, err = Load() if err == nil { t.Error("Expected error when JWT_SECRET is missing") } } // TestConfigAllowedOrigins tests that allowed origins are parsed correctly func TestConfigAllowedOrigins(t *testing.T) { // Set required vars os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test") os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here") os.Setenv("ALLOWED_ORIGINS", "http://localhost:3000,http://localhost:8000,http://localhost:8001") defer func() { os.Unsetenv("DATABASE_URL") os.Unsetenv("JWT_SECRET") os.Unsetenv("ALLOWED_ORIGINS") }() cfg, err := Load() if err != nil { t.Fatalf("Failed to load config: %v", err) } expected := []string{"http://localhost:3000", "http://localhost:8000", "http://localhost:8001"} if len(cfg.AllowedOrigins) != len(expected) { t.Errorf("Expected %d origins, got %d", len(expected), len(cfg.AllowedOrigins)) } for i, origin := range cfg.AllowedOrigins { if origin != expected[i] { t.Errorf("At index %d: expected '%s', got '%s'", i, expected[i], origin) } } } // TestConfigDebugSettings tests debug-related settings for different environments func TestConfigDebugSettings(t *testing.T) { // Set required vars os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test") os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here") defer func() { os.Unsetenv("DATABASE_URL") os.Unsetenv("JWT_SECRET") }() // Test development environment t.Run("development", func(t *testing.T) { os.Setenv("ENVIRONMENT", "development") defer os.Unsetenv("ENVIRONMENT") cfg, err := Load() if err != nil { t.Fatalf("Failed to load config: %v", err) } if cfg.Environment != "development" { t.Errorf("Expected 'development', got '%s'", cfg.Environment) } }) // Test staging environment t.Run("staging", func(t *testing.T) { os.Setenv("ENVIRONMENT", "staging") defer os.Unsetenv("ENVIRONMENT") cfg, err := Load() if err != nil { t.Fatalf("Failed to load config: %v", err) } if cfg.Environment != "staging" { t.Errorf("Expected 'staging', got '%s'", cfg.Environment) } }) // Test production environment t.Run("production", func(t *testing.T) { os.Setenv("ENVIRONMENT", "production") defer os.Unsetenv("ENVIRONMENT") cfg, err := Load() if err != nil { t.Fatalf("Failed to load config: %v", err) } if cfg.Environment != "production" { t.Errorf("Expected 'production', got '%s'", cfg.Environment) } }) } // TestConfigStagingPorts tests that staging uses different ports func TestConfigStagingPorts(t *testing.T) { // Set required vars os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5433/breakpilot_staging") os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here") os.Setenv("ENVIRONMENT", "staging") os.Setenv("PORT", "8081") defer func() { os.Unsetenv("DATABASE_URL") os.Unsetenv("JWT_SECRET") os.Unsetenv("ENVIRONMENT") os.Unsetenv("PORT") }() cfg, err := Load() if err != nil { t.Fatalf("Failed to load config: %v", err) } if cfg.Port != "8081" { t.Errorf("Expected staging port '8081', got '%s'", cfg.Port) } if cfg.Environment != "staging" { t.Errorf("Expected 'staging', got '%s'", cfg.Environment) } }