127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
package database
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestGenerateRandomPassword(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
length int
|
|
}{
|
|
{"Short password", 8},
|
|
{"Medium password", 16},
|
|
{"Long password", 32},
|
|
{"Very short password", 3},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
password, err := GenerateRandomPassword(tt.length)
|
|
if err != nil {
|
|
t.Fatalf("GenerateRandomPassword() error = %v", err)
|
|
}
|
|
|
|
if len(password) != tt.length {
|
|
t.Errorf("Password length = %v, want %v", len(password), tt.length)
|
|
}
|
|
|
|
// For passwords >= 4 chars, check complexity
|
|
if tt.length >= 4 {
|
|
hasUpper := false
|
|
hasLower := false
|
|
hasDigit := false
|
|
hasSpecial := false
|
|
|
|
for _, char := range password {
|
|
switch {
|
|
case char >= 'A' && char <= 'Z':
|
|
hasUpper = true
|
|
case char >= 'a' && char <= 'z':
|
|
hasLower = true
|
|
case char >= '0' && char <= '9':
|
|
hasDigit = true
|
|
case strings.ContainsRune("!@#$%^&*()_+-=[]{}|;:,.<>?", char):
|
|
hasSpecial = true
|
|
}
|
|
}
|
|
|
|
if !hasUpper || !hasLower || !hasDigit || !hasSpecial {
|
|
t.Errorf("Password lacks required complexity: upper=%v, lower=%v, digit=%v, special=%v",
|
|
hasUpper, hasLower, hasDigit, hasSpecial)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenerateRandomPasswordUniqueness(t *testing.T) {
|
|
// Generate multiple passwords and ensure they're different
|
|
passwords := make(map[string]bool)
|
|
const numPasswords = 100
|
|
|
|
for i := 0; i < numPasswords; i++ {
|
|
password, err := GenerateRandomPassword(16)
|
|
if err != nil {
|
|
t.Fatalf("GenerateRandomPassword() error = %v", err)
|
|
}
|
|
|
|
if passwords[password] {
|
|
t.Errorf("Duplicate password generated: %s", password)
|
|
}
|
|
passwords[password] = true
|
|
}
|
|
}
|
|
|
|
func TestHashPassword(t *testing.T) {
|
|
password := "testPassword123!"
|
|
|
|
hash, err := HashPassword(password)
|
|
if err != nil {
|
|
t.Fatalf("HashPassword() error = %v", err)
|
|
}
|
|
|
|
// Check that hash has correct format
|
|
if !strings.HasPrefix(hash, "$argon2id$") {
|
|
t.Errorf("Hash doesn't have correct prefix: %s", hash)
|
|
}
|
|
|
|
// Verify password
|
|
valid, err := VerifyPassword(password, hash)
|
|
if err != nil {
|
|
t.Fatalf("VerifyPassword() error = %v", err)
|
|
}
|
|
if !valid {
|
|
t.Error("VerifyPassword() returned false for correct password")
|
|
}
|
|
|
|
// Verify wrong password fails
|
|
valid, err = VerifyPassword("wrongPassword", hash)
|
|
if err != nil {
|
|
t.Fatalf("VerifyPassword() error = %v", err)
|
|
}
|
|
if valid {
|
|
t.Error("VerifyPassword() returned true for wrong password")
|
|
}
|
|
}
|
|
|
|
func TestHashPasswordUniqueness(t *testing.T) {
|
|
password := "testPassword123!"
|
|
|
|
// Same password should produce different hashes due to salt
|
|
hash1, err := HashPassword(password)
|
|
if err != nil {
|
|
t.Fatalf("HashPassword() error = %v", err)
|
|
}
|
|
|
|
hash2, err := HashPassword(password)
|
|
if err != nil {
|
|
t.Fatalf("HashPassword() error = %v", err)
|
|
}
|
|
|
|
if hash1 == hash2 {
|
|
t.Error("Same password produced identical hashes (salt not working)")
|
|
}
|
|
}
|