Files
Charon/backend/internal/models/auth_user_test.go

133 lines
3.6 KiB
Go

package models
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func setupAuthUserTestDB(t *testing.T) *gorm.DB {
dsn := filepath.Join(t.TempDir(), "test.db") + "?_busy_timeout=5000&_journal_mode=WAL"
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
require.NoError(t, err)
require.NoError(t, db.AutoMigrate(&AuthUser{}))
return db
}
func TestAuthUser_BeforeCreate(t *testing.T) {
db := setupAuthUserTestDB(t)
t.Run("generates UUID when empty", func(t *testing.T) {
user := &AuthUser{
Username: "testuser",
Email: "test@example.com",
PasswordHash: "hash",
}
require.NoError(t, db.Create(user).Error)
assert.NotEmpty(t, user.UUID)
assert.Len(t, user.UUID, 36) // UUID format
})
t.Run("keeps existing UUID", func(t *testing.T) {
customUUID := "custom-uuid-value"
user := &AuthUser{
UUID: customUUID,
Username: "testuser2",
Email: "test2@example.com",
PasswordHash: "hash",
}
require.NoError(t, db.Create(user).Error)
assert.Equal(t, customUUID, user.UUID)
})
}
func TestAuthUser_SetPassword(t *testing.T) {
t.Run("hashes password", func(t *testing.T) {
user := &AuthUser{}
err := user.SetPassword("mypassword123")
require.NoError(t, err)
assert.NotEmpty(t, user.PasswordHash)
assert.NotEqual(t, "mypassword123", user.PasswordHash)
// bcrypt hashes start with $2a$ or $2b$
assert.Contains(t, user.PasswordHash, "$2a$")
})
t.Run("empty password", func(t *testing.T) {
user := &AuthUser{}
err := user.SetPassword("")
require.NoError(t, err)
assert.NotEmpty(t, user.PasswordHash)
})
}
func TestAuthUser_CheckPassword(t *testing.T) {
user := &AuthUser{}
require.NoError(t, user.SetPassword("correctpassword"))
t.Run("correct password returns true", func(t *testing.T) {
assert.True(t, user.CheckPassword("correctpassword"))
})
t.Run("wrong password returns false", func(t *testing.T) {
assert.False(t, user.CheckPassword("wrongpassword"))
})
t.Run("empty password returns false", func(t *testing.T) {
assert.False(t, user.CheckPassword(""))
})
}
func TestAuthUser_HasRole(t *testing.T) {
t.Run("empty roles returns false", func(t *testing.T) {
user := &AuthUser{Roles: ""}
assert.False(t, user.HasRole("admin"))
})
t.Run("single role match", func(t *testing.T) {
user := &AuthUser{Roles: "admin"}
assert.True(t, user.HasRole("admin"))
assert.False(t, user.HasRole("user"))
})
t.Run("multiple roles", func(t *testing.T) {
user := &AuthUser{Roles: "admin,user,editor"}
assert.True(t, user.HasRole("admin"))
assert.True(t, user.HasRole("user"))
assert.True(t, user.HasRole("editor"))
assert.False(t, user.HasRole("guest"))
})
t.Run("roles with spaces", func(t *testing.T) {
user := &AuthUser{Roles: "admin, user, editor"}
assert.True(t, user.HasRole("admin"))
assert.True(t, user.HasRole("user"))
assert.True(t, user.HasRole("editor"))
})
}
func TestSplitRoles(t *testing.T) {
tests := []struct {
name string
input string
expected []string
}{
{"empty string", "", []string{}},
{"single role", "admin", []string{"admin"}},
{"multiple roles", "admin,user", []string{"admin", "user"}},
{"with spaces", "admin, user, editor", []string{"admin", "user", "editor"}},
{"trailing comma", "admin,user,", []string{"admin", "user"}},
{"leading comma", ",admin,user", []string{"admin", "user"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := splitRoles(tt.input)
assert.Equal(t, tt.expected, result)
})
}
}