""" Unit Tests - Pydantic Schemas - ServiceManagerWeb Tests para validación de schemas en app.api.schemas. No requieren base de datos ni red. """ import pytest from pydantic import ValidationError import uuid # ============================================================ # AUTH SCHEMAS # ============================================================ class TestAuthSchemas: """Tests para schemas de autenticación.""" def test_login_request_valid(self): """LoginRequest acepta datos válidos.""" from app.api.schemas.auth import LoginRequest schema = LoginRequest( email="user@example.com", password="Pass123!", tenant_slug="my-tenant", ) assert schema.email == "user@example.com" assert schema.tenant_slug == "my-tenant" assert schema.totp_code is None def test_login_request_invalid_email(self): """LoginRequest rechaza email inválido.""" from app.api.schemas.auth import LoginRequest with pytest.raises(ValidationError): LoginRequest(email="not-an-email", password="Pass123!", tenant_slug="t") def test_login_request_with_totp(self): """LoginRequest acepta código TOTP opcional.""" from app.api.schemas.auth import LoginRequest schema = LoginRequest( email="user@example.com", password="Pass123!", tenant_slug="my-tenant", totp_code="123456", ) assert schema.totp_code == "123456" def test_token_response_default_type(self): """TokenResponse tiene token_type=bearer por defecto.""" from app.api.schemas.auth import TokenResponse schema = TokenResponse(access_token="abc123", expires_in=3600) assert schema.token_type == "bearer" # ============================================================ # TENANT SCHEMAS # ============================================================ class TestTenantSchemas: """Tests para schemas de tenants.""" def test_tenant_create_valid(self): """TenantCreate acepta datos mínimos válidos.""" from app.api.schemas.tenant import TenantCreate schema = TenantCreate(name="ACME Corp", slug="acme-corp") assert schema.name == "ACME Corp" assert schema.slug == "acme-corp" assert schema.domain is None def test_tenant_create_with_all_fields(self): """TenantCreate acepta todos los campos opcionales.""" from app.api.schemas.tenant import TenantCreate schema = TenantCreate( name="ACME Corp", slug="acme-corp", domain="acme.com", contact_email="admin@acme.com", contact_phone="+1234567890", ) assert schema.contact_email == "admin@acme.com" def test_tenant_create_invalid_email(self): """TenantCreate rechaza email de contacto inválido.""" from app.api.schemas.tenant import TenantCreate with pytest.raises(ValidationError): TenantCreate(name="Corp", slug="corp", contact_email="bad-email") def test_tenant_update_all_optional(self): """TenantUpdate permite actualización parcial (todos opcionales).""" from app.api.schemas.tenant import TenantUpdate schema = TenantUpdate() assert schema.name is None assert schema.slug is None assert schema.status is None def test_tenant_update_only_name(self): """TenantUpdate permite actualizar solo el nombre.""" from app.api.schemas.tenant import TenantUpdate schema = TenantUpdate(name="New Name") assert schema.name == "New Name" assert schema.slug is None # ============================================================ # USER SCHEMAS # ============================================================ class TestUserSchemas: """Tests para schemas de usuarios.""" def test_user_create_valid(self): """UserCreate acepta datos válidos con defaults.""" from app.api.schemas.user import UserCreate from app.models.user import UserRole schema = UserCreate( email="agent@company.com", first_name="John", last_name="Doe", role=UserRole.AGENT, password="SecurePass123!", ) assert schema.email == "agent@company.com" assert schema.language == "es" assert schema.timezone == "UTC" assert schema.notifications_email is True def test_user_create_invalid_email(self): """UserCreate rechaza email inválido.""" from app.api.schemas.user import UserCreate from app.models.user import UserRole with pytest.raises(ValidationError): UserCreate( email="not-valid", first_name="John", last_name="Doe", role=UserRole.AGENT, password="Pass123!", ) def test_user_create_invalid_role(self): """UserCreate rechaza rol inválido.""" from app.api.schemas.user import UserCreate with pytest.raises(ValidationError): UserCreate( email="user@test.com", first_name="John", last_name="Doe", role="SUPER_VILLAIN", password="Pass123!", ) def test_user_update_all_optional(self): """UserUpdate permite actualización parcial.""" from app.api.schemas.user import UserUpdate schema = UserUpdate() assert schema.email is None assert schema.first_name is None assert schema.is_active is None # ============================================================ # TICKET SCHEMAS # ============================================================ class TestTicketSchemas: """Tests para schemas de tickets.""" def test_ticket_create_valid_minimal(self): """TicketCreate acepta datos mínimos con priority por defecto.""" from app.api.schemas.ticket import TicketCreate schema = TicketCreate( subject="Mi impresora no funciona", description="La impresora del piso 3 no enciende desde esta mañana.", ) assert schema.subject == "Mi impresora no funciona" assert schema.priority == "MEDIUM" assert schema.category_id is None assert schema.affected_system_id is None def test_ticket_create_with_priority(self): """TicketCreate acepta prioridad personalizada.""" from app.api.schemas.ticket import TicketCreate schema = TicketCreate( subject="Sistema caído", description="El sistema principal no responde.", priority="URGENT", ) assert schema.priority == "URGENT" def test_ticket_update_all_optional(self): """TicketUpdate permite actualización parcial.""" from app.api.schemas.ticket import TicketUpdate schema = TicketUpdate() assert schema.subject is None assert schema.status is None assert schema.assigned_to is None def test_ticket_close_request_optional_resolution(self): """TicketCloseRequest acepta resolución vacía.""" from app.api.schemas.ticket import TicketCloseRequest schema = TicketCloseRequest() assert schema.resolution is None def test_comment_create_defaults(self): """CommentCreate tiene is_internal=False por defecto.""" from app.api.schemas.ticket import CommentCreate schema = CommentCreate(content="Este es un comentario de prueba.") assert schema.is_internal is False def test_comment_create_internal(self): """CommentCreate acepta comentario interno.""" from app.api.schemas.ticket import CommentCreate schema = CommentCreate(content="Nota interna.", is_internal=True) assert schema.is_internal is True # ============================================================ # CATEGORY SCHEMAS # ============================================================ class TestCategorySchemas: """Tests para schemas de categorías.""" def test_category_create_defaults(self): """CategoryCreate tiene SLAs por defecto correctos.""" from app.api.schemas.category import CategoryCreate schema = CategoryCreate(name="Hardware") assert schema.sla_response_hours == 24 assert schema.sla_resolution_hours == 72 assert schema.is_active if hasattr(schema, "is_active") else True def test_category_create_custom_sla(self): """CategoryCreate acepta SLAs personalizados.""" from app.api.schemas.category import CategoryCreate schema = CategoryCreate( name="Urgente", sla_response_hours=1, sla_resolution_hours=4, ) assert schema.sla_response_hours == 1 assert schema.sla_resolution_hours == 4 # ============================================================ # SYSTEM SCHEMAS # ============================================================ class TestSystemSchemas: """Tests para schemas de sistemas.""" def test_system_create_valid(self): """SystemCreate acepta datos válidos.""" from app.api.schemas.system import SystemCreate schema = SystemCreate(name="ERP Principal") assert schema.name == "ERP Principal" assert schema.description is None def test_system_update_all_optional(self): """SystemUpdate permite actualización parcial.""" from app.api.schemas.system import SystemUpdate schema = SystemUpdate(is_active=False) assert schema.is_active is False assert schema.name is None