package models import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestUser_SetPassword(t *testing.T) { user := &User{} err := user.SetPassword("testPassword123") require.NoError(t, err) assert.NotEmpty(t, user.Password) assert.NotEqual(t, "testPassword123", user.Password) // Should be hashed } func TestUser_CheckPassword(t *testing.T) { user := &User{} err := user.SetPassword("correctpassword") require.NoError(t, err) tests := []struct { name string password string expected bool }{ {"correct password", "correctpassword", true}, {"wrong password", "wrongpassword", false}, {"empty password", "", false}, {"similar password", "correctpassword1", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := user.CheckPassword(tt.password) assert.Equal(t, tt.expected, result) }) } } func TestUser_GetFullName(t *testing.T) { tests := []struct { name string user User expected string }{ { name: "first and last name", user: User{FirstName: "John", LastName: "Doe", Username: "johndoe"}, expected: "John Doe", }, { name: "first name only", user: User{FirstName: "John", LastName: "", Username: "johndoe"}, expected: "John", }, { name: "username fallback", user: User{FirstName: "", LastName: "", Username: "johndoe"}, expected: "johndoe", }, { name: "last name only returns username", user: User{FirstName: "", LastName: "Doe", Username: "johndoe"}, expected: "johndoe", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.user.GetFullName() assert.Equal(t, tt.expected, result) }) } } func TestUser_TableName(t *testing.T) { user := User{} assert.Equal(t, "auth_user", user.TableName()) } func TestAuthToken_TableName(t *testing.T) { token := AuthToken{} assert.Equal(t, "user_authtoken", token.TableName()) } func TestUserProfile_TableName(t *testing.T) { profile := UserProfile{} assert.Equal(t, "user_userprofile", profile.TableName()) } func TestConfirmationCode_IsValid(t *testing.T) { now := time.Now().UTC() future := now.Add(1 * time.Hour) past := now.Add(-1 * time.Hour) tests := []struct { name string code ConfirmationCode expected bool }{ { name: "valid code", code: ConfirmationCode{IsUsed: false, ExpiresAt: future}, expected: true, }, { name: "used code", code: ConfirmationCode{IsUsed: true, ExpiresAt: future}, expected: false, }, { name: "expired code", code: ConfirmationCode{IsUsed: false, ExpiresAt: past}, expected: false, }, { name: "used and expired", code: ConfirmationCode{IsUsed: true, ExpiresAt: past}, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.code.IsValid() assert.Equal(t, tt.expected, result) }) } } func TestPasswordResetCode_IsValid(t *testing.T) { now := time.Now().UTC() future := now.Add(1 * time.Hour) past := now.Add(-1 * time.Hour) tests := []struct { name string code PasswordResetCode expected bool }{ { name: "valid code", code: PasswordResetCode{Used: false, ExpiresAt: future, Attempts: 0, MaxAttempts: 5}, expected: true, }, { name: "used code", code: PasswordResetCode{Used: true, ExpiresAt: future, Attempts: 0, MaxAttempts: 5}, expected: false, }, { name: "expired code", code: PasswordResetCode{Used: false, ExpiresAt: past, Attempts: 0, MaxAttempts: 5}, expected: false, }, { name: "max attempts reached", code: PasswordResetCode{Used: false, ExpiresAt: future, Attempts: 5, MaxAttempts: 5}, expected: false, }, { name: "attempts under max", code: PasswordResetCode{Used: false, ExpiresAt: future, Attempts: 4, MaxAttempts: 5}, expected: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.code.IsValid() assert.Equal(t, tt.expected, result) }) } } func TestPasswordResetCode_SetAndCheckCode(t *testing.T) { code := &PasswordResetCode{} err := code.SetCode("123456") require.NoError(t, err) assert.NotEmpty(t, code.CodeHash) // Check correct code assert.True(t, code.CheckCode("123456")) // Check wrong code assert.False(t, code.CheckCode("654321")) assert.False(t, code.CheckCode("")) } func TestGenerateConfirmationCode(t *testing.T) { code := GenerateConfirmationCode() assert.Len(t, code, 6) // Generate multiple codes and ensure they're different codes := make(map[string]bool) for i := 0; i < 10; i++ { c := GenerateConfirmationCode() assert.Len(t, c, 6) codes[c] = true } // Most codes should be unique (very unlikely to have collisions) assert.Greater(t, len(codes), 5) } func TestGenerateResetToken(t *testing.T) { token := GenerateResetToken() assert.Len(t, token, 64) // 32 bytes = 64 hex chars // Ensure uniqueness token2 := GenerateResetToken() assert.NotEqual(t, token, token2) }