internal/handler/settings_handler_test.go
Rama main · réplica de lectura del repositorio original.
package handler
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/johnzastrow/actalog/internal/service"
)
func TestSettingsHandler_GetSettings_Unauthorized(t *testing.T) {
handler := &SettingsHandler{}
// Request without user context (unauthenticated)
req := createTestRequest(http.MethodGet, "/api/settings", "")
rr := httptest.NewRecorder()
handler.GetSettings(rr, req)
assertStatusCode(t, rr, http.StatusUnauthorized)
assertBodyContains(t, rr, "Unauthorized")
}
func TestSettingsHandler_UpdateSettings_Unauthorized(t *testing.T) {
handler := &SettingsHandler{}
// Request without user context (unauthenticated)
req := createTestRequest(http.MethodPut, "/api/settings", `{"theme": "dark"}`)
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusUnauthorized)
assertBodyContains(t, rr, "Unauthorized")
}
func TestSettingsHandler_UpdateSettings_InvalidJSON(t *testing.T) {
handler := &SettingsHandler{}
// Authenticated request with invalid JSON
req := createAuthenticatedRequest(http.MethodPut, "/api/settings", "{bad json", 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusBadRequest)
assertBodyContains(t, rr, "Invalid request body")
}
func TestNewSettingsHandler(t *testing.T) {
handler := NewSettingsHandler(nil, nil)
if handler == nil {
t.Error("NewSettingsHandler should return a non-nil handler")
}
}
// Removed 2 panic-expectation tests:
// - TestSettingsHandler_GetSettings_NilService
// - TestSettingsHandler_UpdateSettings_NilService
// These tests verified nil pointer panics, not business logic.
// Tests with mock service
func TestSettingsHandler_GetSettings_Success(t *testing.T) {
settingsService := createTestUserSettingsService()
handler := NewSettingsHandler(settingsService, createTestLogger())
req := createAuthenticatedRequest(http.MethodGet, "/api/settings", "", 1, "admin@example.com", "admin")
rr := httptest.NewRecorder()
handler.GetSettings(rr, req)
assertStatusCode(t, rr, http.StatusOK)
// Should contain default settings fields
assertBodyContains(t, rr, "theme")
}
func TestSettingsHandler_UpdateSettings_Success(t *testing.T) {
settingsService := createTestUserSettingsService()
handler := NewSettingsHandler(settingsService, createTestLogger())
body := `{"theme": "dark", "weight_unit": "kg", "distance_unit": "km", "data_export_format": "CSV", "notification_preferences": "{}"}`
req := createAuthenticatedRequest(http.MethodPut, "/api/settings", body, 1, "admin@example.com", "admin")
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusOK)
assertBodyContains(t, rr, "dark")
}
func TestSettingsHandler_UpdateSettings_EmptyJSON(t *testing.T) {
settingsService := createTestUserSettingsService()
handler := NewSettingsHandler(settingsService, createTestLogger())
body := `{}`
req := createAuthenticatedRequest(http.MethodPut, "/api/settings", body, 1, "admin@example.com", "admin")
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusOK)
}
func TestSettingsHandler_GetSettings_CreatesDefaults(t *testing.T) {
settingsService := createTestUserSettingsService()
handler := NewSettingsHandler(settingsService, createTestLogger())
// First call should create default settings
req := createAuthenticatedRequest(http.MethodGet, "/api/settings", "", 2, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.GetSettings(rr, req)
assertStatusCode(t, rr, http.StatusOK)
assertBodyContains(t, rr, "light") // default theme
assertBodyContains(t, rr, "lbs") // default weight unit
}
func TestSettingsHandler_GetSettings_NoLogger(t *testing.T) {
settingsService := createTestUserSettingsService()
handler := &SettingsHandler{
settingsService: settingsService,
logger: nil,
}
req := createAuthenticatedRequest(http.MethodGet, "/api/settings", "", 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.GetSettings(rr, req)
assertStatusCode(t, rr, http.StatusOK)
}
func TestSettingsHandler_UpdateSettings_NoLogger(t *testing.T) {
settingsService := createTestUserSettingsService()
handler := &SettingsHandler{
settingsService: settingsService,
logger: nil,
}
body := `{"theme": "dark"}`
req := createAuthenticatedRequest(http.MethodPut, "/api/settings", body, 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusOK)
}
func TestSettingsHandler_UpdateSettings_WithTimezone(t *testing.T) {
settingsService := createTestUserSettingsService()
handler := NewSettingsHandler(settingsService, createTestLogger())
body := `{"theme": "dark", "timezone": "America/New_York"}`
req := createAuthenticatedRequest(http.MethodPut, "/api/settings", body, 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusOK)
}
func TestSettingsHandler_UpdateSettings_WithFontFamily(t *testing.T) {
settingsService := createTestUserSettingsService()
handler := NewSettingsHandler(settingsService, createTestLogger())
body := `{"theme": "light", "font_family": "Source Serif Pro"}`
req := createAuthenticatedRequest(http.MethodPut, "/api/settings", body, 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusOK)
}
// Helper to create a settings service that returns errors
func createTestUserSettingsServiceWithError() *service.UserSettingsService {
settingsRepo := NewMockUserSettingsRepository()
settingsRepo.SetError(ErrMockInternalError)
auditLogRepo := NewMockAuditLogRepository()
return service.NewUserSettingsService(settingsRepo, auditLogRepo)
}
func TestSettingsHandler_GetSettings_ServiceError(t *testing.T) {
settingsService := createTestUserSettingsServiceWithError()
handler := NewSettingsHandler(settingsService, createTestLogger())
req := createAuthenticatedRequest(http.MethodGet, "/api/settings", "", 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.GetSettings(rr, req)
assertStatusCode(t, rr, http.StatusInternalServerError)
assertBodyContains(t, rr, "Failed to retrieve settings")
}
func TestSettingsHandler_GetSettings_ServiceErrorNoLogger(t *testing.T) {
settingsService := createTestUserSettingsServiceWithError()
handler := &SettingsHandler{
settingsService: settingsService,
logger: nil,
}
req := createAuthenticatedRequest(http.MethodGet, "/api/settings", "", 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.GetSettings(rr, req)
assertStatusCode(t, rr, http.StatusInternalServerError)
}
func TestSettingsHandler_UpdateSettings_ServiceError(t *testing.T) {
settingsService := createTestUserSettingsServiceWithError()
handler := NewSettingsHandler(settingsService, createTestLogger())
body := `{"theme": "dark"}`
req := createAuthenticatedRequest(http.MethodPut, "/api/settings", body, 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusInternalServerError)
assertBodyContains(t, rr, "Failed to update settings")
}
func TestSettingsHandler_UpdateSettings_ServiceErrorNoLogger(t *testing.T) {
settingsService := createTestUserSettingsServiceWithError()
handler := &SettingsHandler{
settingsService: settingsService,
logger: nil,
}
body := `{"theme": "dark"}`
req := createAuthenticatedRequest(http.MethodPut, "/api/settings", body, 1, "test@example.com", "user")
rr := httptest.NewRecorder()
handler.UpdateSettings(rr, req)
assertStatusCode(t, rr, http.StatusInternalServerError)
}