package config import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestConfigValidator_ValidatePort(t *testing.T) { validator := NewConfigValidator() tests := []struct { name string port int wantErr bool }{ {"valid port", 8080, false}, {"min port", 1, false}, {"max port", 65535, false}, {"invalid negative", -1, true}, {"invalid too high", 65536, true}, {"invalid zero", 0, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validator.ValidatePort(tt.port) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestConfigValidator_ValidateURL(t *testing.T) { validator := NewConfigValidator() tests := []struct { name string url string expectedScheme string wantErr bool }{ {"valid postgres URL", "postgres://user:pass@localhost:5432/db", "postgres", false}, {"valid postgresql URL", "postgresql://user:pass@localhost:5432/db", "postgresql", false}, {"valid redis URL", "redis://localhost:6379", "redis", false}, {"valid rediss URL", "rediss://localhost:6380", "rediss", false}, {"invalid scheme", "http://localhost", "postgres", true}, {"empty URL", "", "postgres", true}, {"malformed URL", "://invalid", "postgres", true}, {"missing scheme", "localhost:5432/db", "postgres", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validator.ValidateURL(tt.url, tt.expectedScheme) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestConfigValidator_ValidateEnum(t *testing.T) { validator := NewConfigValidator() tests := []struct { name string value string allowed []string wantErr bool }{ { name: "valid value in enum", value: "INFO", allowed: []string{"DEBUG", "INFO", "WARN", "ERROR"}, wantErr: false, }, { name: "case sensitive match", value: "info", allowed: []string{"INFO", "WARN"}, wantErr: true, }, { name: "value not in enum", value: "TRACE", allowed: []string{"DEBUG", "INFO", "WARN", "ERROR"}, wantErr: true, }, { name: "empty value with empty allowed", value: "", allowed: []string{}, wantErr: true, }, { name: "empty value in allowed", value: "", allowed: []string{"", "value1"}, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validator.ValidateEnum(tt.value, tt.allowed) if tt.wantErr { assert.Error(t, err) assert.Contains(t, err.Error(), "not allowed") } else { assert.NoError(t, err) } }) } } func TestConfigValidator_ValidateSecretLength(t *testing.T) { validator := NewConfigValidator() tests := []struct { name string secret string minLength int wantErr bool }{ {"valid secret", "my-super-secret-key-that-is-long-enough", 32, false}, {"exact length", strings.Repeat("a", 32), 32, false}, {"too short", "short", 32, true}, {"empty secret", "", 1, true}, {"empty secret with min 0", "", 0, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validator.ValidateSecretLength(tt.secret, tt.minLength) if tt.wantErr { assert.Error(t, err) assert.Contains(t, err.Error(), "at least") } else { assert.NoError(t, err) } }) } } func TestConfigValidator_ValidatePositiveInt(t *testing.T) { validator := NewConfigValidator() tests := []struct { name string value int fieldName string wantErr bool }{ {"valid positive", 42, "test_field", false}, {"valid one", 1, "test_field", false}, {"invalid zero", 0, "test_field", true}, {"invalid negative", -1, "test_field", true}, {"invalid large negative", -1000, "test_field", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validator.ValidatePositiveInt(tt.value, tt.fieldName) if tt.wantErr { assert.Error(t, err) assert.Contains(t, err.Error(), "must be positive") assert.Contains(t, err.Error(), tt.fieldName) } else { assert.NoError(t, err) } }) } } func TestNewConfigValidator(t *testing.T) { validator := NewConfigValidator() assert.NotNil(t, validator) } func TestConfigValidator_ValidateURL_MultipleSchemes(t *testing.T) { validator := NewConfigValidator() // Test avec différents schémas PostgreSQL err1 := validator.ValidateURL("postgres://localhost/db", "postgres") assert.NoError(t, err1) err2 := validator.ValidateURL("postgresql://localhost/db", "postgresql") assert.NoError(t, err2) // Test avec schéma Redis err3 := validator.ValidateURL("redis://localhost:6379", "redis") assert.NoError(t, err3) err4 := validator.ValidateURL("rediss://localhost:6380", "rediss") assert.NoError(t, err4) } func TestConfigValidator_ValidateEnum_ErrorMessages(t *testing.T) { validator := NewConfigValidator() err := validator.ValidateEnum("invalid", []string{"valid1", "valid2", "valid3"}) require.Error(t, err) assert.Contains(t, err.Error(), "not allowed") assert.Contains(t, err.Error(), "valid1, valid2, valid3") } func TestConfigValidator_ValidateSecretLength_ErrorMessages(t *testing.T) { validator := NewConfigValidator() err := validator.ValidateSecretLength("short", 32) require.Error(t, err) assert.Contains(t, err.Error(), "at least 32") assert.Contains(t, err.Error(), "got 5") } func TestConfigValidator_ValidatePositiveInt_ErrorMessages(t *testing.T) { validator := NewConfigValidator() err := validator.ValidatePositiveInt(-5, "rate_limit") require.Error(t, err) assert.Contains(t, err.Error(), "rate_limit") assert.Contains(t, err.Error(), "must be positive") assert.Contains(t, err.Error(), "got -5") }