package utils import ( "baron-sso-backend/internal/domain" "testing" "github.com/stretchr/testify/assert" ) func TestValidatePasswordWithPolicy(t *testing.T) { policy := &domain.PasswordPolicy{ MinLength: 8, Lowercase: true, Uppercase: true, Number: true, NonAlphanumeric: true, MinCharacterTypes: 3, } t.Run("Valid Password", func(t *testing.T) { err := ValidatePasswordWithPolicy(policy, "Pass1234!") assert.NoError(t, err) }) t.Run("Nil Policy", func(t *testing.T) { err := ValidatePasswordWithPolicy(nil, "") assert.NoError(t, err) }) t.Run("Too Short", func(t *testing.T) { err := ValidatePasswordWithPolicy(policy, "P123!") assert.Error(t, err) assert.Contains(t, err.Error(), "최소 8자") }) t.Run("Missing Lowercase", func(t *testing.T) { err := ValidatePasswordWithPolicy(policy, "PASS1234!") assert.Error(t, err) assert.Contains(t, err.Error(), "소문자") }) t.Run("Missing Uppercase", func(t *testing.T) { err := ValidatePasswordWithPolicy(policy, "pass1234!") assert.Error(t, err) assert.Contains(t, err.Error(), "대문자") }) t.Run("Missing Number", func(t *testing.T) { err := ValidatePasswordWithPolicy(policy, "Password!") assert.Error(t, err) assert.Contains(t, err.Error(), "숫자") }) t.Run("Missing Symbol", func(t *testing.T) { err := ValidatePasswordWithPolicy(policy, "Pass1234") assert.Error(t, err) assert.Contains(t, err.Error(), "특수문자") }) t.Run("Missing Minimum Character Types", func(t *testing.T) { err := ValidatePasswordWithPolicy(&domain.PasswordPolicy{MinLength: 4, MinCharacterTypes: 4}, "abcd") assert.Error(t, err) assert.Contains(t, err.Error(), "4가지") }) } func TestGeneratePasswordWithPolicy(t *testing.T) { policy := &domain.PasswordPolicy{ MinLength: 16, Lowercase: true, Uppercase: true, Number: true, NonAlphanumeric: true, } t.Run("Generate and Validate", func(t *testing.T) { password, err := GeneratePasswordWithPolicy(policy) assert.NoError(t, err) assert.Len(t, password, 16) err = ValidatePasswordWithPolicy(policy, password) assert.NoError(t, err, "Generated password '%s' does not satisfy policy", password) }) t.Run("Nil Policy Uses Default Length", func(t *testing.T) { password, err := GeneratePasswordWithPolicy(nil) assert.NoError(t, err) assert.Len(t, password, 12) }) t.Run("Minimum Character Types Adds Optional Categories", func(t *testing.T) { policy := &domain.PasswordPolicy{ MinLength: 4, Lowercase: true, MinCharacterTypes: 4, } password, err := GeneratePasswordWithPolicy(policy) assert.NoError(t, err) assert.Len(t, password, 4) assert.NoError(t, ValidatePasswordWithPolicy(policy, password)) }) t.Run("Required Categories Raise Short Minimum Length", func(t *testing.T) { policy := &domain.PasswordPolicy{ MinLength: 1, Lowercase: true, Uppercase: true, Number: true, NonAlphanumeric: true, } password, err := GeneratePasswordWithPolicy(policy) assert.NoError(t, err) assert.Len(t, password, 4) assert.NoError(t, ValidatePasswordWithPolicy(policy, password)) }) } func TestPasswordPolicyRandomHelpersRejectInvalidInput(t *testing.T) { _, err := randomIndex(0) assert.Error(t, err) _, err = randomChar("") assert.Error(t, err) assert.NoError(t, shuffleRunes([]rune("a"))) }