Files
goplt/services/identity/internal/password/password_test.go

211 lines
4.8 KiB
Go

package password
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestHash(t *testing.T) {
t.Parallel()
tests := []struct {
name string
password string
wantErr bool
}{
{
name: "valid password",
password: "testpassword123",
wantErr: false,
},
{
name: "empty password",
password: "",
wantErr: false, // Empty password is valid, just hashed
},
{
name: "long password",
password: "this is a very long password with many characters and symbols !@#$%^&*()",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hash, err := Hash(tt.password)
if tt.wantErr {
require.Error(t, err)
assert.Empty(t, hash)
} else {
require.NoError(t, err)
assert.NotEmpty(t, hash)
// Verify hash format: $argon2id$v=19$m=65536,t=3,p=4$salt$hash
assert.Contains(t, hash, "$argon2id$")
assert.Contains(t, hash, "v=19")
assert.Contains(t, hash, "m=65536")
assert.Contains(t, hash, "t=3")
assert.Contains(t, hash, "p=4")
}
})
}
}
func TestVerify(t *testing.T) {
t.Parallel()
tests := []struct {
name string
password string
hash string
want bool
wantErr bool
skip bool
}{
{
name: "correct password",
password: "testpassword123",
hash: "", // Will be generated
want: true,
wantErr: false,
},
{
name: "incorrect password",
password: "wrongpassword",
hash: "", // Will be generated from different password
want: false,
wantErr: false,
},
{
name: "invalid hash format - too few parts",
password: "testpassword123",
hash: "$argon2id$v=19$m=65536",
want: false,
wantErr: true,
},
{
name: "invalid hash format - wrong algorithm",
password: "testpassword123",
hash: "$bcrypt$v=19$m=65536,t=3,p=4$salt$hash",
want: false,
wantErr: true,
},
{
name: "invalid hash format - malformed version",
password: "testpassword123",
hash: "$argon2id$v=invalid$m=65536,t=3,p=4$salt$hash",
want: false,
wantErr: true,
},
{
name: "invalid hash format - malformed parameters",
password: "testpassword123",
hash: "$argon2id$v=19$m=invalid,t=3,p=4$salt$hash",
want: false,
wantErr: true,
},
{
name: "invalid hash format - invalid base64 salt",
password: "testpassword123",
hash: "$argon2id$v=19$m=65536,t=3,p=4$invalid-base64$hash",
want: false,
wantErr: true,
},
{
name: "invalid hash format - invalid base64 hash",
password: "testpassword123",
hash: "", // Will be generated and then corrupted
want: false,
wantErr: true,
skip: true, // Skip this test - corrupting base64 is complex
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Skip test if marked
if tt.skip {
t.Skip("Skipping test")
}
var hash string
var err error
// Generate hash if needed
if tt.hash == "" {
if tt.name == "incorrect password" {
// Generate hash for a different password
hash, err = Hash("differentpassword")
require.NoError(t, err)
} else {
hash, err = Hash(tt.password)
require.NoError(t, err)
}
} else {
hash = tt.hash
}
// Verify
got, err := Verify(tt.password, hash)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
assert.Equal(t, tt.want, got)
})
}
}
func TestHash_Verify_RoundTrip(t *testing.T) {
t.Parallel()
passwords := []string{
"testpassword123",
"",
"!@#$%^&*()",
"very long password with spaces and special characters !@#$%^&*()_+-=[]{}|;:,.<>?",
"unicode-测试-пароль",
}
for _, password := range passwords {
t.Run(password, func(t *testing.T) {
hash, err := Hash(password)
require.NoError(t, err)
assert.NotEmpty(t, hash)
// Verify the same password
valid, err := Verify(password, hash)
require.NoError(t, err)
assert.True(t, valid, "Password should verify correctly")
// Verify different password
invalid, err := Verify("wrongpassword", hash)
require.NoError(t, err)
assert.False(t, invalid, "Wrong password should not verify")
})
}
}
func TestHash_Uniqueness(t *testing.T) {
t.Parallel()
password := "testpassword123"
hashes := make(map[string]bool)
// Generate multiple hashes for the same password
// They should be different due to random salt
for i := 0; i < 10; i++ {
hash, err := Hash(password)
require.NoError(t, err)
assert.NotContains(t, hashes, hash, "Each hash should be unique due to random salt")
hashes[hash] = true
// But all should verify correctly
valid, err := Verify(password, hash)
require.NoError(t, err)
assert.True(t, valid, "All hashes should verify correctly")
}
}