initial
This commit is contained in:
126
internal/database/password_test.go
Normal file
126
internal/database/password_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
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)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user