Ctrl K
ComunidadGuías…

internal/handler/settings_handler_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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)
}